void DThinker::DestroyMostThinkersInList (FThinkerList &list, int stat) { if (stat != STAT_PLAYER) { DestroyThinkersInList (list); } else if (list.Sentinel != NULL) { // If it's a voodoo doll, destroy it. Otherwise, simply remove // it from the list. G_FinishTravel() will find it later from // a players[].mo link and destroy it then, after copying various // information to a new player. for (DThinker *probe = list.Sentinel->NextThinker, *next; probe != list.Sentinel; probe = next) { next = probe->NextThinker; if (!probe->IsKindOf(RUNTIME_CLASS(APlayerPawn)) || // <- should not happen static_cast<AActor *>(probe)->player == NULL || static_cast<AActor *>(probe)->player->mo != probe) { probe->Destroy(); } else { probe->Remove(); // Technically, this doesn't need to be in any list now, since // it's only going to be found later and destroyed before ever // needing to tick again, but by moving it to a separate list, // I can keep my debug assertions that all thinkers are either // euthanizing or in a list. Thinkers[MAX_STATNUM+1].AddTail(probe); } } } }
void DThinker::SerializeAll (FArchive &arc, bool hubLoad, bool noStorePlayers) { DThinker *thinker; if (arc.IsStoring () && noStorePlayers) { thinker = FirstThinker; while (thinker) { // Don't store player mobjs. if (!(thinker->IsKindOf(RUNTIME_CLASS(AActor)) && static_cast<AActor *>(thinker)->type == MT_PLAYER)) { arc << (BYTE)1; arc << thinker; } thinker = thinker->m_Next; } arc << (BYTE)0; } else if (arc.IsStoring ()) { thinker = FirstThinker; while (thinker) { arc << (BYTE)1; arc << thinker; thinker = thinker->m_Next; } arc << (BYTE)0; } else { if (hubLoad || noStorePlayers) DestroyMostThinkers (); else DestroyAllThinkers (); BYTE more; arc >> more; while (more) { DThinker *thinker; arc >> thinker; arc >> more; } // killough 3/26/98: Spawn icon landings: P_SpawnBrainTargets (); } }
// Destroy all thinkers except for player-controlled actors void DThinker::DestroyMostThinkers () { DThinker *thinker = FirstThinker; while (thinker) { DThinker *next = thinker->m_Next; if (!thinker->IsKindOf (RUNTIME_CLASS (AActor)) || static_cast<AActor *>(thinker)->player == NULL || static_cast<AActor *>(thinker)->player->mo != static_cast<AActor *>(thinker)) { thinker->Destroy (); } thinker = next; } DObject::EndFrame (); }
int DThinker::TickThinkers (FThinkerList *list, FThinkerList *dest) { int count = 0; DThinker *node = list->GetHead(); if (node == NULL) { return 0; } while (node != list->Sentinel) { ++count; NextToThink = node->NextThinker; if (node->ObjectFlags & OF_JustSpawned) { // Leave OF_JustSpawn set until after Tick() so the ticker can check it. if (dest != NULL) { // Move thinker from this list to the destination list node->Remove(); dest->AddTail(node); } node->PostBeginPlay(); } else if (dest != NULL) { // Move thinker from this list to the destination list I_Error("There is a thinker in the fresh list that has already ticked.\n"); } if (!(node->ObjectFlags & OF_EuthanizeMe)) { // Only tick thinkers not scheduled for destruction // [BC] Don't tick the consoleplayer's actor in client // mode, because that's done in the main prediction function if (( NETWORK_InClientMode() == false ) || ( node->IsKindOf( RUNTIME_CLASS( AActor )) == false ) || ( static_cast<AActor *>( node ) != players[consoleplayer].mo )) { node->Tick(); } node->ObjectFlags &= ~OF_JustSpawned; GC::CheckGC(); } node = NextToThink; } return count; }
DThinker *FThinkerIterator::Next () { if (m_ParentType == NULL) { return NULL; } do { do { if (m_CurrThinker != NULL) { while (!(m_CurrThinker->ObjectFlags & OF_Sentinel)) { DThinker *thinker = m_CurrThinker; m_CurrThinker = thinker->NextThinker; if (thinker->IsKindOf(m_ParentType)) { return thinker; } } } if ((m_SearchingFresh = !m_SearchingFresh)) { m_CurrThinker = DThinker::FreshThinkers[m_Stat].GetHead(); } } while (m_SearchingFresh); if (m_SearchStats) { m_Stat++; if (m_Stat > MAX_STATNUM) { m_Stat = STAT_FIRST_THINKING; } } m_CurrThinker = DThinker::Thinkers[m_Stat].GetHead(); m_SearchingFresh = false; } while (m_SearchStats && m_Stat != STAT_FIRST_THINKING); return NULL; }