//////////////////////////////////////////////////////////////////////////////////// // Initialize // // This function scans through the list of tracks and hooks itself up with the // track (and possibly lane) //////////////////////////////////////////////////////////////////////////////////// void Initialize() { mTrack = 0; mLane = 0; mCols = 0; mRows = 0; hstring target = mEnt->target; for (int track=0; track<mRailTracks.size(); track++) { if (mRailTracks[track].mName==target) { mTrack = &(mRailTracks[track]); break; } } if (mTrack==0) { for (int lane=0; lane<mRailLanes.size(); lane++) { if (mRailLanes[lane].mName==target) { mLane = &(mRailLanes[lane]); mTrack = mLane->mTrack; break; } } } assert(mTrack!=0); if (mTrack) { mTrack->mMovers.push_back(this); mCols = (int)((mEnt->maxs[mTrack->mWAxis] - mEnt->mins[mTrack->mWAxis]) / mTrack->mGridCellSize) + 1; mRows = (int)((mEnt->maxs[mTrack->mHAxis] - mEnt->mins[mTrack->mHAxis]) / mTrack->mGridCellSize) + 1; // Make Sure The Mover Fits In The Track And Lane //------------------------------------------------ if (mRows>mTrack->mRows) { // assert(0); mRows = mTrack->mRows; } if (mCols>mTrack->mCols) { // assert(0); mCols = mTrack->mCols; } if (mLane && mCols>(mLane->mMaxCol - mLane->mMinCol + 1)) { // assert(0); mCols = (mLane->mMaxCol - mLane->mMinCol + 1); } } }
void Rail_Initialize() { for (int lane=0; lane<mRailLanes.size(); lane++) { mRailLanes[lane].Initialize(); } for (int mover=0; mover<mRailMovers.size(); mover++) { mRailMovers[mover].Initialize(); } // Precache All The Woosh Sounds //------------------------------- if (!mRailMovers.empty()) { mWooshMed.push_back(G_SoundIndex("sound/effects/woosh1")); mWooshSml.push_back(G_SoundIndex("sound/effects/woosh2")); mWooshMed.push_back(G_SoundIndex("sound/effects/woosh3")); mWooshSml.push_back(G_SoundIndex("sound/effects/woosh4")); mWooshLar.push_back(G_SoundIndex("sound/effects/woosh5")); mWooshSml.push_back(G_SoundIndex("sound/effects/woosh6")); mWooshSup.push_back(G_SoundIndex("sound/effects/woosh7")); mWooshSup.push_back(G_SoundIndex("sound/effects/woosh8")); mWooshSup.push_back(G_SoundIndex("sound/effects/woosh9")); mWooshLar.push_back(G_SoundIndex("sound/effects/woosh10")); mWooshLar.push_back(G_SoundIndex("sound/effects/woosh11")); mWooshLar.push_back(G_SoundIndex("sound/effects/woosh12")); mWooshSml.push_back(G_SoundIndex("sound/effects/woosh13")); mWooshMed.push_back(G_SoundIndex("sound/effects/woosh14")); mWooshMed.push_back(G_SoundIndex("sound/effects/woosh15")); mWooshMed.push_back(G_SoundIndex("sound/effects/woosh16")); mWooshSml.push_back(G_SoundIndex("sound/effects/woosh17")); mWooshMed.push_back(G_SoundIndex("sound/effects/woosh18")); mWooshMed.push_back(G_SoundIndex("sound/effects/woosh19")); mWooshMed.push_back(G_SoundIndex("sound/effects/woosh20")); mWooshMed.push_back(G_SoundIndex("sound/effects/woosh21")); mWooshLar.push_back(G_SoundIndex("sound/effects/woosh22")); mWooshLar.push_back(G_SoundIndex("sound/effects/woosh23")); mWooshSup.push_back(G_SoundIndex("sound/effects/woosh24")); mWooshSup.push_back(G_SoundIndex("sound/effects/woosh25")); mWooshMed.push_back(G_SoundIndex("sound/effects/woosh26")); mWooshMed.push_back(G_SoundIndex("sound/effects/woosh27")); mWooshMed.push_back(G_SoundIndex("sound/effects/woosh28")); mWooshLar.push_back(G_SoundIndex("sound/effects/woosh29")); mWooshTun.push_back(G_SoundIndex("sound/effects/whoosh_tunnel")); } }
//////////////////////////////////////////////////////////////////////////////////////// // Vehicle_Find // // Will look through all registered vehicles and choose the closest one that the given // entity can get to. // //////////////////////////////////////////////////////////////////////////////////////// gentity_t* Vehicle_Find(gentity_t *ent) { gentity_t* closest = 0; float closestDist = 0; float curDist = 0; for (int i=0; i<mRegistered.size(); i++) { if (!mRegistered[i]->owner) { curDist = Distance(mRegistered[i]->currentOrigin, ent->currentOrigin); if (curDist<1000 && (!closest || curDist<closestDist)) { if (NAV::InSameRegion(ent, mRegistered[i])) { closest = mRegistered[i]; closestDist = curDist; } } } } return closest; }
//////////////////////////////////////////////////////////////////////////////////// // Initialize // // This function scans through the list of tracks and hooks itself up with the // track //////////////////////////////////////////////////////////////////////////////////// void Initialize() { mTrack = 0; mMinCol = 0; mMaxCol = 0; // int dummy; for (int i=0; i<mRailTracks.size(); i++) { if (mRailTracks[i].mName==mNameTrack) { mTrack = &(mRailTracks[i]); mTrack->SnapVectorToGrid(mMins); mTrack->SnapVectorToGrid(mMaxs); mMinCol = (int)((mMins[mTrack->mWAxis] - mTrack->mMins[mTrack->mWAxis])/mTrack->mGridCellSize); mMaxCol = (int)((mMaxs[mTrack->mWAxis] - mTrack->mMins[mTrack->mWAxis] - (mTrack->mGridCellSize/2.0f))/mTrack->mGridCellSize); //if (mTrack->mNegative) //{ // mMinCol = (mTrack->mCols - mMinCol - 1); // mMaxCol = (mTrack->mCols - mMaxCol - 1); //} // mTrack->mCells.get_cell_coords(mMins[mTrack->mWAxis], 0, mMinCol, dummy); // mTrack->mCells.get_cell_coords((mMaxs[mTrack->mWAxis]-10.0f), 0, mMaxCol, dummy); break; } } assert(mTrack!=0); }
void Rail_UnLockCenterOfTrack(const char* trackName) { hstring name = trackName; for (int track=0; track<mRailTracks.size(); track++) { if (mRailTracks[track].mName==name) { mRailTracks[track].mCenterLocked = false; return; } } assert(0); }
void CRailTrack::Update() { mNextUpdateTime = level.time + mNextUpdateDelay; // Now, Attempt To Add A Number Of Movers To The Track //----------------------------------------------------- int attempt; int startCol; int stopCol; int atCol; int testColIndex; for (attempt=0; attempt<mNumMoversPerRow; attempt++) { // Randomly Select A Mover And Test To See If It Is Active //--------------------------------------------------------- CRailMover* mover = mMovers[Q_irand(0, mMovers.size()-1)]; if (mover->Active()) { continue; } // Don't Spawn Until Start Time Has Expired //------------------------------------------ if (level.time < ((mover->mLane)?(mover->mLane->mStartTime):(mStartTime))) { continue; } // If Center Locked, Stop Spawning Center Track Movers //----------------------------------------------------- if (mover->mCenter && mCenterLocked) { continue; } // Restrict It To A Lane //----------------------- if (mover->mLane) { startCol = mover->mLane->mMinCol; stopCol = mover->mLane->mMaxCol+1; } // Or Let It Go Anywhere On The Track //------------------------------------ else { startCol = 0; stopCol = mCols; } stopCol -= (mover->mCols-1); // If The Mover Is Too Big To Fit In The Lane, Go On To Next Attempt //------------------------------------------------------------------- if (stopCol<=startCol) { assert(0); // Should Not Happen continue; } // Force It To Center //-------------------- if (mover->mCenter && stopCol!=(startCol+1)) { startCol = ((mCols/2) - (mover->mCols/2)); stopCol = startCol+1; } // Construct A List Of Columns To Test For Insertion //--------------------------------------------------- mTestCols.clear(); for (int i=startCol; i<stopCol; i++) { mTestCols.push_back(i); } // Now Try All The Cols To See If The Building Can Fit //----------------------------------------------------- while (!mTestCols.empty()) { // Randomly Pick A Column, Then Remove It From The Vector //-------------------------------------------------------- testColIndex = Q_irand(0, mTestCols.size()-1); atCol = mTestCols[testColIndex]; mTestCols.erase_swap(testColIndex); if (TestMoverInCells(mover, atCol)) { // Ok, We've Found A Safe Column To Insert This Mover //---------------------------------------------------- InsertMoverInCells(mover, atCol); // Now Transport The Actual Mover Entity Into Position, Link It & Send It Off //---------------------------------------------------------------------------- CVec3 StartPos(mGridBottomLeftCorner); StartPos[mWAxis] += ((atCol * mGridCellSize) + ((mover->mCols/2.0f) * mGridCellSize)); StartPos[mHAxis] += (((mover->mRows/2.0f) * mGridCellSize) * ((mNegative)?(1):(-1))); StartPos[2] = 0; // If Centered, Actually Put It At EXACTLY The Right Position On The Width Axis //------------------------------------------------------------------------------ if (mover->mCenter) { StartPos[mWAxis] = mGridCenter[mWAxis]; float deltaOffset = mGridCenter[mWAxis] - mover->mOriginOffset[mWAxis]; if (deltaOffset<(mGridCellSize*0.5f) ) { StartPos[mWAxis] -= deltaOffset; } } StartPos -= mover->mOriginOffset; G_SetOrigin(mover->mEnt, StartPos.v); // Start It Moving //----------------- VectorCopy(StartPos.v, mover->mEnt->s.pos.trBase); VectorCopy(mVelocity.v, mover->mEnt->s.pos.trDelta); mover->mEnt->s.pos.trTime = level.time; mover->mEnt->s.pos.trDuration = mTravelTimeMilliseconds + (mNextUpdateDelay*mover->mRows); mover->mEnt->s.pos.trType = TR_LINEAR_STOP; mover->mEnt->s.eFlags &= ~EF_NODRAW; mover->mSoundPlayed = false; // Successfully Inserted This Mover. Now Move On To The Next Mover //------------------------------------------------------------------ break; } } } // Incriment The Current Row //--------------------------- mRow++; if (mRow>=mRows) { mRow = 0; } // Erase The Erase Row //--------------------- int EraseRow = mRow - MAX_ROW_HISTORY; if (EraseRow<0) { EraseRow += mRows; } for (int col=0; col<mCols; col++) { mCells.get(col, EraseRow) = 0; } }
void Rail_Update() { if (mRailSystemActive)// && false) { for (int track=0; track<mRailTracks.size(); track++) { if (level.time>mRailTracks[track].mNextUpdateTime && !mRailTracks[track].mMovers.empty()) { mRailTracks[track].Update(); } } // Is The Player Outside? //------------------------ if (player && gi.WE_IsOutside(player->currentOrigin)) { int wooshSound; vec3_t wooshSoundPos; vec3_t moverOrigin; vec3_t playerToMover; float playerToMoverDistance; float playerToMoverDistanceFraction; // Iterate Over All The Movers //----------------------------- for (int moverIndex=0; moverIndex<mRailMovers.size(); moverIndex++) { CRailMover& mover = mRailMovers[moverIndex]; // Is It Active, And Has The Sound Already Played On It? //-------------------------------------------------------- if (mover.Active() && !mover.mSoundPlayed) { VectorAdd(mover.mEnt->currentOrigin, mover.mOriginOffset.v, moverOrigin); VectorSubtract(moverOrigin, player->currentOrigin, playerToMover); playerToMover[2] = 0.0f; playerToMoverDistance = VectorNormalize(playerToMover); // Is It Close Enough? //--------------------- if ((( mover.mLane || !mover.mCenter) && // Not Center Track (playerToMoverDistance<WOOSH_ALL_RANGE) && // And Close Enough (DotProduct(playerToMover, mover.mTrack->mDirection.v)>-0.45f)) // And On The Side || //OR ((!mover.mLane && mover.mCenter) && // Is Center Track (playerToMoverDistance<WOOSH_SUPPORT_RANGE || // And Close Enough for Support (playerToMoverDistance<WOOSH_TUNNEL_RANGE && mover.mRows>10)) // Or Close Enough For Tunnel )) { mover.mSoundPlayed = true; wooshSound = 0; // The Centered Entities Play Right On The Player's Head For Full Volume //----------------------------------------------------------------------- if (mover.mCenter && !mover.mLane) { VectorCopy(player->currentOrigin, wooshSoundPos); wooshSoundPos[2] += 50; // If It Is Very Long, Play The Tunnel Sound //------------------------------------------- if (mover.mRows>10) { wooshSound = mWooshTun[Q_irand(0, mWooshTun.size()-1)]; } // Otherwise It Is A Support //--------------------------- else { wooshSound = mWooshSup[Q_irand(0, mWooshSup.size()-1)]; } } // All Other Entities Play At A Fraction Of Their Normal Range //------------------------------------------------------------- else { // Scale The Play Pos By The Square Of The Distance //-------------------------------------------------- playerToMoverDistanceFraction = playerToMoverDistance/WOOSH_ALL_RANGE; playerToMoverDistanceFraction *= playerToMoverDistanceFraction; playerToMoverDistanceFraction *= 0.6f; playerToMoverDistance *= playerToMoverDistanceFraction; VectorMA(player->currentOrigin, playerToMoverDistance, playerToMover, wooshSoundPos); // Large Building //---------------- if (mover.mRows>4) { wooshSound = mWooshLar[Q_irand(0, mWooshLar.size()-1)]; } // Medium Building //----------------- else if (mover.mRows>2) { wooshSound = mWooshMed[Q_irand(0, mWooshMed.size()-1)]; } // Small Building //---------------- else { wooshSound = mWooshSml[Q_irand(0, mWooshSml.size()-1)]; } } // If A Woosh Sound Was Selected, Play It Now //-------------------------------------------- if (wooshSound) { G_SoundAtSpot(wooshSoundPos, wooshSound, qfalse); if (WOOSH_DEBUG) { CG_DrawEdge(player->currentOrigin, wooshSoundPos, EDGE_WHITE_TWOSECOND); } } } } } } } }
//////////////////////////////////////////////////////////////////////////////////////// // Update The Packs, Delete Dead Leaders, Join / Split Packs, Find MY Leader //////////////////////////////////////////////////////////////////////////////////////// gentity_t* NPC_AnimalUpdateLeader(void) { // Find The Closest Pack Leader, Not Counting Myself //--------------------------------------------------- gentity_t* closestLeader = 0; float closestDist = 0; int myLeaderNum = 0; for (int i=0; i<mPacks.size(); i++) { // Dump Dead Leaders //------------------- if (mPacks[i]==0 || mPacks[i]->health<=0) { if (mPacks[i]==NPC->client->leader) { NPC->client->leader = 0; } mPacks.erase_swap(i); if (i>=mPacks.size()) { closestLeader = 0; break; } } // Don't Count Self //------------------ if (mPacks[i]==NPC) { myLeaderNum = i; continue; } float Dist = Distance(mPacks[i]->currentOrigin, NPC->currentOrigin); if (!closestLeader || Dist<closestDist) { closestDist = Dist; closestLeader = mPacks[i]; } } // In Joining Distance? //---------------------- if (closestLeader && closestDist<JOIN_PACK_DISTANCE) { // Am I Already A Leader? //------------------------ if (NPC->client->leader==NPC) { mPacks.erase_swap(myLeaderNum); // Erase Myself From The Leader List } // Join The Pack! //---------------- NPC->client->leader = closestLeader; } // Do I Have A Leader? //--------------------- if (NPC->client->leader) { // AM I A Leader? //---------------- if (NPC->client->leader!=NPC) { // If Our Leader Is Dead, Clear Him Out if ( NPC->client->leader->health<=0 || NPC->client->leader->inuse == 0) { NPC->client->leader = 0; } // If My Leader Isn't His Own Leader, Then, Use His Leader //--------------------------------------------------------- else if (NPC->client->leader->client->leader!=NPC->client->leader) { // Eh. Can this get more confusing? NPC->client->leader = NPC->client->leader->client->leader; } // If Our Leader Is Too Far Away, Clear Him Out //------------------------------------------------------ else if ( Distance(NPC->client->leader->currentOrigin, NPC->currentOrigin)>LEAVE_PACK_DISTANCE) { NPC->client->leader = 0; } } } // If We Couldn't Find A Leader, Then Become One //----------------------------------------------- else if (!mPacks.full()) { NPC->client->leader = NPC; mPacks.push_back(NPC); } return NPC->client->leader; }