2006-02-24 04:48:15 +00:00
|
|
|
/*
|
|
|
|
** dthinker.cpp
|
|
|
|
** Implements the base class for almost anything in a level that might think
|
|
|
|
**
|
|
|
|
**---------------------------------------------------------------------------
|
2006-06-11 01:37:00 +00:00
|
|
|
** Copyright 1998-2006 Randy Heit
|
2006-02-24 04:48:15 +00:00
|
|
|
** All rights reserved.
|
|
|
|
**
|
|
|
|
** Redistribution and use in source and binary forms, with or without
|
|
|
|
** modification, are permitted provided that the following conditions
|
|
|
|
** are met:
|
|
|
|
**
|
|
|
|
** 1. Redistributions of source code must retain the above copyright
|
|
|
|
** notice, this list of conditions and the following disclaimer.
|
|
|
|
** 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
|
|
** documentation and/or other materials provided with the distribution.
|
|
|
|
** 3. The name of the author may not be used to endorse or promote products
|
|
|
|
** derived from this software without specific prior written permission.
|
|
|
|
**
|
|
|
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
**---------------------------------------------------------------------------
|
|
|
|
**
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "dthinker.h"
|
|
|
|
#include "stats.h"
|
|
|
|
#include "p_local.h"
|
|
|
|
#include "statnums.h"
|
|
|
|
#include "i_system.h"
|
|
|
|
#include "doomerrors.h"
|
|
|
|
|
|
|
|
|
|
|
|
static cycle_t ThinkCycles;
|
|
|
|
extern cycle_t BotSupportCycles;
|
|
|
|
extern cycle_t BotWTG;
|
|
|
|
|
2008-03-13 00:41:16 +00:00
|
|
|
IMPLEMENT_POINTY_CLASS (DThinker)
|
|
|
|
DECLARE_POINTER(NextThinker)
|
|
|
|
DECLARE_POINTER(PrevThinker)
|
|
|
|
END_POINTERS
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-03-13 00:41:16 +00:00
|
|
|
static DThinker *NextToThink;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-03-13 00:41:16 +00:00
|
|
|
FThinkerList DThinker::Thinkers[MAX_STATNUM+1];
|
|
|
|
FThinkerList DThinker::FreshThinkers[MAX_STATNUM+1];
|
2006-02-24 04:48:15 +00:00
|
|
|
bool DThinker::bSerialOverride = false;
|
|
|
|
|
2008-03-13 00:41:16 +00:00
|
|
|
void FThinkerList::AddTail(DThinker *thinker)
|
2008-02-22 01:45:32 +00:00
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
if (Sentinel == NULL)
|
|
|
|
{
|
|
|
|
Sentinel = new DThinker(DThinker::NO_LINK);
|
|
|
|
Sentinel->ObjectFlags |= OF_Sentinel;
|
|
|
|
Sentinel->NextThinker = Sentinel;
|
|
|
|
Sentinel->PrevThinker = Sentinel;
|
|
|
|
GC::WriteBarrier(Sentinel);
|
|
|
|
}
|
|
|
|
DThinker *tail = Sentinel->PrevThinker;
|
|
|
|
assert(tail->NextThinker == Sentinel);
|
|
|
|
thinker->PrevThinker = tail;
|
|
|
|
thinker->NextThinker = Sentinel;
|
|
|
|
tail->NextThinker = thinker;
|
|
|
|
Sentinel->PrevThinker = thinker;
|
|
|
|
GC::WriteBarrier(thinker, tail);
|
|
|
|
GC::WriteBarrier(thinker, Sentinel);
|
|
|
|
GC::WriteBarrier(tail, thinker);
|
|
|
|
GC::WriteBarrier(Sentinel, thinker);
|
|
|
|
}
|
|
|
|
|
|
|
|
DThinker *FThinkerList::GetHead() const
|
|
|
|
{
|
|
|
|
if (Sentinel == NULL || Sentinel->NextThinker == Sentinel)
|
2008-02-22 01:45:32 +00:00
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return Sentinel->NextThinker;
|
|
|
|
}
|
|
|
|
|
|
|
|
DThinker *FThinkerList::GetTail() const
|
|
|
|
{
|
|
|
|
if (Sentinel == NULL || Sentinel->PrevThinker == Sentinel)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return Sentinel->PrevThinker;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FThinkerList::IsEmpty() const
|
|
|
|
{
|
|
|
|
return Sentinel == NULL || Sentinel->NextThinker == NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DThinker::SaveList(FArchive &arc, DThinker *node)
|
|
|
|
{
|
|
|
|
if (node != NULL)
|
|
|
|
{
|
|
|
|
while (!(node->ObjectFlags & OF_Sentinel))
|
2008-02-22 01:45:32 +00:00
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
arc << node;
|
|
|
|
node = node->NextThinker;
|
|
|
|
}
|
2008-02-22 01:45:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DThinker::SerializeAll(FArchive &arc, bool hubLoad)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
DThinker *thinker;
|
|
|
|
BYTE stat;
|
|
|
|
int statcount;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
// Save lists of thinkers, but not by storing the first one and letting
|
|
|
|
// the archiver catch the rest. (Which leads to buttloads of recursion
|
|
|
|
// and makes the file larger.) Instead, we explicitly save each thinker
|
|
|
|
// in sequence. When restoring an archive, we also have to maintain
|
|
|
|
// the thinker lists here instead of relying on the archiver to do it
|
|
|
|
// for us.
|
|
|
|
|
2008-02-22 01:45:32 +00:00
|
|
|
if (arc.IsStoring())
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
for (statcount = i = 0; i <= MAX_STATNUM; i++)
|
|
|
|
{
|
2008-02-22 01:45:32 +00:00
|
|
|
statcount += (!Thinkers[i].IsEmpty() || !FreshThinkers[i].IsEmpty());
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
arc << statcount;
|
|
|
|
for (i = 0; i <= MAX_STATNUM; i++)
|
|
|
|
{
|
2008-02-22 01:45:32 +00:00
|
|
|
if (!Thinkers[i].IsEmpty() || !FreshThinkers[i].IsEmpty())
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
stat = i;
|
|
|
|
arc << stat;
|
2008-03-13 00:41:16 +00:00
|
|
|
SaveList(arc, Thinkers[i].GetHead());
|
|
|
|
SaveList(arc, FreshThinkers[i].GetHead());
|
2006-02-24 04:48:15 +00:00
|
|
|
thinker = NULL;
|
|
|
|
arc << thinker; // Save a final NULL for this list
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (hubLoad)
|
2008-02-22 01:45:32 +00:00
|
|
|
DestroyMostThinkers();
|
2006-02-24 04:48:15 +00:00
|
|
|
else
|
2008-02-22 01:45:32 +00:00
|
|
|
DestroyAllThinkers();
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
// Prevent the constructor from inserting thinkers into a list.
|
|
|
|
bSerialOverride = true;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
arc << statcount;
|
|
|
|
while (statcount > 0)
|
|
|
|
{
|
|
|
|
arc << stat << thinker;
|
|
|
|
while (thinker != NULL)
|
|
|
|
{
|
2008-02-22 01:45:32 +00:00
|
|
|
// Thinkers with the OF_JustSpawned flag set go in the FreshThinkers
|
|
|
|
// list. Anything else goes in the regular Thinkers list.
|
|
|
|
if (thinker->ObjectFlags & OF_JustSpawned)
|
|
|
|
{
|
|
|
|
FreshThinkers[stat].AddTail(thinker);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Thinkers[stat].AddTail(thinker);
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
arc << thinker;
|
|
|
|
}
|
|
|
|
statcount--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (class CDoomError &)
|
|
|
|
{
|
|
|
|
bSerialOverride = false;
|
2008-02-22 01:45:32 +00:00
|
|
|
DestroyAllThinkers();
|
2006-02-24 04:48:15 +00:00
|
|
|
throw;
|
|
|
|
}
|
|
|
|
bSerialOverride = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DThinker::DThinker (int statnum) throw()
|
|
|
|
{
|
|
|
|
if (bSerialOverride)
|
|
|
|
{ // The serializer will insert us into the right list
|
2008-03-13 00:41:16 +00:00
|
|
|
NextThinker = NULL;
|
|
|
|
PrevThinker = NULL;
|
2006-02-24 04:48:15 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ObjectFlags |= OF_JustSpawned;
|
|
|
|
if ((unsigned)statnum > MAX_STATNUM)
|
|
|
|
{
|
|
|
|
statnum = MAX_STATNUM;
|
|
|
|
}
|
|
|
|
FreshThinkers[statnum].AddTail (this);
|
|
|
|
}
|
|
|
|
|
2008-03-13 00:41:16 +00:00
|
|
|
DThinker::DThinker(no_link_type foo) throw()
|
|
|
|
{
|
|
|
|
foo; // Avoid unused argument warnings.
|
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
DThinker::~DThinker ()
|
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
assert(NextThinker == NULL && PrevThinker == NULL);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DThinker::Destroy ()
|
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
if (NextThinker != NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
Remove();
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-03-13 00:41:16 +00:00
|
|
|
Super::Destroy();
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
2008-03-12 02:56:11 +00:00
|
|
|
void DThinker::Remove()
|
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
if (this == NextToThink)
|
2008-03-12 02:56:11 +00:00
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
NextToThink = NextThinker;
|
|
|
|
}
|
|
|
|
DThinker *prev = PrevThinker;
|
|
|
|
DThinker *next = NextThinker;
|
|
|
|
assert(prev != NULL && next != NULL);
|
|
|
|
prev->NextThinker = next;
|
|
|
|
next->PrevThinker = prev;
|
|
|
|
GC::WriteBarrier(prev, next);
|
|
|
|
GC::WriteBarrier(next, prev);
|
|
|
|
NextThinker = NULL;
|
|
|
|
PrevThinker = NULL;
|
2008-03-12 02:56:11 +00:00
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
void DThinker::PostBeginPlay ()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2006-04-13 02:01:40 +00:00
|
|
|
DThinker *DThinker::FirstThinker (int statnum)
|
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
DThinker *node;
|
2006-04-13 02:01:40 +00:00
|
|
|
|
|
|
|
if ((unsigned)statnum > MAX_STATNUM)
|
|
|
|
{
|
|
|
|
statnum = MAX_STATNUM;
|
|
|
|
}
|
2008-03-13 00:41:16 +00:00
|
|
|
node = Thinkers[statnum].GetHead();
|
|
|
|
if (node == NULL)
|
2006-04-13 02:01:40 +00:00
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
node = FreshThinkers[statnum].GetHead();
|
|
|
|
if (node == NULL)
|
2006-04-13 02:01:40 +00:00
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2008-03-13 00:41:16 +00:00
|
|
|
return node;
|
2006-04-13 02:01:40 +00:00
|
|
|
}
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
void DThinker::ChangeStatNum (int statnum)
|
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
FThinkerList *list;
|
2008-03-12 02:56:11 +00:00
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
if ((unsigned)statnum > MAX_STATNUM)
|
|
|
|
{
|
|
|
|
statnum = MAX_STATNUM;
|
|
|
|
}
|
2008-03-13 00:41:16 +00:00
|
|
|
Remove();
|
2006-02-24 04:48:15 +00:00
|
|
|
if ((ObjectFlags & OF_JustSpawned) && statnum >= STAT_FIRST_THINKING)
|
|
|
|
{
|
2008-03-12 02:56:11 +00:00
|
|
|
list = &FreshThinkers[statnum];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
list = &Thinkers[statnum];
|
|
|
|
}
|
|
|
|
list->AddTail(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mark the first thinker of each list
|
|
|
|
void DThinker::MarkRoots()
|
|
|
|
{
|
|
|
|
for (int i = 0; i <= MAX_STATNUM; ++i)
|
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
GC::Mark(Thinkers[i].Sentinel);
|
|
|
|
GC::Mark(FreshThinkers[i].Sentinel);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Destroy every thinker
|
|
|
|
void DThinker::DestroyAllThinkers ()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i <= MAX_STATNUM; i++)
|
|
|
|
{
|
|
|
|
if (i != STAT_TRAVELLING)
|
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
DestroyThinkersInList (Thinkers[i]);
|
|
|
|
DestroyThinkersInList (FreshThinkers[i]);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
2008-03-13 00:41:16 +00:00
|
|
|
GC::FullGC();
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Destroy all thinkers except for player-controlled actors
|
|
|
|
// Players are simply removed from the list of thinkers and
|
|
|
|
// will be added back after serialization is complete.
|
|
|
|
void DThinker::DestroyMostThinkers ()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i <= MAX_STATNUM; i++)
|
|
|
|
{
|
|
|
|
if (i != STAT_TRAVELLING)
|
|
|
|
{
|
|
|
|
DestroyMostThinkersInList (Thinkers[i], i);
|
|
|
|
DestroyMostThinkersInList (FreshThinkers[i], i);
|
|
|
|
}
|
|
|
|
}
|
2008-03-13 00:41:16 +00:00
|
|
|
GC::FullGC();
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
2008-03-13 00:41:16 +00:00
|
|
|
void DThinker::DestroyThinkersInList (FThinkerList &list)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
if (list.Sentinel != NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
DThinker *node = list.Sentinel->NextThinker;
|
|
|
|
while (node != list.Sentinel)
|
|
|
|
{
|
|
|
|
DThinker *next = node->NextThinker;
|
|
|
|
node->Destroy();
|
|
|
|
node = next;
|
|
|
|
}
|
|
|
|
list.Sentinel->Destroy();
|
|
|
|
list.Sentinel = NULL;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-13 00:41:16 +00:00
|
|
|
void DThinker::DestroyMostThinkersInList (FThinkerList &list, int stat)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
if (stat != STAT_PLAYER)
|
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
DestroyThinkersInList (list);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-03-13 00:41:16 +00:00
|
|
|
else if (list.Sentinel != NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
DThinker *node = list.Sentinel->NextThinker;
|
|
|
|
while (node != list.Sentinel)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
DThinker *next = node->NextThinker;
|
|
|
|
node->Remove();
|
2006-02-24 04:48:15 +00:00
|
|
|
node = next;
|
|
|
|
}
|
2008-03-13 00:41:16 +00:00
|
|
|
list.Sentinel->Destroy();
|
|
|
|
list.Sentinel = NULL;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DThinker::RunThinkers ()
|
|
|
|
{
|
|
|
|
int i, count;
|
|
|
|
|
|
|
|
ThinkCycles = BotSupportCycles = BotWTG = 0;
|
|
|
|
|
|
|
|
clock (ThinkCycles);
|
|
|
|
|
|
|
|
// Tick every thinker left from last time
|
|
|
|
for (i = STAT_FIRST_THINKING; i <= MAX_STATNUM; ++i)
|
|
|
|
{
|
|
|
|
TickThinkers (&Thinkers[i], NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Keep ticking the fresh thinkers until there are no new ones.
|
|
|
|
do
|
|
|
|
{
|
|
|
|
count = 0;
|
|
|
|
for (i = STAT_FIRST_THINKING; i <= MAX_STATNUM; ++i)
|
|
|
|
{
|
|
|
|
count += TickThinkers (&FreshThinkers[i], &Thinkers[i]);
|
|
|
|
}
|
|
|
|
} while (count != 0);
|
|
|
|
|
|
|
|
unclock (ThinkCycles);
|
|
|
|
}
|
|
|
|
|
2008-03-13 00:41:16 +00:00
|
|
|
int DThinker::TickThinkers (FThinkerList *list, FThinkerList *dest)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
int count = 0;
|
2008-03-13 00:41:16 +00:00
|
|
|
DThinker *node = list->GetHead();
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-03-13 00:41:16 +00:00
|
|
|
if (node == NULL)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (node != list->Sentinel)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
++count;
|
2008-03-13 00:41:16 +00:00
|
|
|
NextToThink = node->NextThinker;
|
|
|
|
if (node->ObjectFlags & OF_JustSpawned)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
node->ObjectFlags &= ~OF_JustSpawned;
|
2006-02-24 04:48:15 +00:00
|
|
|
if (dest != NULL)
|
|
|
|
{ // Move thinker from this list to the destination list
|
2008-03-13 00:41:16 +00:00
|
|
|
node->Remove();
|
|
|
|
dest->AddTail(node);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-03-13 00:41:16 +00:00
|
|
|
node->PostBeginPlay();
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else if (dest != NULL)
|
|
|
|
{ // Move thinker from this list to the destination list
|
2008-03-13 00:41:16 +00:00
|
|
|
I_Error("There is a thinker in the fresh list that has already ticked.\n");
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
2008-03-13 00:41:16 +00:00
|
|
|
if (!(node->ObjectFlags & OF_EuthanizeMe))
|
2006-02-24 04:48:15 +00:00
|
|
|
{ // Only tick thinkers not scheduled for destruction
|
2008-03-13 00:41:16 +00:00
|
|
|
node->Tick ();
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
node = NextToThink;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DThinker::Tick ()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-03-13 10:06:53 +00:00
|
|
|
void DThinker::PointerSubstitution(DObject *old, DObject *notOld)
|
|
|
|
{
|
|
|
|
// Pointer substitution must not, under any circumstances, change
|
|
|
|
// the linked thinker list or the game will freeze badly.
|
|
|
|
DThinker *next = NextThinker;
|
|
|
|
DThinker *prev = PrevThinker;
|
|
|
|
Super::PointerSubstitution(old, notOld);
|
|
|
|
NextThinker = next;
|
|
|
|
PrevThinker = prev;
|
|
|
|
}
|
|
|
|
|
2006-05-10 02:40:43 +00:00
|
|
|
FThinkerIterator::FThinkerIterator (const PClass *type, int statnum)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
if ((unsigned)statnum > MAX_STATNUM)
|
|
|
|
{
|
|
|
|
m_Stat = STAT_FIRST_THINKING;
|
|
|
|
m_SearchStats = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_Stat = statnum;
|
|
|
|
m_SearchStats = false;
|
|
|
|
}
|
|
|
|
m_ParentType = type;
|
2008-03-13 00:41:16 +00:00
|
|
|
m_CurrThinker = DThinker::Thinkers[m_Stat].GetHead();
|
2006-02-24 04:48:15 +00:00
|
|
|
m_SearchingFresh = false;
|
|
|
|
}
|
|
|
|
|
2006-05-10 02:40:43 +00:00
|
|
|
FThinkerIterator::FThinkerIterator (const PClass *type, int statnum, DThinker *prev)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
if ((unsigned)statnum > MAX_STATNUM)
|
|
|
|
{
|
|
|
|
m_Stat = STAT_FIRST_THINKING;
|
|
|
|
m_SearchStats = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_Stat = statnum;
|
|
|
|
m_SearchStats = false;
|
|
|
|
}
|
|
|
|
m_ParentType = type;
|
2008-03-13 00:41:16 +00:00
|
|
|
if (prev == NULL || (prev->NextThinker->ObjectFlags & OF_Sentinel))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
Reinit();
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
m_CurrThinker = prev->NextThinker;
|
2006-02-24 04:48:15 +00:00
|
|
|
m_SearchingFresh = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FThinkerIterator::Reinit ()
|
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
m_CurrThinker = DThinker::Thinkers[m_Stat].GetHead();
|
2006-02-24 04:48:15 +00:00
|
|
|
m_SearchingFresh = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
DThinker *FThinkerIterator::Next ()
|
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
if (m_ParentType == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
if (m_CurrThinker != NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
while (!(m_CurrThinker->ObjectFlags & OF_Sentinel))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
DThinker *thinker = m_CurrThinker;
|
|
|
|
m_CurrThinker = thinker->NextThinker;
|
|
|
|
if (thinker->IsKindOf(m_ParentType))
|
|
|
|
{
|
|
|
|
return thinker;
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((m_SearchingFresh = !m_SearchingFresh))
|
|
|
|
{
|
2008-03-13 00:41:16 +00:00
|
|
|
m_CurrThinker = DThinker::FreshThinkers[m_Stat].GetHead();
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
} while (m_SearchingFresh);
|
|
|
|
if (m_SearchStats)
|
|
|
|
{
|
|
|
|
m_Stat++;
|
|
|
|
if (m_Stat > MAX_STATNUM)
|
|
|
|
{
|
|
|
|
m_Stat = STAT_FIRST_THINKING;
|
|
|
|
}
|
|
|
|
}
|
2008-03-13 00:41:16 +00:00
|
|
|
m_CurrThinker = DThinker::Thinkers[m_Stat].GetHead();
|
2006-02-24 04:48:15 +00:00
|
|
|
m_SearchingFresh = false;
|
|
|
|
} while (m_SearchStats && m_Stat != STAT_FIRST_THINKING);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-09-14 00:02:31 +00:00
|
|
|
ADD_STAT (think)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2006-09-14 00:02:31 +00:00
|
|
|
FString out;
|
|
|
|
out.Format ("Think time = %04.1f ms",
|
2006-02-24 04:48:15 +00:00
|
|
|
SecondsPerCycle * (double)ThinkCycles * 1000);
|
2006-09-14 00:02:31 +00:00
|
|
|
return out;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|