Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // p_tick.h -------------------------------------------------------------------
- // Enumeration
- // For thinkers needing savegame enumeration.
- void setOrdinal(unsigned int i) { ordinal = shouldSerialize() ? i : 0; }
- unsigned int getOrdinal() const { return ordinal; }
- // Serialization
- // When using serialize, always call your parent implementation!
- virtual void serialize(SaveArchive &arc);
- // De-swizzling should restore pointers to other thinkers.
- virtual void deSwizzle() {}
- virtual bool shouldSerialize() const { return !removed; }
- virtual const char *getClassName() const { return "Thinker"; }
- ...
- //
- // Thinker Factory
- //
- // haleyjd 12/07/10: The save game code needs to be able to construct thinkers
- // of any class without resort to a gigantic switch statement. This calls for
- // a factory pattern.
- //
- class ThinkerType
- {
- protected:
- ThinkerType *next;
- const char *name;
- public:
- ThinkerType(const char *pName);
- // newThinker is a pure virtual method that must be overridden by a child
- // class to construct a specific type of thinker
- virtual Thinker *newThinker() const = 0;
- // FindType is a static method that will find the ThinkerType given the
- // name of a Thinker-descendent class (ie., "FireFlickerThinker"). The returned
- // object can then be used to construct a new instance of that type by
- // calling the newThinker method. The instance can then be fed to the
- // serialization mechanism.
- static ThinkerType *FindType(const char *pName); // find a type in the list
- };
- //
- // IMPLEMENT_THINKER_TYPE
- //
- // Use this macro once per Thinker descendant. Best placed near the Think
- // routine.
- // Example:
- // IMPLEMENT_THINKER_TYPE(FireFlickerThinker)
- // This defines FireFlickerThinkerType, which constructs a ThinkerType parent
- // with "FireFlickerThinker" as its name member and which returns a new FireFlickerThinker
- // instance via its newThinker virtual method.
- //
- #define IMPLEMENT_THINKER_TYPE(name) \
- class name ## Type : public ThinkerType \
- { \
- protected: \
- static name ## Type global ## name ## Type ; \
- public: \
- name ## Type() : ThinkerType( #name ) {} \
- virtual Thinker *newThinker() const { return new name ; } \
- }; \
- name ## Type name ## Type :: global ## name ## Type;
- // p_saveg.cpp ----------------------------------------------------------------
- static void P_NumberThinkers(void)
- {
- Thinker *th;
- num_thinkers = 0; // init to 0
- // killough 2/14/98:
- // count the number of thinkers, and mark each one with its index, using
- // the prev field as a placeholder, since it can be restored later.
- // haleyjd 11/26/10: Replaced with virtual enumeration facility
- for(th = thinkercap.next; th != &thinkercap; th = th->next)
- {
- th->setOrdinal(num_thinkers + 1);
- if(th->getOrdinal() == num_thinkers + 1) // if accepted, increment
- ++num_thinkers;
- }
- }
- static void P_DeNumberThinkers(void)
- {
- Thinker *th;
- for(th = thinkercap.next; th != &thinkercap; th = th->next)
- th->setOrdinal(0);
- }
- //
- // P_NumForThinker
- //
- // Get the mobj number from the mobj.
- //
- unsigned int P_NumForThinker(Thinker *th)
- {
- return th ? th->getOrdinal() : 0; // 0 == NULL
- }
- //
- // P_ThinkerForNum
- //
- Thinker *P_ThinkerForNum(unsigned int n)
- {
- return n <= num_thinkers ? thinker_p[n] : NULL;
- }
- ...
- //
- // Thinkers
- //
- #define tc_end "TC_END"
- //
- // P_RemoveAllThinkers
- //
- static void P_RemoveAllThinkers(void)
- {
- Thinker *th;
- // FIXME/TODO: This leaks all mobjs til the next level by calling
- // Thinker::InitThinkers. This should really be handled more
- // uniformly with a virtual method.
- // remove all the current thinkers
- for(th = thinkercap.next; th != &thinkercap; )
- {
- Thinker *next;
- Mobj *mo;
- next = th->next;
- if((mo = dynamic_cast<Mobj *>(th)))
- mo->removeThinker();
- else
- delete th;
- th = next;
- }
- // Clear out the list
- Thinker::InitThinkers();
- }
- //
- // P_ArchiveThinkers
- //
- // 2/14/98 killough: substantially modified to fix savegame bugs
- //
- static void P_ArchiveThinkers(SaveArchive &arc)
- {
- Thinker *th;
- // first, save or load count of enumerated thinkers
- arc << num_thinkers;
- if(arc.isSaving())
- {
- // save off the current thinkers
- for(th = thinkercap.next; th != &thinkercap; th = th->next)
- {
- if(th->shouldSerialize())
- th->serialize(arc);
- }
- // add a terminating marker
- arc.WriteLString(tc_end);
- }
- else
- {
- char *className = "";
- size_t len;
- unsigned int idx = 1; // Start at index 1, as 0 means NULL
- ThinkerType *thinkerType;
- Thinker *newThinker;
- // allocate thinker table
- thinker_p = (Thinker **)(calloc(num_thinkers+1, sizeof(Thinker *)));
- // clear out the thinker list
- P_RemoveAllThinkers();
- while(1)
- {
- if(*className != '\0')
- free(className);
- // Get the next class name
- arc.ArchiveLString(className, len);
- // Find the ThinkerType matching this name
- if(!(thinkerType = ThinkerType::FindType(className)))
- {
- if(!strcmp(className, tc_end))
- break; // Reached end of thinker list
- else
- I_Error("Unknown tclass %s in savegame\n", className);
- }
- // Create a thinker of the appropriate type and load it
- newThinker = thinkerType->newThinker();
- newThinker->serialize(arc);
- // Put it in the table
- thinker_p[idx++] = newThinker;
- // Add it
- newThinker->addThinker();
- }
- // Now, call deswizzle to fix up mutual references between thinkers, such
- // as mobj targets/tracers and ACS triggers.
- for(th = thinkercap.next; th != &thinkercap; th = th->next)
- th->deSwizzle();
- // killough 3/26/98: Spawn icon landings:
- // haleyjd 3/30/03: call P_InitThingLists
- P_InitThingLists();
- }
- // Do sound targets
- P_ArchiveSoundTargets(arc);
- }
- //
- // killough 11/98
- //
- // Same as P_SetTarget() in p_tick.c, except that the target is nullified
- // first, so that no old target's reference count is decreased (when loading
- // savegames, old targets are indices, not really pointers to targets).
- //
- void P_SetNewTarget(Mobj **mop, Mobj *targ)
- {
- *mop = NULL;
- P_SetTarget<Mobj>(mop, targ);
- }
- // FIN ------------------------------------------------------------------------
Add Comment
Please, Sign In to add comment