int LasersAreRelated (int o1, int o2) { CObject *objP1, *objP2; short id1, id2; fix ct1, ct2; if ((o1 < 0) || (o2 < 0)) return 0; objP1 = OBJECTS + o1; objP2 = OBJECTS + o2; id1 = objP1->info.nId; ct1 = objP1->cType.laserInfo.xCreationTime; // See if o2 is the parent of o1 if (objP1->info.nType == OBJ_WEAPON) if ((objP1->cType.laserInfo.parent.nObject == o2) && (objP1->cType.laserInfo.parent.nSignature == objP2->info.nSignature)) { // o1 is a weapon, o2 is the parent of 1, so if o1 is PROXIMITY_BOMB and o2 is player, they are related only if o1 < 2.0 seconds old if (LaserCreationTimeout (id1, ct1)) return 0; return 1; } id2 = objP2->info.nId; ct2 = objP2->cType.laserInfo.xCreationTime; // See if o1 is the parent of o2 if (objP2->info.nType == OBJ_WEAPON) if ((objP2->cType.laserInfo.parent.nObject == o1) && (objP2->cType.laserInfo.parent.nSignature == objP1->info.nSignature)) { // o2 is a weapon, o1 is the parent of 2, so if o2 is PROXIMITY_BOMB and o1 is player, they are related only if o1 < 2.0 seconds old if (LaserCreationTimeout (id2, ct2)) return 0; return 1; } // They must both be weapons if ((objP1->info.nType != OBJ_WEAPON) || (objP2->info.nType != OBJ_WEAPON)) return 0; // Here is the 09/07/94 change -- Siblings must be identical, others can hurt each other // See if they're siblings... // MK: 06/08/95, Don't allow prox bombs to detonate for 3/4 second. Else too likely to get toasted by your own bomb if hit by opponent. if (objP1->cType.laserInfo.parent.nSignature == objP2->cType.laserInfo.parent.nSignature) { if ((id1 != PROXMINE_ID) && (id2 != PROXMINE_ID) && (id1 != SMARTMINE_ID) && (id2 != SMARTMINE_ID)) return 1; // If neither is older than 1/2 second, then can't blow up! if ((gameData.time.xGame > (ct1 + I2X (1)/2) * gameStates.gameplay.slowmo [0].fSpeed) || (gameData.time.xGame > (ct2 + I2X (1)/2) * gameStates.gameplay.slowmo [0].fSpeed)) return 0; return 1; } // Anything can cause a collision with a robot super prox mine. if (WeaponIsMine (id1) || WeaponIsMine (id2)) return 0; if (!COMPETITION && EGI_FLAG (bKillMissiles, 0, 0, 0) && (gameData.objs.bIsMissile [id1] || gameData.objs.bIsMissile [id2])) return 0; return 1; }
static int RenderWeapon (CObject* objP, int bForce) { if (gameStates.render.nType != 1) return 0; if (gameStates.render.nShadowPass != 2) { if (automap.m_bDisplay && !AM_SHOW_POWERUPS (1)) return 0; if (objP->info.nType != OBJ_WEAPON) DrawWeaponVClip (objP); else { if (WeaponIsMine (objP->info.nId)) { if (!DoObjectSmoke (objP)) DrawWeaponVClip (objP); } else if ((objP->info.nId != OMEGA_ID) || !(SHOW_LIGHTNING && gameOpts->render.lightning.bOmega && !gameStates.render.bOmegaModded)) { DrawWeaponVClip (objP); if (objP->info.nId != OMEGA_ID) { RenderLightTrail (objP); RenderMslLockIndicator (objP); } } } } return 1; }
static int RenderWeaponModel (CObject* objP, int bDepthSort, int bSpectate) { if (automap.m_bDisplay && !AM_SHOW_POWERUPS (1)) return 0; if (!(gameStates.app.bNostalgia || gameOpts->render.powerups.b3D) && WeaponIsMine (objP->info.nId) && (objP->info.nId != SMALLMINE_ID)) ConvertWeaponToVClip (objP); else { if (gameStates.render.nType != 1) return 0; if (gameData.objs.bIsMissile [objP->info.nId]) { //make missiles smaller during launch if ((objP->cType.laserInfo.parent.nType == OBJ_PLAYER) && (gameData.models.renderModels [1][108].m_bValid > 0)) { //hires player ship float dt = X2F (gameData.time.xGame - objP->CreationTime ()); if (dt < 1) { fix xScale = (fix) (I2X (1) + I2X (1) * dt * dt) / 2; gameData.models.vScale.Set (xScale, xScale, xScale); } } //DoObjectSmoke (objP); DrawPolygonObject (objP, bDepthSort, 0); #if RENDER_HITBOX # if 0 DrawShieldSphere (objP, 0.66f, 0.2f, 0.0f, 0.4f); # else RenderHitbox (objP, 0.5f, 0.0f, 0.6f, 0.4f); # endif #endif RenderThrusterFlames (objP); gameData.models.vScale.SetZero (); } else { #if RENDER_HITBOX # if 0 DrawShieldSphere (objP, 0.66f, 0.2f, 0.0f, 0.4f); # else RenderHitbox (objP, 0.5f, 0.0f, 0.6f, 0.4f); # endif #endif if (objP->info.nType != OBJ_WEAPON) { DrawPolygonObject (objP, bDepthSort, 0); if ((objP->info.nId != SMALLMINE_ID) && !gameStates.render.bQueryCoronas) RenderLightTrail (objP); } else { if ((objP->info.nId == VULCAN_ID) || (objP->info.nId == GAUSS_ID)) { if (SHOW_OBJ_FX && extraGameInfo [0].bTracers) { if (!gameStates.render.bQueryCoronas) RenderLightTrail (objP); gameData.models.vScale.Set (I2X (1) / 4, I2X (1) / 4, I2X (2)); CFixVector vSavedPos = objP->info.position.vPos; objP->info.position.vPos += objP->info.position.mOrient.FVec (); DrawPolygonObject (objP, bDepthSort, 0); objP->info.position.vPos = vSavedPos; } } else { if ((objP->info.nId != SMALLMINE_ID) && !gameStates.render.bQueryCoronas) RenderLightTrail (objP); DrawPolygonObject (objP, bDepthSort, 0); } gameData.models.vScale.SetZero (); } } } return 1; }
CObject* CreateExplosion (CObject* parentP, short nSegment, CFixVector& vPos, fix xSize, ubyte nVClip, fix xMaxDamage, fix xMaxDistance, fix xMaxForce, short nParent) { short nObject; CObject *explObjP, *objP; fix dist, force, damage; CFixVector vHit, vForce; int nType, id; int flash = parentP ? static_cast<int> (gameData.weapons.info [parentP->info.nId].flash) : 0; nObject = CreateFireball (nVClip, nSegment, vPos, xSize, RT_FIREBALL); if (nObject < 0) { #if TRACE console.printf (1, "Can'nType create CObject in /*Object*/CreateExplosionSub.\n"); #endif return NULL; } explObjP = OBJECTS + nObject; //now set explosion-specific data explObjP->info.xLifeLeft = gameData.eff.vClips [0][nVClip].xTotalTime; explObjP->cType.explInfo.nSpawnTime = -1; explObjP->cType.explInfo.nDeleteObj = -1; explObjP->cType.explInfo.nDeleteTime = -1; if (xMaxDamage <= 0) return explObjP; // -- now legal for xBadAss explosions on a CWall. Assert (this != NULL); FORALL_OBJS (objP, i) { nType = objP->info.nType; id = objP->info.nId; // Weapons used to be affected by xBadAss explosions, but this introduces serious problems. // When a smart bomb blows up, if one of its children goes right towards a nearby CWall, it will // blow up, blowing up all the children. So I remove it. MK, 09/11/94 if (objP == parentP) continue; if (objP->info.nFlags & OF_SHOULD_BE_DEAD) continue; if (nType == OBJ_WEAPON) { if (!WeaponIsMine (objP->info.nId)) continue; } else if (nType == OBJ_ROBOT) { if (nParent < 0) continue; if ((OBJECTS [nParent].info.nType == OBJ_ROBOT) && (OBJECTS [nParent].info.nId == id)) continue; } else if ((nType != OBJ_REACTOR) && (nType != OBJ_PLAYER)) continue; dist = CFixVector::Dist (objP->info.position.vPos, explObjP->info.position.vPos); // Make damage be from 'xMaxDamage' to 0.0, where 0.0 is 'xMaxDistance' away; if (dist >= xMaxDistance) continue; if (!ObjectToObjectVisibility (explObjP, objP, FQ_TRANSWALL)) continue; damage = xMaxDamage - FixMulDiv (dist, xMaxDamage, xMaxDistance); force = xMaxForce - FixMulDiv (dist, xMaxForce, xMaxDistance); // Find the force vector on the CObject CFixVector::NormalizedDir(vForce, objP->info.position.vPos, explObjP->info.position.vPos); vForce *= force; // Find where the point of impact is... (vHit) vHit = explObjP->info.position.vPos - objP->info.position.vPos; vHit *= (FixDiv (objP->info.xSize, objP->info.xSize + dist)); if (nType == OBJ_WEAPON) { objP->ApplyForce (vForce); if (WeaponIsMine (objP->info.nId) && (FixMul (dist, force) > I2X (8000))) { //prox bombs have chance of blowing up objP->Die (); objP->ExplodeBadassWeapon (objP->info.position.vPos); } } else if (nType == OBJ_ROBOT) { CFixVector vNegForce; fix xScale = -2 * (7 - gameStates.app.nDifficultyLevel) / 8; objP->ApplyForce (vForce); // If not a boss, stun for 2 seconds at 32 force, 1 second at 16 force if (flash && !ROBOTINFO (objP->info.nId).bossFlag) { tAIStaticInfo *aip = &objP->cType.aiInfo; int nForce = X2I (FixDiv (vForce.Mag () * flash, gameData.time.xFrame) / 128) + 2; if (explObjP->cType.aiInfo.SKIP_AI_COUNT * gameData.time.xFrame >= I2X (1)) aip->SKIP_AI_COUNT--; else { aip->SKIP_AI_COUNT += nForce; objP->mType.physInfo.rotThrust [X] = ((d_rand () - 16384) * nForce) / 16; objP->mType.physInfo.rotThrust [Y] = ((d_rand () - 16384) * nForce) / 16; objP->mType.physInfo.rotThrust [Z] = ((d_rand () - 16384) * nForce) / 16; objP->mType.physInfo.flags |= PF_USES_THRUST; } } vNegForce [X] = vForce [X] * xScale; vNegForce [Y] = vForce [Y] * xScale; vNegForce [Z] = vForce [Z] * xScale; objP->ApplyRotForce (vNegForce); if (objP->info.xShields >= 0) { if (ROBOTINFO (objP->info.nId).bossFlag && bossProps [gameStates.app.bD1Mission][ROBOTINFO (objP->info.nId).bossFlag - BOSS_D2].bInvulKinetic) damage /= 4; if (objP->ApplyDamageToRobot (damage, nParent)) { if (!gameStates.gameplay.bNoBotAI && parentP && (nParent == LOCALPLAYER.nObject)) cockpit->AddPointsToScore (ROBOTINFO (objP->info.nId).scoreValue); } } if (!flash && ROBOTINFO (objP->info.nId).companion) BuddyOuchMessage (damage); } else if (nType == OBJ_REACTOR) { if (objP->info.xShields >= 0) objP->ApplyDamageToReactor (damage, nParent); } else if (nType == OBJ_PLAYER) { CObject* killerP = NULL; CFixVector vRotForce; // Hack!Warning!Test code! if (flash && (objP->info.nId == gameData.multiplayer.nLocalPlayer)) { int fe = min (I2X (4), force * flash / 32); // For four seconds or less if (parentP->cType.laserInfo.parent.nSignature == gameData.objs.consoleP->info.nSignature) { fe /= 2; force /= 2; } if (force > I2X (1)) { paletteManager.SetFlashDuration (fe); force = PK1 + X2I (PK2 * force); paletteManager.BumpEffect (force, force, force); #if TRACE console.printf (CON_DBG, "force = %7.3f, adding %i\n", X2F (force), PK1 + X2I (PK2*force)); #endif } } if (parentP && IsMultiGame && (parentP->info.nType == OBJ_PLAYER)) killerP = parentP; vRotForce = vForce; if (nParent > -1) { killerP = OBJECTS + nParent; if (killerP != gameData.objs.consoleP) // if someone else whacks you, cut force by 2x vRotForce [X] /= 2; vRotForce [Y] /= 2; vRotForce [Z] /= 2; } vRotForce [X] /= 2; vRotForce [Y] /= 2; vRotForce [Z] /= 2; objP->ApplyForce (vForce); objP->ApplyRotForce (vRotForce); if (gameStates.app.nDifficultyLevel == 0) damage /= 4; if (objP->info.xShields >= 0) objP->ApplyDamageToPlayer (killerP, damage); } }
tObject *ObjectCreateExplosionSub (tObject *objP, short nSegment, vmsVector *vPos, fix xSize, ubyte nVClip, fix xMaxDamage, fix xMaxDistance, fix xMaxForce, short nParent) { short nObject; tObject *explObjP, *obj0P; fix dist, force, damage; vmsVector pos_hit, vForce; int i, t, id; nObject = CreateObject (OBJ_FIREBALL, nVClip, -1, nSegment, vPos, &vmdIdentityMatrix, xSize, CT_EXPLOSION, MT_NONE, RT_FIREBALL, 1); if (nObject < 0) { #if TRACE con_printf (1, "Can't create tObject in ObjectCreateExplosionSub.\n"); #endif return NULL; } explObjP = gameData.objs.objects + nObject; //now set explosion-specific data explObjP->lifeleft = gameData.eff.vClips [0][nVClip].xTotalTime; explObjP->cType.explInfo.nSpawnTime = -1; explObjP->cType.explInfo.nDeleteObj = -1; explObjP->cType.explInfo.nDeleteTime = -1; if (xMaxDamage <= 0) return explObjP; // -- now legal for xBadAss explosions on a tWall. Assert (objP != NULL); for (i = 0, obj0P = gameData.objs.objects; i <= gameData.objs.nLastObject; i++, obj0P++) { t = obj0P->nType; id = obj0P->id; // Weapons used to be affected by xBadAss explosions, but this introduces serious problems. // When a smart bomb blows up, if one of its children goes right towards a nearby tWall, it will // blow up, blowing up all the children. So I remove it. MK, 09/11/94 if (obj0P == objP) continue; if (obj0P->flags & OF_SHOULD_BE_DEAD) continue; if (t == OBJ_WEAPON) { if (!WeaponIsMine (obj0P->id)) continue; } else if (t == OBJ_ROBOT) { if (nParent < 0) continue; if ((gameData.objs.objects [nParent].nType == OBJ_ROBOT) && (gameData.objs.objects [nParent].id == id)) continue; } else if ((t != OBJ_REACTOR) && (t != OBJ_PLAYER)) continue; dist = VmVecDistQuick (&obj0P->position.vPos, &explObjP->position.vPos); // Make damage be from 'xMaxDamage' to 0.0, where 0.0 is 'xMaxDistance' away; if (dist >= xMaxDistance) continue; if (!ObjectToObjectVisibility (explObjP, obj0P, FQ_TRANSWALL)) continue; damage = xMaxDamage - FixMulDiv (dist, xMaxDamage, xMaxDistance); force = xMaxForce - FixMulDiv (dist, xMaxForce, xMaxDistance); // Find the force vector on the tObject VmVecNormalizedDirQuick (&vForce, &obj0P->position.vPos, &explObjP->position.vPos); VmVecScale (&vForce, force); // Find where the point of impact is... (pos_hit) VmVecSub (&pos_hit, &explObjP->position.vPos, &obj0P->position.vPos); VmVecScale (&pos_hit, FixDiv (obj0P->size, obj0P->size + dist)); if (t == OBJ_WEAPON) { PhysApplyForce (obj0P, &vForce); if (WeaponIsMine (obj0P->id) && (FixMul (dist, force) > i2f (8000))) { //prox bombs have chance of blowing up KillObject (obj0P); ExplodeBadassWeapon (obj0P, &obj0P->position.vPos); } } else if (t == OBJ_ROBOT) { vmsVector vNegForce; fix xScale = -2 * (7 - gameStates.app.nDifficultyLevel) / 8; PhysApplyForce (obj0P, &vForce); // If not a boss, stun for 2 seconds at 32 force, 1 second at 16 force if (objP && (!ROBOTINFO (obj0P->id).bossFlag) && (gameData.weapons.info [objP->id].flash)) { tAIStatic *aip = &obj0P->cType.aiInfo; int force_val = f2i (FixDiv (VmVecMagQuick (&vForce) * gameData.weapons.info [objP->id].flash, gameData.time.xFrame)/128) + 2; if (explObjP->cType.aiInfo.SKIP_AI_COUNT * gameData.time.xFrame >= F1_0) aip->SKIP_AI_COUNT--; else { aip->SKIP_AI_COUNT += force_val; obj0P->mType.physInfo.rotThrust.p.x = ((d_rand () - 16384) * force_val)/16; obj0P->mType.physInfo.rotThrust.p.y = ((d_rand () - 16384) * force_val)/16; obj0P->mType.physInfo.rotThrust.p.z = ((d_rand () - 16384) * force_val)/16; obj0P->mType.physInfo.flags |= PF_USES_THRUST; } } vNegForce.p.x = vForce.p.x * xScale; vNegForce.p.y = vForce.p.y * xScale; vNegForce.p.z = vForce.p.z * xScale; PhysApplyRot (obj0P, &vNegForce); if (obj0P->shields >= 0) { if (ROBOTINFO (obj0P->id).bossFlag && bossProps [gameStates.app.bD1Mission][ROBOTINFO (obj0P->id).bossFlag-BOSS_D2].bInvulKinetic) damage /= 4; if (ApplyDamageToRobot (obj0P, damage, nParent) && objP && (nParent == LOCALPLAYER.nObject)) AddPointsToScore (ROBOTINFO (obj0P->id).scoreValue); } if (objP && (ROBOTINFO (obj0P->id).companion) && !gameData.weapons.info [objP->id].flash) { int i, count; char szOuch [6*4 + 2]; count = f2i (damage / 8); if (count > 4) count = 4; else if (count <= 0) count = 1; szOuch [0] = 0; for (i = 0; i < count; i++) { strcat (szOuch, TXT_BUDDY_OUCH); strcat (szOuch, " "); } BuddyMessage (szOuch); } } else if (t == OBJ_REACTOR) { if (obj0P->shields >= 0) ApplyDamageToReactor (obj0P, damage, nParent); } else if (t == OBJ_PLAYER) { tObject *killerP = NULL; vmsVector vForce2; // Hack!Warning!Test code! if (objP && gameData.weapons.info [objP->id].flash && obj0P->id==gameData.multiplayer.nLocalPlayer) { int fe = min (F1_0*4, force*gameData.weapons.info [objP->id].flash/32); // For four seconds or less if (objP->cType.laserInfo.nParentSig == gameData.objs.console->nSignature) { fe /= 2; force /= 2; } if (force > F1_0) { gameData.render.xFlashEffect = fe; PALETTE_FLASH_ADD (PK1 + f2i (PK2*force), PK1 + f2i (PK2*force), PK1 + f2i (PK2*force)); #if TRACE con_printf (CONDBG, "force = %7.3f, adding %i\n", f2fl (force), PK1 + f2i (PK2*force)); #endif } } if (objP && IsMultiGame && (objP->nType == OBJ_PLAYER)) killerP = objP; vForce2 = vForce; if (nParent > -1) { killerP = gameData.objs.objects + nParent; if (killerP != gameData.objs.console) // if someone else whacks you, cut force by 2x vForce2.p.x /= 2; vForce2.p.y /= 2; vForce2.p.z /= 2; } vForce2.p.x /= 2; vForce2.p.y /= 2; vForce2.p.z /= 2; PhysApplyForce (obj0P, &vForce); PhysApplyRot (obj0P, &vForce2); if (gameStates.app.nDifficultyLevel == 0) damage /= 4; if (obj0P->shields >= 0) ApplyDamageToPlayer (obj0P, killerP, damage); } } return explObjP; }