BOOLEAN TimeSpaceMatterConflict (ELEMENT *ElementPtr) { HELEMENT hTestElement, hSuccElement; INTERSECT_CONTROL ElementControl; ElementControl.IntersectStamp.origin.x = WORLD_TO_DISPLAY (ElementPtr->current.location.x); ElementControl.IntersectStamp.origin.y = WORLD_TO_DISPLAY (ElementPtr->current.location.y); ElementControl.IntersectStamp.frame = SetEquFrameIndex (ElementPtr->current.image.farray[0], ElementPtr->current.image.frame); ElementControl.EndPoint = ElementControl.IntersectStamp.origin; for (hTestElement = GetHeadElement (); hTestElement != 0; hTestElement = hSuccElement) { ELEMENT *TestElementPtr; LockElement (hTestElement, &TestElementPtr); hSuccElement = GetSuccElement (TestElementPtr); if (TestElementPtr != ElementPtr && (CollidingElement (TestElementPtr) /* ship in transition */ || (TestElementPtr->state_flags & PLAYER_SHIP))) { INTERSECT_CONTROL TestElementControl; TestElementControl.IntersectStamp.origin.x = WORLD_TO_DISPLAY (TestElementPtr->current.location.x); TestElementControl.IntersectStamp.origin.y = WORLD_TO_DISPLAY (TestElementPtr->current.location.y); TestElementControl.IntersectStamp.frame = SetEquFrameIndex (TestElementPtr->current.image.farray[0], TestElementPtr->current.image.frame); TestElementControl.EndPoint = TestElementControl.IntersectStamp.origin; if (DrawablesIntersect (&ElementControl, &TestElementControl, MAX_TIME_VALUE)) { UnlockElement (hTestElement); break; } } UnlockElement (hTestElement); } return (hTestElement != 0 ? TRUE : FALSE); }
static void spawn_point_defense (PELEMENT ElementPtr) { STARSHIPPTR StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); if (ElementPtr->state_flags & PLAYER_SHIP) { HELEMENT hDefense; hDefense = AllocElement (); if (hDefense) { ELEMENTPTR DefensePtr; LockElement (hDefense, &DefensePtr); DefensePtr->state_flags = APPEARING | NONSOLID | FINITE_LIFE | (ElementPtr->state_flags & (GOOD_GUY | BAD_GUY)); { DefensePtr->death_func = spawn_point_defense; } GetElementStarShip (ElementPtr, &StarShipPtr); SetElementStarShip (DefensePtr, StarShipPtr); UnlockElement (hDefense); PutElement (hDefense); } } else { BOOLEAN PaidFor; HELEMENT hObject, hNextObject; ELEMENTPTR ShipPtr; PaidFor = FALSE; LockElement (StarShipPtr->hShip, &ShipPtr); for (hObject = GetTailElement (); hObject; hObject = hNextObject) { ELEMENTPTR ObjectPtr; LockElement (hObject, &ObjectPtr); hNextObject = GetPredElement (ObjectPtr); if (ObjectPtr != ShipPtr && CollidingElement (ObjectPtr) && !OBJECT_CLOAKED (ObjectPtr)) { #define LASER_RANGE (UWORD)100 SIZE delta_x, delta_y; delta_x = ObjectPtr->next.location.x - ShipPtr->next.location.x; delta_y = ObjectPtr->next.location.y - ShipPtr->next.location.y; if (delta_x < 0) delta_x = -delta_x; if (delta_y < 0) delta_y = -delta_y; delta_x = WORLD_TO_DISPLAY (delta_x); delta_y = WORLD_TO_DISPLAY (delta_y); if ((UWORD)delta_x <= LASER_RANGE && (UWORD)delta_y <= LASER_RANGE && (UWORD)delta_x * (UWORD)delta_x + (UWORD)delta_y * (UWORD)delta_y <= LASER_RANGE * LASER_RANGE) { HELEMENT hPointDefense; LASER_BLOCK LaserBlock; if (!PaidFor) { if (!DeltaEnergy (ShipPtr, -SPECIAL_ENERGY_COST)) break; ProcessSound (SetAbsSoundIndex ( /* POINT_DEFENSE_LASER */ StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 1)); StarShipPtr->special_counter = StarShipPtr->RaceDescPtr->characteristics.special_wait; PaidFor = TRUE; } LaserBlock.cx = ShipPtr->next.location.x; LaserBlock.cy = ShipPtr->next.location.y; LaserBlock.face = 0; LaserBlock.ex = ObjectPtr->next.location.x - ShipPtr->next.location.x; LaserBlock.ey = ObjectPtr->next.location.y - ShipPtr->next.location.y; LaserBlock.sender = (ShipPtr->state_flags & (GOOD_GUY | BAD_GUY)) | IGNORE_SIMILAR; LaserBlock.pixoffs = 0; LaserBlock.color = BUILD_COLOR (MAKE_RGB15 (0x1F, 0x1F, 0x1F), 0x0F); hPointDefense = initialize_laser (&LaserBlock); if (hPointDefense) { ELEMENTPTR PDPtr; LockElement (hPointDefense, &PDPtr); SetElementStarShip (PDPtr, StarShipPtr); PDPtr->hTarget = 0; UnlockElement (hPointDefense); PutElement (hPointDefense); } } } UnlockElement (hObject); } UnlockElement (StarShipPtr->hShip); } }
static void self_destruct (PELEMENT ElementPtr) { STARSHIPPTR StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); if (ElementPtr->state_flags & PLAYER_SHIP) { HELEMENT hDestruct; hDestruct = AllocElement (); if (hDestruct) { ELEMENTPTR DestructPtr; LockElement (hDestruct, &DestructPtr); DestructPtr->state_flags = APPEARING | NONSOLID | FINITE_LIFE | (ElementPtr->state_flags & (GOOD_GUY | BAD_GUY)); DestructPtr->next.location = ElementPtr->next.location; DestructPtr->life_span = 0; DestructPtr->pParent = ElementPtr->pParent; DestructPtr->hTarget = 0; DestructPtr->death_func = self_destruct; UnlockElement (hDestruct); PutElement (hDestruct); } ElementPtr->state_flags |= NONSOLID; ElementPtr->life_span = 0; ElementPtr->preprocess_func = destruct_preprocess; } else { HELEMENT hElement, hNextElement; for (hElement = GetHeadElement (); hElement != 0; hElement = hNextElement) { ELEMENTPTR ObjPtr; LockElement (hElement, &ObjPtr); hNextElement = GetSuccElement (ObjPtr); if (CollidingElement (ObjPtr) || ORZ_MARINE (ObjPtr)) { #define DESTRUCT_RANGE 180 SIZE delta_x, delta_y; DWORD dist; if ((delta_x = ObjPtr->next.location.x - ElementPtr->next.location.x) < 0) delta_x = -delta_x; if ((delta_y = ObjPtr->next.location.y - ElementPtr->next.location.y) < 0) delta_y = -delta_y; delta_x = WORLD_TO_DISPLAY (delta_x); delta_y = WORLD_TO_DISPLAY (delta_y); if (delta_x <= DESTRUCT_RANGE && delta_y <= DESTRUCT_RANGE && (dist = (DWORD)(delta_x * delta_x) + (DWORD)(delta_y * delta_y)) <= (DWORD)(DESTRUCT_RANGE * DESTRUCT_RANGE)) { #define MAX_DESTRUCTION (DESTRUCT_RANGE / 10) SIZE destruction; destruction = ((MAX_DESTRUCTION * (DESTRUCT_RANGE - square_root (dist))) / DESTRUCT_RANGE) + 1; if (ObjPtr->state_flags & PLAYER_SHIP) { if (!DeltaCrew (ObjPtr, -destruction)) ObjPtr->life_span = 0; } else if (!GRAVITY_MASS (ObjPtr->mass_points)) { if ((BYTE)destruction < ObjPtr->hit_points) ObjPtr->hit_points -= (BYTE)destruction; else { ObjPtr->hit_points = 0; ObjPtr->life_span = 0; } } } } UnlockElement (hElement); } } }
// When hit by Baul spray, gas clouds explodes transforming into a lethal shockwave. static void generate_shockwave (ELEMENT *ElementPtr, BYTE which_player) { STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); // Gas is still 'solid' when it's hit by the spray. Let's make a shockwave and kill the gas cloud. if (!(ElementPtr->state_flags & NONSOLID)) { HELEMENT hShockwave; hShockwave = AllocElement (); if (hShockwave) { ELEMENT *ShockwavePtr; STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); PutElement (hShockwave); LockElement (hShockwave, &ShockwavePtr); SetElementStarShip (ShockwavePtr, StarShipPtr); ShockwavePtr->hit_points = ShockwavePtr->mass_points = 0; ShockwavePtr->playerNr = which_player; ShockwavePtr->state_flags = APPEARING | FINITE_LIFE | NONSOLID | IGNORE_SIMILAR; ShockwavePtr->life_span = SHOCKWAVE_FRAMES; SetPrimType (&(GLOBAL (DisplayArray))[ShockwavePtr->PrimIndex], STAMP_PRIM); ShockwavePtr->current.image.farray = StarShipPtr->RaceDescPtr->ship_data.special; ShockwavePtr->current.image.frame = SetAbsFrameIndex(StarShipPtr->RaceDescPtr->ship_data.special[0], LAST_GAS_INDEX); ShockwavePtr->next.image.frame = SetAbsFrameIndex(ElementPtr->current.image.frame, LAST_GAS_INDEX); ShockwavePtr->current.location = ElementPtr->current.location; ShockwavePtr->preprocess_func = shockwave_preprocess; ShockwavePtr->postprocess_func = NULL; ShockwavePtr->death_func = NULL; ZeroVelocityComponents (&ShockwavePtr->velocity); UnlockElement (hShockwave); } // Gas dies on the next turn. ElementPtr->state_flags |= NONSOLID; // Explosion sounds. ProcessSound (SetAbsSoundIndex (StarShipPtr->RaceDescPtr->ship_data.ship_sounds, 2), ElementPtr); ProcessSound (SetAbsSoundIndex (GameSounds, TARGET_DAMAGED_FOR_6_PLUS_PT), ElementPtr); } { // This is called during PostProcessQueue(), close to or at the end, // for the temporary shockwave element to apply the damage. // The effects are not seen until the next frame. HELEMENT hElement, hNextElement; for (hElement = GetHeadElement (); hElement != 0; hElement = hNextElement) { ELEMENT *ObjPtr; LockElement (hElement, &ObjPtr); hNextElement = GetSuccElement (ObjPtr); if (IS_GAS (ObjPtr)) { SIZE delta_x, delta_y; DWORD dist; if ((delta_x = ObjPtr->next.location.x - ElementPtr->next.location.x) < 0) delta_x = -delta_x; if ((delta_y = ObjPtr->next.location.y - ElementPtr->next.location.y) < 0) delta_y = -delta_y; delta_x = WORLD_TO_DISPLAY (delta_x); delta_y = WORLD_TO_DISPLAY (delta_y); if (delta_x <= SHOCKWAVE_RANGE && delta_y <= SHOCKWAVE_RANGE && (dist = (DWORD)(delta_x * delta_x) + (DWORD)(delta_y * delta_y)) <= (DWORD)(SHOCKWAVE_RANGE * SHOCKWAVE_RANGE)) { SIZE destruction; destruction = ((MAX_DESTRUCTION * (SHOCKWAVE_RANGE - square_root (dist))) / SHOCKWAVE_RANGE) + 1; // The shockwave is delayed according to how far it is from the shockwave that set it off. ObjPtr->life_span = (10 / destruction); ObjPtr->death_func = generate_shockwave_2; ObjPtr->playerNr = which_player; } } else if (CollidingElement (ObjPtr) || ORZ_MARINE (ObjPtr)) { SIZE delta_x, delta_y; DWORD dist; if ((delta_x = ObjPtr->next.location.x - ElementPtr->next.location.x) < 0) delta_x = -delta_x; if ((delta_y = ObjPtr->next.location.y - ElementPtr->next.location.y) < 0) delta_y = -delta_y; delta_x = WORLD_TO_DISPLAY (delta_x); delta_y = WORLD_TO_DISPLAY (delta_y); if (delta_x <= SHOCKWAVE_RANGE && delta_y <= SHOCKWAVE_RANGE && (dist = (DWORD)(delta_x * delta_x) + (DWORD)(delta_y * delta_y)) <= (DWORD)(SHOCKWAVE_RANGE * SHOCKWAVE_RANGE)) { SIZE destruction; destruction = ((MAX_DESTRUCTION * (SHOCKWAVE_RANGE - square_root (dist))) / SHOCKWAVE_RANGE) + 1; if (ObjPtr->state_flags & PLAYER_SHIP && ObjPtr->playerNr != which_player) { STARSHIP *EnemyShipPtr; GetElementStarShip (ObjPtr, &EnemyShipPtr); // Deal damage to ships except shield-using Yehat & Utwig. if (!((EnemyShipPtr->SpeciesID == YEHAT_ID || EnemyShipPtr->SpeciesID == UTWIG_ID) && ObjPtr->life_span > NORMAL_LIFE)) { if (!DeltaCrew (ObjPtr, -destruction)) ObjPtr->life_span = 0; } // Charge Utwig shield. else if (EnemyShipPtr->SpeciesID == UTWIG_ID && ObjPtr->life_span > NORMAL_LIFE) ObjPtr->life_span += destruction; } else if (!GRAVITY_MASS (ObjPtr->mass_points) && ObjPtr->playerNr != which_player) { if ((BYTE)destruction < ObjPtr->hit_points) ObjPtr->hit_points -= (BYTE)destruction; else { ObjPtr->hit_points = 0; ObjPtr->life_span = 0; } } } } UnlockElement (hElement); } } }
// XXX: This function should be split into two static void self_destruct (ELEMENT *ElementPtr) { STARSHIP *StarShipPtr; GetElementStarShip (ElementPtr, &StarShipPtr); if (ElementPtr->state_flags & PLAYER_SHIP) { HELEMENT hDestruct; // Spawn a temporary element, which dies in this same frame, in order // to defer the effects of the glory explosion. // It will be the last element (or one of the last) for which the // death_func will be called from PostProcessQueue() in this frame. hDestruct = AllocElement (); if (hDestruct) { ELEMENT *DestructPtr; LockElement (hDestruct, &DestructPtr); DestructPtr->playerNr = ElementPtr->playerNr; DestructPtr->state_flags = APPEARING | NONSOLID | FINITE_LIFE; DestructPtr->next.location = ElementPtr->next.location; DestructPtr->life_span = 0; DestructPtr->pParent = ElementPtr->pParent; DestructPtr->hTarget = 0; DestructPtr->death_func = self_destruct; UnlockElement (hDestruct); PutElement (hDestruct); } ElementPtr->state_flags |= NONSOLID; // The ship is now dead. It's death_func, i.e. ship_death(), will be // called the next frame. ElementPtr->life_span = 0; ElementPtr->preprocess_func = destruct_preprocess; } else { // This is called during PostProcessQueue(), close to or at the end, // for the temporary destruct element to apply the effects of glory // explosion. The effects are not seen until the next frame. HELEMENT hElement, hNextElement; for (hElement = GetHeadElement (); hElement != 0; hElement = hNextElement) { ELEMENT *ObjPtr; LockElement (hElement, &ObjPtr); hNextElement = GetSuccElement (ObjPtr); if (CollidingElement (ObjPtr) || ORZ_MARINE (ObjPtr)) { #define DESTRUCT_RANGE 180 SIZE delta_x, delta_y; DWORD dist; if ((delta_x = ObjPtr->next.location.x - ElementPtr->next.location.x) < 0) delta_x = -delta_x; if ((delta_y = ObjPtr->next.location.y - ElementPtr->next.location.y) < 0) delta_y = -delta_y; delta_x = WORLD_TO_DISPLAY (delta_x); delta_y = WORLD_TO_DISPLAY (delta_y); if (delta_x <= DESTRUCT_RANGE && delta_y <= DESTRUCT_RANGE && (dist = (DWORD)(delta_x * delta_x) + (DWORD)(delta_y * delta_y)) <= (DWORD)(DESTRUCT_RANGE * DESTRUCT_RANGE)) { #define MAX_DESTRUCTION (DESTRUCT_RANGE / 10) SIZE destruction; destruction = ((MAX_DESTRUCTION * (DESTRUCT_RANGE - square_root (dist))) / DESTRUCT_RANGE) + 1; if (ObjPtr->state_flags & PLAYER_SHIP) { if (!DeltaCrew (ObjPtr, -destruction)) ObjPtr->life_span = 0; } else if (!GRAVITY_MASS (ObjPtr->mass_points)) { if ((BYTE)destruction < ObjPtr->hit_points) ObjPtr->hit_points -= (BYTE)destruction; else { ObjPtr->hit_points = 0; ObjPtr->life_span = 0; } } } } UnlockElement (hElement); } } }
BOOLEAN CalculateGravity (ELEMENT *ElementPtr) { BOOLEAN retval, HasGravity; HELEMENT hTestElement, hSuccElement; retval = FALSE; HasGravity = (BOOLEAN)(CollidingElement (ElementPtr) && GRAVITY_MASS (ElementPtr->mass_points + 1)); for (hTestElement = GetHeadElement (); hTestElement != 0; hTestElement = hSuccElement) { BOOLEAN TestHasGravity; ELEMENT *TestElementPtr; LockElement (hTestElement, &TestElementPtr); if (TestElementPtr != ElementPtr && CollidingElement (TestElementPtr) && (TestHasGravity = GRAVITY_MASS (TestElementPtr->mass_points + 1)) != HasGravity) { COUNT abs_dx, abs_dy; SIZE dx, dy; if (!(ElementPtr->state_flags & PRE_PROCESS)) { dx = ElementPtr->current.location.x - TestElementPtr->current.location.x; dy = ElementPtr->current.location.y - TestElementPtr->current.location.y; } else { dx = ElementPtr->next.location.x - TestElementPtr->next.location.x; dy = ElementPtr->next.location.y - TestElementPtr->next.location.y; } #ifdef DEBUG_GRAVITY if (TestElementPtr->state_flags & PLAYER_SHIP) { log_add (log_Debug, "CalculateGravity:"); log_add (log_Debug, "\tdx = %d, dy = %d", dx, dy); } #endif /* DEBUG_GRAVITY */ dx = WRAP_DELTA_X (dx); dy = WRAP_DELTA_Y (dy); #ifdef DEBUG_GRAVITY if (TestElementPtr->state_flags & PLAYER_SHIP) log_add (log_Debug, "\twrap_dx = %d, wrap_dy = %d", dx, dy); #endif /* DEBUG_GRAVITY */ abs_dx = dx >= 0 ? dx : -dx; abs_dy = dy >= 0 ? dy : -dy; abs_dx = WORLD_TO_DISPLAY (abs_dx); abs_dy = WORLD_TO_DISPLAY (abs_dy); #ifdef DEBUG_GRAVITY if (TestElementPtr->state_flags & PLAYER_SHIP) log_add (log_Debug, "\tdisplay_dx = %d, display_dy = %d", abs_dx, abs_dy); #endif /* DEBUG_GRAVITY */ if (abs_dx <= GRAVITY_THRESHOLD && abs_dy <= GRAVITY_THRESHOLD) { DWORD dist_squared; dist_squared = (DWORD)(abs_dx * abs_dx) + (DWORD)(abs_dy * abs_dy); if (dist_squared <= (DWORD)(GRAVITY_THRESHOLD * GRAVITY_THRESHOLD)) { #ifdef NEVER COUNT magnitude; #define DIFUSE_GRAVITY RES_SCALE(175) // JMS_GFX: Because of the ifdef NEVER this is actually never run. Well, changed it for consistency dist_squared += (DWORD)abs_dx * (DIFUSE_GRAVITY << 1) + (DWORD)abs_dy * (DIFUSE_GRAVITY << 1) + ((DWORD)(DIFUSE_GRAVITY * DIFUSE_GRAVITY) << 1); if ((magnitude = (COUNT)((DWORD)(GRAVITY_THRESHOLD * GRAVITY_THRESHOLD) / dist_squared)) == 0) magnitude = 1; #define MAX_MAGNITUDE RES_SCALE(6) // JMS_GFX: Because of the ifdef NEVER this is actually never run. Well, changed it for consistency else if (magnitude > MAX_MAGNITUDE) magnitude = MAX_MAGNITUDE; log_add (log_Debug, "magnitude = %u", magnitude); #endif /* NEVER */ #ifdef DEBUG_GRAVITY if (TestElementPtr->state_flags & PLAYER_SHIP) log_add (log_Debug, "dist_squared = %lu", dist_squared); #endif /* DEBUG_GRAVITY */ if (TestHasGravity) { retval = TRUE; UnlockElement (hTestElement); break; } else { COUNT angle; angle = ARCTAN (dx, dy); DeltaVelocityComponents (&TestElementPtr->velocity, COSINE (angle, WORLD_TO_VELOCITY (RES_SCALE(1))), SINE (angle, WORLD_TO_VELOCITY (RES_SCALE(1)))); // JMS_GFX if (TestElementPtr->state_flags & PLAYER_SHIP) { STARSHIP *StarShipPtr; GetElementStarShip (TestElementPtr, &StarShipPtr); StarShipPtr->cur_status_flags &= ~SHIP_AT_MAX_SPEED; StarShipPtr->cur_status_flags |= SHIP_IN_GRAVITY_WELL; } } } } } hSuccElement = GetSuccElement (TestElementPtr); UnlockElement (hTestElement); } return (retval); }