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; }
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; }
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; }
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; }
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); }
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(); } }
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; }
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; }