aboutsummaryrefslogtreecommitdiff
path: root/src/p_tick.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/p_tick.c')
-rw-r--r--src/p_tick.c291
1 files changed, 291 insertions, 0 deletions
diff --git a/src/p_tick.c b/src/p_tick.c
new file mode 100644
index 0000000..6046046
--- /dev/null
+++ b/src/p_tick.c
@@ -0,0 +1,291 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000,2002 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Thinker, Ticker.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#include "doomstat.h"
35#include "p_user.h"
36#include "p_spec.h"
37#include "p_tick.h"
38#include "p_map.h"
39#include "r_fps.h"
40
41int leveltime;
42
43static boolean newthinkerpresent;
44
45//
46// THINKERS
47// All thinkers should be allocated by Z_Malloc
48// so they can be operated on uniformly.
49// The actual structures will vary in size,
50// but the first element must be thinker_t.
51//
52
53// killough 8/29/98: we maintain several separate threads, each containing
54// a special class of thinkers, to allow more efficient searches.
55thinker_t thinkerclasscap[th_all+1];
56
57//
58// P_InitThinkers
59//
60
61void P_InitThinkers(void)
62{
63 int i;
64
65 for (i=0; i<NUMTHCLASS; i++) // killough 8/29/98: initialize threaded lists
66 thinkerclasscap[i].cprev = thinkerclasscap[i].cnext = &thinkerclasscap[i];
67
68 thinkercap.prev = thinkercap.next = &thinkercap;
69}
70
71//
72// killough 8/29/98:
73//
74// We maintain separate threads of friends and enemies, to permit more
75// efficient searches.
76//
77
78void P_UpdateThinker(thinker_t *thinker)
79{
80 register thinker_t *th;
81 // find the class the thinker belongs to
82
83 int class =
84 thinker->function == P_RemoveThinkerDelayed ? th_delete :
85 thinker->function == P_MobjThinker &&
86 ((mobj_t *) thinker)->health > 0 &&
87 (((mobj_t *) thinker)->flags & MF_COUNTKILL ||
88 ((mobj_t *) thinker)->type == MT_SKULL) ?
89 ((mobj_t *) thinker)->flags & MF_FRIEND ?
90 th_friends : th_enemies : th_misc;
91
92 {
93 /* Remove from current thread, if in one */
94 if ((th = thinker->cnext)!= NULL)
95 (th->cprev = thinker->cprev)->cnext = th;
96 }
97
98 // Add to appropriate thread
99 th = &thinkerclasscap[class];
100 th->cprev->cnext = thinker;
101 thinker->cnext = th;
102 thinker->cprev = th->cprev;
103 th->cprev = thinker;
104}
105
106//
107// P_AddThinker
108// Adds a new thinker at the end of the list.
109//
110
111void P_AddThinker(thinker_t* thinker)
112{
113 thinkercap.prev->next = thinker;
114 thinker->next = &thinkercap;
115 thinker->prev = thinkercap.prev;
116 thinkercap.prev = thinker;
117
118 thinker->references = 0; // killough 11/98: init reference counter to 0
119
120 // killough 8/29/98: set sentinel pointers, and then add to appropriate list
121 thinker->cnext = thinker->cprev = NULL;
122 P_UpdateThinker(thinker);
123 newthinkerpresent = true;
124}
125
126//
127// killough 11/98:
128//
129// Make currentthinker external, so that P_RemoveThinkerDelayed
130// can adjust currentthinker when thinkers self-remove.
131
132static thinker_t *currentthinker;
133
134//
135// P_RemoveThinkerDelayed()
136//
137// Called automatically as part of the thinker loop in P_RunThinkers(),
138// on nodes which are pending deletion.
139//
140// If this thinker has no more pointers referencing it indirectly,
141// remove it, and set currentthinker to one node preceeding it, so
142// that the next step in P_RunThinkers() will get its successor.
143//
144
145void P_RemoveThinkerDelayed(thinker_t *thinker)
146{
147 if (!thinker->references)
148 {
149 { /* Remove from main thinker list */
150 thinker_t *next = thinker->next;
151 /* Note that currentthinker is guaranteed to point to us,
152 * and since we're freeing our memory, we had better change that. So
153 * point it to thinker->prev, so the iterator will correctly move on to
154 * thinker->prev->next = thinker->next */
155 (next->prev = currentthinker = thinker->prev)->next = next;
156 }
157 {
158 /* Remove from current thinker class list */
159 thinker_t *th = thinker->cnext;
160 (th->cprev = thinker->cprev)->cnext = th;
161 }
162 Z_Free(thinker);
163 }
164}
165
166//
167// P_RemoveThinker
168//
169// Deallocation is lazy -- it will not actually be freed
170// until its thinking turn comes up.
171//
172// killough 4/25/98:
173//
174// Instead of marking the function with -1 value cast to a function pointer,
175// set the function to P_RemoveThinkerDelayed(), so that later, it will be
176// removed automatically as part of the thinker process.
177//
178
179void P_RemoveThinker(thinker_t *thinker)
180{
181 R_StopInterpolationIfNeeded(thinker);
182 thinker->function = P_RemoveThinkerDelayed;
183
184 P_UpdateThinker(thinker);
185}
186
187/* cph 2002/01/13 - iterator for thinker list
188 * WARNING: Do not modify thinkers between calls to this functin
189 */
190thinker_t* P_NextThinker(thinker_t* th, th_class cl)
191{
192 thinker_t* top = &thinkerclasscap[cl];
193 if (!th) th = top;
194 th = cl == th_all ? th->next : th->cnext;
195 return th == top ? NULL : th;
196}
197
198/*
199 * P_SetTarget
200 *
201 * This function is used to keep track of pointer references to mobj thinkers.
202 * In Doom, objects such as lost souls could sometimes be removed despite
203 * their still being referenced. In Boom, 'target' mobj fields were tested
204 * during each gametic, and any objects pointed to by them would be prevented
205 * from being removed. But this was incomplete, and was slow (every mobj was
206 * checked during every gametic). Now, we keep a count of the number of
207 * references, and delay removal until the count is 0.
208 */
209
210void P_SetTarget(mobj_t **mop, mobj_t *targ)
211{
212 if (*mop) // If there was a target already, decrease its refcount
213 (*mop)->thinker.references--;
214 if ((*mop = targ)) // Set new target and if non-NULL, increase its counter
215 targ->thinker.references++;
216}
217
218//
219// P_RunThinkers
220//
221// killough 4/25/98:
222//
223// Fix deallocator to stop using "next" pointer after node has been freed
224// (a Doom bug).
225//
226// Process each thinker. For thinkers which are marked deleted, we must
227// load the "next" pointer prior to freeing the node. In Doom, the "next"
228// pointer was loaded AFTER the thinker was freed, which could have caused
229// crashes.
230//
231// But if we are not deleting the thinker, we should reload the "next"
232// pointer after calling the function, in case additional thinkers are
233// added at the end of the list.
234//
235// killough 11/98:
236//
237// Rewritten to delete nodes implicitly, by making currentthinker
238// external and using P_RemoveThinkerDelayed() implicitly.
239//
240
241static void P_RunThinkers (void)
242{
243 for (currentthinker = thinkercap.next;
244 currentthinker != &thinkercap;
245 currentthinker = currentthinker->next)
246 {
247 if (newthinkerpresent)
248 R_ActivateThinkerInterpolations(currentthinker);
249 if (currentthinker->function)
250 currentthinker->function(currentthinker);
251 }
252 newthinkerpresent = false;
253}
254
255//
256// P_Ticker
257//
258
259void P_Ticker (void)
260{
261 int i;
262
263 /* pause if in menu and at least one tic has been run
264 *
265 * killough 9/29/98: note that this ties in with basetic,
266 * since G_Ticker does the pausing during recording or
267 * playback, and compenates by incrementing basetic.
268 *
269 * All of this complicated mess is used to preserve demo sync.
270 */
271
272 if (paused || (menuactive && !demoplayback && !netgame &&
273 players[consoleplayer].viewz != 1))
274 return;
275
276 R_UpdateInterpolations ();
277
278 P_MapStart();
279 // not if this is an intermission screen
280 if(gamestate==GS_LEVEL)
281 for (i=0; i<MAXPLAYERS; i++)
282 if (playeringame[i])
283 P_PlayerThink(&players[i]);
284
285 P_RunThinkers();
286 P_UpdateSpecials();
287 P_RespawnSpecials();
288 P_MapEnd();
289 leveltime++; // for par times
290}
291