#include #include "..\2dfw\fw.h" #include "main.h" #include "explosn.h" #define ATTACK_STYLE_ATTACK 1 #define ATTACK_STYLE_DODGE 2 #define ATTACK_STAGE_AVAILABLE 0 // Available to be assigned #define ATTACK_STAGE_TAKE_OFF 1 // Initial turn to face downwards #define ATTACK_STAGE_SWOOP 2 // actual swoop into player #define ATTACK_STAGE_GLIDE 4 // float down from top of screen #define ATTACK_STAGE_LAND 8 // turn back into bulk formation #define MAX_ATTACKERS (15) typedef struct { int attack_style; int stage; int originalxpos; int originalypos; int xanim; int xpos; int ypos; int angle; int targetangle; int speed; int actorID; int maxbombwait; int bombwait; int minattackxpos; int maxattackxpos; short voice; } attack; typedef struct { attack leader[1]; // Leader information // Now follows details we need about the squadren int actorID[3]; int originalxpos[3]; int originalypos[3]; } formation; attack attackers[MAX_ATTACKERS]; // Maximum number of attackers int PrevPlayerMovementDirection; void initAttackers ( void ) { // Can we accomodate a new attacker ? int currentAttacker; attack* attackPtr; attackPtr = attackers; for ( currentAttacker = 0; currentAttacker < MAX_ATTACKERS; currentAttacker++ ) { attackPtr->stage = ATTACK_STAGE_AVAILABLE; attackPtr++; } } int isActorAttacking ( int actorID ) { attack* attackPtr; int cannotdrop = 0; int currentAttacker; // first check that the actor is not already attacking attackPtr = attackers; for ( currentAttacker = 0; currentAttacker < MAX_ATTACKERS; currentAttacker++ ) { if ( attackPtr->stage != ATTACK_STAGE_AVAILABLE ) { if ( attackPtr->actorID == actorID ) { cannotdrop = 1; break; } } attackPtr++; } return ( cannotdrop ); } void startAttacker ( int actorID, int angle, int speed, int bombwait ) { // Can we accomodate a new attacker ? int currentAttacker; attack* attackPtr; int cannotdrop = 0; if ( fwActorGetOnStage(actorID) == OFF_STAGE ) { cannotdrop = 1; } if ( cannotdrop == 0 ) { // first check that the actor is not already attacking attackPtr = attackers; for ( currentAttacker = 0; currentAttacker < MAX_ATTACKERS; currentAttacker++ ) { if ( attackPtr->stage != ATTACK_STAGE_AVAILABLE ) { if ( attackPtr->actorID == actorID ) { cannotdrop = 1; break; } } attackPtr++; } } if ( cannotdrop == 0 ) { attackPtr = attackers; for ( currentAttacker = 0; currentAttacker < MAX_ATTACKERS; currentAttacker++ ) { if ( attackPtr->stage == ATTACK_STAGE_AVAILABLE ) { // We have one avaialabel so set it up now attackPtr->stage = ATTACK_STAGE_TAKE_OFF; attackPtr->attack_style = ATTACK_STYLE_ATTACK; attackPtr->angle = 0; // attackPtr->targetangle = ((rand()*120) >> 15)+180-60; attackPtr->targetangle = angle; // attackPtr->speed = 64; attackPtr->speed = speed; attackPtr->actorID = actorID; attackPtr->maxbombwait = bombwait; attackPtr->bombwait = bombwait; attackPtr->voice = playSound ( SoundsVabID, 2, 127 ); break; } attackPtr++; } } } void moveAttackers ( void ) { int currentAttacker; attack* attackPtr; unsigned xdistance; unsigned ydistance; attackPtr = attackers; for ( currentAttacker = 0; currentAttacker < MAX_ATTACKERS; currentAttacker++ ) { // if the actor is no longer on stage then it must have died // and therefore we can end this particular attack if ( fwActorGetOnStage( attackPtr->actorID ) == OFF_STAGE ) { // Remember to put the sprite back where it should be and animated to move with the // main body // How to do this is dependent on the stage we are at switch ( attackPtr->stage ) { case ATTACK_STAGE_SWOOP: attackPtr->xpos = attackPtr->originalxpos; attackPtr->ypos = attackPtr->originalypos; fwActorSetAngle ( attackPtr->actorID, attackPtr->angle ); fwActorPos ( attackPtr->actorID, attackPtr->xpos, attackPtr->ypos ); fwActorAnimateXPos(attackPtr->actorID, attackPtr->xanim); break; case ATTACK_STAGE_GLIDE: attackPtr->ypos = attackPtr->originalypos; fwActorPos ( attackPtr->actorID, attackPtr->xpos, attackPtr->ypos ); } // we can safely always do the following attackPtr->angle = 0; fwActorSetAngle ( attackPtr->actorID, attackPtr->angle ); // Remeber to switch the sound off too stopSound ( attackPtr->voice, SoundsVabID, 2 ); attackPtr->stage = ATTACK_STAGE_AVAILABLE; } switch ( attackPtr->stage ) { case ATTACK_STAGE_AVAILABLE: // This one is currently unused.. ignore it break; case ATTACK_STAGE_TAKE_OFF: // Rotate the invader to its desired angle if ( attackPtr->angle == 0 ) { if ( attackPtr->targetangle > 180 ) attackPtr->angle = 359; else attackPtr->angle=1; } else if ( attackPtr->angle > attackPtr->targetangle ) { attackPtr->angle-=4; if ( attackPtr->angle < attackPtr->targetangle ) attackPtr->angle = attackPtr->targetangle; } else { attackPtr->angle+=4; if ( attackPtr->angle > attackPtr->targetangle ) attackPtr->angle = attackPtr->targetangle; } fwActorSetAngle ( attackPtr->actorID, attackPtr->angle ); if ( attackPtr->angle == attackPtr->targetangle ) { attackPtr->xpos = fwActorGetXPos(attackPtr->actorID); attackPtr->ypos = fwActorGetYPos(attackPtr->actorID); attackPtr->xanim = fwActorGetAnimateXPos(attackPtr->actorID); fwActorAnimateXPos(attackPtr->actorID, -1); // get the sprite info will cause the sprite to re-calc its position fwActorGet ( attackPtr->actorID ); attackPtr->originalxpos = fwActorGetXPos(attackPtr->actorID); attackPtr->originalypos = fwActorGetYPos(attackPtr->actorID); attackPtr->minattackxpos = attackPtr->xpos - ( 50 << STAGE_SHIFT ); attackPtr->maxattackxpos = attackPtr->xpos + ( 50 << STAGE_SHIFT ); attackPtr->stage = ATTACK_STAGE_SWOOP; fwActorPos ( attackPtr->actorID, attackPtr->xpos, attackPtr->ypos ); } break; case ATTACK_STAGE_SWOOP: // if the player has changer direction and I am in front ( 22.5 degrees either side if his front ) // then reverse direction too. if ( PrevPlayerMovementDirection != PlayerMovementDirection && PlayerMovementDirection != PLAYER_MOVE_STILL ) { if ( attackPtr->xpos > PlayerXPos ) xdistance = attackPtr->xpos - PlayerXPos; else xdistance = PlayerXPos - attackPtr->xpos; ydistance = PlayerYPos - attackPtr->ypos; if ( xdistance < (ydistance>>1) ) { attackPtr->targetangle = 180 + ( 180 - attackPtr->targetangle ); } } // if Im moving away from the player and I have exceeded my limit then turn back if ( attackPtr->xpos > PlayerXPos && attackPtr->targetangle < 180 && attackPtr->xpos > attackPtr->maxattackxpos ) { attackPtr->targetangle = 180 + ( 180 - attackPtr->targetangle ); } if ( attackPtr->xpos < PlayerXPos && attackPtr->targetangle > 180 && attackPtr->xpos < attackPtr->minattackxpos ) { attackPtr->targetangle = 180 + ( 180 - attackPtr->targetangle ); } if ( attackPtr->angle != attackPtr->targetangle ) { if ( attackPtr->angle > attackPtr->targetangle ) { attackPtr->angle-=4; if ( attackPtr->angle < attackPtr->targetangle ) attackPtr->angle = attackPtr->targetangle; } else { attackPtr->angle+=4; if ( attackPtr->angle > attackPtr->targetangle ) attackPtr->angle = attackPtr->targetangle; } } // simply update the position based on speed and angle // dont forget to update the actual angle of the actor fwActorSetAngle ( attackPtr->actorID, attackPtr->angle ); attackPtr->xpos += ( fwAngleGetSin ( attackPtr->angle ) * attackPtr->speed ) >> 8; attackPtr->ypos += ( fwAngleGetCos ( attackPtr->angle ) * attackPtr->speed ) >> 8; fwActorPos ( attackPtr->actorID, attackPtr->xpos, attackPtr->ypos ); fwActorSetAngle ( attackPtr->actorID, attackPtr->angle ); attackPtr->bombwait--; if ( attackPtr->bombwait == 0 ) { attackPtr->bombwait = attackPtr->maxbombwait; enemyDropBomb ( attackPtr->xpos, attackPtr->ypos ); } // swoop ends when either we fall off the bottom // or fall off the sides if ( attackPtr->xpos < 0 || attackPtr->xpos > ( fwDirectScreenWidth () << STAGE_SHIFT ) || attackPtr->ypos > ( fwDirectScreenHeight() << STAGE_SHIFT ) ) { attackPtr->xpos = attackPtr->originalxpos; attackPtr->ypos = -(fwActorGetPixelWidth(attackPtr->actorID) << STAGE_SHIFT); attackPtr->angle = 180; fwActorSetAngle ( attackPtr->actorID, attackPtr->angle ); fwActorPos ( attackPtr->actorID, attackPtr->xpos, attackPtr->ypos ); fwActorAnimateXPos(attackPtr->actorID, attackPtr->xanim); attackPtr->stage = ATTACK_STAGE_GLIDE; } break; case ATTACK_STAGE_GLIDE: if ( attackPtr->ypos < attackPtr->originalypos ) { attackPtr->ypos+=(1<>1; fwActorPos ( attackPtr->actorID, attackPtr->xpos, attackPtr->ypos ); } else { fwActorPos ( attackPtr->actorID, attackPtr->originalxpos, attackPtr->originalypos ); fwActorAnimateXPos(attackPtr->actorID, attackPtr->xanim); attackPtr->stage = ATTACK_STAGE_LAND; } break; case ATTACK_STAGE_LAND: // Rotate the invader to its desired angle if ( attackPtr->angle < 180 ) { attackPtr->angle-=4; if ( attackPtr->angle < 0 ) attackPtr->angle = 0; } else { attackPtr->angle+=4; if ( attackPtr->angle > 359 ) attackPtr->angle = 0; } fwActorSetAngle ( attackPtr->actorID, attackPtr->angle ); if ( attackPtr->angle == 0 ) { attackPtr->stage = ATTACK_STAGE_AVAILABLE; } break; } attackPtr++; } if ( PlayerMovementDirection == PLAYER_MOVE_LEFT || PlayerMovementDirection == PLAYER_MOVE_RIGHT ) PrevPlayerMovementDirection = PlayerMovementDirection; }