1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: p_tick.c 1512 2020-04-04 08:51:13Z wesleyjohnson $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Portions Copyright (C) 1998-2000 by DooM Legacy Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 //
20 // $Log: p_tick.c,v $
21 // Revision 1.6  2001/01/25 22:15:44  bpereira
22 // added heretic support
23 //
24 // Revision 1.5  2000/11/02 17:50:09  stroggonmeth
25 // Big 3Dfloors & FraggleScript commit!!
26 //
27 // Revision 1.4  2000/10/21 08:43:31  bpereira
28 // Revision 1.3  2000/10/08 13:30:01  bpereira
29 // Revision 1.2  2000/02/27 00:42:10  hurdler
30 // Revision 1.1.1.1  2000/02/22 20:32:32  hurdler
31 // Initial import into CVS (v1.29 pr3)
32 //
33 //
34 // DESCRIPTION:
35 //      Archiving: SaveGame I/O.
36 //      Thinker, Ticker.
37 //
38 //-----------------------------------------------------------------------------
39 
40 
41 #include "doomstat.h"
42 #include "p_tick.h"
43 #include "g_game.h"
44 #include "p_local.h"
45 #include "z_zone.h"
46 #include "t_script.h"
47 
48 
49 
50 tic_t     leveltime;
51 
52 //
53 // THINKERS
54 // All thinkers should be allocated by Z_Malloc
55 // so they can be operated on uniformly.
56 // The actual structures will vary in size,
57 // but the first element must be thinker_t.
58 //
59 
60 
61 
62 // Both the head and tail of the thinker list.
63 // Linked by next, prev.
64 thinker_t  thinkercap;
65 // MBF, class-lists.
66 // Linked by cnext, cprev.
67 thinker_t  thinkerclasscap[NUMTHCLASS];
68 
69 #ifdef THINKER_INTERPOLATIONS
70 static byte  newthinkerpresent = true;
71 #endif
72 
73 
74 //
75 // P_Init_Thinkers
76 //
P_Init_Thinkers(void)77 void P_Init_Thinkers (void)
78 {
79     int i;
80 
81     // [WDJ] MBF, from MBF, PrBoom.
82     // Init all class-list.
83     for( i=0; i<NUMTHCLASS; i++ )
84       thinkerclasscap[i].cprev = thinkerclasscap[i].cnext = &thinkerclasscap[i];
85 
86     thinkercap.prev = thinkercap.next  = &thinkercap;
87 }
88 
89 
90 
91 
92 //
93 // P_AddThinker
94 // Adds a new thinker at the end of the list.
95 //
P_AddThinker(thinker_t * thinker)96 void P_AddThinker (thinker_t* thinker)
97 {
98     thinkercap.prev->next = thinker;
99     thinker->next = &thinkercap;
100     thinker->prev = thinkercap.prev;
101     thinkercap.prev = thinker;
102 
103     // From MBF, PrBoom
104 #ifdef REFERENCE_COUNTING
105     thinker->references = 0;    // killough 11/98: init reference counter to 0
106 #endif
107     // killough 8/29/98: init pointers, and then add to appropriate list
108     thinker->cnext = thinker->cprev = NULL;  // init
109     P_UpdateClassThink(thinker, TH_unknown);
110 
111 #ifdef THINKER_INTERPOLATIONS
112     newthinkerpresent = true;
113 #endif
114 }
115 
116 
117 //
118 // P_RemoveThinker
119 // Deallocation is lazy -- it will not actually be freed
120 // until its thinking turn comes up.
121 //
P_RemoveThinker(thinker_t * thinker)122 void P_RemoveThinker (thinker_t* thinker)
123 {
124     // Setup an action function that does removal.
125     thinker->function.acp1 = (actionf_p1) T_RemoveThinker;
126 
127     // [WDJ] MBF, from MBF, PrBoom
128     // killough 8/29/98: remove immediately from class-list
129 
130     // haleyjd 11/09/06: NO! Doing this here was always suspect to me, and
131     // sure enough: if a monster's removed at the wrong time, it gets put
132     // back into the list improperly and starts causing an infinite loop in
133     // the AI code. We'll follow PrBoom's lead and create a th_delete class
134     // for thinkers awaiting deferred removal.
135 
136     // [WDJ] Being in a delete list does nothing to stop being found.
137     // Delete class links, and let acp1 block linking again.
138     P_UpdateClassThink( thinker, TH_delete );
139 }
140 
141 // Thinker function that removes the thinker.
142 // In PrBoom, MBF, this is called P_RemoveThinkerDelayed, and is more
143 // complicated, using reference counts and modifying currentthinker.
144 // Our RunThinker handles removal better.
T_RemoveThinker(thinker_t * remthink)145 void T_RemoveThinker( thinker_t* remthink )
146 {
147     // [WDJ] MBF, from MBF, PrBoom
148 #ifdef REFERENCE_COUNTING
149     if( remthink->references )  return;
150 #endif
151 
152     // Remove from current class-list, if in one.
153     P_UpdateClassThink( remthink, TH_none );
154 
155     // Unlink and delete the thinker
156     remthink->next->prev = remthink->prev;
157     remthink->prev->next = remthink->next;
158     Z_Free (remthink);  // mobj, etc.
159 }
160 
161 
162 // [WDJ] MBF, from MBF, PrBoom, EternityEngine.
163 // killough 8/29/98:
164 // [WDJ] Heavily rewritten to eliminate unused class-lists.
165 // Make readable.
166 //
167 // Maintain separate class-lists of friends and enemies, to permit more
168 // efficient searches.
169 //
170 
P_UpdateClassThink(thinker_t * thinker,int tclass)171 void P_UpdateClassThink(thinker_t *thinker, int tclass )
172 {
173     register thinker_t * th;
174 
175     if( tclass == TH_unknown )
176     {
177         // Find the class where the thinker belongs.
178         // Most common case first.
179         tclass = TH_misc;
180         if( thinker->function.acp1 == (actionf_p1)P_MobjThinker )
181         {
182             register mobj_t * mo = (mobj_t *) thinker;
183             if( mo->health > 0
184                 && ( mo->flags & MF_COUNTKILL || mo->type == MT_SKULL) )
185             {
186                 tclass = (mo->flags & MF_FRIEND)? TH_friends : TH_enemies;
187             }
188         }
189     }
190 
191     // Remove from current class-list, if in one.
192     th = thinker->cnext;
193     if( th != NULL)
194     {
195         th->cprev = thinker->cprev;
196         th->cprev->cnext = th;
197     }
198 
199     // Prevent linking dead mobj.
200     if( thinker->function.acp1 == (actionf_p1)T_RemoveThinker
201         || tclass >= NUMTHCLASS )  // TH_none, etc.
202     {
203         // Not in any class-list.
204         // Prevent unlinking again.
205         thinker->cprev = thinker->cnext = NULL;
206         return;
207     }
208 
209     // Add to the appropriate class-list.
210     th = &thinkerclasscap[tclass];
211     thinker->cnext = th;
212     thinker->cprev = th->cprev;
213     th->cprev->cnext = thinker;
214     th->cprev = thinker;
215     return;
216 
217 }
218 
219 // Move to be first or last.
220 //  first : 0=last, 1=first.
P_MoveClassThink(thinker_t * thinker,byte first)221 void P_MoveClassThink(thinker_t *thinker, byte first)
222 {
223     register thinker_t * th;
224 
225     // Remove from current thread, if in one.
226     th = thinker->cnext;
227     if( th != NULL)
228     {
229         th->cprev = thinker->cprev;
230         thinker->cprev->cnext = th;
231     }
232 
233     // prevent linking dead mobj
234     if( thinker->function.acp1 == (actionf_p1)T_RemoveThinker )
235     {
236         // Not in any class-list.
237         // Prevent unlinking again.
238         thinker->cprev = thinker->cnext = NULL;
239         return;
240     }
241 
242     // Add to appropriate thread list.
243     register mobj_t * mo = (mobj_t *) thinker;
244     th = &thinkerclasscap[ (mo->flags & MF_FRIEND)? TH_friends : TH_enemies ];
245     if( first )
246     {
247         thinker->cprev = th;
248         thinker->cnext = th->cnext;
249         th->cnext->cprev = thinker;
250         th->cnext = thinker;
251     }
252     else
253     {   // Last
254         thinker->cnext = th;
255         thinker->cprev = th->cprev;
256         th->cprev->cnext = thinker;
257         th->cprev = thinker;
258     }
259 }
260 
261 
262 // Move range cap to th, to be last in class-list.
263 //  cap: is a class-list.
264 //  thnext: becomes new first in class-list.
P_MoveClasslistRangeLast(thinker_t * cap,thinker_t * thnext)265 void P_MoveClasslistRangeLast( thinker_t * cap, thinker_t * thnext )
266 {
267     // cap is head of a class-list.
268     // Link first in class-list to end of class-list.
269     cap->cnext->cprev = cap->cprev;
270     cap->cprev->cnext = cap->cnext;
271     // Break list before th.  Make thnext first in class-list.
272     register thinker_t * tp = thnext->cprev;
273     cap->cprev = tp;
274     tp->cnext = cap;
275     thnext->cprev = cap;
276     cap->cnext = thnext;
277 }
278 
279 
280 #ifdef REFERENCE_COUNTING
281 //
282 // P_SetReference
283 //
284 // This function is used to keep track of pointer references to mobj thinkers.
285 // In Doom, objects such as lost souls could sometimes be removed despite
286 // their still being referenced. In Boom, 'target' mobj fields were tested
287 // during each gametic, and any objects pointed to by them would be prevented
288 // from being removed. But this was incomplete, and was slow (every mobj was
289 // checked during every gametic). Now, we keep a count of the number of
290 // references, and delay removal until the count is 0.
291 
292 //  rm_mo: remove reference
293 //  add_mo:  add reference
P_SetReference(mobj_t * rm_mo,mobj_t * add_mo)294 void P_SetReference(mobj_t *rm_mo, mobj_t *add_mo)
295 {
296   if(rm_mo)  // If there was a target already, decrease its refcount
297     rm_mo->thinker.references--;
298   if(targ)  // Set new target and if non-NULL, increase its counter
299     add_mo->thinker.references++;
300 }
301 #endif
302 
303 
304 //
305 // P_RunThinkers
306 //
P_RunThinkers(void)307 void P_RunThinkers (void)
308 {
309     thinker_t*  currentthinker;
310     thinker_t*  next_thinker;
311 
312     currentthinker = thinkercap.next;
313     while (currentthinker != &thinkercap)
314     {
315         next_thinker = currentthinker->next;  // because of T_RemoveThinker
316 #ifdef THINKER_INTERPOLATIONS
317         if (newthinkerpresent)
318             R_ActivateThinkerInterpolations(currentthinker);
319 #endif
320         if (currentthinker->function.acp1)
321         {
322             currentthinker->function.acp1 (currentthinker);
323         }
324         currentthinker = next_thinker;
325     }
326 #ifdef THINKER_INTERPOLATIONS
327     newthinkerpresent = false;
328 #endif
329 }
330 
331 
332 
333 //
334 // P_Ticker
335 //
336 
P_Ticker(void)337 void P_Ticker (void)
338 {
339     int  i;
340 
341     // [WDJ] From PrBoom, adapted to game_comp_tic.
342     // Pause if in menu and at least one tic has been run.
343     // killough 9/29/98: note that this ties in with basetic,
344     // since G_Ticker does the pausing during recording or playback,
345     // and compensates by incrementing basetic (not incrementing game_comp_tic).
346     // All of this complicated mess is used to preserve demo sync.
347     // PrBoom and EternityEngine test (players[consoleplayer].viewz != 1)
348     // as test that one tic has run.
349     // Heretic only has paused.
350     if (paused
351         || (menuactive && !netgame && !demoplayback
352             && (players[consoleplayer].viewz != 1) ))
353         return;
354 
355 #ifdef THINKER_INTERPOLATIONS
356     R_UpdateInterpolations();
357 #endif
358 
359     // From PrBoom, EternityEngine, may affect demo sync.
360     // Not if this is an intermission screen.
361     if( gamestate == GS_LEVEL || gamestate == GS_DEDICATEDSERVER )
362     {
363         for (i=0 ; i<MAXPLAYERS ; i++)
364         {
365             if (playeringame[i])
366                 P_PlayerThink (&players[i]);
367         }
368     }
369 
370     P_RunThinkers ();
371     P_UpdateSpecials ();
372     if( cv_itemrespawn.EV )  P_RespawnSpecials ();
373 
374     P_AmbientSound();
375 
376     // for par times
377     leveltime++;
378 
379 #ifdef FRAGGLESCRIPT
380     // SoM: Update FraggleScript...
381     T_DelayedScripts();
382 #endif
383 }
384