int DoAnyRobotDyingFrame (tObject *objP) { if (objP->cType.aiInfo.xDyingStartTime) { int bDeathRoll = ROBOTINFO (objP->id).bDeathRoll; int rval = DoRobotDyingFrame (objP, objP->cType.aiInfo.xDyingStartTime, min (bDeathRoll/2+1,6)*F1_0, &objP->cType.aiInfo.bDyingSoundPlaying, ROBOTINFO (objP->id).deathrollSound, bDeathRoll*F1_0/8, bDeathRoll*F1_0/2); if (rval) { ExplodeObject (objP, F1_0/4); DigiLinkSoundToObject2 (SOUND_BADASS_EXPLOSION, OBJ_IDX (objP), 0, F2_0, F1_0*512, SOUNDCLASS_EXPLOSION); if ((gameData.missions.nCurrentLevel < 0) && (ROBOTINFO (objP->id).thief)) RecreateThief (objP); } return 1; } return 0; }
// ----------------------------------------------------------------------------------------------------------- //given an CObject and a gun number, return position in 3-space of gun //fills in gun_point int CalcGunPoint (CFixVector *vGunPoint, CObject *objP, int nGun) { CPolyModel* pm = gameData.models.polyModels [0] + objP->rType.polyObjInfo.nModel; tRobotInfo* botInfoP; CFixVector* vGunPoints, vGunPos, vRot; CFixMatrix m; int nSubModel; //submodel number Assert(objP->info.renderType == RT_POLYOBJ || objP->info.renderType == RT_MORPH); //Assert(objP->info.nId < gameData.bots.nTypes [gameStates.app.bD1Data]); botInfoP = &ROBOTINFO (objP->info.nId); if (!(vGunPoints = GetGunPoints (objP, nGun))) return 0; vGunPos = vGunPoints [nGun]; nSubModel = botInfoP->gunSubModels [nGun]; //instance up the tree for this gun while (nSubModel != 0) { m = CFixMatrix::Create (objP->rType.polyObjInfo.animAngles [nSubModel]); CFixMatrix::Transpose (m); vRot = m * vGunPos; vGunPos = vRot + pm->SubModels ().offsets [nSubModel]; nSubModel = pm->SubModels ().parents [nSubModel]; } //now instance for the entire CObject //VmVecInc (&vGunPos, gameData.models.offsets + botInfoP->nModel); *vGunPoint = *objP->View () * vGunPos; *vGunPoint += objP->info.position.vPos; return 1; }
void MakeNearbyRobotSnipe (void) { CObject *objP; tRobotInfo *botInfoP; short bfsList [MNRS_SEG_MAX]; int nObject, nBfsLength, i; CreateBfsList (OBJSEG (TARGETOBJ), bfsList, &nBfsLength, MNRS_SEG_MAX); for (i = 0; i < nBfsLength; i++) { nObject = SEGMENTS [bfsList [i]].m_objects; //Assert (nObject >= 0); while (nObject != -1) { objP = OBJECTS + nObject; botInfoP = &ROBOTINFO (objP->info.nId); if ((objP->info.nType == OBJ_ROBOT) && (objP->info.nId != ROBOT_BRAIN) && (objP->cType.aiInfo.behavior != AIB_SNIPE) && (objP->cType.aiInfo.behavior != AIB_RUN_FROM) && !botInfoP->bossFlag && !botInfoP->companion) { objP->cType.aiInfo.behavior = AIB_SNIPE; gameData.ai.localInfo [nObject].mode = AIM_SNIPE_ATTACK; return; } nObject = objP->info.nNextInSeg; } } }
CFixVector *GetGunPoints (CObject *objP, int nGun) { if (!objP) return NULL; tGunInfo* giP = gameData.models.gunInfo + objP->rType.polyObjInfo.nModel; CFixVector* vDefaultGunPoints, *vGunPoints; int nDefaultGuns, nGuns; if (objP->info.nType == OBJ_PLAYER) { vDefaultGunPoints = gameData.pig.ship.player->gunPoints; nDefaultGuns = N_PLAYER_GUNS; } else if (objP->info.nType == OBJ_ROBOT) { vDefaultGunPoints = ROBOTINFO (objP->info.nId).gunPoints; nDefaultGuns = MAX_GUNS; } else return NULL; if (0 < (nGuns = giP->nGuns)) vGunPoints = giP->vGunPoints; else { if (!(nGuns = nDefaultGuns)) return NULL; vGunPoints = vDefaultGunPoints; } if (abs (nGun) >= nDefaultGuns) nGun = (nGun < 0) ? -(nDefaultGuns - 1) : nDefaultGuns - 1; return vGunPoints; }
// ----------------------------------------------------------------------------------------------------------- //for test, set a robot to a specific state void setRobotState(tObject *objP,int state) { int g,j,jo; tRobotInfo *ri; jointlist *jl; Assert(objP->nType == OBJ_ROBOT); ri = &ROBOTINFO (objP->id); for (g=0;g<ri->nGuns+1;g++) { jl = &ri->animStates[g][state]; jo = jl->offset; for (j=0;j<jl->n_joints;j++,jo++) { int jn; jn = gameData.bots.joints[jo].jointnum; objP->rType.polyObjInfo.animAngles[jn] = gameData.bots.joints[jo].angles; } } }
// ----------------------------------------------------------------------------------------------------------- //given an tObject and a gun number, return position in 3-space of gun //fills in gun_point int CalcGunPoint (vmsVector *vGunPoint, tObject *objP, int nGun) { tPolyModel *pm = gameData.models.polyModels + objP->rType.polyObjInfo.nModel; tRobotInfo *botInfoP; vmsVector *vGunPoints, vGunPos, vRot; vmsMatrix m; int nSubModel, bCustom = 0; //submodel number Assert(objP->renderType == RT_POLYOBJ || objP->renderType==RT_MORPH); //Assert(objP->id < gameData.bots.nTypes [gameStates.app.bD1Data]); botInfoP = &ROBOTINFO (objP->id); if (!(vGunPoints = GetGunPoints (objP, nGun))) return 0; vGunPos = vGunPoints [nGun]; nSubModel = botInfoP->gunSubModels [nGun]; //instance up the tree for this gun while (nSubModel != 0) { VmAngles2Matrix (&m, &objP->rType.polyObjInfo.animAngles [nSubModel]); VmTransposeMatrix (&m); VmVecRotate (&vRot, &vGunPos, &m); VmVecAdd (&vGunPos, &vRot, &pm->subModels.offsets [nSubModel]); nSubModel = pm->subModels.parents [nSubModel]; } //now instance for the entire tObject VmVecRotate (vGunPoint, &vGunPos, ObjectView (objP)); VmVecInc (vGunPoint, &objP->position.vPos); return 1; }
// ---------------------------------------------------------------------------------- // When some robots collide with the CPlayerData, they attack. // If CPlayerData is cloaked, then robot probably didn't actually collide, deal with that here. void DoAIRobotHitAttack (CObject *robotP, CObject *playerobjP, CFixVector *vCollision) { tAILocalInfo *ailP = gameData.ai.localInfo + OBJ_IDX (robotP); tRobotInfo *botInfoP = &ROBOTINFO (robotP->info.nId); if (!gameStates.app.cheats.bRobotsFiring) return; // If CPlayerData is dead, stop firing. if (OBJECTS [LOCALPLAYER.nObject].info.nType == OBJ_GHOST) return; if (botInfoP->attackType != 1) return; if (ailP->nextPrimaryFire > 0) return; if (!(LOCALPLAYER.flags & PLAYER_FLAGS_CLOAKED)) { if (CFixVector::Dist (OBJPOS (gameData.objs.consoleP)->vPos, robotP->info.position.vPos) < robotP->info.xSize + gameData.objs.consoleP->info.xSize + I2X (2)) { playerobjP->CollidePlayerAndNastyRobot (robotP, *vCollision); if (botInfoP->energyDrain && LOCALPLAYER.energy) { LOCALPLAYER.energy -= I2X (botInfoP->energyDrain); if (LOCALPLAYER.energy < 0) LOCALPLAYER.energy = 0; } } } robotP->cType.aiInfo.GOAL_STATE = AIS_RECOVER; SetNextFireTime (robotP, ailP, botInfoP, 1); // 1 = nGun: 0 is special (uses nextSecondaryFire) }
int DoAnyRobotDyingFrame (CObject *objP) { if (objP->cType.aiInfo.xDyingStartTime) { int bDeathRoll = ROBOTINFO (objP->info.nId).bDeathRoll; int rval = DoRobotDyingFrame (objP, objP->cType.aiInfo.xDyingStartTime, I2X (min (bDeathRoll / 2 + 1, 6)), &objP->cType.aiInfo.bDyingSoundPlaying, ROBOTINFO (objP->info.nId).deathrollSound, I2X (bDeathRoll) / 8, I2X (bDeathRoll) / 2); if (rval) { objP->Explode (I2X (1)/4); audio.CreateObjectSound (SOUND_BADASS_EXPLOSION, SOUNDCLASS_EXPLOSION, objP->Index (), 0, I2X (2), I2X (512)); if ((gameData.missions.nCurrentLevel < 0) && (ROBOTINFO (objP->info.nId).thief)) RecreateThief (objP); } return 1; } return 0; }
// -------------------------------------------------------------------------------------------------------------------- // Lead the CPlayerData, returning point to fire at in vFirePoint. // Rules: // Player not cloaked // Player must be moving at a speed >= MIN_LEAD_SPEED // Player not farther away than MAX_LEAD_DISTANCE // dot (vector_to_player, player_direction) must be in -LEAD_RANGE,LEAD_RANGE // if firing a matter weapon, less leading, based on skill level. int LeadPlayer (CObject *objP, CFixVector *vFirePoint, CFixVector *vBelievedPlayerPos, int nGuns, CFixVector *vFire) { fix dot, xPlayerSpeed, xDistToPlayer, xMaxWeaponSpeed, xProjectedTime; CFixVector vPlayerMovementDir, vVecToPlayer; int nWeaponType; CWeaponInfo *wiP; tRobotInfo *botInfoP; if (LOCALPLAYER.flags & PLAYER_FLAGS_CLOAKED) return 0; vPlayerMovementDir = gameData.objs.consoleP->mType.physInfo.velocity; xPlayerSpeed = CFixVector::Normalize(vPlayerMovementDir); if (xPlayerSpeed < MIN_LEAD_SPEED) return 0; vVecToPlayer = *vBelievedPlayerPos - *vFirePoint; xDistToPlayer = CFixVector::Normalize(vVecToPlayer); if (xDistToPlayer > MAX_LEAD_DISTANCE) return 0; dot = CFixVector::Dot (vVecToPlayer, vPlayerMovementDir); if ((dot < -LEAD_RANGE) || (dot > LEAD_RANGE)) return 0; // Looks like it might be worth trying to lead the player. botInfoP = &ROBOTINFO (objP->info.nId); nWeaponType = botInfoP->nWeaponType; if ((nGuns == 0) && (botInfoP->nSecWeaponType != -1)) nWeaponType = botInfoP->nSecWeaponType; wiP = gameData.weapons.info + nWeaponType; xMaxWeaponSpeed = wiP->speed [gameStates.app.nDifficultyLevel]; if (xMaxWeaponSpeed < I2X (1)) return 0; // Matter weapons: // At Rookie or Trainee, don't lead at all. // At higher skill levels, don't lead as well. Accomplish this by screwing up xMaxWeaponSpeed. if (wiP->matter) { if (gameStates.app.nDifficultyLevel <= 1) return 0; else xMaxWeaponSpeed *= (NDL-gameStates.app.nDifficultyLevel); } xProjectedTime = FixDiv (xDistToPlayer, xMaxWeaponSpeed); (*vFire)[X] = ComputeLeadComponent ((*vBelievedPlayerPos)[X], (*vFirePoint)[X], gameData.objs.consoleP->mType.physInfo.velocity[X], xProjectedTime); (*vFire)[Y] = ComputeLeadComponent ((*vBelievedPlayerPos)[Y], (*vFirePoint)[Y], gameData.objs.consoleP->mType.physInfo.velocity[Y], xProjectedTime); (*vFire)[Z] = ComputeLeadComponent ((*vBelievedPlayerPos)[Z], (*vFirePoint)[Z], gameData.objs.consoleP->mType.physInfo.velocity[Z], xProjectedTime); CFixVector::Normalize(*vFire); Assert (CFixVector::Dot (*vFire, objP->info.position.mOrient.FVec ()) < I2X (3)/2); // Make sure not firing at especially strange angle. If so, try to correct. If still bad, give up after one try. if (CFixVector::Dot (*vFire, objP->info.position.mOrient.FVec ()) < I2X (1)/2) { *vFire += vVecToPlayer; *vFire *= I2X (1)/2; if (CFixVector::Dot (*vFire, objP->info.position.mOrient.FVec ()) < I2X (1)/2) { return 0; } } return 1; }
int CObject::Update (void) { short nPrevSegment = (short) info.nSegment; #if DBG if ((info.nType == OBJ_WEAPON) && (info.nId == SMARTMINE_BLOB_ID)) { nDbgObj = OBJ_IDX (this); nDbgObj = nDbgObj; } if (OBJ_IDX (this) == nDbgObj) nDbgObj = nDbgObj; #endif if (info.nType == OBJ_ROBOT) { if (gameOpts->gameplay.bNoThief && (!IsMultiGame || IsCoopGame) && ROBOTINFO (info.nId).thief) { info.xShields = 0; info.xLifeLeft = 0; Die (); } else { fix xMaxShields = RobotDefaultShields (this); if (info.xShields > xMaxShields) info.xShields = xMaxShields; } } info.vLastPos = info.position.vPos; // Save the current position RepairDamage (); HandleSpecialSegment (); if ((info.xLifeLeft != IMMORTAL_TIME) && (info.xLifeLeft != ONE_FRAME_TIME) && (gameData.physics.xTime != I2X (1))) info.xLifeLeft -= (fix) (gameData.physics.xTime / gameStates.gameplay.slowmo [0].fSpeed); //...inevitable countdown towards death gameStates.render.bDropAfterburnerBlob = 0; if ((gameData.physics.xTime != I2X (1)) && UpdateControl ()) { UpdateEffects (); return 1; } if (info.xLifeLeft < 0) { // We died of old age Die (); if ((info.nType == OBJ_WEAPON) && WI_damage_radius (info.nId)) ExplodeBadassWeapon (info.position.vPos); else if (info.nType == OBJ_ROBOT) //make robots explode Explode (0); } if ((info.nType == OBJ_NONE) || (info.nFlags & OF_SHOULD_BE_DEAD)) { return 1; //CObject has been deleted } UpdateMovement (); UpdateEffects (); if (CheckTriggerHits (nPrevSegment)) return 0; CheckWallPhysics (); CheckGuidedMissileThroughExit (nPrevSegment); CheckAfterburnerBlobDrop (); return 1; }
void KillBuddy (int bVerbose) { int i; tObject *objP = gameData.objs.objects; // Kill buddy. for (i = 0; i <= gameData.objs.nLastObject; i++, objP++) if ((objP->nType == OBJ_ROBOT) && ROBOTINFO (objP->id).companion) { gameData.objs.objects [i].flags |= OF_EXPLODING | OF_SHOULD_BE_DEAD; if (bVerbose) HUDInitMessage (TXT_BUDDY_TOASTED); } }
void KillAllRobots (int bVerbose) { int i, nKilled = 0; tObject *objP; //int boss_index = -1; // Kill all bots except for Buddy bot and boss. However, if only boss and buddy left, kill boss. for (i = 0, objP = gameData.objs.objects; i <= gameData.objs.nLastObject; i++, objP++) if ((objP->nType == OBJ_ROBOT) && !(ROBOTINFO (objP->id).companion || ROBOTINFO (objP->id).bossFlag)) { nKilled++; if (gameStates.app.bNostalgia) objP->flags |= OF_EXPLODING | OF_SHOULD_BE_DEAD; else { ApplyDamageToRobot (objP, objP->shields + 1, -1); objP->flags |= OF_ARMAGEDDON; } } // Toast the buddy if nothing else toasted! if (!nKilled) nKilled += KillAllBuddyBots (bVerbose); if (bVerbose) HUDInitMessage (TXT_BOTS_TOASTED, nKilled); }
void CTrigger::DoTeleportBot (CObject* objP) { if (m_info.nLinks) { short nSegment = m_info.segments [d_rand () % m_info.nLinks]; if (objP->info.nSegment != nSegment) { objP->info.nSegment = nSegment; objP->info.position.vPos = SEGMENTS [nSegment].Center (); objP->RelinkToSeg (nSegment); if (ROBOTINFO (objP->info.nId).bossFlag) { int i = gameData.bosses.Find (objP->Index ()); if (i >= 0) gameData.bosses [i].Setup (objP->Index ()); } } } }
void KillThief (int bVerbose) { int i; tObject *objP; for (i = 0, objP = gameData.objs.objects; i <= gameData.objs.nLastObject; i++, objP++) if ((objP->nType == OBJ_ROBOT) && ROBOTINFO (objP->id).thief) { if (gameStates.app.bNostalgia) objP->flags |= OF_EXPLODING|OF_SHOULD_BE_DEAD; else { ApplyDamageToRobot (objP, objP->shields + 1, -1); objP->flags |= OF_ARMAGEDDON; } if (bVerbose) HUDInitMessage (TXT_THIEF_TOASTED); } }
void CObject::UpdateEffects (void) { if (info.nType == OBJ_ROBOT) { if (ROBOTINFO (info.nId).energyDrain) { RequestEffects (ROBOT_LIGHTNINGS); } } else if ((info.nType == OBJ_PLAYER) && gameOpts->render.lightnings.bPlayers) { int nType = SEGMENTS [info.nSegment].m_nType; if (nType == SEGMENT_IS_FUELCEN) RequestEffects (PLAYER_LIGHTNINGS); else if (nType == SEGMENT_IS_REPAIRCEN) RequestEffects (PLAYER_LIGHTNINGS); else RequestEffects (DESTROY_LIGHTNINGS); } }
void CObject::UpdateEffects (void) { if (info.nType == OBJ_ROBOT) { if (ROBOTINFO (info.nId).energyDrain) { RequestEffects (ROBOT_LIGHTNINGS); } } else if ((info.nType == OBJ_PLAYER) && gameOpts->render.lightning.bPlayers) { int nType = SEGMENTS [OBJSEG (this)].m_nType; if (gameData.fusion.xCharge > I2X (2)) RequestEffects (PLAYER_LIGHTNINGS); else if (nType == SEGMENT_IS_FUELCEN) RequestEffects (PLAYER_LIGHTNINGS); else if (nType == SEGMENT_IS_REPAIRCEN) RequestEffects (PLAYER_LIGHTNINGS); else RequestEffects (DESTROY_LIGHTNINGS); } }
// ------------------------------------------------------------------------------------------------------- // SmoothPath // Takes an existing path and makes it nicer. // Drops as many leading points as possible still maintaining direct accessibility // from current position to first point. // Will not shorten path to fewer than 3 points. // Returns number of points. // Starting position in pointSegP doesn't change.p. // Changed, MK, 10/18/95. I think this was causing robots to get hung up on walls. // Only drop up to the first three points. int SmoothPath (CObject *objP, tPointSeg *pointSegP, int numPoints) { #if 1 return numPoints; #else int i, nFirstPoint = 0; tFVIQuery fq; tFVIData hitData; int hitType; if (numPoints <= 4) return numPoints; // Prevent the buddy from polishing his path twice in one frame, which can cause him to get hung up. Pretty ugly, huh? if (ROBOTINFO (objP->info.nId).companion) { if (gameData.app.nFrameCount == Last_buddy_polish_path_frame) return numPoints; Last_buddy_polish_path_frame = gameData.app.nFrameCount; } fq.p0 = &objP->info.position.vPos; fq.startSeg = objP->info.nSegment; fq.radP0 = fq.radP1 = objP->info.xSize; fq.thisObjNum = objP->Index (); fq.ignoreObjList = NULL; fq.flags = 0; fq.bCheckVisibility = false; for (i = 0; i < 2; i++) { fq.p1 = &pointSegP [i].point; hitType = FindVectorIntersection (&fq, &hitData); if (hitType != HIT_NONE) break; nFirstPoint = i + 1; } if (nFirstPoint) { // Scrunch down all the pointSegP. for (i = nFirstPoint; i < numPoints; i++) pointSegP [i - nFirstPoint] = pointSegP [i]; } return numPoints - nFirstPoint; #endif }
int KillAllBuddyBots (int bVerbose) { int i, nKilled = 0; tObject *objP; //int boss_index = -1; for (i = 0, objP = gameData.objs.objects; i <= gameData.objs.nLastObject; i++, objP++) if ((objP->nType == OBJ_ROBOT) && ROBOTINFO (objP->id).companion) { if (gameStates.app.bNostalgia) objP->flags |= OF_EXPLODING|OF_SHOULD_BE_DEAD; else ApplyDamageToRobot (objP, objP->shields + 1, -1); if (bVerbose) HUDInitMessage (TXT_BUDDY_TOASTED); nKilled++; } if (bVerbose) HUDInitMessage (TXT_BOTS_TOASTED, nKilled); return nKilled; }
void PagingTouchRobot (int robotIndex) { int i; // Page in robotIndex PagingTouchModel (ROBOTINFO (robotIndex).nModel); if (ROBOTINFO (robotIndex).nExp1VClip>-1) PagingTouchVClip (&gameData.eff.vClips [0][ROBOTINFO (robotIndex).nExp1VClip], 0); if (ROBOTINFO (robotIndex).nExp2VClip>-1) PagingTouchVClip (&gameData.eff.vClips [0][ROBOTINFO (robotIndex).nExp2VClip], 0); // Page in his weapons PagingTouchWeapon (ROBOTINFO (robotIndex).nWeaponType); // A super-boss can gate in robots... if (ROBOTINFO (robotIndex).bossFlag == 2) { for (i = 0; i < 13; i++) PagingTouchRobot (superBossGateTypeList [i]); PagingTouchVClip (&gameData.eff.vClips [0][VCLIP_MORPHING_ROBOT], 0); } }
void LoadRobotTextures (int robotIndex) { int i; // Page in robotIndex LoadModelTextures (ROBOTINFO (robotIndex).nModel); if (ROBOTINFO (robotIndex).nExp1VClip >= 0) LoadVClipTextures (&gameData.eff.vClips [0][ROBOTINFO (robotIndex).nExp1VClip], 0); if (ROBOTINFO (robotIndex).nExp2VClip >= 0) LoadVClipTextures (&gameData.eff.vClips [0][ROBOTINFO (robotIndex).nExp2VClip], 0); // Page in his weapons LoadWeaponTextures (ROBOTINFO (robotIndex).nWeaponType); // A super-boss can gate in robots... if (ROBOTINFO (robotIndex).bossFlag == 2) { for (i = 0; i < 13; i++) LoadRobotTextures (superBossGateTypeList [i]); LoadVClipTextures (&gameData.eff.vClips [0][VCLIP_MORPHING_ROBOT], 0); } }
void AIIdleAnimation (CObject *objP) { #if DBG if (objP->Index () == nDbgObj) nDbgObj = nDbgObj; #endif if (gameOpts->gameplay.bIdleAnims) { int h, i, j; CSegment *segP = SEGMENTS + objP->info.nSegment; CFixVector *vVertex, vVecToGoal, vGoal = gameData.objs.vRobotGoals [objP->Index ()]; for (i = 0; i < 8; i++) { vVertex = gameData.segs.vertices + segP->m_verts [i]; if ((vGoal[X] == (*vVertex)[X]) && (vGoal[Y] == (*vVertex)[Y]) && (vGoal[Z] == (*vVertex)[Z])) break; } vVecToGoal = vGoal - objP->info.position.vPos; CFixVector::Normalize (vVecToGoal); if (i == 8) h = 1; else if (AITurnTowardsVector (&vVecToGoal, objP, ROBOTINFO (objP->info.nId).turnTime [2]) < I2X (1) - I2X (1) / 5) { if (CFixVector::Dot (vVecToGoal, objP->info.position.mOrient.FVec ()) > I2X (1) - I2X (1) / 5) h = rand () % 2 == 0; else h = 0; } else if (MoveTowardsPoint (objP, &vGoal, objP->info.xSize * 3 / 2)) h = rand () % 8 == 0; else h = 1; if (h && (rand () % 25 == 0)) { j = rand () % 8; if ((j == i) || (rand () % 3 == 0)) vGoal = SEGMENTS [objP->info.nSegment].Center (); else vGoal = gameData.segs.vertices [segP->m_verts [j]]; gameData.objs.vRobotGoals [objP->Index ()] = vGoal; DoSillyAnimation (objP); } } }
int NetworkVerifyPlayers (void) { int i, j, t, bCoop = IsCoopGame; int nPlayers, nPlayerObjs [MAX_PLAYERS], bHaveReactor = !bCoop; CObject *objP; CPlayerData *playerP; for (j = 0, playerP = gameData.multiplayer.players; j < MAX_PLAYERS; j++, playerP++) nPlayerObjs [j] = playerP->connected ? playerP->nObject : -1; #if 0 if (gameData.app.nGameMode & GM_MULTI_ROBOTS) #endif // bHaveReactor = 1; // multiplayer maps do not need a control center ... nPlayers = 0; FORALL_OBJS (objP, i) { i = objP->Index (); t = objP->info.nType; if (t == OBJ_GHOST) { for (j = 0; j < MAX_PLAYERS; j++) { if (nPlayerObjs [j] == i) { nPlayers++; break; } } } else if (t == OBJ_PLAYER) { if (!(i && bCoop)) nPlayers++; } else if (t == OBJ_COOP) { if (bCoop) nPlayers++; } else if (bCoop) { if ((t == OBJ_REACTOR) || ((t == OBJ_ROBOT) && ROBOTINFO (objP->info.nId).bossFlag)) bHaveReactor = 1; } if (nPlayers >= gameData.multiplayer.nMaxPlayers) return 1; }
// ----------------------------------------------------------------------------------------------------------- //given an tObject and a gun number, return position in 3-space of gun //fills in gun_point int CalcGunPoint (vmsVector *vGunPoint, tObject *objP, int nGun) { tPolyModel *pm; tRobotInfo *botInfoP; vmsVector pnt; vmsMatrix m; int mn; //submodel number Assert(objP->renderType == RT_POLYOBJ || objP->renderType==RT_MORPH); //Assert(objP->id < gameData.bots.nTypes [gameStates.app.bD1Data]); botInfoP = &ROBOTINFO (objP->id); if (!botInfoP->nGuns) return 0; pm = gameData.models.polyModels + botInfoP->nModel; if (nGun >= botInfoP->nGuns) { //Int3(); nGun = 0; } // Assert(nGun < botInfoP->nGuns); pnt = botInfoP->gunPoints [nGun]; mn = botInfoP->gunSubModels [nGun]; //instance up the tree for this gun while (mn != 0) { vmsVector tpnt; VmAngles2Matrix (&m, &objP->rType.polyObjInfo.animAngles [mn]); VmTransposeMatrix (&m); VmVecRotate (&tpnt, &pnt, &m); VmVecAdd (&pnt, &tpnt, &pm->subModels.offsets [mn]); mn = pm->subModels.parents [mn]; } //now instance for the entire tObject VmCopyTransposeMatrix (&m, &objP->position.mOrient); VmVecRotate (vGunPoint, &pnt, &m); VmVecInc (vGunPoint, &objP->position.vPos); return 1; }
void KillAllBossRobots (int bVerbose) { int i, nKilled = 0; tObject *objP; if (gameStates.gameplay.bKillBossCheat) gameStates.gameplay.bKillBossCheat = 0; else { for (i = 0, objP = gameData.objs.objects; i<=gameData.objs.nLastObject; i++, objP++) if ((objP->nType == OBJ_ROBOT) && ROBOTINFO (objP->id).bossFlag) { nKilled++; if (gameStates.app.bNostalgia) objP->flags |= OF_EXPLODING | OF_SHOULD_BE_DEAD; else { ApplyDamageToRobot (objP, objP->shields + 1, -1); objP->flags |= OF_ARMAGEDDON; } gameStates.gameplay.bKillBossCheat = 1; } } if (bVerbose) HUDInitMessage (TXT_BOTS_TOASTED, nKilled); }
fix CalcObjectLight (CObject *objP, fix *xEngineGlow) { fix xLight; if (gameStates.render.bBuildModels) return I2X (1); if (IsMultiGame && netGame.BrightPlayers && (objP->info.nType == OBJ_PLAYER)) { xLight = I2X (1); // If option set for bright players in netgame, brighten them gameOpts->ogl.bLightObjects = 0; } else xLight = ComputeObjectLight (objP, NULL); //make robots brighter according to robot glow field if (objP->info.nType == OBJ_ROBOT) xLight += (ROBOTINFO (objP->info.nId).glow << 12); //convert 4:4 to 16:16 else if (objP->info.nType == OBJ_WEAPON) { if (objP->info.nId == FLARE_ID) xLight += I2X (2); } else if (objP->info.nType == OBJ_MARKER) xLight += I2X (2); ComputeEngineGlow (objP, xEngineGlow); return xLight; }
void AIIdleAnimation (tObject *objP) { if (gameOpts->gameplay.bIdleAnims) { int h, i, j; tSegment *segP = gameData.segs.segments + objP->nSegment; vmsVector *vVertex, vVecToGoal, vGoal = gameData.objs.vRobotGoals [OBJ_IDX (objP)]; for (i = 0; i < 8; i++) { vVertex = gameData.segs.vertices + segP->verts [i]; if ((vGoal.p.x == vVertex->p.x) && (vGoal.p.y == vVertex->p.y) && (vGoal.p.z == vVertex->p.z)) break; } VmVecNormalize (VmVecSub (&vVecToGoal, &vGoal, &objP->position.vPos)); if (i == 8) h = 1; else if (AITurnTowardsVector (&vVecToGoal, objP, ROBOTINFO (objP->id).turnTime [2]) < F1_0 - F1_0 / 5) { if (VmVecDot (&vVecToGoal, &objP->position.mOrient.fVec) > F1_0 - F1_0 / 5) h = rand () % 2 == 0; else h = 0; } else if (MoveTowardsPoint (objP, &vGoal, objP->size * 3 / 2)) h = rand () % 8 == 0; else h = 1; if (h && (rand () % 25 == 0)) { j = rand () % 8; if ((j == i) || (rand () % 3 == 0)) COMPUTE_SEGMENT_CENTER_I (&vGoal, objP->nSegment); else vGoal = gameData.segs.vertices [segP->verts [j]]; gameData.objs.vRobotGoals [OBJ_IDX (objP)] = vGoal; DoSillyAnimation (objP); } } }
// -------------------------------------------------------------------------------------------------------------------- // Note: Parameter gameData.ai.vVecToPlayer is only passed now because guns which aren't on the forward vector from the // center of the robot will not fire right at the player. We need to aim the guns at the player. Barring that, we cheat. // When this routine is complete, the parameter gameData.ai.vVecToPlayer should not be necessary. void AIFireLaserAtPlayer (CObject *objP, CFixVector *vFirePoint, int nGun, CFixVector *vBelievedPlayerPos) { short nShot, nObject = objP->Index (); tAILocalInfo *ailP = gameData.ai.localInfo + nObject; tRobotInfo *botInfoP = &ROBOTINFO (objP->info.nId); CFixVector vFire; CFixVector bpp_diff; short nWeaponType; fix aim, dot; int count, i; Assert (nObject >= 0); // If this robot is only awake because a camera woke it up, don't fire. if (objP->cType.aiInfo.SUB_FLAGS & SUB_FLAGS_CAMERA_AWAKE) return; if (!gameStates.app.cheats.bRobotsFiring) return; if (objP->info.controlType == CT_MORPH) return; // If player is exploded, stop firing. if (gameStates.app.bPlayerExploded) return; if (objP->cType.aiInfo.xDyingStartTime) return; // No firing while in death roll. // Don't let the boss fire while in death roll. Sorry, this is the easiest way to do this. // If you try to key the boss off objP->cType.aiInfo.xDyingStartTime, it will hose the endlevel stuff. if (ROBOTINFO (objP->info.nId).bossFlag) { i = gameData.bosses.Find (nObject); if ((i < 0) || (gameData.bosses [i].m_nDyingStartTime)) return; } // If CPlayerData is cloaked, maybe don't fire based on how long cloaked and randomness. if (LOCALPLAYER.flags & PLAYER_FLAGS_CLOAKED) { fix xCloakTime = gameData.ai.cloakInfo [nObject % MAX_AI_CLOAK_INFO].lastTime; if ((gameData.time.xGame - xCloakTime > CLOAK_TIME_MAX/4) && (d_rand () > FixDiv (gameData.time.xGame - xCloakTime, CLOAK_TIME_MAX)/2)) { SetNextFireTime (objP, ailP, botInfoP, nGun); return; } } // Handle problem of a robot firing through a CWall because its gun tip is on the other // CSide of the CWall than the robot's center. For speed reasons, we normally only compute // the vector from the gun point to the player. But we need to know whether the gun point // is separated from the robot's center by a CWall. If so, don't fire! if (objP->cType.aiInfo.SUB_FLAGS & SUB_FLAGS_GUNSEG) { // Well, the gun point is in a different CSegment than the robot's center. // This is almost always ok, but it is not ok if something solid is in between. int nGunSeg = FindSegByPos (*vFirePoint, objP->info.nSegment, 1, 0); // See if these segments are connected, which should almost always be the case. short nConnSide = SEGMENTS [nGunSeg].ConnectedSide (&SEGMENTS [objP->info.nSegment]); if (nConnSide != -1) { // They are connected via nConnSide in CSegment objP->info.nSegment. // See if they are unobstructed. if (!(SEGMENTS [objP->info.nSegment].IsDoorWay (nConnSide, NULL) & WID_FLY_FLAG)) { // Can't fly through, so don't let this bot fire through! return; } } else { // Well, they are not directly connected, so use FindVectorIntersection to see if they are unobstructed. tFVIQuery fq; tFVIData hit_data; int fate; fq.startSeg = objP->info.nSegment; fq.p0 = &objP->info.position.vPos; fq.p1 = vFirePoint; fq.radP0 = fq.radP1 = 0; fq.thisObjNum = objP->Index (); fq.ignoreObjList = NULL; fq.flags = FQ_TRANSWALL; fate = FindVectorIntersection (&fq, &hit_data); if (fate != HIT_NONE) { Int3 (); // This bot's gun is poking through a CWall, so don't fire. MoveTowardsSegmentCenter (objP); // And decrease chances it will happen again. return; } } } // Set position to fire at based on difficulty level and robot's aiming ability aim = I2X (FIRE_K) - (FIRE_K-1)* (botInfoP->aim << 8); // I2X (1) in bitmaps.tbl = same as used to be. Worst is 50% more error. // Robots aim more poorly during seismic disturbance. if (gameStates.gameplay.seismic.nMagnitude) { fix temp = I2X (1) - abs (gameStates.gameplay.seismic.nMagnitude); if (temp < I2X (1)/2) temp = I2X (1)/2; aim = FixMul (aim, temp); } // Lead the CPlayerData half the time. // Note that when leading the CPlayerData, aim is perfect. This is probably acceptable since leading is so hacked in. // Problem is all robots will lead equally badly. if (d_rand () < 16384) { if (LeadPlayer (objP, vFirePoint, vBelievedPlayerPos, nGun, &vFire)) // Stuff direction to fire at in vFirePoint. goto player_led; } dot = 0; count = 0; // Don't want to sit in this loop foreverd:\temp\dm_test. i = (NDL - gameStates.app.nDifficultyLevel - 1) * 4; while ((count < 4) && (dot < I2X (1)/4)) { bpp_diff[X] = (*vBelievedPlayerPos)[X] + FixMul ((d_rand ()-16384) * i, aim); bpp_diff[Y] = (*vBelievedPlayerPos)[Y] + FixMul ((d_rand ()-16384) * i, aim); bpp_diff[Z] = (*vBelievedPlayerPos)[Z] + FixMul ((d_rand ()-16384) * i, aim); CFixVector::NormalizedDir(vFire, bpp_diff, *vFirePoint); dot = CFixVector::Dot (objP->info.position.mOrient.FVec (), vFire); count++; } player_led: nWeaponType = botInfoP->nWeaponType; if ((botInfoP->nSecWeaponType != -1) && ((nWeaponType < 0) || !nGun)) nWeaponType = botInfoP->nSecWeaponType; if (nWeaponType < 0) return; if (0 > (nShot = CreateNewLaserEasy (&vFire, vFirePoint, objP->Index (), (ubyte) nWeaponType, 1))) return; lightClusterManager.AddForAI (objP, nObject, nShot); objP->Shots ().nObject = nShot; objP->Shots ().nSignature = OBJECTS [nShot].info.nSignature; if (IsMultiGame) { AIMultiSendRobotPos (nObject, -1); MultiSendRobotFire (nObject, objP->cType.aiInfo.CURRENT_GUN, &vFire); } #if 1 if (++(objP->cType.aiInfo.CURRENT_GUN) >= botInfoP->nGuns) { if ((botInfoP->nGuns == 1) || (botInfoP->nSecWeaponType == -1)) objP->cType.aiInfo.CURRENT_GUN = 0; else objP->cType.aiInfo.CURRENT_GUN = 1; } #endif CreateAwarenessEvent (objP, PA_NEARBY_ROBOT_FIRED); SetNextFireTime (objP, ailP, botInfoP, nGun); }
int DrawPolygonObject (CObject *objP, int bDepthSort, int bForce) { fix xLight; int imSave = 0; fix xEngineGlow [2]; //element 0 is for engine glow, 1 for headlight int bBlendPolys = 0; int bBrightPolys = 0; int bGatling = 0; int bCloaked = ObjectIsCloaked (objP); int bEnergyWeapon; int i, id, bOk = 0; if (objP->info.nType == 255) return 0; id = (int) objP->info.nId; if ((id < 0) || (id == 255)) bEnergyWeapon = id = 0; else { #if 0 bGatling = ((objP->info.nType == OBJ_WEAPON) && ((id == VULCAN_ID) || (id == GAUSS_ID))); #endif bEnergyWeapon = (objP->info.nType == OBJ_WEAPON) && gameData.objs.bIsWeapon [id] && !gameData.objs.bIsMissile [id]; } #if SHADOWS if (!bForce && FAST_SHADOWS && !gameOpts->render.shadows.bSoft && (gameStates.render.nShadowPass == 3)) return 1; #endif if (gameStates.render.bBuildModels) xLight = I2X (1); else { xLight = CalcObjectLight (objP, xEngineGlow); if ((bCloaked || bEnergyWeapon) && bDepthSort && (gameStates.render.nShadowPass != 2)) { transparencyRenderer.AddObject (objP); return 1; } if (DrawHiresObject (objP, xLight, xEngineGlow)) return 1; gameStates.render.bBrightObject = bEnergyWeapon; gameOpts->render.bDepthSort = -gameOpts->render.bDepthSort; imSave = gameStates.render.nInterpolationMethod; if (bLinearTMapPolyObjs) gameStates.render.nInterpolationMethod = 1; } if (objP->rType.polyObjInfo.nTexOverride != -1) { #if DBG CPolyModel* pm = gameData.models.polyModels [0] + objP->rType.polyObjInfo.nModel; #endif tBitmapIndex bm = gameData.pig.tex.bmIndex [0][objP->rType.polyObjInfo.nTexOverride], bmiP [MAX_MODEL_TEXTURES]; #if DBG Assert (pm->TextureCount () <= 12); #endif for (i = 0; i < MAX_MODEL_TEXTURES; i++) //fill whole array, in case simple model needs more bmiP [i] = bm; bOk = DrawPolyModel (objP, &objP->info.position.vPos, &objP->info.position.mOrient, reinterpret_cast<CAngleVector*> ( &objP->rType.polyObjInfo.animAngles), objP->rType.polyObjInfo.nModel, objP->rType.polyObjInfo.nSubObjFlags, xLight, xEngineGlow, bmiP, NULL); } else { if (bCloaked) { if (objP->info.nType == OBJ_PLAYER) bOk = DrawCloakedObject (objP, xLight, xEngineGlow, gameData.multiplayer.players [id].cloakTime, gameData.multiplayer.players [id].cloakTime + CLOAK_TIME_MAX); else if (objP->info.nType == OBJ_ROBOT) { if (!ROBOTINFO (id).bossFlag) bOk = DrawCloakedObject (objP, xLight, xEngineGlow, gameData.time.xGame - I2X (10), gameData.time.xGame + I2X (10)); else if (0 <= (i = gameData.bosses.Find (objP->Index ()))) bOk = DrawCloakedObject (objP, xLight, xEngineGlow, gameData.bosses [i].m_nCloakStartTime, gameData.bosses [i].m_nCloakEndTime); } } else { tBitmapIndex *bmiAltTex = (objP->rType.polyObjInfo.nAltTextures > 0) ? mpTextureIndex [objP->rType.polyObjInfo.nAltTextures - 1] : NULL; // Snipers get bright when they fire. if (!gameStates.render.bBuildModels) { if ((objP->info.nType == OBJ_ROBOT) && (gameData.ai.localInfo [objP->Index ()].nextPrimaryFire < I2X (1) / 8) && (objP->cType.aiInfo.behavior == AIB_SNIPE)) xLight = 2 * xLight + I2X (1); bBlendPolys = bEnergyWeapon && (gameData.weapons.info [id].nInnerModel > -1); bBrightPolys = bGatling || (bBlendPolys && WI_energy_usage (id)); if (bEnergyWeapon) { if (gameOpts->legacy.bRender) gameStates.render.grAlpha = GrAlpha (FADE_LEVELS - 2); else ogl.BlendFunc (GL_ONE, GL_ONE); } if (bBlendPolys) { #if 0 fix xDistToEye = CFixVector::Dist(gameData.objs.viewerP->info.position.vPos, objP->info.position.vPos); if (xDistToEye < gameData.models.nSimpleModelThresholdScale * I2X (2)) #endif bOk = DrawPolyModel (objP, &objP->info.position.vPos, &objP->info.position.mOrient, objP->rType.polyObjInfo.animAngles, gameData.weapons.info [id].nInnerModel, objP->rType.polyObjInfo.nSubObjFlags, bBrightPolys ? I2X (1) : xLight, xEngineGlow, bmiAltTex, NULL); } if (bEnergyWeapon) gameStates.render.grAlpha = GrAlpha (4 * FADE_LEVELS / 5); else if (!bBlendPolys) gameStates.render.grAlpha = 1.0f; } bOk = DrawPolyModel (objP, &objP->info.position.vPos, &objP->info.position.mOrient, objP->rType.polyObjInfo.animAngles, objP->rType.polyObjInfo.nModel, objP->rType.polyObjInfo.nSubObjFlags, (bGatling || bBrightPolys) ? I2X (1) : xLight, xEngineGlow, bmiAltTex, (bGatling || bEnergyWeapon) ? gameData.weapons.color + id : NULL); if (!gameStates.render.bBuildModels) { if (!gameOpts->legacy.bRender) ogl.BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gameStates.render.grAlpha = 1.0f; } } } if (!gameStates.render.bBuildModels) { gameStates.render.nInterpolationMethod = imSave; gameStates.render.bBrightObject = 0; gameOpts->render.bDepthSort = -gameOpts->render.bDepthSort; } return bOk; }
int GetCloakInfo (CObject *objP, fix xCloakStartTime, fix xCloakEndTime, tCloakInfo *ciP) { tCloakInfo ci = {0, CLOAKED_FADE_LEVEL, I2X (1), I2X (1), I2X (1), 0, 0}; int i; if (!(xCloakStartTime || xCloakEndTime)) { if (objP->info.nType == OBJ_PLAYER) { xCloakStartTime = gameData.multiplayer.players [objP->info.nId].cloakTime; xCloakEndTime = gameData.multiplayer.players [objP->info.nId].cloakTime + CLOAK_TIME_MAX; } else if (objP->info.nType == OBJ_ROBOT) { if (!ROBOTINFO (objP->info.nId).bossFlag) { xCloakStartTime = gameData.time.xGame - I2X (10); xCloakEndTime = gameData.time.xGame + I2X (10); } else if (0 <= (i = gameData.bosses.Find (objP->Index ()))) { xCloakStartTime = gameData.bosses [i].m_nCloakStartTime; xCloakEndTime = gameData.bosses [i].m_nCloakEndTime; } } } if (xCloakStartTime != 0x7fffffff) ci.xTotalTime = xCloakEndTime - xCloakStartTime; else ci.xTotalTime = gameData.time.xGame; if (objP->info.nType == OBJ_PLAYER) { ci.xFadeinDuration = CLOAK_FADEIN_DURATION_PLAYER; ci.xFadeoutDuration = CLOAK_FADEOUT_DURATION_PLAYER; } else if (objP->info.nType == OBJ_ROBOT) { ci.xFadeinDuration = CLOAK_FADEIN_DURATION_ROBOT; ci.xFadeoutDuration = CLOAK_FADEOUT_DURATION_ROBOT; } else return 0; ci.xDeltaTime = gameData.time.xGame - ((xCloakStartTime == 0x7fffffff) ? 0 : xCloakStartTime); #if 0 if (ci.xDeltaTime < ci.xFadeinDuration) { // make object transparent during second half ci.nFadeValue = X2I (FixDiv (ci.xFadeinDuration - ci.xDeltaTime, ci.xFadeinDuration) * CLOAKED_FADE_LEVEL); ci.bFading = 1; } #else // only decrease light during first half of cloak initiation time if (ci.xDeltaTime < ci.xFadeinDuration / 2) { ci.xLightScale = FixDiv (ci.xFadeinDuration / 2 - ci.xDeltaTime, ci.xFadeinDuration / 2); ci.bFading = -1; } else if (ci.xDeltaTime < ci.xFadeinDuration) { // make object transparent during second half ci.nFadeValue = X2I (FixDiv (ci.xDeltaTime - ci.xFadeinDuration / 2, ci.xFadeinDuration / 2) * CLOAKED_FADE_LEVEL); ci.bFading = 1; } #endif else if ((xCloakStartTime == 0x7fffffff) || (gameData.time.xGame < xCloakEndTime - ci.xFadeoutDuration)) { static int nCloakDelta = 0, nCloakDir = 1; static fix xCloakTimer = 0; //note, if more than one cloaked CObject is visible at once, the //pulse rate will change! xCloakTimer -= gameData.time.xFrame; while (xCloakTimer < 0) { xCloakTimer += ci.xFadeoutDuration / 12; nCloakDelta += nCloakDir; if (nCloakDelta == 0 || nCloakDelta == 4) nCloakDir = -nCloakDir; } ci.nFadeValue = CLOAKED_FADE_LEVEL - nCloakDelta; } else if (gameData.time.xGame < xCloakEndTime - ci.xFadeoutDuration / 2) { ci.nFadeValue = X2I (FixDiv (ci.xTotalTime - ci.xFadeoutDuration / 2 - ci.xDeltaTime, ci.xFadeoutDuration / 2) * CLOAKED_FADE_LEVEL); ci.bFading = -1; } else { ci.xLightScale = (fix) ((float) (ci.xFadeoutDuration / 2 - (ci.xTotalTime - ci.xDeltaTime) / (float) (ci.xFadeoutDuration / 2))); ci.bFading = 1; } if (ciP) *ciP = ci; return ci.bFading; }
// ----------------------------------------------------------------------------- //if an effect is hit, and it can blow up, then blow it up //returns true if it blew up int CSegment::CheckEffectBlowup (int nSide, CFixVector& vHit, CObject* blowerP, int bForceBlowup) { int tm, tmf, ec, nBitmap = 0; int bOkToBlow = 0, nSwitchType = -1; short nSound, bPermaTrigger; ubyte vc; fix u, v; fix xDestSize; tEffectClip* ecP = NULL; CBitmap* bmP; CWall* wallP; CTrigger* trigP; CObject* parentP = (!blowerP || (blowerP->cType.laserInfo.parent.nObject < 0)) ? NULL : OBJECTS + blowerP->cType.laserInfo.parent.nObject; // If this CWall has a CTrigger and the blowerP-upper is not the CPlayerData or the buddy, abort! if (parentP) { if ((parentP->info.nType == OBJ_ROBOT) && ROBOTINFO (parentP->info.nId).companion) bOkToBlow = 1; if (!(bOkToBlow || (parentP->info.nType == OBJ_PLAYER)) && ((wallP = Wall (nSide)) && (wallP->nTrigger < gameData.trigs.m_nTriggers))) return 0; } if (!(tm = m_sides [nSide].m_nOvlTex)) return 0; tmf = m_sides [nSide].m_nOvlOrient; //tm flags ec = gameData.pig.tex.tMapInfoP [tm].nEffectClip; if (ec < 0) { if (gameData.pig.tex.tMapInfoP [tm].destroyed == -1) return 0; nBitmap = -1; nSwitchType = 0; } else { ecP = gameData.eff.effectP + ec; if (ecP->flags & EF_ONE_SHOT) return 0; nBitmap = ecP->nDestBm; if (nBitmap < 0) return 0; nSwitchType = 1; } //check if it's an animation (monitor) or casts light bmP = gameData.pig.tex.bitmapP + gameData.pig.tex.bmIndexP [tm].index; LoadBitmap (gameData.pig.tex.bmIndexP [tm].index, gameStates.app.bD1Data); //this can be blown up...did we hit it? if (!bForceBlowup) { HitPointUV (nSide, &u, &v, NULL, vHit, 0); //evil: always say face zero bForceBlowup = !PixelTranspType (tm, tmf, m_sides [nSide].m_nFrame, u, v); } if (!bForceBlowup) return 0; if (IsMultiGame && netGame.bIndestructibleLights && !nSwitchType) return 0; //note: this must get called before the texture changes, //because we use the light value of the texture to change //the static light in the CSegment wallP = Wall (nSide); bPermaTrigger = (trigP = Trigger (nSide)) && (trigP->flags & TF_PERMANENT); if (!bPermaTrigger) SubtractLight (Index (), nSide); if (gameData.demo.nState == ND_STATE_RECORDING) NDRecordEffectBlowup (Index (), nSide, vHit); if (nSwitchType) { xDestSize = ecP->xDestSize; vc = ecP->nDestVClip; } else { xDestSize = I2X (20); vc = 3; } /*Object*/CreateExplosion (short (Index ()), vHit, xDestSize, vc); if (nSwitchType) { if ((nSound = gameData.eff.vClipP [vc].nSound) != -1) audio.CreateSegmentSound (nSound, Index (), 0, vHit); if ((nSound = ecP->nSound) != -1) //kill sound audio.DestroySegmentSound (Index (), nSide, nSound); if (!bPermaTrigger && (ecP->nDestEClip != -1) && (gameData.eff.effectP [ecP->nDestEClip].nSegment == -1)) { tEffectClip *newEcP = gameData.eff.effectP + ecP->nDestEClip; int nNewBm = newEcP->changingWallTexture; if (ChangeTextures (-1, nNewBm)) { newEcP->xTimeLeft = EffectFrameTime (newEcP); newEcP->nCurFrame = 0; newEcP->nSegment = Index (); newEcP->nSide = nSide; newEcP->flags |= EF_ONE_SHOT | ecP->flags; newEcP->flags &= ~EF_INITIALIZED; newEcP->nDestBm = ecP->nDestBm; Assert ((nNewBm != 0) && (m_sides [nSide].m_nOvlTex != 0)); m_sides [nSide].m_nOvlTex = nNewBm; //replace with destoyed } } else { Assert ((nBitmap != 0) && (m_sides [nSide].m_nOvlTex != 0)); if (!bPermaTrigger) m_sides [nSide].m_nOvlTex = nBitmap; //replace with destoyed } } else { if (!bPermaTrigger) m_sides [nSide].m_nOvlTex = gameData.pig.tex.tMapInfoP [tm].destroyed; //assume this is a light, and play light sound audio.CreateSegmentSound (SOUND_LIGHT_BLOWNUP, Index (), 0, vHit); } return 1; //blew up! }