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; } }
//////////////////////////////////////////////////////////////////////////////////////// // 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; }