Input AIManager::driveToPoint(int playerNum, vec3 pos) {
	lastDriveToPos = pos;

	reversing[playerNum] = false;
	
	Entity* ai = state->getPlayer(playerNum);
	vec3 aiPos = ai->getPos();

	Input input = Input();
	input.forward = carSpeed;
	input.backward = 0;
	input.turnL = 0;
	input.turnR = 0;
	input.tiltBackward = 0;
	input.tiltForward = 0;
	input.spinL = 0;
	input.spinR = 0;
	input.rollL = 0;
	input.rollR = 0;

	

	float dot = facing(ai, pos);
	float side = beside(ai, pos);

	
	
	// If not facing towards point
	if (dot < 0.95f) {
		// Turn
		if (side < 0) {
			input.turnR = -side;
		}
		else {
			input.turnL = side;
		}
	}

	prevPosition[playerNum] = aiPos;

	//AI has a powerup
	if (state->getPlayer(playerNum)->getCurrentPowerup() != -1)
	{
		if (state->getPlayer(playerNum)->getCurrentPowerup() != POWERUPS::BOMB){
			input.powerup = true;
		}
		else {
			double dist = abs(length(state->getPlayer(playerNum)->getPos() - state->getGoldenBuggy()->getPos()));

			if (dist <= 5)
			{
				//Use the bomb powerup if the AI is close to the golden buggy
				input.powerup = true;
			}
		}
	}

	return input;
}
Beispiel #2
0
	Location getFacing(const Location& loc, const int32_t angle) {
		Location facing(loc);
		ExactModelCoordinate emc = facing.getMapCoordinates();
		// remove grid rotation from angle, to guarantee uniform angles (not grid based)
		double tmpAngle = static_cast<double>(angle) - loc.getLayer()->getCellGrid()->getRotation();
		emc.x += Mathd::Cos(tmpAngle * (Mathd::pi()/180.0));
		emc.y -= Mathd::Sin(tmpAngle * (Mathd::pi()/180.0));
		facing.setMapCoordinates(emc);

		return facing;
	}
Beispiel #3
0
bool visibleAndFacing( const Intersection& isectA, const Intersection& isectB, const RTScene& scene )
{
	if(!facing(isectA, isectB))
	{
		return false;
	}
	//make sure they're facing each other first 
	float3 dir = normalize(isectB.position - isectA.position);
	//now trace the ray...
	Ray ray(isectA.position, dir);
	IntersectionQuery query(ray);
	//float desiredT = glm::length(isectB.position - isectA.position);

	Intersection sceneIsect;
	intersectScene(scene, query, &sceneIsect, nullptr);
	//see if we hit isect B
	if(!sceneIsect.hit) return false;
	//if(fabs(sceneIsect.t - desiredT) > 0.0001) return false;
	if(sceneIsect.primitiveId != isectB.primitiveId) return false;
	return true;
}
Beispiel #4
0
bool visibleAndFacing( const float3& posA, const float3& nA, 
	const float3& posB, const float3& nB, 
	const RTScene& scene )
{

	if(!facing(posA, nA, posB, nB))
	{
		return false;
	}
	//make sure they're facing each other first 
	float3 dir = normalize(posB - posA);
	//now trace the ray...
	Ray ray(posA, dir);
	IntersectionQuery query(ray);
	float desiredT = glm::length(posB - posA);

	Intersection sceneIsect;
	intersectScene(scene, query, &sceneIsect, nullptr);
	//see if we hit isect B
	if(!sceneIsect.hit) return false;
	if(fabs(sceneIsect.t - desiredT) > 0.0001) return false;
	return true;
}
Beispiel #5
0
float3 directLight(
	Rand& rand, 
	const RTScene& scene, 
	const PathVertex& vertex,
	const ShadingCS& shadingCS)
{
	//TODO: this does not work for multiple lights!
	auto & light = scene.accl->lights[0];
	float3 lightPos;
	float lightPdf; 
	//t is already incorporated into pdf
	float lightT;
	float3 wiDirectWorld;
	//sample the light
	light.sample(rand, vertex.position, &lightPos, &wiDirectWorld, &lightPdf, &lightT);

	//see if we're occluded
	Ray shadowRay(vertex.position, wiDirectWorld);
	//we cannot ignore the light here, as we need to differentiate b/t hit empty space
	//and hit light

	IntersectionQuery shadowQuery(shadowRay);	
	Intersection sceneIsect;
	Intersection lightIsect;
	intersectScene(scene, shadowQuery, &sceneIsect, &lightIsect);
	bool hitLight = hitLightFirst(sceneIsect, lightIsect) 
		&& lightIsect.lightId == light.id;
	if(hitLight && facing(vertex.position, vertex.normal, lightIsect.position, lightIsect.normal))
	{
		float3 wiDirect = shadingCS.local(wiDirectWorld);
		float3 brdfEval = vertex.material->eval(wiDirect, shadingCS.local(vertex.woWorld));
		float3 cosTheta = float3(dot(vertex.normal, wiDirectWorld));
		float3 le = light.material.emission;
		return le * brdfEval * cosTheta / lightPdf;
	}
	return float3(0);
}
Beispiel #6
0
void playHelper(){
    // GET DIR
    if(check(PINB,5)){
        direction=true; //SET THE ROBOT DIRECTION TO SHOOT
    } else {
        direction=false;
    }
    // direction = directionPacket;
    // READ ADC VALS
    int adc1 = ADC0_read();
    int adc2 = ADC1_read();
    //m_usb_tx_string("adc1, adc2 = (");
    //m_usb_tx_int(adc1);
    //m_usb_tx_string(", ");
    //m_usb_tx_int(adc2);
    //m_usb_tx_string(")\n");
    int adcDiff = adc2 - adc1;
    if(direction) m_usb_tx_string("direction true\n");
    else m_usb_tx_string("direction false\n");
    if(timer>=1){
        turnLeft();
        m_wait(1000);
        backward();
        m_wait(500);
        timer = 0;
    } else if(hasPuck()){// ROBOT SWITCH PUSHED.. PUCK IS SEEN
        m_green(OFF);
        m_wait(100);
        unsigned int xTarg;
        unsigned int yTarg = 60;
        if(direction){                  // Face goal A
            xTarg = 240;
        } else {                        // Face goal B
            xTarg = 0;
        } 
        // ROTATE TO FACE GOAL
        if(!facing(xTarg,yTarg)) return;
        if(direction){                  // Try to go to A
            if(myPos[X]>160){           // Close enough, fire!
                m_green(ON);
                fire();
            } else {
                m_green(OFF);           // Too far, keep going forward
                forward();           
            }
        } else {                        // Try to go to B
            if(myPos[X]<80){            // Close enough, fire!
                m_green(ON);
                fire();
            } else {                    // Too far, keep going forward
                m_green(OFF);
                forward();     
            }    
        }
    } else if(adc1>960||adc2>960){        // PUCK SEEN, hone in..
        if(adcDiff>10){
            spinLeft();
        } else if(adcDiff<-10){
            spinRight();
        } else {
            forward();
        }
    } else{                               // PUCK NOT SEEN, keep spinning..
        m_green(OFF);
        spinRight();
    }
}
Beispiel #7
0
void playStriker(){
	
    // GET DIR
    if(check(PINB,5)){
        direction=true; //SET THE ROBOT DIRECTION TO SHOOT
    } else {
        direction=false;
    }
    // GET POS
    getPos();
    // SEND LOCATION TO HELPER
    //buffer[1]=myPos[X];
    //buffer[2]=myPos[Y];
    //buffer[3]=direction;
    //m_rf_send(TXADDRESS, buffer, PACKET_LENGTH);
    // READ ADC VALS
    int adc1 = ADC0_read();
    int adc2 = ADC1_read();
    // m_usb_tx_string("adc1, adc2 = (");
    // m_usb_tx_int(adc1);
    // m_usb_tx_string(", ");
    // m_usb_tx_int(adc2);
    // m_usb_tx_string(")\n");
    int adcDiff = adc2 - adc1;
    // TIMER CHECKS
    //m_usb_tx_string("myLastPos(x,y): (");
    //m_usb_tx_int(myLastPos[X]);
    //m_usb_tx_string(", ");
    //m_usb_tx_int(myLastPos[Y]);
    //m_usb_tx_string(") TIMER:");
    //m_usb_tx_int(timer);
    //m_usb_tx_string("\n");
    if(timer>5 && timer<10){
        backward();
        m_wait(250);
        turnLeft();
        m_wait(250);
        backward();
        m_wait(250);
        timer = 0;
    } else if(hasPuck()){// ROBOT SWITCH PUSHED.. PUCK IS SEEN
        m_green(OFF);
        m_wait(100);
        unsigned int xTarg;
        unsigned int yTarg = 60;
        if(direction){                  // Face goal A
            xTarg = 240;
        } else {                        // Face goal B
            xTarg = 0;
        } 
        // ROTATE TO FACE GOAL
        if(!facing(xTarg,yTarg)) return;
        if(direction){                  // Try to go to A
            if(myPos[X]>160){           // Close enough, fire!
                m_green(ON);
                fire();
            } else {
                m_green(OFF);           // Too far, keep going forward
                forward();           
            }
        } else {                        // Try to go to B
            if(myPos[X]<80){            // Close enough, fire!
                m_green(ON);
                fire();
            } else {                    // Too far, keep going forward
                m_green(OFF);
                forward();     
            }    
        }
    } else if(adc1>960||adc2>960){        // PUCK SEEN, hone in..
        if(adcDiff>10){
            spinLeft();
        } else if(adcDiff<-10){
            spinRight();
        } else {
            forward();
        }
    } else{                               //PUCK NOT SEEN, keep spinning..
        m_green(OFF);
        spinRight();
    }
}
void Trigger_WeaponGiver::Render()
{
  if (isActive())
  {
    switch (EntityType())
    {
      case type_rail_gun:
        {
          gdi->BluePen();
          gdi->BlueBrush();
          gdi->Circle(Pos(), 3);
          gdi->ThickBluePen();
          gdi->Line(Pos(), Vector2D(Pos().x, Pos().y-9));
        }

        break;

      case type_shotgun:
        {

          gdi->BlackBrush();
          gdi->BrownPen();
          const double sz = 3.0;
          gdi->Circle(Pos().x-sz,Pos().y, sz);
          gdi->Circle(Pos().x+sz,Pos().y, sz);
        }

        break;

	  case type_smg:
	    {
			gdi->RedBrush();
			gdi->YellowPen();
			const double sz = 3.0;
			gdi->Circle(Pos().x - sz, Pos().y, sz);
			gdi->Circle(Pos().x + sz, Pos().y, sz);
	    }

		break;

	  case type_revolver:
		{
		    gdi->BlackBrush();
		    gdi->BlackPen();
			const double sz = 2.0;
			gdi->Circle(Pos().x - sz, Pos().y, sz);
			gdi->Circle(Pos().x + sz, Pos().y, sz);
			gdi->Circle(Pos().x - sz / 2.0, Pos().y + sz / 2.0, sz);
			gdi->Circle(Pos().x + sz / 2.0, Pos().y + sz / 2.0, sz);
			gdi->Circle(Pos().x - sz / 2.0, Pos().y - sz / 2.0, sz);
			gdi->Circle(Pos().x + sz / 2.0, Pos().y - sz / 2.0, sz);
		}

		break;

	  case type_minigun:
	  {
		  gdi->RedPen();
		  gdi->RedBrush();
		  gdi->Circle(Pos(), 2);
		  gdi->ThickRedPen();
		  gdi->Line(Pos(), Vector2D(Pos().x, Pos().y - 9));
	  }

	  break;

      case type_rocket_launcher:
        {

           Vector2D facing(-1,0);

           m_vecRLVBTrans = WorldTransform(m_vecRLVB,
                                          Pos(),
                                          facing,
                                          facing.Perp(),
                                          Vector2D(2.5,2.5));

            gdi->RedPen();
            gdi->ClosedShape(m_vecRLVBTrans);
        }
      
        break;



    }//end switch
  }
}
Input AIManager::testAIEvade(int playerNum) {	
	Entity* ai = state->getPlayer(playerNum);
	vec3 aiPos = ai->getPos();

	Entity* player = NULL;
	float shortestLength = 0;
	for (unsigned int i = 0; i < state->numberOfPlayers(); i++) {
		if (i != playerNum) {
			Entity* indexedPlayer = state->getPlayer(i);
			vec3 playerPos = indexedPlayer->getPos();
			vec3 distance = playerPos - aiPos;

			float len = length(distance);
			if (len < shortestLength || player == NULL) {
				shortestLength = len;
				player = indexedPlayer;
			}
		}
	}
	
	Input input = Input();
	input.forward = carSpeed;
	input.backward = 0;
	input.turnL = 0;
	input.turnR = 0;
	input.tiltBackward = 0;
	input.tiltForward = 0;
	input.spinL = 0;
	input.spinR = 0;
	input.rollL = 0;
	input.rollR = 0;

	float dot = facing(ai, player);
	float side = beside(ai, player);


	float distance = length(aiPos - player->getPos());
	float speed = ((PlayerInfo*)ai)->getFSpeed();
	
	// If facing car and very close
	if (dot >= 0.8 && distance <= 10) {
		// Go backwards
		input.forward = 0.0f;
		input.backward = carSpeed;
		// if still moving forwards
		if (!reversing[playerNum] && speed > 0) {
			// Do not turn as direction of turning will be changing soon
			input.turnL = 0;
			input.turnR = 0;
		}
		// If moving backwards
		else if ((!reversing[playerNum] && speed <= 0) || reversing[playerNum]) {
			reversing[playerNum] = true;
				// Turn
			if (side > 0) {
				input.turnL = dot;
			}
			else {
				input.turnR = dot;
			}
		}
	}
	else if (dot > -0.9) {
		// If still moving backwards, do not turn as turning direction will be changing soon
		if (reversing[playerNum] && speed < 0) {
			input.turnL = 0;
			input.turnR = 0;
		}
		// If moving forwards
		else if ((reversing[playerNum] && speed >= 0) || !reversing[playerNum]) {
			reversing[playerNum] = false;
				// Turn
			if (side > 0) {
				input.turnR = side;
			}
			else {
				input.turnL = -side;
			}
		}
	}

	prevPosition[playerNum] = aiPos;

	return input;
}
// If result is negative, ai is facing away from player
// If result is positive ai is facing player
// Returns value between -1 and 1
float AIManager::facing(Entity* object, Entity* target) {
	vec3 targetPos = target->getPos();
	
	return facing(object, targetPos);
}
Input AIManager::recover(int playerNum) {
	// If recovery just started
	if (collisionRecoveryCounter == 0) {
		// Reverse direction
		reversing[playerNum] = !reversing[playerNum];
	}

	

	Input input = Input();
	if (reversing[playerNum]) {
		input.forward = 0;
		input.backward = carSpeed;
	}
	else {
		input.forward = carSpeed;
		input.backward = 0;
	}

	input.turnL = 0;
	input.turnR = 0;
	input.tiltBackward = 0;
	input.tiltForward = 0;
	input.spinL = 0;
	input.spinR = 0;
	input.rollL = 0;
	input.rollR = 0;

	float dot = facing(state->getPlayer(playerNum), infoAtCollision.getPos());
	float side = beside(state->getPlayer(playerNum), infoAtCollision.getPos());

	if (dot > 1) {
		dot = 1.0f;
	}
	else if (dot < -1) {
		dot = -1;
	}
	else if (dot != dot) {
		dot = 1;
	}

	if (side > 1) {
		side = 1.0f;
	}
	else if (side < -1) {
		side = -1;
	}
	else if (side != side) {
		side = 1;
	}

	if (reversing[playerNum]) {
		if (side > 0) {
			input.turnL = dot;
		}
		else {
			input.turnR = dot;
		}
	}
	else {
		if (side > 0) {
			input.turnR = dot;
		}
		else {
			input.turnL = dot;
		}
	}

	if (timer.getTimeSince(collisionStartTime) >= 0.9f) {
		input.jump = true;
	}

	return input;
}
Input AIManager::testAIChase(unsigned int aiNum){
	/*
	Notes about AI stuff
	point vec=hispos-prevpos; 	// vec is the 1-frame position difference
	vec=vec*N; 					// we project N frames into the future
	point futurepos=hispos+vec; // and build the future projection
	reaim(mypos,myyaw,futurepos);
	mypos.x = mypos.x + cos(myyaw) * speed;
	mypos.z = mypos.z + sin(myyaw) * speed;
	*/

	vec3 goldenBuggyLoc = state->getGoldenBuggy()->getPos();
	prevPosition[aiNum] = goldenBuggyLoc;
	vec3 myPos = state->getPlayer(aiNum)->getPos();
	vec3 vec = goldenBuggyLoc - prevPosition[aiNum];
	vec = vec * vec3(30, 30, 30); // we project N frames into the future

	vec3 futurepos = goldenBuggyLoc + vec;
	double dX_chaseAI = myPos.x;
	double dY_chaseAI = myPos.y;
	double dZ_chaseAI = myPos.z;

	double yaw_chaseAI = atan2(dZ_chaseAI, dX_chaseAI);

	double dX_golden = goldenBuggyLoc.x;
	double dY_golden = goldenBuggyLoc.y;
	double dZ_golden = goldenBuggyLoc.z;

	double yaw_golden = atan2(dZ_golden, dX_golden);


	Input input = Input();
	input.forward = 0.5f;
	input.backward = 0;
	input.turnL = 0;
	input.turnR = 0;
	input.tiltBackward = 0;
	input.tiltForward = 0;
	input.spinL = 0;
	input.spinR = 0;
	input.rollL = 0;
	input.rollR = 0;

	

	Entity* ai = state->getPlayer(aiNum);
	Entity* goldenBuggy = state->getGoldenBuggy();

	float dot = facing(ai, goldenBuggy);
	if (dot < 0.9){
		if (dot > 0){
			float result = beside(ai, goldenBuggy);

			if (result > 0){
				input.turnR = -result;
			}
			else{
				input.turnL = result;
			}

		}
		else {
			float result = beside(ai, goldenBuggy);

			if (result > 0){
				input.turnR = -result;
			}
			else{
				input.turnL = result;
			}

		}
	}

	if (state->getPlayer(aiNum)->getCurrentPowerup() != -1)
	{
		if (state->getPlayer(aiNum)->getCurrentPowerup() != POWERUPS::BOMB)
		{
			input.powerup = true;
		}
		else
		{
			
			double dist = abs(length(state->getPlayer(aiNum)->getPos() - state->getGoldenBuggy()->getPos()));

			if (dist <= 5)
			{
				//Use the bomb powerup if the AI is close to the golden buggy
				input.powerup = true;
			}
		}
	}

	return input;
	
	
}
Beispiel #13
0
short effect::act()
{
	short temp;
	Sint32 xd, yd, distance, generic;
	oblink *foelist, *here;
	walker *newob;
	short numfoes;

	// Make sure everyone we're poshorting to is valid
	if (foe && foe->dead)
		foe = NULL;
	if (leader && leader->dead)
		leader = NULL;
	if (owner && owner->dead)
		owner = NULL;

	collide_ob = NULL; // always start with no collison..

	// Any special actions ..
	switch (family) // determine what to do..
	{
		case FAMILY_GHOST_SCARE:
			if (owner)
				center_on(owner);
			break;
		case FAMILY_MAGIC_SHIELD: // revolve around owner
			if (!owner || owner->dead)
			{
				dead = 1;
				death();
				break;
			}
			switch (drawcycle % 16)
			{
				case 0:
					xd = 0;
					yd = -24;
					break;
				case 1:
					xd = -9;
					yd = -22;
					break;
				case 2:
					xd = -17;
					yd = -17;
					break;
				case 3:
					xd = -22;
					yd = -9;
					break;

				case 4:
					xd = -24;
					yd = 0;
					break;
				case 5:
					xd = -22;
					yd = 9;
					break;
				case 6:
					xd = -17;
					yd = 17;
					break;
				case 7:
					xd = -9;
					yd = 22;
					break;

				case 8:
					xd = 0;
					yd = 24;
					break;
				case 9:
					xd = 9;
					yd = 22;
					break;
				case 10:
					xd = 17;
					yd = 17;
					break;
				case 11:
					xd = 22;
					yd = 9;
					break;

				case 12:
					xd = 24;
					yd = 0;
					break;
				case 13:
					xd = 22;
					yd = -9;
					break;
				case 14:
					xd = 17;
					yd = -17;
					break;
				case 15:
					xd = 9;
					yd = -22;
					break;
			}
			center_on(owner);
			setxy( (short)( xpos+xd ), (short) (ypos+yd) );
			foelist = screenp->find_foe_weapons_in_range(
			              screenp->oblist, sizex, &temp, this);
			here = foelist;
			while (foelist)  // first weapons
			{
				stats->hitpoints -= foelist->ob->damage;
				foelist->ob->dead = 1;
				foelist->ob->death();
				foelist = foelist->next;
			}
			delete_list(here);
			foelist = screenp->find_foes_in_range(
			              screenp->oblist, sizex, &temp, this);
			here = foelist;
			while (foelist) // second enemies
			{
				stats->hitpoints -= foelist->ob->damage;
				attack(foelist->ob);
				dead = 0;
				foelist = foelist->next;
			}
			delete_list(here);
			if ( (stats->hitpoints <= 0) || (lifetime-- < 0) )
			{
				dead = 1;
				death();
			}
			break; // end of magic shield case
		case FAMILY_BOOMERANG: // fighter's boomerang
			// Zardus: FIX: if the drawcycle is in its >253s, the boomerang dies. This will fix the bug where
			// the boomerang comes back to 0 (owner) after spiraling around all the way if the owner has
			// that good of an ability (to keep its life so high). This caps boomerang ability, though... Another
			// fix could be to make the drawcycle var an int or at least something with more capacity than char.
			if (!owner || owner->dead || drawcycle > 253)
			{
				dead = 1;
				death();
				break;
			}
			switch (drawcycle % 16)
			{
				case 0:
					xd = 0;
					yd = -24;
					break;
				case 1:
					xd = -9;
					yd = -22;
					break;
				case 2:
					xd = -17;
					yd = -17;
					break;
				case 3:
					xd = -22;
					yd = -9;
					break;

				case 4:
					xd = -24;
					yd = 0;
					break;
				case 5:
					xd = -22;
					yd = 9;
					break;
				case 6:
					xd = -17;
					yd = 17;
					break;
				case 7:
					xd = -9;
					yd = 22;
					break;

				case 8:
					xd = 0;
					yd = 24;
					break;
				case 9:
					xd = 9;
					yd = 22;
					break;
				case 10:
					xd = 17;
					yd = 17;
					break;
				case 11:
					xd = 22;
					yd = 9;
					break;

				case 12:
					xd = 24;
					yd = 0;
					break;
				case 13:
					xd = 22;
					yd = -9;
					break;
				case 14:
					xd = 17;
					yd = -17;
					break;
				case 15:
					xd = 9;
					yd = -22;
					break;
			}
			xd *= (drawcycle+4);
			xd /= 48;
			yd *= (drawcycle+4);
			yd /= 48;
			center_on(owner);
			setxy((short) (xpos+xd), (short) (ypos+yd) );
			foelist = screenp->find_foe_weapons_in_range(
			              screenp->oblist, sizex*2, &temp, this);
			here = foelist;
			while (foelist)  // first weapons
			{
				stats->hitpoints -= foelist->ob->damage;
				foelist->ob->dead = 1;
				foelist->ob->death();
				foelist = foelist->next;
			}
			delete_list(here);
			foelist = screenp->find_foes_in_range(
			              screenp->oblist, sizex, &temp, this);
			here = foelist;
			while (foelist) // second enemies
			{
				stats->hitpoints -= foelist->ob->damage;
				attack(foelist->ob);
				dead = 0;
				foelist = foelist->next;
			}
			delete_list(here);
			if ( (stats->hitpoints <= 0) || (lifetime-- < 0) )
			{
				dead = 1;
				death();
			}
			break; // end of boomerang case
		case FAMILY_KNIFE_BACK: // returning blade
			if (!owner || owner->dead)
			{
				dead = 1;
				break;
			}
			distance = distance_to_ob(owner);
			if (distance > 10)
			{
				xd = yd = 0; // zero out distance movements
				if (owner->xpos > xpos)
				{
					if ( (owner->xpos - xpos) > stepsize )
						xd = stepsize;
					else
						xd = owner->xpos - xpos;
				}
				else if (owner->xpos < xpos)
				{
					if ( (xpos - owner->xpos) > stepsize )
						xd = -stepsize;
					else
						xd = owner->xpos - xpos;
				}
				if (owner->ypos > ypos)
				{
					if ( (owner->ypos - ypos) > stepsize )
						yd = stepsize;
					else
						yd = owner->ypos - ypos;
				}
				else if (owner->ypos < ypos)
				{
					if ( (ypos - owner->ypos) > stepsize )
						yd = -stepsize;
					else
						yd = owner->ypos - ypos;
				}
				setxy((short) (xpos+xd), (short) (ypos+yd) );
				newob = screenp->add_ob(ORDER_WEAPON, FAMILY_KNIFE);
				newob->damage = damage;
				newob->owner = owner;
				newob->team_num = team_num;
				newob->death_called = 1; // to ensure no spawning of more ..
				newob->setxy(xpos, ypos);
				if (!screenp->query_object_passable((short) (xpos+xd), (short) (ypos+yd), newob))
				{
					newob->attack(newob->collide_ob);
					damage /= 4;
					//setxy(xpos-(2*xd)+random(xd), ypos-(2*yd)+random(yd));
				}
				newob->dead = 1;
			}
			else
			{
				owner->weapons_left++;
				//if (owner->user != -1)
				//{
				//  sprintf(message, "Knives now %d", owner->weapons_left);
				//  screenp->do_notify(message, owner);
				//}
				ani_type = ANI_WALK;
				dead = 1;
			}
			break;
		case FAMILY_CLOUD: // poison cloud
			if (lifetime > 0)
				lifetime--;
			else
			{
				dead = 1;
				death();
			}
			if (lifetime < 8)
				invisibility_left +=3;
			if (invisibility_left > 0)
				invisibility_left--;
			// Hit any nearby foes (not friends, for now)
			foelist = screenp->find_foes_in_range(
			              screenp->oblist, sizex, &temp, this);
			here = foelist;
			while (foelist) //
			{
				if (hits(xpos, ypos, sizex, sizey, // this is the cloud
				         foelist->ob->xpos, foelist->ob->ypos,
				         foelist->ob->sizex, foelist->ob->sizey)
				   )
				{
					attack(foelist->ob);
				} // end of actual hit
				foelist = foelist->next;
			}
			delete_list(here);
			// Are we performing some action?
			if (stats->commandlist)
				temp = stats->do_command();
			else
			{
				xd = yd = 0;
				while (xd == 0 && yd == 0)
				{
					xd = random(3)-1;
					yd = random(3)-1;
				}
				stats->add_command(COMMAND_WALK, (short) random(20), (short) xd, (short) yd);
			}
			break; // end of cloud
		case FAMILY_CHAIN: // chain lightning ..
			if (!leader || lineofsight<1 || !owner) // lost our leader, etc.? kill us ..
			{
				dead = 1;
				death();
				return 1;
			}
			// Are we at our leader? If so, attack him :)
			if (hits(xpos, ypos, sizex, sizey,
			         leader->xpos, leader->ypos, leader->sizex, leader->sizey))
			{
				// Do things ..
				newob = screenp->add_ob(ORDER_FX, FAMILY_EXPLOSION);
				if (!newob)
				{
					dead = 1;
					death();
					return 1; // failsafe
				}
				newob->owner = owner;
				newob->team_num = team_num;
				newob->stats->level = stats->level;
				newob->damage = damage;
				newob->ani_type = ANI_EXPLODE;
				newob->center_on(this);
				leader->skip_exit += 3; // can't hit us for 3 rounds ..
				if (on_screen())
					screenp->soundp->play_sound(SOUND_EXPLODE);
				// Now make new objects to seek out foes ..
				// First, are our offspring powerful enough at 1/2 our power?
				generic = (damage)/2;
				if (owner->myguy)
					foelist = screenp->find_foes_in_range(screenp->oblist,
					                                      240+(owner->myguy->intelligence/2), &temp, this);
				else
					foelist = screenp->find_foes_in_range(screenp->oblist,
					                                      240+stats->level*5, &temp, this);
				if (temp && generic>20) // more foes to find ..
				{
					here = foelist;
					numfoes = random(owner->stats->level)+1;
					while (here && numfoes--)
					{
						if (here->ob != leader && here->ob->skip_exit<1) // don't hit current guy, etc.
						{
							newob = screenp->add_ob(ORDER_FX, FAMILY_CHAIN);
							if (!newob)
							{
								delete_list(foelist);
								return 0; // failsafe
							}
							newob->owner = owner;  // our caster
							newob->leader = here->ob; // guy to attack
							newob->stats->level = stats->level;
							newob->stats->set_bit_flags(BIT_MAGICAL, 1);
							newob->damage = generic;
							newob->team_num = team_num;
							newob->center_on(this);
						} // end of wasn't current guy case
						here = here->next;
					} // end of loop for nearby foes we found
				} // end of check for nearby foes

				// Clean up our list .. ?
				// Zardus: TAG: nah, lets use delete_list
				/*here = foelist->next;
				while (here)
				{
					delete foelist;
					foelist = here;
					here = here->next;
				}
				delete foelist;*/
				delete_list(foelist);
				dead = 1;
				death();
				return 1;
			}
			// Move toward our leader ..
			lineofsight--;
			distance = distance_to_ob_center(leader);
			if (distance > stepsize*2)
			{
				xd = yd = 0; // zero out distance movements
				if (leader->xpos > xpos)
				{
					if ( (leader->xpos - xpos) > stepsize )
						xd = stepsize;
					else
						xd = leader->xpos - xpos;
				}
				else if (leader->xpos < xpos)
				{
					if ( (xpos - leader->xpos) > stepsize )
						xd = -stepsize;
					else
						xd = leader->xpos - xpos;
				}
				if (leader->ypos > ypos)
				{
					if ( (leader->ypos - ypos) > stepsize )
						yd = stepsize;
					else
						yd = leader->ypos - ypos;
				}
				else if (leader->ypos < ypos)
				{
					if ( (ypos - leader->ypos) > stepsize )
						yd = -stepsize;
					else
						yd = leader->ypos - ypos;
				}
				// Set our facing?
				curdir = facing(xd, yd);
				set_frame(ani[curdir][0]);
			} // end of big step
			else
			{
				//xd = leader->xpos;
				//yd = leader->ypos;
				center_on(leader);
				return 1;
			}
			setxy((short) (xpos+xd), (short) (ypos+yd) );
			return 1;  // so as not to animate, etc.
			//break; // end of FAMILY_CHAIN

		case FAMILY_DOOR_OPEN:

			// Here is how doors work.  They start out as a FAMILY_DOOR
			//  from ORDER_WEAPON under the weaplist.  When the door is
			//  collided with, the obmap marks the door as dead, and spawns
			//  the FAMILY_DOOR_OPEN on the weaplist (this object).  It
			//  animates ANI_DOOR_OPEN, and when it is done, it dies and
			//  spawns a FAMILY_DOOR_OPEN on the fxlist.  The amusing part
			//  is that now that it is on the fxlist, it won't act anymore,
			//  thus preventing it from continuously respawning itself.

			if (ani_type != ANI_WALK)
				return animate();
			newob = screenp->add_fx_ob(ORDER_FX, FAMILY_DOOR_OPEN);
			if (!newob)
				break;
			newob->ani_type = ANI_WALK;
			newob->setxy(xpos, ypos);
			newob->stats->level = stats->level;
			newob->team_num = team_num;
			newob->ignore = 1;
			newob->curdir = curdir;
			// set correct frame
			newob->animate();
			dead = 1;
			death();
			return 1;
			break;

		default:
			break;
	}

	// Complete previous animations (like firing)
	if (ani_type != ANI_WALK)
		return animate();

	switch (family) // determine what to do..
	{
		default:
			dead = 1;
			death();
			break;
	}

	return 0;
}