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 decelerate_preprocess (ELEMENT *ElementPtr) { SIZE dx, dy; GetCurrentVelocityComponents (&ElementPtr->velocity, &dx, &dy); dx /= 2; dy /= 2; SetVelocityComponents (&ElementPtr->velocity, dx, dy); if (dx == 0 && dy == 0) { ElementPtr->preprocess_func = buzztrack_preprocess; } spin_preprocess (ElementPtr); }
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 gas_preprocess (ELEMENT *ElementPtr) { STARSHIP *StarShipPtr; SDWORD dx, dy; // Baul's gas now flies forward. Slow down the gas smoothly. GetCurrentVelocityComponentsSdword (&ElementPtr->velocity, &dx, &dy); if (dx != 0 || dy != 0) { dx = (SDWORD)(dx * 9 / 10); dy = (SDWORD)(dy * 9 / 10); SetVelocityComponents (&ElementPtr->velocity, dx, dy); } GetElementStarShip (ElementPtr, &StarShipPtr); // Move to next image frame. (Abusing thrust_wait to slow down the anim.) if (ElementPtr->thrust_wait > 0) --ElementPtr->thrust_wait; else { // Abusing thrust_wait to slow down the anim. (Should help performance a bit.) ElementPtr->thrust_wait = 1; // This makes the gas animate even if the ships are not moving and the screen is stationary. ElementPtr->state_flags |= CHANGING; if (GetFrameIndex (ElementPtr->current.image.frame) >= LAST_DISSOLVE_INDEX && GetFrameIndex (ElementPtr->current.image.frame) < LAST_DISSOLVE_INDEX + NUM_EMERGE_FRAMES) ElementPtr->next.image.frame = IncFrameIndex (ElementPtr->current.image.frame); else if (GetFrameIndex (ElementPtr->current.image.frame) < LAST_GAS_INDEX - 1) ElementPtr->next.image.frame = IncFrameIndex (ElementPtr->current.image.frame); else ElementPtr->next.image.frame = SetAbsFrameIndex (ElementPtr->current.image.frame, 0); } // If enemy ship dies, remove the gas (this prevents game crashing upon enemy ship dying with gas on it). if ((!(ElementPtr->state_flags & IGNORE_VELOCITY) && ElementPtr->hTarget == 0) || StarShipPtr->RaceDescPtr->ship_info.crew_level == 0) { ElementPtr->life_span = 0; ElementPtr->state_flags |= DISAPPEARING; } // When the gas has collided with enemy ship, it sticks to the ship until expires. // (When the gas is sticking to enemy ship, the gas's IGNORE_VELOCITY flag is disabled.) else if (!(ElementPtr->state_flags & IGNORE_VELOCITY) && !(ElementPtr->state_flags & DISAPPEARING)) { ELEMENT *eptr; SIZE offs_x, offs_y; SBYTE leftOrRight, upOrDown; COUNT angle, angleCorrect; static BYTE alignment[NUM_SIDES]={0,0}; // eptr points to enemy ship now. LockElement (ElementPtr->hTarget, &eptr); // Make gas's location the same as the enemy ship's. ElementPtr->next.location = eptr->next.location; // Randomize the gas's location so every gas cloud doesn't stick to the same place on the enemy ship. GetElementStarShip (eptr, &StarShipPtr); angle = (ElementPtr->weapon_element_index) % 16; alignment[ElementPtr->playerNr] = ElementPtr->weapon_element_index % 4; if (alignment[ElementPtr->playerNr] == 0) { leftOrRight = -1; upOrDown = 1; angleCorrect = 0; } else if (alignment[ElementPtr->playerNr] == 1) { leftOrRight = 1; upOrDown = -1; angleCorrect = 0; } else if (alignment[ElementPtr->playerNr] == 2) { leftOrRight = -1; upOrDown = 1; angleCorrect = HALF_CIRCLE / 2; } else { leftOrRight = 1; upOrDown = -1; angleCorrect = HALF_CIRCLE / 2; } offs_x = SINE (angle - angleCorrect, (ElementPtr->weapon_element_index % 16) * (5 << RESOLUTION_FACTOR)); offs_y = COSINE (angle - angleCorrect, (ElementPtr->weapon_element_index % 16) * (5 << RESOLUTION_FACTOR)); ElementPtr->next.location.x = ElementPtr->next.location.x + leftOrRight * offs_x; ElementPtr->next.location.y = ElementPtr->next.location.y + upOrDown * offs_y; if (ElementPtr->turn_wait) { HELEMENT hEffect; hEffect = AllocElement (); if (hEffect) { // eptr points to the new gas element now. LockElement (hEffect, &eptr); eptr->playerNr = ElementPtr->playerNr; eptr->state_flags = FINITE_LIFE | GASSY_SUBSTANCE | CHANGING; eptr->life_span = 1; eptr->thrust_wait = 1; eptr->weapon_element_index = ElementPtr->weapon_element_index; eptr->current = eptr->next = ElementPtr->next; eptr->preprocess_func = gas_preprocess; eptr->collision_func = gas_collision; // No need to have death_func here: It carries on from the declaration in gas_collision. // In fact, if gas_death is put here as death_func, it just messes up the graphics. SetPrimType (&(GLOBAL (DisplayArray))[eptr->PrimIndex], STAMP_PRIM); GetElementStarShip (ElementPtr, &StarShipPtr); SetElementStarShip (eptr, StarShipPtr); eptr->hTarget = ElementPtr->hTarget; UnlockElement (hEffect); PutElement (hEffect); } } UnlockElement (ElementPtr->hTarget); } }
static void sis_hyper_preprocess (ELEMENT *ElementPtr) { SIZE udx, udy, dx, dy; SIZE AccelerateDirection; STARSHIP *StarShipPtr; if (ElementPtr->state_flags & APPEARING) ElementPtr->velocity = GLOBAL (velocity); AccelerateDirection = 0; GetElementStarShip (ElementPtr, &StarShipPtr); ++StarShipPtr->weapon_counter; /* no shooting in hyperspace! */ if ((GLOBAL (autopilot)).x == ~0 || (GLOBAL (autopilot)).y == ~0 || (StarShipPtr->cur_status_flags & (LEFT | RIGHT | THRUST))) { LeaveAutoPilot: (GLOBAL (autopilot)).x = (GLOBAL (autopilot)).y = ~0; if (!(StarShipPtr->cur_status_flags & THRUST) || (GLOBAL_SIS (FuelOnBoard) == 0 && GET_GAME_STATE (ARILOU_SPACE_SIDE) <= 1)) { AccelerateDirection = -1; GetCurrentVelocityComponents (&ElementPtr->velocity, &dx, &dy); udx = dx << 4; udy = dy << 4; StarShipPtr->cur_status_flags &= ~THRUST; } } else { SIZE facing; POINT universe; universe.x = LOGX_TO_UNIVERSE (GLOBAL_SIS (log_x)); universe.y = LOGY_TO_UNIVERSE (GLOBAL_SIS (log_y)); udx = (GLOBAL (autopilot)).x - universe.x; udy = -((GLOBAL (autopilot)).y - universe.y); if ((dx = udx) < 0) dx = -dx; if ((dy = udy) < 0) dy = -dy; if (dx <= 1 && dy <= 1) goto LeaveAutoPilot; facing = NORMALIZE_FACING (ANGLE_TO_FACING (ARCTAN (udx, udy))); /* This prevents ship from flying backwards on auto-pilot. * It could also theoretically abort autopilot in a bad savegame */ if ((StarShipPtr->cur_status_flags & SHIP_AT_MAX_SPEED) /*|| (ElementPtr->state_flags & APPEARING)*/ ) { if (NORMALIZE_FACING (StarShipPtr->ShipFacing + ANGLE_TO_FACING (QUADRANT) - facing) > ANGLE_TO_FACING (HALF_CIRCLE)) goto LeaveAutoPilot; facing = StarShipPtr->ShipFacing; } else if ((int)facing != (int)StarShipPtr->ShipFacing && ElementPtr->turn_wait == 0) { if (NORMALIZE_FACING ( StarShipPtr->ShipFacing - facing ) >= ANGLE_TO_FACING (HALF_CIRCLE)) { facing = NORMALIZE_FACING (facing - 1); StarShipPtr->cur_status_flags |= RIGHT; } else if ((int)StarShipPtr->ShipFacing != (int)facing) { facing = NORMALIZE_FACING (facing + 1); StarShipPtr->cur_status_flags |= LEFT; } if ((int)facing == (int)StarShipPtr->ShipFacing) { ZeroVelocityComponents (&ElementPtr->velocity); } } GetCurrentVelocityComponents (&ElementPtr->velocity, &dx, &dy); if ((GLOBAL_SIS (FuelOnBoard) || GET_GAME_STATE (ARILOU_SPACE_SIDE) > 1) && (int)facing == (int)StarShipPtr->ShipFacing) { StarShipPtr->cur_status_flags |= SHIP_AT_MAX_SPEED; AccelerateDirection = 1; } else { AccelerateDirection = -1; udx = dx << 4; udy = dy << 4; } } if (ElementPtr->thrust_wait == 0 && AccelerateDirection) { COUNT dist; SIZE speed, velocity_increment; velocity_increment = WORLD_TO_VELOCITY ( StarShipPtr->RaceDescPtr->characteristics.thrust_increment); if ((dist = square_root ((long)udx * udx + (long)udy * udy)) == 0) dist = 1; /* prevent divide by zero */ speed = square_root ((long)dx * dx + (long)dy * dy); if (AccelerateDirection < 0) { dy = (speed / velocity_increment - 1) * velocity_increment; if (dy < speed - velocity_increment) dy = speed - velocity_increment; if ((speed = dy) < 0) speed = 0; StarShipPtr->cur_status_flags &= ~SHIP_AT_MAX_SPEED; } else { SIZE max_velocity; AccelerateDirection = 0; max_velocity = WORLD_TO_VELOCITY ( StarShipPtr->RaceDescPtr->characteristics.max_thrust); dy = (speed / velocity_increment + 1) * velocity_increment; if (dy < speed + velocity_increment) dy = speed + velocity_increment; if ((speed = dy) > max_velocity) { speed = max_velocity; StarShipPtr->cur_status_flags |= SHIP_AT_MAX_SPEED; } } dx = (SIZE)((long)udx * speed / (long)dist); dy = (SIZE)((long)udy * speed / (long)dist); SetVelocityComponents (&ElementPtr->velocity, dx, dy); ElementPtr->thrust_wait = StarShipPtr->RaceDescPtr->characteristics.thrust_wait; } }
static void explosion_preprocess (ELEMENT *ShipPtr) { BYTE i; i = (NUM_EXPLOSION_FRAMES * 3) - ShipPtr->life_span; switch (i) { case 25: ShipPtr->preprocess_func = NULL; case 0: case 1: case 2: case 20: case 21: case 22: case 23: case 24: i = 1; break; case 3: case 4: case 5: case 18: case 19: i = 2; break; case 15: SetPrimType (&DisplayArray[ShipPtr->PrimIndex], NO_PRIM); ShipPtr->state_flags |= CHANGING; default: i = 3; break; } do { HELEMENT hElement; hElement = AllocElement (); if (hElement) { COUNT angle, dist; DWORD rand_val; ELEMENT *ElementPtr; extern FRAME explosion[]; PutElement (hElement); LockElement (hElement, &ElementPtr); ElementPtr->playerNr = NEUTRAL_PLAYER_NUM; ElementPtr->state_flags = APPEARING | FINITE_LIFE | NONSOLID; ElementPtr->life_span = 9; SetPrimType (&DisplayArray[ElementPtr->PrimIndex], STAMP_PRIM); ElementPtr->current.image.farray = explosion; ElementPtr->current.image.frame = explosion[0]; rand_val = TFB_Random (); angle = LOBYTE (HIWORD (rand_val)); dist = DISPLAY_TO_WORLD (LOBYTE (LOWORD (rand_val)) % 8); if (HIBYTE (LOWORD (rand_val)) < 256 * 1 / 3) dist += DISPLAY_TO_WORLD (8); ElementPtr->current.location.x = ShipPtr->current.location.x + COSINE (angle, dist); ElementPtr->current.location.y = ShipPtr->current.location.y + SINE (angle, dist); ElementPtr->preprocess_func = animation_preprocess; rand_val = TFB_Random (); angle = LOBYTE (LOWORD (rand_val)); dist = WORLD_TO_VELOCITY ( DISPLAY_TO_WORLD (HIBYTE (LOWORD (rand_val)) % 5)); SetVelocityComponents (&ElementPtr->velocity, COSINE (angle, dist), SINE (angle, dist)); UnlockElement (hElement); } } while (--i); }
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); }