static COUNT initialize_autoaim_laser (ELEMENT *ShipPtr, HELEMENT LaserArray[]) { COUNT orig_facing; SIZE delta_facing; STARSHIP *StarShipPtr; LASER_BLOCK LaserBlock; GetElementStarShip (ShipPtr, &StarShipPtr); LaserBlock.face = orig_facing = StarShipPtr->ShipFacing; if ((delta_facing = TrackShip (ShipPtr, &LaserBlock.face)) > 0) LaserBlock.face = NORMALIZE_FACING (orig_facing + delta_facing); ShipPtr->hTarget = 0; LaserBlock.cx = ShipPtr->next.location.x; LaserBlock.cy = ShipPtr->next.location.y; LaserBlock.ex = COSINE (FACING_TO_ANGLE (LaserBlock.face), LASER_RANGE); LaserBlock.ey = SINE (FACING_TO_ANGLE (LaserBlock.face), LASER_RANGE); LaserBlock.sender = ShipPtr->playerNr; LaserBlock.flags = IGNORE_SIMILAR; LaserBlock.pixoffs = ARILOU_OFFSET; LaserBlock.color = BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x0A), 0x0E); LaserArray[0] = initialize_laser (&LaserBlock); return (1); }
static void druuge_postprocess (ELEMENT *ElementPtr) { STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); /* if just fired cannon */ if ((StarShipPtr->cur_status_flags & WEAPON) && StarShipPtr->weapon_counter == StarShipPtr->RaceDescPtr->characteristics.weapon_wait) { COUNT angle; SIZE cur_delta_x, cur_delta_y; StarShipPtr->cur_status_flags &= ~SHIP_AT_MAX_SPEED; angle = FACING_TO_ANGLE (StarShipPtr->ShipFacing) + HALF_CIRCLE; DeltaVelocityComponents (&ElementPtr->velocity, COSINE (angle, RECOIL_VELOCITY), SINE (angle, RECOIL_VELOCITY)); GetCurrentVelocityComponents (&ElementPtr->velocity, &cur_delta_x, &cur_delta_y); if ((long)cur_delta_x * (long)cur_delta_x + (long)cur_delta_y * (long)cur_delta_y > (long)MAX_RECOIL_VELOCITY * (long)MAX_RECOIL_VELOCITY) { angle = ARCTAN (cur_delta_x, cur_delta_y); SetVelocityComponents (&ElementPtr->velocity, COSINE (angle, MAX_RECOIL_VELOCITY), SINE (angle, MAX_RECOIL_VELOCITY)); } } }
static void spawn_doggy (ELEMENT *ElementPtr) { HELEMENT hDoggyElement; if ((hDoggyElement = AllocElement ()) != 0) { COUNT angle; ELEMENT *DoggyElementPtr; STARSHIP *StarShipPtr; ElementPtr->state_flags |= DEFY_PHYSICS; PutElement (hDoggyElement); LockElement (hDoggyElement, &DoggyElementPtr); DoggyElementPtr->hit_points = DOGGY_HITS; DoggyElementPtr->mass_points = DOGGY_MASS; DoggyElementPtr->thrust_wait = 0; DoggyElementPtr->playerNr = ElementPtr->playerNr; DoggyElementPtr->state_flags = APPEARING; DoggyElementPtr->life_span = NORMAL_LIFE; SetPrimType (&(GLOBAL (DisplayArray))[DoggyElementPtr->PrimIndex], STAMP_PRIM); { DoggyElementPtr->preprocess_func = doggy_preprocess; DoggyElementPtr->postprocess_func = NULL; DoggyElementPtr->collision_func = doggy_collision; DoggyElementPtr->death_func = doggy_death; } GetElementStarShip (ElementPtr, &StarShipPtr); angle = FACING_TO_ANGLE (StarShipPtr->ShipFacing) + HALF_CIRCLE; DoggyElementPtr->current.location.x = ElementPtr->next.location.x + COSINE (angle, DISPLAY_TO_WORLD (CHENJESU_OFFSET + DOGGY_OFFSET)); DoggyElementPtr->current.location.y = ElementPtr->next.location.y + SINE (angle, DISPLAY_TO_WORLD (CHENJESU_OFFSET + DOGGY_OFFSET)); DoggyElementPtr->current.image.farray = StarShipPtr->RaceDescPtr->ship_data.special; DoggyElementPtr->current.image.frame = StarShipPtr->RaceDescPtr->ship_data.special[0]; SetVelocityVector (&DoggyElementPtr->velocity, DOGGY_SPEED, NORMALIZE_FACING (ANGLE_TO_FACING (angle))); SetElementStarShip (DoggyElementPtr, StarShipPtr); ProcessSound (SetAbsSoundIndex ( /* RELEASE_DOGGY */ StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 4), DoggyElementPtr); UnlockElement (hDoggyElement); } }
static void cannon_collision (ELEMENT *ElementPtr0, POINT *pPt0, ELEMENT *ElementPtr1, POINT *pPt1) { weapon_collision (ElementPtr0, pPt0, ElementPtr1, pPt1); if ((ElementPtr1->state_flags & PLAYER_SHIP) && ElementPtr1->crew_level && !GRAVITY_MASS (ElementPtr1->mass_points + 1)) { COUNT angle; SIZE cur_delta_x, cur_delta_y; STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr1, &StarShipPtr); StarShipPtr->cur_status_flags &= ~(SHIP_AT_MAX_SPEED | SHIP_BEYOND_MAX_SPEED); angle = FACING_TO_ANGLE ( GetFrameIndex (ElementPtr0->next.image.frame) ); DeltaVelocityComponents (&ElementPtr1->velocity, COSINE (angle, RECOIL_VELOCITY), SINE (angle, RECOIL_VELOCITY)); GetCurrentVelocityComponents (&ElementPtr1->velocity, &cur_delta_x, &cur_delta_y); if ((long)cur_delta_x * (long)cur_delta_x + (long)cur_delta_y * (long)cur_delta_y > (long)MAX_RECOIL_VELOCITY * (long)MAX_RECOIL_VELOCITY) { angle = ARCTAN (cur_delta_x, cur_delta_y); SetVelocityComponents (&ElementPtr1->velocity, COSINE (angle, MAX_RECOIL_VELOCITY), SINE (angle, MAX_RECOIL_VELOCITY)); } } }
static void pump_up_postprocess (ELEMENT *ElementPtr) { if (ElementPtr->state_flags & APPEARING) { ZeroVelocityComponents (&ElementPtr->velocity); } else { HELEMENT hPumpUp; ELEMENT *EPtr; ELEMENT *ShipPtr; STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); LockElement (StarShipPtr->hShip, &ShipPtr); initialize_pump_up (ShipPtr, &hPumpUp); DeltaEnergy (ShipPtr, 0); UnlockElement (StarShipPtr->hShip); LockElement (hPumpUp, &EPtr); EPtr->current.image.frame = ElementPtr->current.image.frame; EPtr->turn_wait = ElementPtr->turn_wait; EPtr->thrust_wait = ElementPtr->thrust_wait; if (--EPtr->thrust_wait == 0) { if ((EPtr->turn_wait & ~REVERSE_DIR) < MAX_PUMP - 1) { ++EPtr->turn_wait; EPtr->current.image.frame = SetRelFrameIndex ( EPtr->current.image.frame, NUM_PUMP_ANIMS); ProcessSound (SetAbsSoundIndex ( StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 2), EPtr); } EPtr->thrust_wait = LEVEL_COUNTER; } EPtr->mass_points = EPtr->hit_points = (PUMPUP_DAMAGE << (ElementPtr->turn_wait & ~REVERSE_DIR)); SetElementStarShip (EPtr, StarShipPtr); if (EPtr->thrust_wait & 1) { COUNT frame_index; frame_index = GetFrameIndex (EPtr->current.image.frame); if (((EPtr->turn_wait & REVERSE_DIR) && (frame_index % NUM_PUMP_ANIMS) != 0) || (!(EPtr->turn_wait & REVERSE_DIR) && ((frame_index + 1) % NUM_PUMP_ANIMS) == 0)) { --frame_index; EPtr->turn_wait |= REVERSE_DIR; } else { ++frame_index; EPtr->turn_wait &= ~REVERSE_DIR; } EPtr->current.image.frame = SetAbsFrameIndex ( EPtr->current.image.frame, frame_index); } if (StarShipPtr->cur_status_flags & StarShipPtr->old_status_flags & WEAPON) { StarShipPtr->weapon_counter = WEAPON_WAIT; } else { SIZE dx, dy; COUNT angle; EPtr->life_span = PUMPUP_LIFE; EPtr->preprocess_func = pump_up_preprocess; EPtr->postprocess_func = 0; angle = FACING_TO_ANGLE (StarShipPtr->ShipFacing); SetVelocityComponents (&EPtr->velocity, COSINE (angle, WORLD_TO_VELOCITY (PUMPUP_SPEED)), SINE (angle, WORLD_TO_VELOCITY (PUMPUP_SPEED))); GetCurrentVelocityComponents (&ShipPtr->velocity, &dx, &dy); dx = dx * 1/2; dy = dy * 1/2; // Add some of the Trader's velocity to its projectiles. DeltaVelocityComponents (&EPtr->velocity, dx, dy); EPtr->current.location.x -= VELOCITY_TO_WORLD (dx); EPtr->current.location.y -= VELOCITY_TO_WORLD (dy); ProcessSound (SetAbsSoundIndex ( StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 3), EPtr); } UnlockElement (hPumpUp); PutElement (hPumpUp); SetPrimType (&(GLOBAL (DisplayArray))[ElementPtr->PrimIndex], NO_PRIM); ElementPtr->state_flags |= NONSOLID; } }
static void supox_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, COUNT ConcernCounter) { STARSHIP *StarShipPtr; EVALUATE_DESC *lpEvalDesc; GetElementStarShip (ShipPtr, &StarShipPtr); lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; if (StarShipPtr->special_counter || lpEvalDesc->ObjectPtr == 0) StarShipPtr->ship_input_state &= ~SPECIAL; else { BOOLEAN LinedUp; COUNT direction_angle; SIZE delta_x, delta_y; delta_x = lpEvalDesc->ObjectPtr->next.location.x - ShipPtr->next.location.x; delta_y = lpEvalDesc->ObjectPtr->next.location.y - ShipPtr->next.location.y; direction_angle = ARCTAN (delta_x, delta_y); LinedUp = (BOOLEAN)(NORMALIZE_ANGLE (NORMALIZE_ANGLE (direction_angle - FACING_TO_ANGLE (StarShipPtr->ShipFacing)) + QUADRANT) <= HALF_CIRCLE); if (!LinedUp || lpEvalDesc->which_turn > 20 || NORMALIZE_ANGLE ( lpEvalDesc->facing - (FACING_TO_ANGLE (StarShipPtr->ShipFacing) + HALF_CIRCLE) + OCTANT ) > QUADRANT) StarShipPtr->ship_input_state &= ~SPECIAL; else if (LinedUp && lpEvalDesc->which_turn <= 12) StarShipPtr->ship_input_state |= SPECIAL; if (StarShipPtr->ship_input_state & SPECIAL) lpEvalDesc->MoveState = PURSUE; } ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); if (StarShipPtr->ship_input_state & SPECIAL) StarShipPtr->ship_input_state |= THRUST | WEAPON; lpEvalDesc = &ObjectsOfConcern[ENEMY_WEAPON_INDEX]; if (StarShipPtr->special_counter == 0 && lpEvalDesc->ObjectPtr && lpEvalDesc->MoveState == AVOID && ShipPtr->turn_wait == 0) { StarShipPtr->ship_input_state &= ~THRUST; StarShipPtr->ship_input_state |= SPECIAL; if (!(StarShipPtr->cur_status_flags & (LEFT | RIGHT))) StarShipPtr->ship_input_state |= 1 << ((BYTE)TFB_Random () & 1); else StarShipPtr->ship_input_state |= StarShipPtr->cur_status_flags & (LEFT | RIGHT); } }
static void initialize_diagonal_flame (ELEMENT *ElementPtr) { COUNT i; STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; GetElementStarShip (ElementPtr, &StarShipPtr); MissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.weapon; MissileBlock.index = 0; MissileBlock.sender = ElementPtr->playerNr; MissileBlock.flags = IGNORE_SIMILAR; MissileBlock.pixoffs = ILWRATH_OFFSET; MissileBlock.speed = MISSILE_SPEED; MissileBlock.hit_points = MISSILE_HITS; MissileBlock.damage = MISSILE_DAMAGE; MissileBlock.life = MISSILE_LIFE; MissileBlock.preprocess_func = flame_preprocess; MissileBlock.blast_offs = MISSILE_OFFSET; for(i = 0; i < 2; ++i) { HELEMENT hFlame; if (i == 0) { MissileBlock.cx = ElementPtr->next.location.x + COSINE(FACING_TO_ANGLE(StarShipPtr->ShipFacing + 4), -32); MissileBlock.cy = ElementPtr->next.location.y + SINE(FACING_TO_ANGLE(StarShipPtr->ShipFacing + 4), -32); MissileBlock.face = NORMALIZE_FACING (StarShipPtr->ShipFacing + 2); } else { MissileBlock.cx = ElementPtr->next.location.x + COSINE(FACING_TO_ANGLE(StarShipPtr->ShipFacing + 4), 32); MissileBlock.cy = ElementPtr->next.location.y + SINE(FACING_TO_ANGLE(StarShipPtr->ShipFacing + 4), 32); MissileBlock.face = NORMALIZE_FACING (StarShipPtr->ShipFacing - 2); } hFlame = initialize_missile (&MissileBlock); if (hFlame) { SIZE dx, dy; ELEMENT *FlamePtr; LockElement (hFlame, &FlamePtr); SetElementStarShip (FlamePtr, StarShipPtr); FlamePtr->hTarget = 0; GetCurrentVelocityComponents (&ElementPtr->velocity, &dx, &dy); DeltaVelocityComponents (&FlamePtr->velocity, dx, dy); FlamePtr->current.location.x -= VELOCITY_TO_WORLD (dx); FlamePtr->current.location.y -= VELOCITY_TO_WORLD (dy); FlamePtr->collision_func = flame_collision; FlamePtr->turn_wait = 0; UnlockElement (hFlame); PutElement (hFlame); } } }
static COUNT initialize_weapon (ELEMENT *ShipPtr, HELEMENT WeaponArray[]) { COUNT i; STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; GetElementStarShip (ShipPtr, &StarShipPtr); MissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.weapon; // MissileBlock.face = StarShipPtr->ShipFacing; MissileBlock.face = MissileBlock.index = StarShipPtr->ShipFacing; MissileBlock.sender = ShipPtr->playerNr; MissileBlock.flags = IGNORE_SIMILAR; MissileBlock.speed = (MISSILE_SPEED << RESOLUTION_FACTOR); MissileBlock.hit_points = MISSILE_HITS; MissileBlock.damage = MISSILE_DAMAGE; MissileBlock.life = MISSILE_LIFE; MissileBlock.blast_offs = MISSILE_OFFSET; MissileBlock.preprocess_func = 0; for (i = 0; i < 2; ++i) { if (i == 0) { MissileBlock.pixoffs = THRADDASH_OFFSET_2; MissileBlock.cx = ShipPtr->next.location.x; MissileBlock.cy = ShipPtr->next.location.y; } else if (StarShipPtr->static_counter == 0) { MissileBlock.pixoffs = THRADDASH_OFFSET_1; MissileBlock.cx = ShipPtr->next.location.x + COSINE(FACING_TO_ANGLE (MissileBlock.face + 4), -25); MissileBlock.cy = ShipPtr->next.location.y + SINE(FACING_TO_ANGLE (MissileBlock.face + 4), -25); } else { MissileBlock.pixoffs = THRADDASH_OFFSET_1; MissileBlock.cx = ShipPtr->next.location.x + COSINE(FACING_TO_ANGLE (MissileBlock.face + 4), 25); MissileBlock.cy = ShipPtr->next.location.y + SINE(FACING_TO_ANGLE (MissileBlock.face + 4), 25); } if ((WeaponArray[i] = initialize_missile (&MissileBlock))) { SIZE dx, dy; ELEMENT *WeaponPtr; LockElement (WeaponArray[i], &WeaponPtr); GetCurrentVelocityComponents (&ShipPtr->velocity, &dx, &dy); DeltaVelocityComponents (&WeaponPtr->velocity, dx, dy); WeaponPtr->current.location.x -= VELOCITY_TO_WORLD (dx); WeaponPtr->current.location.y -= VELOCITY_TO_WORLD (dy); // WeaponPtr->collision_func = repulsor_collision; UnlockElement (WeaponArray[i]); } } return (2); }
static void thraddash_intelligence (ELEMENT *ShipPtr, EVALUATE_DESC *ObjectsOfConcern, COUNT ConcernCounter) { STARSHIP *StarShipPtr; EVALUATE_DESC *lpEvalDesc; lpEvalDesc = &ObjectsOfConcern[ENEMY_SHIP_INDEX]; if (lpEvalDesc->ObjectPtr) { #define STATIONARY_SPEED WORLD_TO_VELOCITY (DISPLAY_TO_WORLD (4)) SIZE dx, dy; GetCurrentVelocityComponents ( &lpEvalDesc->ObjectPtr->velocity, &dx, &dy ); if (lpEvalDesc->which_turn > 8 || (long)dx * dx + (long)dy * dy <= (long)STATIONARY_SPEED * STATIONARY_SPEED) lpEvalDesc->MoveState = PURSUE; else lpEvalDesc->MoveState = ENTICE; } ship_intelligence (ShipPtr, ObjectsOfConcern, ConcernCounter); GetElementStarShip (ShipPtr, &StarShipPtr); if (StarShipPtr->special_counter == 0) { StarShipPtr->ship_input_state &= ~SPECIAL; if (ObjectsOfConcern[ENEMY_WEAPON_INDEX].ObjectPtr && ObjectsOfConcern[ENEMY_WEAPON_INDEX].MoveState == ENTICE) { if ((StarShipPtr->ship_input_state & THRUST) || (ShipPtr->turn_wait == 0 && !(StarShipPtr->ship_input_state & (LEFT | RIGHT))) || NORMALIZE_FACING (ANGLE_TO_FACING ( GetVelocityTravelAngle ( &ObjectsOfConcern[ENEMY_WEAPON_INDEX].ObjectPtr->velocity ) + HALF_CIRCLE + OCTANT) - StarShipPtr->ShipFacing) > ANGLE_TO_FACING (QUADRANT)) StarShipPtr->ship_input_state |= SPECIAL; } else if (lpEvalDesc->ObjectPtr) { if (lpEvalDesc->MoveState == PURSUE) { if (StarShipPtr->RaceDescPtr->ship_info.energy_level >= WEAPON_ENERGY_COST + SPECIAL_ENERGY_COST && ShipPtr->turn_wait == 0 && !(StarShipPtr->ship_input_state & (LEFT | RIGHT)) && (!(StarShipPtr->cur_status_flags & SPECIAL) || !(StarShipPtr->cur_status_flags & (SHIP_AT_MAX_SPEED | SHIP_BEYOND_MAX_SPEED)))) StarShipPtr->ship_input_state |= SPECIAL; } else if (lpEvalDesc->MoveState == ENTICE) { COUNT direction_angle; SIZE delta_x, delta_y; delta_x = lpEvalDesc->ObjectPtr->next.location.x - ShipPtr->next.location.x; delta_y = lpEvalDesc->ObjectPtr->next.location.y - ShipPtr->next.location.y; direction_angle = ARCTAN (delta_x, delta_y); if ((lpEvalDesc->which_turn > 24 && !(StarShipPtr->ship_input_state & (LEFT | RIGHT))) || (lpEvalDesc->which_turn <= 16 && NORMALIZE_ANGLE (direction_angle - (FACING_TO_ANGLE (StarShipPtr->ShipFacing) + HALF_CIRCLE) + QUADRANT) <= HALF_CIRCLE && (lpEvalDesc->which_turn < 12 || NORMALIZE_ANGLE (direction_angle - (GetVelocityTravelAngle ( &lpEvalDesc->ObjectPtr->velocity ) + HALF_CIRCLE) + (OCTANT + 2)) <= ((OCTANT + 2) << 1)))) StarShipPtr->ship_input_state |= SPECIAL; } } if ((StarShipPtr->ship_input_state & SPECIAL) && StarShipPtr->RaceDescPtr->ship_info.energy_level >= SPECIAL_ENERGY_COST) StarShipPtr->ship_input_state &= ~THRUST; } }
// Primary weapon. It must deal at least 1 damage, otherwise it won't interact with other // elements, not even gas. However, we can prevent this damage with a separate collision function. static COUNT initialize_spray (ELEMENT *ShipPtr, HELEMENT SprayArray[]) { STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; SIZE offs_x, offs_y; COUNT i, angle; static COUNT spray_side[NUM_SIDES]={0,0}; GetElementStarShip (ShipPtr, &StarShipPtr); angle = FACING_TO_ANGLE (StarShipPtr->ShipFacing); for (i = 0; i < NUM_SPRAYS; i++) { BYTE damage; // Only the foremost one deals damage if (i == NUM_SPRAYS-1) damage = 1; else damage = 0; // This mechanism can be used to alter the "pipe" from which the spray particles come. spray_side[ShipPtr->playerNr] = (spray_side[ShipPtr->playerNr] + 1) % 2; if(spray_side[ShipPtr->playerNr]) { offs_x = -SINE (angle, SPRAY_HORZ_OFFSET + (i << RESOLUTION_FACTOR)); offs_y = COSINE (angle, SPRAY_HORZ_OFFSET + (i << RESOLUTION_FACTOR)); } else { offs_x = -SINE (angle, SPRAY_HORZ_OFFSET + (i << RESOLUTION_FACTOR)); offs_y = COSINE (angle, SPRAY_HORZ_OFFSET + (i << RESOLUTION_FACTOR)); } MissileBlock.cx = ShipPtr->next.location.x + offs_x; MissileBlock.cy = ShipPtr->next.location.y + offs_y; MissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.weapon; MissileBlock.face = StarShipPtr->ShipFacing; MissileBlock.index = 0; MissileBlock.sender = ShipPtr->playerNr; MissileBlock.flags = IGNORE_SIMILAR | GASSY_SUBSTANCE; MissileBlock.pixoffs = 4 + ((i * SPRAY_DIST) << RESOLUTION_FACTOR); MissileBlock.speed = MISSILE_SPEED << RESOLUTION_FACTOR; // JMS_GFX MissileBlock.hit_points = MISSILE_HITS; MissileBlock.damage = damage; MissileBlock.life = MISSILE_LIFE; MissileBlock.preprocess_func = spray_preprocess; MissileBlock.blast_offs = MISSILE_OFFSET; SprayArray[i] = initialize_missile (&MissileBlock); if (SprayArray[i]) { ELEMENT *SprayPtr; LockElement (SprayArray[i], &SprayPtr); SprayPtr->collision_func = spray_collision; SprayPtr->thrust_wait = 1; // This makes the spray shoot in a slight angle towards the centerline. // If you want a "curved" shot, put this mechanism into spray_preprocess // where it accelerates the whot towards the centerline on every frame. offs_x = -SINE (angle, (100 << RESOLUTION_FACTOR)); offs_y = COSINE (angle, (100 << RESOLUTION_FACTOR)); DeltaVelocityComponents (&SprayPtr->velocity, offs_x, offs_y); UnlockElement (SprayArray[i]); } } return (NUM_SPRAYS); }
// Secondary weapon: Gas cloud. // The IGNORE_VELOCITY flag is very important: It doesn't only stop the gas from reacting to gravity, // (see collide.h) but it also makes it possible for the gas to stick to enemy ship (see this file's other gas functions). static void spawn_gas (ELEMENT *ShipPtr) { STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; HELEMENT Missile; SIZE offs_x, offs_y; COUNT angle; static COUNT gas_side[NUM_SIDES] = {0, 0}; static COUNT gas_number[NUM_SIDES] = {0, 0}; GetElementStarShip (ShipPtr, &StarShipPtr); gas_number[ShipPtr->playerNr] = (gas_number[ShipPtr->playerNr] + 1) % 32; gas_side[ShipPtr->playerNr] = (gas_side[ShipPtr->playerNr] + 1) % 2; angle = FACING_TO_ANGLE (StarShipPtr->ShipFacing); // This mechanism can be used to alter the "pipe" from which the gas clouds come. if(gas_side[ShipPtr->playerNr]) { offs_x = -SINE (angle, GAS_HORZ_OFFSET); offs_y = COSINE (angle, GAS_HORZ_OFFSET); } else { offs_x = -SINE (angle, GAS_HORZ_OFFSET); offs_y = COSINE (angle, GAS_HORZ_OFFSET); } MissileBlock.cx = ShipPtr->next.location.x + offs_x; MissileBlock.cy = ShipPtr->next.location.y + offs_y; MissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.special; MissileBlock.face = StarShipPtr->ShipFacing;// Baul's gas now flies forward. (this was: (StarShipPtr->ShipFacing - 8) % 16;) MissileBlock.index = LAST_DISSOLVE_INDEX; // Start with the gas emerge animation which is the last .pngs in gasXX.ani MissileBlock.sender = ShipPtr->playerNr; MissileBlock.flags = GASSY_SUBSTANCE | IGNORE_VELOCITY; // Don't erase the IGNORE_VELOCITY. It's very important. MissileBlock.pixoffs = GAS_OFFSET; MissileBlock.speed = GAS_INIT_SPEED; MissileBlock.hit_points = GAS_HITS; MissileBlock.damage = GAS_DAMAGE; MissileBlock.life = GAS_LIFE; MissileBlock.preprocess_func = gas_preprocess; MissileBlock.blast_offs = 0; Missile = initialize_missile (&MissileBlock); if (Missile) { ELEMENT *GasPtr; SIZE dx, dy; // Baul's gas now flies forward. LockElement (Missile, &GasPtr); // Baul's gas now flies forward. GetCurrentVelocityComponents (&ShipPtr->velocity, &dx, &dy); DeltaVelocityComponents (&GasPtr->velocity, dx, dy); GasPtr->current.location.x -= VELOCITY_TO_WORLD (dx); GasPtr->current.location.y -= VELOCITY_TO_WORLD (dy); GasPtr->collision_func = gas_collision; GasPtr->death_func = gas_death; GasPtr->thrust_wait = 1; GasPtr->weapon_element_index = gas_number[ShipPtr->playerNr]; SetElementStarShip (GasPtr, StarShipPtr); ProcessSound (SetAbsSoundIndex (StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1), GasPtr); UnlockElement (Missile); PutElement (Missile); } }
static COUNT initialize_dual_weapons (ELEMENT *ShipPtr, HELEMENT WeaponArray[]) { #define CENTER_OFFS DISPLAY_TO_WORLD (4) COORD cx, cy; COUNT facing, angle; SIZE offs_x, offs_y; STARSHIP *StarShipPtr; GetElementStarShip (ShipPtr, &StarShipPtr); facing = StarShipPtr->ShipFacing; angle = FACING_TO_ANGLE (facing); cx = ShipPtr->next.location.x + COSINE (angle, CENTER_OFFS); cy = ShipPtr->next.location.y + SINE (angle, CENTER_OFFS); if (ShipPtr->next.image.farray == StarShipPtr->RaceDescPtr->ship_data.ship) { #define WING_OFFS DISPLAY_TO_WORLD (10) COORD ex, ey; LASER_BLOCK LaserBlock; ELEMENT *LaserPtr; LaserBlock.sender = ShipPtr->state_flags & (GOOD_GUY | BAD_GUY); LaserBlock.pixoffs = 0; LaserBlock.color = BUILD_COLOR (MAKE_RGB15 (0x1F, 0x0A, 0x0A), 0x0C); LaserBlock.face = facing; ex = cx + COSINE (angle, LASER_RANGE); ey = cy + SINE (angle, LASER_RANGE); offs_x = -SINE (angle, WING_OFFS); offs_y = COSINE (angle, WING_OFFS); LaserBlock.cx = cx + offs_x; LaserBlock.cy = cy + offs_y; LaserBlock.ex = ex - LaserBlock.cx; LaserBlock.ey = ey - LaserBlock.cy; if ((WeaponArray[0] = initialize_laser (&LaserBlock))) { LockElement (WeaponArray[0], &LaserPtr); LaserPtr->collision_func = twin_laser_collision; UnlockElement (WeaponArray[0]); } LaserBlock.cx = cx - offs_x; LaserBlock.cy = cy - offs_y; LaserBlock.ex = ex - LaserBlock.cx; LaserBlock.ey = ey - LaserBlock.cy; if ((WeaponArray[1] = initialize_laser (&LaserBlock))) { LockElement (WeaponArray[1], &LaserPtr); LaserPtr->collision_func = twin_laser_collision; UnlockElement (WeaponArray[1]); } } else { #define MISSILE_HITS 1 #define MISSILE_DAMAGE 1 #define MISSILE_OFFSET 0 #define MISSILE_LIFE 40 #define LAUNCH_OFFS DISPLAY_TO_WORLD (4) MISSILE_BLOCK TorpBlock; ELEMENT *TorpPtr; TorpBlock.farray = StarShipPtr->RaceDescPtr->ship_data.weapon; TorpBlock.sender = (ShipPtr->state_flags & (GOOD_GUY | BAD_GUY)) | IGNORE_SIMILAR; TorpBlock.pixoffs = 0; TorpBlock.speed = MISSILE_SPEED; TorpBlock.hit_points = MISSILE_HITS; TorpBlock.damage = MISSILE_DAMAGE; TorpBlock.life = MISSILE_LIFE; TorpBlock.preprocess_func = missile_preprocess; TorpBlock.blast_offs = MISSILE_OFFSET; TorpBlock.face = TorpBlock.index = NORMALIZE_FACING (facing - 1); offs_x = -SINE (FACING_TO_ANGLE (TorpBlock.face), LAUNCH_OFFS); offs_y = COSINE (FACING_TO_ANGLE (TorpBlock.face), LAUNCH_OFFS); TorpBlock.cx = cx + offs_x; TorpBlock.cy = cy + offs_y; if ((WeaponArray[0] = initialize_missile (&TorpBlock))) { LockElement (WeaponArray[0], &TorpPtr); TorpPtr->turn_wait = TRACK_WAIT; UnlockElement (WeaponArray[0]); } TorpBlock.face = TorpBlock.index = NORMALIZE_FACING (facing + 1); TorpBlock.cx = cx - offs_x; TorpBlock.cy = cy - offs_y; if ((WeaponArray[1] = initialize_missile (&TorpBlock))) { LockElement (WeaponArray[1], &TorpPtr); TorpPtr->turn_wait = TRACK_WAIT; UnlockElement (WeaponArray[1]); } } return (2); }
// Preprocess function for spawning a ship into or out of battle. // Used when a new ship warps in, or a ship escapes by warping out, but not // when a Pkunk ship is reborn. void ship_transition (ELEMENT *ElementPtr) { if (ElementPtr->state_flags & PLAYER_SHIP) { if (ElementPtr->state_flags & APPEARING) { ElementPtr->life_span = HYPERJUMP_LIFE; ElementPtr->preprocess_func = ship_transition; ElementPtr->postprocess_func = NULL; SetPrimType (&DisplayArray[ElementPtr->PrimIndex], NO_PRIM); ElementPtr->state_flags |= NONSOLID | FINITE_LIFE | CHANGING; } else if (ElementPtr->life_span < HYPERJUMP_LIFE) { if (ElementPtr->life_span == NORMAL_LIFE && ElementPtr->crew_level) { ElementPtr->current.image.frame = ElementPtr->next.image.frame = SetEquFrameIndex ( ElementPtr->current.image.farray[0], ElementPtr->current.image.frame); SetPrimType (&DisplayArray[ElementPtr->PrimIndex], STAMP_PRIM); InitIntersectStartPoint (ElementPtr); InitIntersectEndPoint (ElementPtr); InitIntersectFrame (ElementPtr); ZeroVelocityComponents (&ElementPtr->velocity); ElementPtr->state_flags &= ~(NONSOLID | FINITE_LIFE); ElementPtr->state_flags |= CHANGING; ElementPtr->preprocess_func = ship_preprocess; ElementPtr->postprocess_func = ship_postprocess; } return; } } { HELEMENT hShipImage; ELEMENT *ShipImagePtr; STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); LockElement (StarShipPtr->hShip, &ShipImagePtr); if (!(ShipImagePtr->state_flags & NONSOLID)) { ElementPtr->preprocess_func = NULL; } else if ((hShipImage = AllocElement ())) { #define TRANSITION_SPEED DISPLAY_TO_WORLD (40 << RESOLUTION_FACTOR) // JMS_GFX #define TRANSITION_LIFE 1 COUNT angle; PutElement (hShipImage); angle = FACING_TO_ANGLE (StarShipPtr->ShipFacing); LockElement (hShipImage, &ShipImagePtr); ShipImagePtr->playerNr = NEUTRAL_PLAYER_NUM; ShipImagePtr->state_flags = APPEARING | FINITE_LIFE | NONSOLID; ShipImagePtr->thrust_wait = TRANSITION_LIFE; ShipImagePtr->life_span = ShipImagePtr->thrust_wait; // When the element "dies", in the death_func // 'cycle_ion_trail', it is given new life a number of // times, by setting life_span to thrust_wait. SetPrimType (&DisplayArray[ShipImagePtr->PrimIndex], STAMPFILL_PRIM); SetPrimColor (&DisplayArray[ShipImagePtr->PrimIndex], START_ION_COLOR); ShipImagePtr->colorCycleIndex = 0; ShipImagePtr->current.image = ElementPtr->current.image; ShipImagePtr->current.location = ElementPtr->current.location; if (!(ElementPtr->state_flags & PLAYER_SHIP)) { ShipImagePtr->current.location.x += COSINE (angle, TRANSITION_SPEED); ShipImagePtr->current.location.y += SINE (angle, TRANSITION_SPEED); ElementPtr->preprocess_func = NULL; } else if (ElementPtr->crew_level) { ShipImagePtr->current.location.x -= COSINE (angle, TRANSITION_SPEED) * (ElementPtr->life_span - 1); ShipImagePtr->current.location.y -= SINE (angle, TRANSITION_SPEED) * (ElementPtr->life_span - 1); ShipImagePtr->current.location.x = WRAP_X (ShipImagePtr->current.location.x); ShipImagePtr->current.location.y = WRAP_Y (ShipImagePtr->current.location.y); } ShipImagePtr->preprocess_func = ship_transition; ShipImagePtr->death_func = cycle_ion_trail; SetElementStarShip (ShipImagePtr, StarShipPtr); UnlockElement (hShipImage); } UnlockElement (StarShipPtr->hShip); } }
void spawn_ion_trail (ELEMENT *ElementPtr) { STARSHIP *StarShipPtr; SHIP_INFO *ShipInfoPtr; HELEMENT hIonElement; assert (ElementPtr->state_flags & PLAYER_SHIP); // JMS: Get the pointers to element's owner ship. // They are needed to see if the ship's thrust is damaged GetElementStarShip (ElementPtr, &StarShipPtr); ShipInfoPtr = &StarShipPtr->RaceDescPtr->ship_info; hIonElement = AllocElement (); if (hIonElement) { #define ION_LIFE 1 COUNT angle; RECT r; ELEMENT *IonElementPtr; STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); angle = FACING_TO_ANGLE (StarShipPtr->ShipFacing) + HALF_CIRCLE; GetFrameRect (StarShipPtr->RaceDescPtr->ship_data.ship[0], &r); r.extent.height = DISPLAY_TO_WORLD (r.extent.height + r.corner.y); InsertElement (hIonElement, GetHeadElement ()); LockElement (hIonElement, &IonElementPtr); IonElementPtr->playerNr = NEUTRAL_PLAYER_NUM; IonElementPtr->state_flags = APPEARING | FINITE_LIFE | NONSOLID; IonElementPtr->thrust_wait = ION_LIFE; IonElementPtr->life_span = IonElementPtr->thrust_wait; // When the element "dies", in the death_func // 'cycle_ion_trail', it is given new life a number of // times, by setting life_span to thrust_wait. SetPrimType (&DisplayArray[IonElementPtr->PrimIndex], POINT_PRIM); // JMS: Damaged thruster emits differently colored particles if (ShipInfoPtr->damage_flags & DAMAGE_THRUST) { SetPrimColor (&DisplayArray[IonElementPtr->PrimIndex], START_ION_COLOR_DAMAGED); } else { SetPrimColor (&DisplayArray[IonElementPtr->PrimIndex], START_ION_COLOR); } IonElementPtr->colorCycleIndex = 0; IonElementPtr->current.image.frame = DecFrameIndex (stars_in_space); IonElementPtr->current.image.farray = &stars_in_space; IonElementPtr->current.location = ElementPtr->current.location; IonElementPtr->current.location.x += (COORD)COSINE (angle, r.extent.height); IonElementPtr->current.location.y += (COORD)SINE (angle, r.extent.height); IonElementPtr->death_func = cycle_ion_trail; SetElementStarShip (IonElementPtr, StarShipPtr); { /* normally done during preprocess, but because * object is being inserted at head rather than * appended after tail it may never get preprocessed. */ IonElementPtr->next = IonElementPtr->current; --IonElementPtr->life_span; IonElementPtr->state_flags |= PRE_PROCESS; } UnlockElement (hIonElement); } }
static COUNT initialize_flak (ELEMENT *ShipPtr, HELEMENT MissileArray[]) { COUNT i; STARSHIP *StarShipPtr; MISSILE_BLOCK MissileBlock; GetElementStarShip (ShipPtr, &StarShipPtr); MissileBlock.cx = ShipPtr->next.location.x; MissileBlock.cy = ShipPtr->next.location.y; MissileBlock.farray = StarShipPtr->RaceDescPtr->ship_data.weapon; MissileBlock.face = MissileBlock.index = StarShipPtr->ShipFacing; MissileBlock.sender = ShipPtr->playerNr; MissileBlock.flags = IGNORE_SIMILAR; MissileBlock.pixoffs = SPATHI_FORWARD_OFFSET; MissileBlock.speed = (MISSILE_SPEED << RESOLUTION_FACTOR); MissileBlock.hit_points = MISSILE_HITS; MissileBlock.damage = MISSILE_DAMAGE; MissileBlock.life = MISSILE_LIFE; MissileBlock.preprocess_func = flak_preprocess; MissileBlock.blast_offs = MISSILE_OFFSET; for(i = 0; i < 3; ++i) { if (i == 0) { MissileBlock.cx = ShipPtr->next.location.x; MissileBlock.cy = ShipPtr->next.location.y; } else if (i == 1) { MissileBlock.cx = ShipPtr->next.location.x + COSINE(FACING_TO_ANGLE(StarShipPtr->ShipFacing + 4), 12); MissileBlock.cy = ShipPtr->next.location.y + SINE(FACING_TO_ANGLE(StarShipPtr->ShipFacing + 4), 12); } else if (i == 2) { MissileBlock.cx = ShipPtr->next.location.x + COSINE(FACING_TO_ANGLE(StarShipPtr->ShipFacing + 4), -12); MissileBlock.cy = ShipPtr->next.location.y + SINE(FACING_TO_ANGLE(StarShipPtr->ShipFacing + 4), -12); } if ((MissileArray[i] = initialize_missile (&MissileBlock))) { SIZE dx, dy, angle, speed; ELEMENT *MissilePtr; LockElement (MissileArray[i], &MissilePtr); if (i > 0) { angle = GetVelocityTravelAngle (&MissilePtr->velocity); GetCurrentVelocityComponents(&MissilePtr->velocity, &dx, &dy); speed = square_root (dx*dx + dy*dy); if (i == 1) angle += 1; else if (i == 2) angle -= 1; SetVelocityComponents(&MissilePtr->velocity, COSINE(angle, speed), SINE(angle, speed)); } GetCurrentVelocityComponents (&ShipPtr->velocity, &dx, &dy); // Add the Eluder's velocity to its projectiles. DeltaVelocityComponents (&MissilePtr->velocity, dx, dy); MissilePtr->current.location.x -= VELOCITY_TO_WORLD (dx); MissilePtr->current.location.y -= VELOCITY_TO_WORLD (dy); MissilePtr->turn_wait = 1; UnlockElement (MissileArray[i]); } } return (3); }
static void phoenix_transition (ELEMENT *ElementPtr) { HELEMENT hShipImage; ELEMENT *ShipImagePtr; STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); LockElement (StarShipPtr->hShip, &ShipImagePtr); if (!(ShipImagePtr->state_flags & NONSOLID)) { ElementPtr->preprocess_func = NULL; } else if ((hShipImage = AllocElement ())) { #define TRANSITION_SPEED DISPLAY_TO_WORLD (20) COUNT angle; PutElement (hShipImage); LockElement (hShipImage, &ShipImagePtr); ShipImagePtr->playerNr = NEUTRAL_PLAYER_NUM; ShipImagePtr->state_flags = APPEARING | FINITE_LIFE | NONSOLID; ShipImagePtr->life_span = TRANSITION_LIFE; SetPrimType (&(GLOBAL (DisplayArray))[ShipImagePtr->PrimIndex], STAMPFILL_PRIM); SetPrimColor ( &(GLOBAL (DisplayArray))[ShipImagePtr->PrimIndex], START_PHOENIX_COLOR); ShipImagePtr->colorCycleIndex = 0; ShipImagePtr->current.image = ElementPtr->current.image; ShipImagePtr->current.location = ElementPtr->current.location; if (!(ElementPtr->state_flags & PLAYER_SHIP)) { angle = ElementPtr->mass_points; ShipImagePtr->current.location.x += COSINE (angle, TRANSITION_SPEED); ShipImagePtr->current.location.y += SINE (angle, TRANSITION_SPEED); ElementPtr->preprocess_func = NULL; } else { angle = FACING_TO_ANGLE (StarShipPtr->ShipFacing); ShipImagePtr->current.location.x -= COSINE (angle, TRANSITION_SPEED) * (ElementPtr->life_span - 1); ShipImagePtr->current.location.y -= SINE (angle, TRANSITION_SPEED) * (ElementPtr->life_span - 1); ShipImagePtr->current.location.x = WRAP_X (ShipImagePtr->current.location.x); ShipImagePtr->current.location.y = WRAP_Y (ShipImagePtr->current.location.y); } ShipImagePtr->mass_points = (BYTE)angle; ShipImagePtr->preprocess_func = phoenix_transition; ShipImagePtr->death_func = spawn_phoenix_trail; SetElementStarShip (ShipImagePtr, StarShipPtr); UnlockElement (hShipImage); } UnlockElement (StarShipPtr->hShip); }