void WiggleObject (CObject *objP) { fix xWiggle; int nParent; CObject *pParent; if (gameStates.render.nShadowPass == 2) return; if (gameOpts->app.bEpilepticFriendly) return; if (!gameStates.app.bNostalgia && (!EGI_FLAG (nDrag, 0, 0, 0) || !EGI_FLAG (bWiggle, 1, 0, 1))) return; nParent = gameData.objs.parentObjs [objP->Index ()]; pParent = (nParent < 0) ? NULL : OBJECTS + nParent; FixFastSinCos (fix (gameData.time.xGame / gameStates.gameplay.slowmo [1].fSpeed), &xWiggle, NULL); if (gameData.time.xFrame < I2X (1))// Only scale wiggle if getting at least 1 FPS, to avoid causing the opposite problem. xWiggle = FixMul (xWiggle * 20, gameData.time.xFrame); //make wiggle fps-independent (based on pre-scaled amount of wiggle at 20 FPS) if (SPECTATOR (objP)) OBJPOS (objP)->vPos += (OBJPOS (objP)->mOrient.UVec () * FixMul (xWiggle, gameData.pig.ship.player->wiggle)) * (I2X (1) / 20); else if ((objP->info.nType == OBJ_PLAYER) || !pParent) objP->mType.physInfo.velocity += objP->info.position.mOrient.UVec () * FixMul (xWiggle, gameData.pig.ship.player->wiggle); else { objP->mType.physInfo.velocity += pParent->info.position.mOrient.UVec () * FixMul (xWiggle, gameData.pig.ship.player->wiggle); objP->info.position.vPos += objP->mType.physInfo.velocity * gameData.time.xFrame; } }
// ---------------------------------------------------------------------------------- // 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) }
fix CheckVectorToHitbox (CFixVector& intersection, CFixVector *p0, CFixVector *p1, CFixVector *vRef, CObject *objP, fix rad, short& nModel) { int iModel, nModels; fix xDist = 0x7fffffff, dMin = 0x7fffffff; CModelHitboxes *pmhb = gameData.models.hitboxes + objP->rType.polyObjInfo.nModel; tBox hb [MAX_HITBOXES + 1]; CFixVector vHit; if (extraGameInfo [IsMultiGame].nHitboxes == 1) { iModel = nModels = 0; } else { iModel = 1; nModels = pmhb->nHitboxes; } if (!vRef) vRef = &OBJPOS (objP)->vPos; intersection.Create (0x7fffffff, 0x7fffffff, 0x7fffffff); TransformHitboxes (objP, vRef, hb); for (; iModel <= nModels; iModel++) { if (FindLineHitboxIntersection (vHit, hb + iModel, p0, p1, p0, rad)) { xDist = RegisterHit (&intersection, &vHit, vRef, dMin); if (dMin > xDist) { dMin = xDist; nModel = iModel; } } } return xDist; }
void UpdateOglHeadLight (void) { tDynLight *pl; tObject *objP; short nPlayer; for (nPlayer = 0; nPlayer < MAX_PLAYERS; nPlayer++) { if (gameData.render.lights.dynamic.nHeadLights [nPlayer] < 0) continue; pl = gameData.render.lights.dynamic.lights + gameData.render.lights.dynamic.nHeadLights [nPlayer]; objP = OBJECTS + gameData.multiplayer.players [nPlayer].nObject; pl->info.vPos = OBJPOS (objP)->vPos; pl->vDir = OBJPOS (objP)->mOrient.fVec; VmVecScaleInc (&pl->info.vPos, &pl->vDir, objP->size / 4); } }
fix CheckHitboxToHitbox (CFixVector& intersection, CObject *objP1, CObject *objP2, CFixVector *p0, CFixVector *p1, short& nModel) { CFixVector vHit, vRef = OBJPOS (objP2)->vPos; int iModel1, nModels1, iModel2, nModels2, nHits = 0; CModelHitboxes *pmhb1 = gameData.models.hitboxes + objP1->rType.polyObjInfo.nModel; CModelHitboxes *pmhb2 = gameData.models.hitboxes + objP2->rType.polyObjInfo.nModel; tBox hb1 [MAX_HITBOXES + 1]; tBox hb2 [MAX_HITBOXES + 1]; fix xDist = 0x7fffffff, dMin = 0x7fffffff; if (extraGameInfo [IsMultiGame].nHitboxes == 1) { iModel1 = nModels1 = iModel2 = nModels2 = 0; } else { iModel1 = iModel2 = 1; nModels1 = pmhb1->nHitboxes; nModels2 = pmhb2->nHitboxes; } #if DBG memset (hb1, 0, sizeof (hb1)); memset (hb2, 0, sizeof (hb2)); #endif TransformHitboxes (objP1, p1, hb1); TransformHitboxes (objP2, &vRef, hb2); for (; iModel1 <= nModels1; iModel1++) { for (; iModel2 <= nModels2; iModel2++) { if (FindHitboxIntersection (vHit, hb1 + iModel1, hb2 + iModel2, p0)) { xDist = RegisterHit (&intersection, &vHit, &vRef, dMin); if (dMin > xDist) { nHits++; dMin = xDist; nModel = iModel1; } } } } if (!nHits) { for (; iModel2 <= nModels2; iModel2++) { if (FindLineHitboxIntersection (vHit, hb2 + iModel2, p0, p1, p0, 0)) { xDist = RegisterHit (&intersection, &vHit, &vRef, dMin); if (dMin > xDist) { nHits++; dMin = xDist; nModel = iModel1; } } } } #if DBG if (nHits) { pmhb1->vHit = pmhb2->vHit = intersection; pmhb1->tHit = pmhb2->tHit = gameStates.app.nSDLTicks; } #endif return nHits ? dMin ? dMin : 1 : 0; }
void DrawShieldSphere (tObject *objP, float red, float green, float blue, float alpha) { if (!CreateShieldSphere ()) return; #if !SIMPLE_SPHERE if (gameData.render.shield.nFaces > 0) #endif { if ((gameOpts->render.bDepthSort > 0) || (gameOpts->render.nPath && !gameOpts->render.bDepthSort)) RIAddSphere (riSphereShield, red, green, blue, alpha, objP); else { tOOF_vector p; fix nSize = gameData.models.polyModels [objP->rType.polyObjInfo.nModel].rad; float fScale, r = f2fl (nSize) * 1.05f; tPosition *posP = OBJPOS (objP); vmsVector vPos; gameStates.ogl.bUseTransform = 1; G3StartInstanceMatrix (&posP->vPos, &posP->mOrient); RenderSphere (&gameData.render.shield, (tOOF_vector *) OOF_VecVms2Oof (&p, gameData.models.offsets + objP->rType.polyObjInfo.nModel), r, r, r, red, green, blue, alpha, bmpShield, 1); G3DoneInstance (); gameStates.ogl.bUseTransform = 0; fScale = gameData.render.shield.pPulse->fScale; VmVecRotate (&vPos, gameData.models.offsets + objP->rType.polyObjInfo.nModel, ObjectView (objP)); VmVecInc (&vPos, &posP->vPos); RenderObjectHalo (&vPos, 3 * nSize / 2, red * fScale, green * fScale, blue * fScale, alpha * fScale, 0); } } }
void DrawShieldSphere (tObject *objP, float red, float green, float blue, float alpha) { if (!CreateShieldSphere ()) return; #if !SIMPLE_SPHERE if (gameData.render.shield.nFaces > 0) #endif { if ((gameOpts->render.bDepthSort > 0) || (RENDERPATH && !gameOpts->render.bDepthSort)) TIAddSphere (riSphereShield, red, green, blue, alpha, objP); else { tOOF_vector p = {0, 0, 0}; fix nSize = gameData.models.polyModels [objP->rType.polyObjInfo.nModel].rad; float fScale, r = X2F (nSize) /** 1.05f*/; tTransformation *posP = OBJPOS (objP); vmsVector vPos; //gameStates.ogl.bUseTransform = 1; glBlendFunc (GL_ONE, GL_ONE); G3StartInstanceMatrix (*PolyObjPos (objP, &vPos), posP->mOrient); RenderSphere (&gameData.render.shield, &p, r, r, r, red, green, blue, alpha, bmpShield, 1, 1); G3DoneInstance (); gameStates.ogl.bUseTransform = 0; fScale = gameData.render.shield.pPulse->fScale; G3StartInstanceMatrix (vPos, posP->mOrient); vPos.SetZero(); RenderObjectHalo (&vPos, 3 * nSize / 2, red * fScale, green * fScale, blue * fScale, alpha * fScale, 0); G3DoneInstance (); } } }
//this function is for when the CPlayerData intentionally drops a powerup //this function is based on DropPowerup() int SpitPowerup (CObject *spitterP, ubyte id, int seed) { short nObject; CObject *objP; CFixVector newVelocity, newPos; tObjTransformation *posP = OBJPOS (spitterP); #if 0 if ((gameData.app.nGameMode & GM_NETWORK) && (gameData.multiplayer.powerupsInMine [(int)id] + PowerupsOnShips (id) >= gameData.multiplayer.maxPowerupsAllowed [id])) return -1; #endif newVelocity = spitterP->mType.physInfo.velocity + spitterP->info.position.mOrient.FVec() * I2X (SPIT_SPEED); newVelocity[X] += (d_rand() - 16384) * SPIT_SPEED * 2; newVelocity[Y] += (d_rand() - 16384) * SPIT_SPEED * 2; newVelocity[Z] += (d_rand() - 16384) * SPIT_SPEED * 2; // Give keys zero velocity so they can be tracked better in multi if (IsMultiGame && (id >= POW_KEY_BLUE) && (id <= POW_KEY_GOLD)) newVelocity.SetZero (); //there's a piece of code which lets the CPlayerData pick up a powerup if //the distance between him and the powerup is less than 2 time their //combined radii. So we need to create powerups pretty far out from //the player. newPos = posP->vPos + posP->mOrient.FVec () * spitterP->info.xSize; if (IsMultiGame && (gameData.multigame.create.nLoc >= MAX_NET_CREATE_OBJECTS)) return (-1); nObject = CreatePowerup (id, (short) (GetTeam (gameData.multiplayer.nLocalPlayer) + 1), (short) OBJSEG (spitterP), newPos, 1); if (nObject < 0) { Int3(); return nObject; } objP = OBJECTS + nObject; objP->mType.physInfo.velocity = newVelocity; objP->mType.physInfo.drag = 512; //1024; objP->mType.physInfo.mass = I2X (1); objP->mType.physInfo.flags = PF_BOUNCE; objP->rType.vClipInfo.nClipIndex = gameData.objs.pwrUp.info [objP->info.nId].nClipIndex; objP->rType.vClipInfo.xFrameTime = gameData.eff.vClipP [objP->rType.vClipInfo.nClipIndex].xFrameTime; objP->rType.vClipInfo.nCurFrame = 0; if (spitterP == gameData.objs.consoleP) objP->cType.powerupInfo.nFlags |= PF_SPAT_BY_PLAYER; switch (objP->info.nId) { case POW_CONCUSSION_1: case POW_CONCUSSION_4: case POW_SHIELD_BOOST: case POW_ENERGY: objP->info.xLifeLeft = (d_rand() + I2X (3)) * 64; // Lives for 3 to 3.5 binary minutes (a binary minute is 64 seconds) if (gameData.app.nGameMode & GM_MULTI) objP->info.xLifeLeft /= 2; break; default: //if (gameData.app.nGameMode & GM_MULTI) // objP->info.xLifeLeft = (d_rand() + I2X (3)) * 64; // Lives for 5 to 5.5 binary minutes (a binary minute is 64 seconds) break; } MultiSendWeapons (1); return nObject; }
CFixMatrix *CObject::View (void) { tObjectViewData *viewP = gameData.objs.viewData +Index (); if (viewP->nFrame != gameData.objs.nFrameCount) { viewP->mView = OBJPOS (this)->mOrient.Transpose (); viewP->nFrame = gameStates.render.nFrameCount; } return &viewP->mView; }
//------------------------------------------------------------------------------ //do special cloaked render int DrawCloakedObject (CObject *objP, fix light, fix *glow, fix xCloakStartTime, fix xCloakEndTime) { tObjTransformation *posP = OBJPOS (objP); tCloakInfo ci; int bOk = 0; if (gameStates.render.bQueryCoronas) return 1; GetCloakInfo (objP, xCloakStartTime, xCloakEndTime, &ci); if (ci.bFading < 0) { fix xNewLight, xSaveGlow; tBitmapIndex * altTextures = NULL; if (objP->rType.polyObjInfo.nAltTextures > 0) altTextures = mpTextureIndex [objP->rType.polyObjInfo.nAltTextures - 1]; xNewLight = FixMul (light, ci.xLightScale); xSaveGlow = glow [0]; glow [0] = FixMul (glow [0], ci.xLightScale); gameData.models.nLightScale = ci.xLightScale; bOk = DrawPolyModel (objP, &posP->vPos, &posP->mOrient, reinterpret_cast<CAngleVector*> (&objP->rType.polyObjInfo.animAngles), objP->rType.polyObjInfo.nModel, objP->rType.polyObjInfo.nSubObjFlags, xNewLight, glow, altTextures, NULL); gameData.models.nLightScale = 0; glow [0] = xSaveGlow; } else { gameStates.render.bCloaked = 1; gameStates.render.grAlpha = GrAlpha (ci.nFadeValue); CCanvas::Current ()->SetColorRGB (0, 0, 0, 255); //set to black (matters for s3) fpDrawTexPolyMulti = G3DrawTexPolyFlat; bOk = DrawPolyModel (objP, &posP->vPos, &posP->mOrient, reinterpret_cast<CAngleVector*> (&objP->rType.polyObjInfo.animAngles), objP->rType.polyObjInfo.nModel, objP->rType.polyObjInfo.nSubObjFlags, light, glow, NULL, NULL); fpDrawTexPolyMulti = G3DrawTexPolyMulti; gameStates.render.grAlpha = 1.0f; gameStates.render.bCloaked = 0; } return bOk; }
void DoPlayerSmoke (tObject *objP, int i) { int h, j, d, nParts, nType; float nScale; tCloud *pCloud; vmsVector fn, mn, vDir, *vDirP; tThrusterInfo ti; static int bForward = 1; if (i < 0) i = objP->info.nId; if ((gameData.multiplayer.players [i].flags & PLAYER_FLAGS_CLOAKED) || (gameStates.render.automap.bDisplay && IsMultiGame && !AM_SHOW_PLAYERS)) { KillObjectSmoke (i); return; } j = OBJ_IDX (objP); if (gameOpts->render.smoke.bDecreaseLag && (i == gameData.multiplayer.nLocalPlayer)) { fn = objP->info.position.mOrient[FVEC]; mn = objP->info.position.vPos - objP->info.vLastPos; vmsVector::Normalize(fn); vmsVector::Normalize(mn); d = vmsVector::Dot(fn, mn); if (d >= -F1_0 / 2) bForward = 1; else { if (bForward) { if ((h = gameData.smoke.objects [j]) >= 0) { KillObjectSmoke (j); DestroySmoke (h); } bForward = 0; nScale = 0; return; } } } #if 0 if (EGI_FLAG (bThrusterFlames, 1, 1, 0)) { if ((a <= F1_0 / 4) && (a || !gameStates.input.bControlsSkipFrame)) //no thruster flames if moving backward DropAfterburnerBlobs (objP, 2, I2X (1), -1, gameData.objs.consoleP, 1); //F1_0 / 4); } #endif if ((gameData.app.nGameMode & GM_NETWORK) && !gameData.multiplayer.players [i].connected) nParts = 0; else if (objP->info.nFlags & (OF_SHOULD_BE_DEAD | OF_DESTROYED)) nParts = 0; else if ((i == gameData.multiplayer.nLocalPlayer) && (gameStates.app.bPlayerIsDead || (gameData.multiplayer.players [i].shields < 0))) nParts = 0; else { h = X2IR (gameData.multiplayer.players [i].shields); nParts = 10 - h / 5; nScale = X2F (objP->info.xSize); if (h <= 25) nScale /= 1.5; else if (h <= 50) nScale /= 2; else nScale /= 3; if (nParts <= 0) { nType = 2; //nParts = (gameStates.entropy.nTimeLastMoved < 0) ? 250 : 125; } else { CreateDamageExplosion (nParts, j); nType = (h > 25); nParts *= 25; nParts += 75; } nParts = objP->mType.physInfo.thrust.IsZero() ? SHIP_MAX_PARTS : SHIP_MAX_PARTS / 2; if (SHOW_SMOKE && nParts && gameOpts->render.smoke.bPlayers) { if (gameOpts->render.smoke.bSyncSizes) { nParts = -MAX_PARTICLES (nParts, gameOpts->render.smoke.nDens [0]); nScale = PARTICLE_SIZE (gameOpts->render.smoke.nSize [0], nScale); } else { nParts = -MAX_PARTICLES (nParts, gameOpts->render.smoke.nDens [1]); nScale = PARTICLE_SIZE (gameOpts->render.smoke.nSize [1], nScale); } if (!objP->mType.physInfo.thrust.IsZero ()) vDirP = NULL; else { // if the ship is standing still, let the thruster smoke move away from it nParts /= 2; nScale /= 2; vDir = OBJPOS (objP)->mOrient [FVEC] * (F1_0 / 8); vDir = -vDir; vDirP = &vDir; } if (0 > (h = gameData.smoke.objects [j])) { //PrintLog ("creating tPlayer smoke\n"); h = SetSmokeObject (j, CreateSmoke (&objP->info.position.vPos, vDirP, NULL, objP->info.nSegment, 2, nParts, nScale, gameOpts->render.smoke.nSize [1], 2, PLR_PART_LIFE / (nType + 1) * (vDirP ? 2 : 1), PLR_PART_SPEED, SMOKE_PARTICLES, j, smokeColors + nType, 1, -1)); } else { if (vDirP) SetSmokeDir (h, vDirP); SetSmokeLife (h, PLR_PART_LIFE / (nType + 1) * (vDirP ? 2 : 1)); SetSmokeType (h, SMOKE_PARTICLES); SetSmokePartScale (h, -nScale); SetSmokeDensity (h, nParts, gameOpts->render.smoke.bSyncSizes ? -1 : gameOpts->render.smoke.nSize [1]); SetSmokeSpeed (gameData.smoke.objects [i], objP->mType.physInfo.thrust.IsZero () ? PLR_PART_SPEED * 2 : PLR_PART_SPEED); } CalcThrusterPos (objP, &ti, 0); for (j = 0; j < 2; j++) if ((pCloud = GetCloud (h, j))) SetCloudPos (pCloud, ti.vPos + j, NULL, objP->info.nSegment); DoGatlingSmoke (objP); return; } } KillObjectSmoke (i); KillGatlingSmoke (objP); }
void CObject::SaveState (CFile& cf) { cf.WriteInt (info.nSignature); cf.WriteByte ((sbyte) info.nType); cf.WriteByte ((sbyte) info.nId); cf.WriteShort (info.nNextInSeg); cf.WriteShort (info.nPrevInSeg); cf.WriteByte ((sbyte) info.controlType); cf.WriteByte ((sbyte) info.movementType); cf.WriteByte ((sbyte) info.renderType); cf.WriteByte ((sbyte) info.nFlags); cf.WriteShort (info.nSegment); cf.WriteShort (info.nAttachedObj); cf.WriteVector (OBJPOS (this)->vPos); cf.WriteMatrix (OBJPOS (this)->mOrient); cf.WriteFix (info.xSize); cf.WriteFix (info.xShields); cf.WriteVector (info.vLastPos); cf.WriteByte (info.contains.nType); cf.WriteByte (info.contains.nId); cf.WriteByte (info.contains.nCount); cf.WriteByte (info.nCreator); cf.WriteFix (info.xLifeLeft); if (info.movementType == MT_PHYSICS) { cf.WriteVector (mType.physInfo.velocity); cf.WriteVector (mType.physInfo.thrust); cf.WriteFix (mType.physInfo.mass); cf.WriteFix (mType.physInfo.drag); cf.WriteFix (mType.physInfo.brakes); cf.WriteVector (mType.physInfo.rotVel); cf.WriteVector (mType.physInfo.rotThrust); cf.WriteFixAng (mType.physInfo.turnRoll); cf.WriteShort ((short) mType.physInfo.flags); } else if (info.movementType == MT_SPINNING) { cf.WriteVector(mType.spinRate); } switch (info.controlType) { case CT_WEAPON: cf.WriteShort (cType.laserInfo.parent.nType); cf.WriteShort (cType.laserInfo.parent.nObject); cf.WriteInt (cType.laserInfo.parent.nSignature); cf.WriteFix (cType.laserInfo.xCreationTime); if (cType.laserInfo.nLastHitObj) cf.WriteShort (gameData.objs.nHitObjects [Index () * MAX_HIT_OBJECTS + cType.laserInfo.nLastHitObj - 1]); else cf.WriteShort (-1); cf.WriteShort (cType.laserInfo.nHomingTarget); cf.WriteFix (cType.laserInfo.xScale); break; case CT_EXPLOSION: cf.WriteFix (cType.explInfo.nSpawnTime); cf.WriteFix (cType.explInfo.nDeleteTime); cf.WriteShort (cType.explInfo.nDeleteObj); cf.WriteShort (cType.explInfo.attached.nParent); cf.WriteShort (cType.explInfo.attached.nPrev); cf.WriteShort (cType.explInfo.attached.nNext); break; case CT_AI: cf.WriteByte ((sbyte) cType.aiInfo.behavior); cf.Write (cType.aiInfo.flags, 1, MAX_AI_FLAGS); cf.WriteShort (cType.aiInfo.nHideSegment); cf.WriteShort (cType.aiInfo.nHideIndex); cf.WriteShort (cType.aiInfo.nPathLength); cf.WriteByte (cType.aiInfo.nCurPathIndex); cf.WriteByte (cType.aiInfo.bDyingSoundPlaying); cf.WriteShort (cType.aiInfo.nDangerLaser); cf.WriteInt (cType.aiInfo.nDangerLaserSig); cf.WriteFix (cType.aiInfo.xDyingStartTime); break; case CT_LIGHT: cf.WriteFix (cType.lightInfo.intensity); break; case CT_POWERUP: cf.WriteInt (cType.powerupInfo.nCount); cf.WriteFix (cType.powerupInfo.xCreationTime); cf.WriteInt (cType.powerupInfo.nFlags); break; } switch (info.renderType) { case RT_MORPH: case RT_POLYOBJ: { int i; cf.WriteInt (rType.polyObjInfo.nModel); for (i = 0; i < MAX_SUBMODELS; i++) cf.WriteAngVec (rType.polyObjInfo.animAngles [i]); cf.WriteInt (rType.polyObjInfo.nSubObjFlags); cf.WriteInt (rType.polyObjInfo.nTexOverride); cf.WriteInt (rType.polyObjInfo.nAltTextures); break; } case RT_WEAPON_VCLIP: case RT_HOSTAGE: case RT_POWERUP: case RT_FIREBALL: case RT_THRUSTER: cf.WriteInt (rType.vClipInfo.nClipIndex); cf.WriteFix (rType.vClipInfo.xFrameTime); cf.WriteByte (rType.vClipInfo.nCurFrame); break; case RT_LASER: break; } }
// ----------------------------------------------------------------------------- //do whatever this thing does in a frame void DoReactorFrame (CObject *objP) { int nBestGun, i; tReactorStates *rStatP; // If a boss level, then gameData.reactor.bPresent will be 0. if (!gameData.reactor.bPresent) return; i = FindReactor (objP); if (i < 0) return; rStatP = gameData.reactor.states + i; #if DBG if (!gameStates.app.cheats.bRobotsFiring || (gameStates.app.bGameSuspended & SUSP_ROBOTS)) return; #else if (!gameStates.app.cheats.bRobotsFiring) return; #endif if (!(rStatP->bHit || rStatP->bSeenPlayer)) { if (gameStates.app.tick40fps.bTick) { // Do ever so often... CFixVector vecToPlayer; fix xDistToPlayer; int i; CSegment *segP = SEGMENTS + objP->info.nSegment; // This is a hack. Since the control center is not processed by // ai_do_frame, it doesn't know how to deal with cloaked dudes. It // seems to work in single-CPlayerData mode because it is actually using // the value of Believed_player_position that was set by the last // person to go through ai_do_frame. But since a no-robots game // never goes through ai_do_frame, I'm making it so the control // center can spot cloaked dudes. if (IsMultiGame) gameData.ai.target.vBelievedPos = OBJPOS (OBJECTS + LOCALPLAYER.nObject)->vPos; // Hack for special control centers which are isolated and not reachable because the // real control center is inside the boss. for (i = 0; i < MAX_SIDES_PER_SEGMENT; i++) if (IS_CHILD (segP->m_children [i])) break; if (i == MAX_SIDES_PER_SEGMENT) return; vecToPlayer = OBJPOS (gameData.objs.consoleP)->vPos - objP->info.position.vPos; xDistToPlayer = CFixVector::Normalize (vecToPlayer); if (xDistToPlayer < I2X (200)) { rStatP->bSeenPlayer = AICanSeeTarget (objP, &objP->info.position.vPos, 0, &vecToPlayer); rStatP->nNextFireTime = 0; } } return; } // Periodically, make the reactor fall asleep if CPlayerData not visible. if (rStatP->bHit || rStatP->bSeenPlayer) { if ((rStatP->xLastVisCheckTime + I2X (5) < gameData.time.xGame) || (rStatP->xLastVisCheckTime > gameData.time.xGame)) { CFixVector vecToPlayer; fix xDistToPlayer; vecToPlayer = gameData.objs.consoleP->info.position.vPos - objP->info.position.vPos; xDistToPlayer = CFixVector::Normalize (vecToPlayer); rStatP->xLastVisCheckTime = gameData.time.xGame; if (xDistToPlayer < I2X (120)) { rStatP->bSeenPlayer = AICanSeeTarget (objP, &objP->info.position.vPos, 0, &vecToPlayer); if (!rStatP->bSeenPlayer) rStatP->bHit = 0; } } } if ((rStatP->nNextFireTime < 0) && !(gameStates.app.bPlayerIsDead && (gameData.time.xGame > gameStates.app.nPlayerTimeOfDeath + I2X (2)))) { nBestGun = CalcBestReactorGun (gameData.reactor.props [objP->info.nId].nGuns, rStatP->vGunPos, rStatP->vGunDir, (LOCALPLAYER.flags & PLAYER_FLAGS_CLOAKED) ? &gameData.ai.target.vBelievedPos : &gameData.objs.consoleP->info.position.vPos); if (nBestGun != -1) { int nRandProb, count; CFixVector vecToGoal; fix xDistToPlayer; fix xDeltaFireTime; if (LOCALPLAYER.flags & PLAYER_FLAGS_CLOAKED) { vecToGoal = gameData.ai.target.vBelievedPos - rStatP->vGunPos[nBestGun]; xDistToPlayer = CFixVector::Normalize (vecToGoal); } else { vecToGoal = gameData.objs.consoleP->info.position.vPos - rStatP->vGunPos [nBestGun]; xDistToPlayer = CFixVector::Normalize (vecToGoal); } if (xDistToPlayer > I2X (300)) { rStatP->bHit = 0; rStatP->bSeenPlayer = 0; return; } if (gameData.app.nGameMode & GM_MULTI) MultiSendCtrlcenFire (&vecToGoal, nBestGun, objP->Index ()); CreateNewLaserEasy (&vecToGoal, &rStatP->vGunPos [nBestGun], objP->Index (), CONTROLCEN_WEAPON_NUM, 1); // some of time, based on level, fire another thing, not directly at CPlayerData, so it might hit him if he's constantly moving. nRandProb = I2X (1) / (abs (gameData.missions.nCurrentLevel) / 4 + 2); count = 0; while ((d_rand () > nRandProb) && (count < 4)) { CFixVector vRand; vRand = CFixVector::Random(); vecToGoal += vRand * (I2X (1)/6); CFixVector::Normalize (vecToGoal); if (IsMultiGame) MultiSendCtrlcenFire (&vecToGoal, nBestGun, objP->Index ()); CreateNewLaserEasy (&vecToGoal, &rStatP->vGunPos [nBestGun], objP->Index (), CONTROLCEN_WEAPON_NUM, 0); count++; } xDeltaFireTime = I2X (NDL - gameStates.app.nDifficultyLevel) / 4; if (gameStates.app.nDifficultyLevel == 0) xDeltaFireTime += (fix) (I2X (1) / 2 * gameStates.gameplay.slowmo [0].fSpeed); if (IsMultiGame) // slow down rate of fire in multi player xDeltaFireTime *= 2; rStatP->nNextFireTime = xDeltaFireTime; } } else rStatP->nNextFireTime -= gameData.physics.xTime; }
void DoPlayerSmoke (CObject *objP, int nPlayer) { int nObject, nSmoke, d, nParts, nType; float nScale; CParticleEmitter *emitterP; CFixVector fn, mn, vDir, *vDirP; tThrusterInfo ti; static int bForward = 1; if (nPlayer < 0) nPlayer = objP->info.nId; if ((gameData.multiplayer.players [nPlayer].flags & PLAYER_FLAGS_CLOAKED) || (automap.m_bDisplay && IsMultiGame && !AM_SHOW_PLAYERS)) { KillObjectSmoke (nPlayer); return; } nObject = objP->Index (); if (gameOpts->render.particles.bDecreaseLag && (nPlayer == gameData.multiplayer.nLocalPlayer)) { fn = objP->info.position.mOrient.FVec (); mn = objP->info.position.vPos - objP->info.vLastPos; CFixVector::Normalize (fn); CFixVector::Normalize (mn); d = CFixVector::Dot (fn, mn); if (d >= -I2X (1) / 2) bForward = 1; else { if (bForward) { if ((nSmoke = particleManager.GetObjectSystem (nObject)) >= 0) { KillObjectSmoke (nObject); particleManager.Destroy (nSmoke); } bForward = 0; nScale = 0; return; } } } #if 0 if (EGI_FLAG (bThrusterFlames, 1, 1, 0)) { if ((a <= I2X (1) / 4) && (a || !gameStates.input.bControlsSkipFrame)) //no thruster flames if moving backward DropAfterburnerBlobs (objP, 2, I2X (1), -1, gameData.objs.consoleP, 1); //I2X (1) / 4); } #endif if ((gameData.app.nGameMode & GM_NETWORK) && !gameData.multiplayer.players [nPlayer].connected) nParts = 0; else if (objP->info.nFlags & (OF_SHOULD_BE_DEAD | OF_DESTROYED)) nParts = 0; else if ((nPlayer == gameData.multiplayer.nLocalPlayer) && (gameStates.app.bPlayerIsDead || (gameData.multiplayer.players [nPlayer].shields < 0))) nParts = 0; else { nSmoke = X2IR (gameData.multiplayer.players [nPlayer].shields); nParts = 10 - nSmoke / 5; nScale = X2F (objP->info.xSize); if (nSmoke <= 25) nScale /= 1.5; else if (nSmoke <= 50) nScale /= 2; else nScale /= 3; if (nParts <= 0) { nType = 2; //nParts = (gameStates.entropy.nTimeLastMoved < 0) ? 250 : 125; } else { CreateDamageExplosion (nParts, nObject); nType = (nSmoke > 25); nParts *= 25; nParts += 75; } nParts = objP->mType.physInfo.thrust.IsZero () ? SHIP_MAX_PARTS : SHIP_MAX_PARTS / 2; if (SHOW_SMOKE && nParts && gameOpts->render.particles.bPlayers) { if (gameOpts->render.particles.bSyncSizes) { nParts = -MAX_PARTICLES (nParts, gameOpts->render.particles.nDens [0]); nScale = PARTICLE_SIZE (gameOpts->render.particles.nSize [0], nScale); } else { nParts = -MAX_PARTICLES (nParts, gameOpts->render.particles.nDens [1]); nScale = PARTICLE_SIZE (gameOpts->render.particles.nSize [1], nScale); } if (!objP->mType.physInfo.thrust.IsZero ()) vDirP = NULL; else { // if the ship is standing still, let the thruster smoke move away from it nParts /= 2; nScale /= 2; vDir = OBJPOS (objP)->mOrient.FVec () * (I2X (1) / 8); vDir = -vDir; vDirP = &vDir; } if (0 > (nSmoke = particleManager.GetObjectSystem (nObject))) { //PrintLog ("creating CPlayerData smoke\n"); nSmoke = particleManager.Create (&objP->info.position.vPos, vDirP, NULL, objP->info.nSegment, 2, nParts, nScale, gameOpts->render.particles.nSize [1], 2, PLR_PART_LIFE / (nType + 1) * (vDirP ? 2 : 1), PLR_PART_SPEED, SMOKE_PARTICLES, nObject, smokeColors + nType, 1, -1); if (nSmoke < 0) return; particleManager.SetObjectSystem (nObject, nSmoke); } else { if (vDirP) particleManager.SetDir (nSmoke, vDirP); particleManager.SetLife (nSmoke, PLR_PART_LIFE / (nType + 1) * (vDirP ? 2 : 1)); particleManager.SetType (nSmoke, SMOKE_PARTICLES); particleManager.SetScale (nSmoke, -nScale); particleManager.SetDensity (nSmoke, nParts, gameOpts->render.particles.bSyncSizes ? -1 : gameOpts->render.particles.nSize [1]); particleManager.SetSpeed (particleManager.GetObjectSystem (nObject), objP->mType.physInfo.thrust.IsZero () ? PLR_PART_SPEED * 2 : PLR_PART_SPEED); } CalcThrusterPos (objP, &ti, 0); for (int i = 0; i < 2; i++) if ((emitterP = particleManager.GetEmitter (nSmoke, i))) emitterP->SetPos (ti.vPos + i, NULL, objP->info.nSegment); DoGatlingSmoke (objP); return; } } KillObjectSmoke (nObject); KillGatlingSmoke (objP); }