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);
}
Beispiel #2
0
/*=========================================================================
* 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;
	}
}