void GBStackBrain::FirePeriodic(GBSensorState & sensor, GBWorld * world) { GBFrames period = PopInteger(); if ( world->CurrentFrame() >= sensor.Time() + period || sensor.Time() <= 0 ) { sensor.Fire(); remaining = 0; PushBoolean(true); } else PushBoolean(false); }
/*========================================================================= * FUNCTION: tVM_Execute * TYPE: public interface * OVERVIEW: execute a basic function * INTERFACE: * parameters: * returns: * the result of the basic function *=======================================================================*/ int tVM_Execute() { int running = 1; u8 bytecode; u8 type; u8 ac_flag; s32 integer; s32 stackindex,index; tVMValue value1,value2,value3; tVMValue retValue;// = (tVMValue*)mem_alloc(sizeof(tVMValue)); /* initialize the running Stack FP */ setFP(FirstFP); /* seek to the entry function */ setFI(0); /* initialize the code reader */ tVM_InitializeCodeReader(); /* execute the byte codes in loop */ while(running) { bytecode = ReadCode(); switch(bytecode) { case C_NOP: break; case C_CONST: { ReadVMValue(&value1); PushVMValue(&value1); break; } case C_LOAD: { ac_flag =ReadAccessFlag(); if(ac_flag == ACCESS_FLAG_GLOBAL) stackindex = ReadIndex(); else stackindex = ReadIndex() + getFP(); LoadVMValue(stackindex,&value1); PushVMValue(&value1); break; } case C_STORE: { ac_flag =ReadAccessFlag(); if(ac_flag == ACCESS_FLAG_GLOBAL) stackindex = ReadIndex(); else stackindex = ReadIndex() + getFP(); PopVMValue(&value1); /* pop the source value */ StoreVMValue(stackindex,&value1); break; } case C_HEAP_LOAD: { type = ReadDataType(); PopVMValue(&value2); /* Pop Addr */ PopVMValue(&value1); /* Pop Base */ tVMValue_HeapLoad(value1.value.ptr_val+value2.value.int_val,type,&value3); /* load the heap memory */ PushVMValue(&value3); /* push the loaded value */ break; } case C_HEAP_STORE: { ptr32 addr; type = ReadDataType(); PopVMValue(&value3); /* Pop Addr */ PopVMValue(&value2); /* Pop Base */ PopVMValue(&value1); /* Pop Value */ addr = (ptr32)(value2.value.ptr_val + value3.value.int_val); if(value1.type != type) { tVMValue_ConvertType(&value1,type); } tVMValue_HeapStore(addr,&value1); break; } case C_FORCE_LOAD: { ac_flag =ReadAccessFlag(); if(ac_flag == ACCESS_FLAG_GLOBAL) stackindex = ReadIndex(); else stackindex = ReadIndex() + getFP(); type = ReadDataType(); ForceLoadVMValue(stackindex,type,&value1); PushVMValue(&value1); break; } case C_ALLOC: { PopVMValue(&value1); value2.type = PtrType; value2.value.ptr_val = (ptr32)mem_alloc(value1.value.int_val); memset(value2.value.ptr_val,0,value1.value.int_val); PushVMValue(&value2); break; } case C_ALLOC_ARRAY: { s32 i; s32 dimension; s32* index_ranges; dimension = ReadInteger(); if(dimension < 1) break; index_ranges = (s32*)mem_alloc(sizeof(s32)*dimension); for(i=0;i<dimension;i++) { PopVMValue(&value1); index_ranges[dimension-i-1] = value1.value.int_val; } value1.type = PtrType; value1.value.ptr_val = tVMValue_HeapAllocMultiArray(dimension,index_ranges,0); PushVMValue(&value1); mem_free(index_ranges); break; } case C_FREE: { PopVMValue(&value1); if(value1.value.ptr_val != NULL) mem_free(value1.value.ptr_val); break; } case C_FREE_ARRAY: { break; } case C_PUSH: { value1.type = ReadDataType(); value1.value.int_val = 0; PushVMValue(&value1); break; } case C_POP: { s32 i; integer = ReadInteger(); for(i=0;i<integer;i++) { PopVMValue(&value1); tVMValue_FreeSelf(&value1); } break; } case C_POP_RESTOP: { s32 i; integer = ReadInteger(); PopVMValue(&value2); /* reserve top value */ for(i=0;i<integer;i++) { PopVMValue(&value1); tVMValue_FreeSelf(&value1); } PushVMValue(&value2); /* push back top value */ break; } case C_CONVERT: { u8 type = (u8)ReadDataType(); PopVMValue(&value1); tVMValue_ConvertType(&value1,type); PushVMValue(&value1); break; } case C_ADD: { PopVMValue(&value2); PopVMValue(&value1); tVMValue_Add(&value1,&value2,&value3); PushVMValue(&value3); tVMValue_FreeSelf(&value1); tVMValue_FreeSelf(&value2); break; } case C_SUB: { PopVMValue(&value2); PopVMValue(&value1); tVMValue_Sub(&value1,&value2,&value3); PushVMValue(&value3); tVMValue_FreeSelf(&value1); tVMValue_FreeSelf(&value2); break; } case C_MUL: { PopVMValue(&value2); PopVMValue(&value1); tVMValue_Mul(&value1,&value2,&value3); PushVMValue(&value3); tVMValue_FreeSelf(&value1); tVMValue_FreeSelf(&value2); break; } case C_DIV: { PopVMValue(&value2); PopVMValue(&value1); tVMValue_Div(&value1,&value2,&value3); PushVMValue(&value3); tVMValue_FreeSelf(&value1); tVMValue_FreeSelf(&value2); break; } case C_MOD: { PopVMValue(&value2); PopVMValue(&value1); tVMValue_Mod(&value1,&value2,&value3); PushVMValue(&value3); tVMValue_FreeSelf(&value1); tVMValue_FreeSelf(&value2); break; } case C_OPP: { PopVMValue(&value1); tVMValue_Opp(&value1,&value2); PushVMValue(&value2); tVMValue_FreeSelf(&value1); break; } case C_AND: { PopVMValue(&value2); PopVMValue(&value1); tVMValue_AND(&value1,&value2,&value3); PushVMValue(&value3); tVMValue_FreeSelf(&value1); tVMValue_FreeSelf(&value2); break; } case C_OR: { PopVMValue(&value2); PopVMValue(&value1); tVMValue_OR(&value1,&value2,&value3); PushVMValue(&value3); tVMValue_FreeSelf(&value1); tVMValue_FreeSelf(&value2); break; } case C_EQ: { PopVMValue(&value2); PopVMValue(&value1); tVMValue_EQ(&value1,&value2,&value3); PushVMValue(&value3); tVMValue_FreeSelf(&value1); tVMValue_FreeSelf(&value2); break; } case C_NOT_EQ: { PopVMValue(&value2); PopVMValue(&value1); tVMValue_NOTEQ(&value1,&value2,&value3); PushVMValue(&value3); tVMValue_FreeSelf(&value1); tVMValue_FreeSelf(&value2); break; } case C_LT: { PopVMValue(&value2); PopVMValue(&value1); tVMValue_LT(&value1,&value2,&value3); PushVMValue(&value3); tVMValue_FreeSelf(&value1); tVMValue_FreeSelf(&value2); break; } case C_LG: { PopVMValue(&value2); PopVMValue(&value1); tVMValue_LG(&value1,&value2,&value3); PushVMValue(&value3); tVMValue_FreeSelf(&value1); tVMValue_FreeSelf(&value2); break; } case C_LT_EQ: { PopVMValue(&value2); PopVMValue(&value1); tVMValue_LTEQ(&value1,&value2,&value3); PushVMValue(&value3); tVMValue_FreeSelf(&value1); tVMValue_FreeSelf(&value2); break; } case C_LG_EQ: { PopVMValue(&value2); PopVMValue(&value1); tVMValue_LGEQ(&value1,&value2,&value3); PushVMValue(&value3); tVMValue_FreeSelf(&value1); tVMValue_FreeSelf(&value2); break; } case C_FJP: { s32 size = ReadIndex(); PopVMValue(&value1); if(value1.value.int_val == 0) /* if it is false */ addIP(size); break; } case C_TJP: { s32 size = ReadIndex(); PopVMValue(&value1); if(value1.value.int_val != 0) /* if it is true */ addIP(size); break; } case C_JMP: { s32 size = ReadIndex(); addIP(size); break; } case C_CALL: { /* read function name */ integer = ReadIndex(); /* push the stack frame */ PushInteger(getIP()); PushInteger(getFI()); PushInteger(getFP()); /* goto the call function code */ tVM_ReleaseCodeReader(); setFI(integer); tVM_InitializeCodeReader(); /* set new FP,RP */ setFP(getSP()); break; } case C_INVOKE: { /* read function name */ index = ReadIndex(); /* execute the native function */ tNativeFunction_Invoke(index); break; } case C_RET: { u32 param_bytes = ReadIndex(); /* get the result of the function */ retValue.type = NullType; PopVMValue(&retValue); /* if this is the start function,then exit the loop */ if(getFP() == FirstFP) { running = 0; /* set flag to stop while */ break; } /* restore last stack frame and return to last function code */ tVM_ReleaseCodeReader(); PopInteger(integer); setFP(integer); PopInteger(integer); setFI(integer); tVM_InitializeCodeReader(); PopInteger(integer); setIP(integer); /* pop the old parameters */ PopBytes(param_bytes); /* push back result of last function */ PushVMValue(&retValue); break; } } } /* close the code reader */ tVM_ReleaseCodeReader(); return 1; }
void GBStackBrain::ExecutePrimitive(GBSymbolIndex index, GBRobot * robot, GBWorld * world) { GBStackDatum temp, temp2, temp3; long tempInt; switch ( index ) { case opNop: break; // stack manipulation case opDrop: Pop(); break; case op2Drop: Pop(); Pop(); break; case opNip: temp = Pop(); Pop(); Push(temp); break; case opRDrop: PopReturn(); break; case opDropN: { int n = PopInteger(); if ( n > stackHeight ) throw GBBadArgumentError(); stackHeight -= n; } break; case opSwap: temp = Pop(); temp2 = Pop(); Push(temp); Push(temp2); break; case op2Swap: { GBVector v1 = PopVector(); GBVector v2 = PopVector(); PushVector(v1); PushVector(v2); } break; case opRotate: temp = Pop(); temp2 = Pop(); temp3 = Pop(); Push(temp2); Push(temp); Push(temp3); break; case opReverseRotate: temp = Pop(); temp2 = Pop(); temp3 = Pop(); Push(temp); Push(temp3); Push(temp2); break; case opDup: temp = Peek(); Push(temp); break; case op2Dup: temp = Peek(2); temp2 = Peek(); Push(temp); Push(temp2); break; case opTuck: temp = Pop(); temp2 = Pop(); Push(temp); Push(temp2); Push(temp); break; case opOver: temp = Peek(2); Push(temp); break; case op2Over: temp = Peek(4); temp2 = Peek(3); Push(temp); Push(temp2); break; case opStackHeight: Push(stackHeight); break; case opStackLimit: Push(kStackLimit); break; case opPick: Push(Peek(PopInteger())); break; case opToReturn: PushReturn(ToAddress(Pop())); break; case opFromReturn: Push(PopReturn()); break; // branches case opJump: pc = ToAddress(Pop()); break; case opCall: ExecuteCall(ToAddress(Pop())); break; case opReturn: pc = PopReturn(); break; case opIfGo: temp = Pop(); if ( Pop().Nonzero() ) pc = ToAddress(temp); break; case opIfElseGo: temp = Pop(); temp2 = Pop(); if ( Pop().Nonzero() ) pc = ToAddress(temp2); else pc = ToAddress(temp); break; case opIfCall: temp = Pop(); if ( Pop().Nonzero() ) ExecuteCall(ToAddress(temp)); break; case opIfElseCall: temp = Pop(); temp2 = Pop(); if ( Pop().Nonzero() ) ExecuteCall(ToAddress(temp2)); else ExecuteCall(ToAddress(temp)); break; case opIfReturn: if ( Pop().Nonzero() ) pc = PopReturn(); break; case opNotIfGo: temp = Pop(); if ( ! Pop().Nonzero() ) pc = ToAddress(temp); break; case opNotIfReturn: if ( ! Pop().Nonzero() ) pc = PopReturn(); break; case opNotIfCall: temp = Pop(); if ( ! Pop().Nonzero() ) ExecuteCall(ToAddress(temp)); break; // arithmetic case opAdd: TwoNumberToNumberOp(&GBNumber::operator +); break; case opSubtract: TwoNumberToNumberOp(&GBNumber::operator -); break; case opNegate: NumberToNumberOp(&GBNumber::operator -); break; // mult and divide are written out because of MrCpp internal error case opMultiply: temp = Pop(); Push(Pop() * temp); break; case opDivide: temp = Pop(); Push(Pop() / temp); break; case opReciprocal: Push(GBNumber(1) / Pop()); break; case opMod: TwoNumberToNumberOp(&GBNumber::Mod); break; case opRem: TwoNumberToNumberOp(&GBNumber::Rem); break; case opSqrt: NumberToNumberOp(&GBNumber::Sqrt); break; case opExponent: TwoNumberToNumberOp(&GBNumber::Exponent); break; case opIsInteger: PushBoolean(Pop().IsInteger()); break; case opFloor: Push(Pop().Floor()); break; case opCeiling: Push(Pop().Ceiling()); break; case opRound: Push(Pop().Round()); break; case opMin: TwoNumberToNumberOp(&GBNumber::Min); break; case opMax: TwoNumberToNumberOp(&GBNumber::Max); break; case opAbs: NumberToNumberOp(&GBNumber::Abs); break; case opSignum: NumberToNumberOp(&GBNumber::Signum); break; case opReorient: NumberToNumberOp(&GBNumber::Reorient); break; case opSine: NumberToNumberOp(&GBNumber::Sin); break; case opCosine: NumberToNumberOp(&GBNumber::Cos); break; case opTangent: NumberToNumberOp(&GBNumber::Tan); break; case opArcSine: NumberToNumberOp(&GBNumber::ArcSin); break; case opArcCosine: NumberToNumberOp(&GBNumber::ArcCos); break; case opArcTangent: NumberToNumberOp(&GBNumber::ArcTan); break; case opRandom: temp = Pop(); Push(world->Randoms().InRange(Pop(), temp)); break; case opRandomAngle: Push(world->Randoms().Angle()); break; case opRandomInt: temp = Pop(); Push(world->Randoms().LongInRange(Pop().Ceiling(), temp.Floor())); break; case opRandomBoolean: PushBoolean(world->Randoms().Boolean(Pop())); break; // constants case opPi: Push(GBNumber::pi); break; case op2Pi: Push(GBNumber::pi * 2); break; case opPiOver2: Push(GBNumber::pi / 2); break; case opE: Push(GBNumber::e); break; case opEpsilon: Push(GBNumber::epsilon); break; case opInfinity: Push(GBNumber::infinity); break; // vector operations case opRectToPolar: { GBVector v = PopVector(); Push(v.Norm()); Push(v.Angle()); } break; case opPolarToRect: temp = Pop(); temp2 = Pop(); PushVector(GBFinePoint::MakePolar(temp2, temp)); break; case opVectorAdd: TwoVectorToVectorOp(&GBFinePoint::operator +); break; case opVectorSubtract: TwoVectorToVectorOp(&GBFinePoint::operator -); break; case opVectorNegate: VectorToVectorOp(&GBFinePoint::operator -); break; case opVectorScalarMultiply: temp = Pop(); PushVector(PopVector() * temp); break; case opVectorScalarDivide: temp = Pop(); PushVector(PopVector() / temp); break; case opVectorNorm: VectorToScalarOp(&GBFinePoint::Norm); break; case opVectorAngle: VectorToScalarOp(&GBFinePoint::Angle); break; case opDotProduct: TwoVectorToScalarOp(&GBFinePoint::DotProduct); break; case opProject: TwoVectorToVectorOp(&GBFinePoint::Projection); break; case opCross: TwoVectorToScalarOp(&GBFinePoint::Cross); break; case opUnitize: VectorToVectorOp(&GBFinePoint::Unit); break; case opDistance: Push((PopVector() - PopVector()).Norm()); break; case opInRange: temp = Pop(); PushBoolean(PopVector().InRange(PopVector(), temp)); break; case opRestrictPosition: { temp = Pop(); //wall distance GBVector pos = PopVector(); Push(pos.x.Max(temp).Min(world->Size().x - temp)); Push(pos.y.Max(temp).Min(world->Size().y - temp)); } break; case opVectorEqual: PushBoolean(PopVector() == PopVector()); break; case opVectorNotEqual: PushBoolean(PopVector() != PopVector()); break; // comparisons case opEqual: PushBoolean(Pop() == Pop()); break; case opNotEqual: PushBoolean(Pop() != Pop()); break; case opLessThan: temp = Pop(); PushBoolean(Pop() < temp); break; case opLessThanOrEqual: temp = Pop(); PushBoolean(Pop() <= temp); break; case opGreaterThan: temp = Pop(); PushBoolean(Pop() > temp); break; case opGreaterThanOrEqual: temp = Pop(); PushBoolean(Pop() >= temp); break; // booleans case opNot: PushBoolean(! Pop().Nonzero()); break; case opAnd: temp = Pop(); temp2 = Pop(); PushBoolean(temp.Nonzero() && temp2.Nonzero()); break; case opOr: temp = Pop(); temp2 = Pop(); PushBoolean(temp.Nonzero() || temp2.Nonzero()); break; case opXor: temp = Pop(); temp2 = Pop(); PushBoolean(temp.Nonzero() && ! temp2.Nonzero() || ! temp.Nonzero() && temp2.Nonzero()); break; case opNand: temp = Pop(); temp2 = Pop(); PushBoolean(! (temp.Nonzero() && temp2.Nonzero())); break; case opNor: temp = Pop(); temp2 = Pop(); PushBoolean(! (temp.Nonzero() || temp2.Nonzero())); break; case opValueConditional: temp = Pop(); temp2 = Pop(); if ( Pop().Nonzero() ) Push(temp2); else Push(temp); break; // misc external case opPrint: DoPrint(ToString(Pop())); if ( world->reportPrints ) NonfatalError(robot->Description() + " prints: " + *lastPrint); break; case opPrintVector: DoPrint(ToString(PopVector())); if ( world->reportPrints ) NonfatalError(robot->Description() + " prints: " + *lastPrint); break; case opBeep: StartSound(siBeep); break; case opStop: SetStatus(bsStopped); break; case opPause: if ( world->reportErrors ) world->running = false; break; case opSync: remaining = 0; break; // basic hardware case opSeekLocation: robot->EngineSeek(PopVector(), GBVector(0, 0)); break; case opSeekMovingLocation: { GBVector vel = PopVector(); robot->EngineSeek(PopVector(), vel); } break; case opDie: robot->Die(robot->Owner()); SetStatus(bsStopped); break; case opWriteLocalMemory: tempInt = PopInteger(); WriteLocalMemory(tempInt, Pop(), robot); break; case opReadLocalMemory: tempInt = PopInteger(); Push(ReadLocalMemory(tempInt, robot)); break; case opWriteLocalVector: tempInt = PopInteger(); WriteLocalMemory(tempInt + 1, Pop(), robot); WriteLocalMemory(tempInt, Pop(), robot); break; case opReadLocalVector: tempInt = PopInteger(); Push(ReadLocalMemory(tempInt, robot)); Push(ReadLocalMemory(tempInt + 1, robot)); break; case opWriteSharedMemory: tempInt = PopInteger(); robot->hardware.radio.Write(Pop(), tempInt, robot->Owner()); break; case opReadSharedMemory: Push(robot->hardware.radio.Read(PopInteger(), robot->Owner())); break; case opWriteSharedVector: tempInt = PopInteger(); robot->hardware.radio.Write(Pop(), tempInt + 1, robot->Owner()); robot->hardware.radio.Write(Pop(), tempInt, robot->Owner()); break; case opReadSharedVector: tempInt = PopInteger(); Push(robot->hardware.radio.Read(tempInt, robot->Owner())); Push(robot->hardware.radio.Read(tempInt + 1, robot->Owner())); break; case opMessagesWaiting: Push(robot->hardware.radio.MessagesWaiting(PopInteger(), robot->Owner())); break; case opSendMessage: { GBMessage sendee; tempInt = PopInteger(); //channel int numArgs = ToInteger(Pop()); //number of numbers for ( int i = 0; i < numArgs; i++ ) { sendee.AddDatum(Pop()); //higher indices in message correspond with earlier numbers in stack. :( } if ( numArgs <= 0 ) throw GBGenericError("Cannot send message of non-positive length"); robot->hardware.radio.Send(sendee, tempInt, robot->Owner()); } break; case opReceiveMessage: { tempInt = PopInteger(); const GBMessage * received = robot->hardware.radio.Receive(tempInt, robot->Owner()); if ( received == 0 ) { Push(0); } else { if ( received->Length() <= 0 ) { throw GBGenericError("non-positive length message received"); } for ( int i = received->Length() - 1; i >= 0; i-- ) Push(received->Datum(i)); Push(received->Length()); } } break; case opClearMessages: robot->hardware.radio.ClearChannel(PopInteger(), robot->Owner()); break; case opSkipMessages: tempInt = PopInteger(); robot->hardware.radio.SkipMessages(tempInt, PopInteger(), robot->Owner()); break; case opTypePopulation: { GBRobotType * theType = robot->Owner()->GetType(PopInteger()); if (theType) Push(theType->Population()); else Push(-1); } break; case opAutoConstruct: { GBConstructorState & ctor = robot->hardware.constructor; if ( robot->Energy() > robot->hardware.MaxEnergy() * .9 ) { if ( ! ctor.Type() ) ctor.Start(robot->Type()); ctor.SetRate(ctor.MaxRate()); } else ctor.SetRate(ctor.Type() && robot->Energy() > ctor.Remaining() + 10 ? ctor.MaxRate() : GBNumber(0)); } break; case opBalanceTypes: { // frac type -- GBRobotType * theType = robot->Owner()->GetType(PopInteger()); GBNumber fraction = Pop(); if (theType && GBNumber(theType->Population()) < fraction * robot->Owner()->Scores().Population()) robot->hardware.constructor.Start(theType); //FIXME don't abort? } break; // sensors case opFireRobotSensor: robot->hardware.sensor1.Fire(); break; case opFireFoodSensor: robot->hardware.sensor2.Fire(); break; case opFireShotSensor: robot->hardware.sensor3.Fire(); break; case opRobotSensorNext: Push(robot->hardware.sensor1.NextResult() ? 1 : 0); break; case opFoodSensorNext: Push(robot->hardware.sensor2.NextResult() ? 1 : 0); break; case opShotSensorNext: Push(robot->hardware.sensor3.NextResult() ? 1 : 0); break; case opPeriodicRobotSensor: FirePeriodic(robot->hardware.sensor1, world); break; case opPeriodicFoodSensor: FirePeriodic(robot->hardware.sensor2, world); break; case opPeriodicShotSensor: FirePeriodic(robot->hardware.sensor3, world); break; // weapons case opFireBlaster: robot->hardware.blaster.Fire(Pop()); break; case opFireGrenade: temp = Pop(); robot->hardware.grenades.Fire(Pop(), temp); break; case opLeadBlaster: { //pos vel -- GBVelocity vel = PopVector() - robot->Velocity(); GBPosition pos = PopVector() - robot->Position(); GBPosition target = LeadShot(pos, vel, robot->hardware.blaster.Speed(), robot->Radius()); if ( target.Nonzero() && target.Norm() <= robot->hardware.blaster.MaxRange() + robot->Radius() ) robot->hardware.blaster.Fire(target.Angle()); } break; case opLeadGrenade: { //pos vel -- GBVelocity vel = PopVector() - robot->Velocity(); GBPosition pos = PopVector() - robot->Position(); GBPosition target = LeadShot(pos, vel, robot->hardware.grenades.Speed(), robot->Radius()); if ( target.Nonzero() && target.Norm() <= robot->hardware.grenades.MaxRange() + robot->Radius() ) robot->hardware.grenades.Fire(target.Norm(), target.Angle()); //worry about short range? } break; case opSetForceField: { //pos angle -- temp = Pop(); GBPosition pos = PopVector() - robot->Position(); robot->hardware.forceField.SetDistance(pos.Norm()); robot->hardware.forceField.SetDirection(pos.Angle()); robot->hardware.forceField.SetAngle(temp); robot->hardware.forceField.SetPower(robot->hardware.forceField.MaxPower()); } break; // otherwise... default: throw GBUnknownInstructionError(); break; } }