diff options
Diffstat (limited to 'src/p_mobj.c')
-rw-r--r-- | src/p_mobj.c | 1526 |
1 files changed, 1526 insertions, 0 deletions
diff --git a/src/p_mobj.c b/src/p_mobj.c new file mode 100644 index 0000000..0f8c8e3 --- /dev/null +++ b/src/p_mobj.c | |||
@@ -0,0 +1,1526 @@ | |||
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-2004 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 | * Moving object handling. Spawn functions. | ||
31 | * | ||
32 | *-----------------------------------------------------------------------------*/ | ||
33 | |||
34 | #include "doomdef.h" | ||
35 | #include "doomstat.h" | ||
36 | #include "m_random.h" | ||
37 | #include "r_main.h" | ||
38 | #include "p_maputl.h" | ||
39 | #include "p_map.h" | ||
40 | #include "p_tick.h" | ||
41 | #include "sounds.h" | ||
42 | #include "st_stuff.h" | ||
43 | #include "hu_stuff.h" | ||
44 | #include "s_sound.h" | ||
45 | #include "info.h" | ||
46 | #include "g_game.h" | ||
47 | #include "p_inter.h" | ||
48 | #include "lprintf.h" | ||
49 | #include "r_demo.h" | ||
50 | |||
51 | // | ||
52 | // P_SetMobjState | ||
53 | // Returns true if the mobj is still present. | ||
54 | // | ||
55 | |||
56 | boolean P_SetMobjState(mobj_t* mobj,statenum_t state) | ||
57 | { | ||
58 | state_t* st; | ||
59 | |||
60 | // killough 4/9/98: remember states seen, to detect cycles: | ||
61 | |||
62 | static statenum_t seenstate_tab[NUMSTATES]; // fast transition table | ||
63 | statenum_t *seenstate = seenstate_tab; // pointer to table | ||
64 | static int recursion; // detects recursion | ||
65 | statenum_t i = state; // initial state | ||
66 | boolean ret = true; // return value | ||
67 | statenum_t tempstate[NUMSTATES]; // for use with recursion | ||
68 | |||
69 | if (recursion++) // if recursion detected, | ||
70 | memset(seenstate=tempstate,0,sizeof tempstate); // clear state table | ||
71 | |||
72 | do | ||
73 | { | ||
74 | if (state == S_NULL) | ||
75 | { | ||
76 | mobj->state = (state_t *) S_NULL; | ||
77 | P_RemoveMobj (mobj); | ||
78 | ret = false; | ||
79 | break; // killough 4/9/98 | ||
80 | } | ||
81 | |||
82 | st = &states[state]; | ||
83 | mobj->state = st; | ||
84 | mobj->tics = st->tics; | ||
85 | mobj->sprite = st->sprite; | ||
86 | mobj->frame = st->frame; | ||
87 | |||
88 | // Modified handling. | ||
89 | // Call action functions when the state is set | ||
90 | |||
91 | if (st->action) | ||
92 | st->action(mobj); | ||
93 | |||
94 | seenstate[state] = 1 + st->nextstate; // killough 4/9/98 | ||
95 | |||
96 | state = st->nextstate; | ||
97 | } while (!mobj->tics && !seenstate[state]); // killough 4/9/98 | ||
98 | |||
99 | if (ret && !mobj->tics) // killough 4/9/98: detect state cycles | ||
100 | doom_printf("Warning: State Cycle Detected"); | ||
101 | |||
102 | if (!--recursion) | ||
103 | for (;(state=seenstate[i]);i=state-1) | ||
104 | seenstate[i] = 0; // killough 4/9/98: erase memory of states | ||
105 | |||
106 | return ret; | ||
107 | } | ||
108 | |||
109 | |||
110 | // | ||
111 | // P_ExplodeMissile | ||
112 | // | ||
113 | |||
114 | void P_ExplodeMissile (mobj_t* mo) | ||
115 | { | ||
116 | mo->momx = mo->momy = mo->momz = 0; | ||
117 | |||
118 | P_SetMobjState (mo, mobjinfo[mo->type].deathstate); | ||
119 | |||
120 | mo->tics -= P_Random(pr_explode)&3; | ||
121 | |||
122 | if (mo->tics < 1) | ||
123 | mo->tics = 1; | ||
124 | |||
125 | mo->flags &= ~MF_MISSILE; | ||
126 | |||
127 | if (mo->info->deathsound) | ||
128 | S_StartSound (mo, mo->info->deathsound); | ||
129 | } | ||
130 | |||
131 | |||
132 | // | ||
133 | // P_XYMovement | ||
134 | // | ||
135 | // Attempts to move something if it has momentum. | ||
136 | // | ||
137 | |||
138 | static void P_XYMovement (mobj_t* mo) | ||
139 | { | ||
140 | player_t *player; | ||
141 | fixed_t xmove, ymove; | ||
142 | |||
143 | //e6y | ||
144 | fixed_t oldx,oldy; // phares 9/10/98: reducing bobbing/momentum on ice | ||
145 | |||
146 | #if 0 | ||
147 | fixed_t ptryx; | ||
148 | fixed_t ptryy; | ||
149 | fixed_t xmove; | ||
150 | fixed_t ymove; | ||
151 | fixed_t oldx,oldy; // phares 9/10/98: reducing bobbing/momentum on ice | ||
152 | // when up against walls | ||
153 | #endif | ||
154 | if (!(mo->momx | mo->momy)) // Any momentum? | ||
155 | { | ||
156 | if (mo->flags & MF_SKULLFLY) | ||
157 | { | ||
158 | |||
159 | // the skull slammed into something | ||
160 | |||
161 | mo->flags &= ~MF_SKULLFLY; | ||
162 | mo->momz = 0; | ||
163 | |||
164 | P_SetMobjState (mo, mo->info->spawnstate); | ||
165 | } | ||
166 | return; | ||
167 | } | ||
168 | |||
169 | player = mo->player; | ||
170 | |||
171 | if (mo->momx > MAXMOVE) | ||
172 | mo->momx = MAXMOVE; | ||
173 | else if (mo->momx < -MAXMOVE) | ||
174 | mo->momx = -MAXMOVE; | ||
175 | |||
176 | if (mo->momy > MAXMOVE) | ||
177 | mo->momy = MAXMOVE; | ||
178 | else if (mo->momy < -MAXMOVE) | ||
179 | mo->momy = -MAXMOVE; | ||
180 | |||
181 | xmove = mo->momx; | ||
182 | ymove = mo->momy; | ||
183 | |||
184 | oldx = mo->x; // phares 9/10/98: new code to reduce bobbing/momentum | ||
185 | oldy = mo->y; // when on ice & up against wall. These will be compared | ||
186 | // to your x,y values later to see if you were able to move | ||
187 | |||
188 | do | ||
189 | { | ||
190 | fixed_t ptryx, ptryy; | ||
191 | // killough 8/9/98: fix bug in original Doom source: | ||
192 | // Large negative displacements were never considered. | ||
193 | // This explains the tendency for Mancubus fireballs | ||
194 | // to pass through walls. | ||
195 | // CPhipps - compatibility optioned | ||
196 | |||
197 | if (xmove > MAXMOVE/2 || ymove > MAXMOVE/2 || | ||
198 | (!comp[comp_moveblock] | ||
199 | && (xmove < -MAXMOVE/2 || ymove < -MAXMOVE/2))) | ||
200 | { | ||
201 | ptryx = mo->x + xmove/2; | ||
202 | ptryy = mo->y + ymove/2; | ||
203 | xmove >>= 1; | ||
204 | ymove >>= 1; | ||
205 | } | ||
206 | else | ||
207 | { | ||
208 | ptryx = mo->x + xmove; | ||
209 | ptryy = mo->y + ymove; | ||
210 | xmove = ymove = 0; | ||
211 | } | ||
212 | |||
213 | // killough 3/15/98: Allow objects to drop off | ||
214 | |||
215 | if (!P_TryMove (mo, ptryx, ptryy, true)) | ||
216 | { | ||
217 | // blocked move | ||
218 | |||
219 | // killough 8/11/98: bouncing off walls | ||
220 | // killough 10/98: | ||
221 | // Add ability for objects other than players to bounce on ice | ||
222 | |||
223 | if (!(mo->flags & MF_MISSILE) && | ||
224 | mbf_features && | ||
225 | (mo->flags & MF_BOUNCES || | ||
226 | (!player && blockline && | ||
227 | variable_friction && mo->z <= mo->floorz && | ||
228 | P_GetFriction(mo, NULL) > ORIG_FRICTION))) | ||
229 | { | ||
230 | if (blockline) | ||
231 | { | ||
232 | fixed_t r = ((blockline->dx >> FRACBITS) * mo->momx + | ||
233 | (blockline->dy >> FRACBITS) * mo->momy) / | ||
234 | ((blockline->dx >> FRACBITS)*(blockline->dx >> FRACBITS)+ | ||
235 | (blockline->dy >> FRACBITS)*(blockline->dy >> FRACBITS)); | ||
236 | fixed_t x = FixedMul(r, blockline->dx); | ||
237 | fixed_t y = FixedMul(r, blockline->dy); | ||
238 | |||
239 | // reflect momentum away from wall | ||
240 | |||
241 | mo->momx = x*2 - mo->momx; | ||
242 | mo->momy = y*2 - mo->momy; | ||
243 | |||
244 | // if under gravity, slow down in | ||
245 | // direction perpendicular to wall. | ||
246 | |||
247 | if (!(mo->flags & MF_NOGRAVITY)) | ||
248 | { | ||
249 | mo->momx = (mo->momx + x)/2; | ||
250 | mo->momy = (mo->momy + y)/2; | ||
251 | } | ||
252 | } | ||
253 | else | ||
254 | mo->momx = mo->momy = 0; | ||
255 | } | ||
256 | else | ||
257 | if (player) // try to slide along it | ||
258 | P_SlideMove (mo); | ||
259 | else | ||
260 | if (mo->flags & MF_MISSILE) | ||
261 | { | ||
262 | // explode a missile | ||
263 | |||
264 | if (ceilingline && | ||
265 | ceilingline->backsector && | ||
266 | ceilingline->backsector->ceilingpic == skyflatnum) | ||
267 | if (demo_compatibility || // killough | ||
268 | mo->z > ceilingline->backsector->ceilingheight) | ||
269 | { | ||
270 | // Hack to prevent missiles exploding | ||
271 | // against the sky. | ||
272 | // Does not handle sky floors. | ||
273 | |||
274 | P_RemoveMobj (mo); | ||
275 | return; | ||
276 | } | ||
277 | P_ExplodeMissile (mo); | ||
278 | } | ||
279 | else // whatever else it is, it is now standing still in (x,y) | ||
280 | mo->momx = mo->momy = 0; | ||
281 | } | ||
282 | } while (xmove || ymove); | ||
283 | |||
284 | // slow down | ||
285 | |||
286 | #if 0 /* killough 10/98: this is unused code (except maybe in .deh files?) */ | ||
287 | if (player && player->cheats & CF_NOMOMENTUM) | ||
288 | { | ||
289 | // debug option for no sliding at all | ||
290 | mo->momx = mo->momy = 0; | ||
291 | player->momx = player->momy = 0; /* killough 10/98 */ | ||
292 | return; | ||
293 | } | ||
294 | #endif | ||
295 | |||
296 | /* no friction for missiles or skulls ever, no friction when airborne */ | ||
297 | if (mo->flags & (MF_MISSILE | MF_SKULLFLY) || mo->z > mo->floorz) | ||
298 | return; | ||
299 | |||
300 | /* killough 8/11/98: add bouncers | ||
301 | * killough 9/15/98: add objects falling off ledges | ||
302 | * killough 11/98: only include bouncers hanging off ledges | ||
303 | */ | ||
304 | if (((mo->flags & MF_BOUNCES && mo->z > mo->dropoffz) || | ||
305 | mo->flags & MF_CORPSE || mo->intflags & MIF_FALLING) && | ||
306 | (mo->momx > FRACUNIT/4 || mo->momx < -FRACUNIT/4 || | ||
307 | mo->momy > FRACUNIT/4 || mo->momy < -FRACUNIT/4) && | ||
308 | mo->floorz != mo->subsector->sector->floorheight) | ||
309 | return; // do not stop sliding if halfway off a step with some momentum | ||
310 | |||
311 | // killough 11/98: | ||
312 | // Stop voodoo dolls that have come to rest, despite any | ||
313 | // moving corresponding player, except in old demos: | ||
314 | |||
315 | if (mo->momx > -STOPSPEED && mo->momx < STOPSPEED && | ||
316 | mo->momy > -STOPSPEED && mo->momy < STOPSPEED && | ||
317 | (!player || !(player->cmd.forwardmove | player->cmd.sidemove) || | ||
318 | (player->mo != mo && compatibility_level >= lxdoom_1_compatibility))) | ||
319 | { | ||
320 | // if in a walking frame, stop moving | ||
321 | |||
322 | // killough 10/98: | ||
323 | // Don't affect main player when voodoo dolls stop, except in old demos: | ||
324 | |||
325 | // if ( player&&(unsigned)((player->mo->state - states)- S_PLAY_RUN1) < 4) | ||
326 | // P_SetMobjState (player->mo, S_PLAY); | ||
327 | if (player && (unsigned)(player->mo->state - states - S_PLAY_RUN1) < 4 | ||
328 | && (player->mo == mo || compatibility_level >= lxdoom_1_compatibility)) | ||
329 | P_SetMobjState(player->mo, S_PLAY); | ||
330 | |||
331 | mo->momx = mo->momy = 0; | ||
332 | |||
333 | /* killough 10/98: kill any bobbing momentum too (except in voodoo dolls) | ||
334 | * cph - DEMOSYNC - needs compatibility check? | ||
335 | */ | ||
336 | if (player && player->mo == mo) | ||
337 | player->momx = player->momy = 0; | ||
338 | } | ||
339 | else | ||
340 | { | ||
341 | /* phares 3/17/98 | ||
342 | * | ||
343 | * Friction will have been adjusted by friction thinkers for | ||
344 | * icy or muddy floors. Otherwise it was never touched and | ||
345 | * remained set at ORIG_FRICTION | ||
346 | * | ||
347 | * killough 8/28/98: removed inefficient thinker algorithm, | ||
348 | * instead using touching_sectorlist in P_GetFriction() to | ||
349 | * determine friction (and thus only when it is needed). | ||
350 | * | ||
351 | * killough 10/98: changed to work with new bobbing method. | ||
352 | * Reducing player momentum is no longer needed to reduce | ||
353 | * bobbing, so ice works much better now. | ||
354 | * | ||
355 | * cph - DEMOSYNC - need old code for Boom demos? | ||
356 | */ | ||
357 | |||
358 | //e6y | ||
359 | if (compatibility_level <= boom_201_compatibility) | ||
360 | { | ||
361 | // phares 3/17/98 | ||
362 | // Friction will have been adjusted by friction thinkers for icy | ||
363 | // or muddy floors. Otherwise it was never touched and | ||
364 | // remained set at ORIG_FRICTION | ||
365 | mo->momx = FixedMul(mo->momx,mo->friction); | ||
366 | mo->momy = FixedMul(mo->momy,mo->friction); | ||
367 | mo->friction = ORIG_FRICTION; // reset to normal for next tic | ||
368 | } | ||
369 | else if (compatibility_level <= lxdoom_1_compatibility) | ||
370 | { | ||
371 | // phares 9/10/98: reduce bobbing/momentum when on ice & up against wall | ||
372 | |||
373 | if ((oldx == mo->x) && (oldy == mo->y)) // Did you go anywhere? | ||
374 | { // No. Use original friction. This allows you to not bob so much | ||
375 | // if you're on ice, but keeps enough momentum around to break free | ||
376 | // when you're mildly stuck in a wall. | ||
377 | mo->momx = FixedMul(mo->momx,ORIG_FRICTION); | ||
378 | mo->momy = FixedMul(mo->momy,ORIG_FRICTION); | ||
379 | } | ||
380 | else | ||
381 | { // Yes. Use stored friction. | ||
382 | mo->momx = FixedMul(mo->momx,mo->friction); | ||
383 | mo->momy = FixedMul(mo->momy,mo->friction); | ||
384 | } | ||
385 | mo->friction = ORIG_FRICTION; // reset to normal for next tic | ||
386 | } | ||
387 | else | ||
388 | { | ||
389 | |||
390 | fixed_t friction = P_GetFriction(mo, NULL); | ||
391 | |||
392 | mo->momx = FixedMul(mo->momx, friction); | ||
393 | mo->momy = FixedMul(mo->momy, friction); | ||
394 | |||
395 | /* killough 10/98: Always decrease player bobbing by ORIG_FRICTION. | ||
396 | * This prevents problems with bobbing on ice, where it was not being | ||
397 | * reduced fast enough, leading to all sorts of kludges being developed. | ||
398 | */ | ||
399 | |||
400 | if (player && player->mo == mo) /* Not voodoo dolls */ | ||
401 | { | ||
402 | player->momx = FixedMul(player->momx, ORIG_FRICTION); | ||
403 | player->momy = FixedMul(player->momy, ORIG_FRICTION); | ||
404 | } | ||
405 | |||
406 | } | ||
407 | |||
408 | } | ||
409 | } | ||
410 | |||
411 | |||
412 | // | ||
413 | // P_ZMovement | ||
414 | // | ||
415 | // Attempt vertical movement. | ||
416 | |||
417 | static void P_ZMovement (mobj_t* mo) | ||
418 | { | ||
419 | /* killough 7/11/98: | ||
420 | * BFG fireballs bounced on floors and ceilings in Pre-Beta Doom | ||
421 | * killough 8/9/98: added support for non-missile objects bouncing | ||
422 | * (e.g. grenade, mine, pipebomb) | ||
423 | */ | ||
424 | |||
425 | if (mo->flags & MF_BOUNCES && mo->momz) { | ||
426 | mo->z += mo->momz; | ||
427 | if (mo->z <= mo->floorz) { /* bounce off floors */ | ||
428 | mo->z = mo->floorz; | ||
429 | if (mo->momz < 0) { | ||
430 | mo->momz = -mo->momz; | ||
431 | if (!(mo->flags & MF_NOGRAVITY)) { /* bounce back with decay */ | ||
432 | mo->momz = mo->flags & MF_FLOAT ? // floaters fall slowly | ||
433 | mo->flags & MF_DROPOFF ? // DROPOFF indicates rate | ||
434 | FixedMul(mo->momz, (fixed_t)(FRACUNIT*.85)) : | ||
435 | FixedMul(mo->momz, (fixed_t)(FRACUNIT*.70)) : | ||
436 | FixedMul(mo->momz, (fixed_t)(FRACUNIT*.45)) ; | ||
437 | |||
438 | /* Bring it to rest below a certain speed */ | ||
439 | if (D_abs(mo->momz) <= mo->info->mass*(GRAVITY*4/256)) | ||
440 | mo->momz = 0; | ||
441 | } | ||
442 | |||
443 | /* killough 11/98: touchy objects explode on impact */ | ||
444 | if (mo->flags & MF_TOUCHY && mo->intflags & MIF_ARMED | ||
445 | && mo->health > 0) | ||
446 | P_DamageMobj(mo, NULL, NULL, mo->health); | ||
447 | else if (mo->flags & MF_FLOAT && sentient(mo)) | ||
448 | goto floater; | ||
449 | return; | ||
450 | } | ||
451 | } else if (mo->z >= mo->ceilingz - mo->height) { | ||
452 | /* bounce off ceilings */ | ||
453 | mo->z = mo->ceilingz - mo->height; | ||
454 | if (mo->momz > 0) { | ||
455 | if (mo->subsector->sector->ceilingpic != skyflatnum) | ||
456 | mo->momz = -mo->momz; /* always bounce off non-sky ceiling */ | ||
457 | else if (mo->flags & MF_MISSILE) | ||
458 | P_RemoveMobj(mo); /* missiles don't bounce off skies */ | ||
459 | else if (mo->flags & MF_NOGRAVITY) | ||
460 | mo->momz = -mo->momz; // bounce unless under gravity | ||
461 | |||
462 | if (mo->flags & MF_FLOAT && sentient(mo)) | ||
463 | goto floater; | ||
464 | |||
465 | return; | ||
466 | } | ||
467 | } else { | ||
468 | if (!(mo->flags & MF_NOGRAVITY)) /* free-fall under gravity */ | ||
469 | mo->momz -= mo->info->mass*(GRAVITY/256); | ||
470 | |||
471 | if (mo->flags & MF_FLOAT && sentient(mo)) goto floater; | ||
472 | return; | ||
473 | } | ||
474 | |||
475 | /* came to a stop */ | ||
476 | mo->momz = 0; | ||
477 | |||
478 | if (mo->flags & MF_MISSILE) { | ||
479 | if (ceilingline && | ||
480 | ceilingline->backsector && | ||
481 | ceilingline->backsector->ceilingpic == skyflatnum && | ||
482 | mo->z > ceilingline->backsector->ceilingheight) | ||
483 | P_RemoveMobj(mo); /* don't explode on skies */ | ||
484 | else | ||
485 | P_ExplodeMissile(mo); | ||
486 | } | ||
487 | |||
488 | if (mo->flags & MF_FLOAT && sentient(mo)) goto floater; | ||
489 | return; | ||
490 | } | ||
491 | |||
492 | /* killough 8/9/98: end bouncing object code */ | ||
493 | |||
494 | // check for smooth step up | ||
495 | |||
496 | if (mo->player && | ||
497 | mo->player->mo == mo && // killough 5/12/98: exclude voodoo dolls | ||
498 | mo->z < mo->floorz) | ||
499 | { | ||
500 | mo->player->viewheight -= mo->floorz-mo->z; | ||
501 | mo->player->deltaviewheight = (VIEWHEIGHT - mo->player->viewheight)>>3; | ||
502 | } | ||
503 | |||
504 | // adjust altitude | ||
505 | |||
506 | mo->z += mo->momz; | ||
507 | |||
508 | floater: | ||
509 | if ((mo->flags & MF_FLOAT) && mo->target) | ||
510 | |||
511 | // float down towards target if too close | ||
512 | |||
513 | if (!((mo->flags ^ MF_FLOAT) & (MF_FLOAT | MF_SKULLFLY | MF_INFLOAT)) && | ||
514 | mo->target) /* killough 11/98: simplify */ | ||
515 | { | ||
516 | fixed_t delta; | ||
517 | if (P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y) < | ||
518 | D_abs(delta = mo->target->z + (mo->height>>1) - mo->z)*3) | ||
519 | mo->z += delta < 0 ? -FLOATSPEED : FLOATSPEED; | ||
520 | } | ||
521 | |||
522 | // clip movement | ||
523 | |||
524 | if (mo->z <= mo->floorz) | ||
525 | { | ||
526 | // hit the floor | ||
527 | |||
528 | /* Note (id): | ||
529 | * somebody left this after the setting momz to 0, | ||
530 | * kinda useless there. | ||
531 | * cph - This was the a bug in the linuxdoom-1.10 source which | ||
532 | * caused it not to sync Doom 2 v1.9 demos. Someone | ||
533 | * added the above comment and moved up the following code. So | ||
534 | * demos would desync in close lost soul fights. | ||
535 | * cph - revised 2001/04/15 - | ||
536 | * This was a bug in the Doom/Doom 2 source; the following code | ||
537 | * is meant to make charging lost souls bounce off of floors, but it | ||
538 | * was incorrectly placed after momz was set to 0. | ||
539 | * However, this bug was fixed in Doom95, Final/Ultimate Doom, and | ||
540 | * the v1.10 source release (which is one reason why it failed to sync | ||
541 | * some Doom2 v1.9 demos) | ||
542 | * I've added a comp_soul compatibility option to make this behavior | ||
543 | * selectable for PrBoom v2.3+. For older demos, we do this here only | ||
544 | * if we're in a compatibility level above Doom 2 v1.9 (in which case we | ||
545 | * mimic the bug and do it further down instead) | ||
546 | */ | ||
547 | |||
548 | if (mo->flags & MF_SKULLFLY && | ||
549 | (!comp[comp_soul] || | ||
550 | (compatibility_level > doom2_19_compatibility && | ||
551 | compatibility_level < prboom_4_compatibility) | ||
552 | )) | ||
553 | mo->momz = -mo->momz; // the skull slammed into something | ||
554 | |||
555 | if (mo->momz < 0) | ||
556 | { | ||
557 | /* killough 11/98: touchy objects explode on impact */ | ||
558 | if (mo->flags & MF_TOUCHY && mo->intflags & MIF_ARMED && mo->health > 0) | ||
559 | P_DamageMobj(mo, NULL, NULL, mo->health); | ||
560 | else | ||
561 | if (mo->player && /* killough 5/12/98: exclude voodoo dolls */ | ||
562 | mo->player->mo == mo && mo->momz < -GRAVITY*8) | ||
563 | { | ||
564 | // Squat down. | ||
565 | // Decrease viewheight for a moment | ||
566 | // after hitting the ground (hard), | ||
567 | // and utter appropriate sound. | ||
568 | |||
569 | mo->player->deltaviewheight = mo->momz>>3; | ||
570 | if (mo->health > 0) /* cph - prevent "oof" when dead */ | ||
571 | S_StartSound (mo, sfx_oof); | ||
572 | } | ||
573 | mo->momz = 0; | ||
574 | } | ||
575 | mo->z = mo->floorz; | ||
576 | |||
577 | /* cph 2001/04/15 - | ||
578 | * This is the buggy lost-soul bouncing code referenced above. | ||
579 | * We've already set momz = 0 normally by this point, so it's useless. | ||
580 | * However we might still have upward momentum, in which case this will | ||
581 | * incorrectly reverse it, so we might still need this for demo sync | ||
582 | */ | ||
583 | if (mo->flags & MF_SKULLFLY && | ||
584 | compatibility_level <= doom2_19_compatibility) | ||
585 | mo->momz = -mo->momz; // the skull slammed into something | ||
586 | |||
587 | if ( (mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP) ) | ||
588 | { | ||
589 | P_ExplodeMissile (mo); | ||
590 | return; | ||
591 | } | ||
592 | } | ||
593 | else // still above the floor // phares | ||
594 | if (!(mo->flags & MF_NOGRAVITY)) | ||
595 | { | ||
596 | if (!mo->momz) | ||
597 | mo->momz = -GRAVITY; | ||
598 | mo->momz -= GRAVITY; | ||
599 | } | ||
600 | |||
601 | if (mo->z + mo->height > mo->ceilingz) | ||
602 | { | ||
603 | /* cph 2001/04/15 - | ||
604 | * Lost souls were meant to bounce off of ceilings; | ||
605 | * new comp_soul compatibility option added | ||
606 | */ | ||
607 | if (!comp[comp_soul] && mo->flags & MF_SKULLFLY) | ||
608 | mo->momz = -mo->momz; // the skull slammed into something | ||
609 | |||
610 | // hit the ceiling | ||
611 | |||
612 | if (mo->momz > 0) | ||
613 | mo->momz = 0; | ||
614 | |||
615 | mo->z = mo->ceilingz - mo->height; | ||
616 | |||
617 | /* cph 2001/04/15 - | ||
618 | * We might have hit a ceiling but had downward momentum (e.g. ceiling is | ||
619 | * lowering on us), so for old demos we must still do the buggy | ||
620 | * momentum reversal here | ||
621 | */ | ||
622 | if (comp[comp_soul] && mo->flags & MF_SKULLFLY) | ||
623 | mo->momz = -mo->momz; // the skull slammed into something | ||
624 | |||
625 | if ( (mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP) ) | ||
626 | { | ||
627 | P_ExplodeMissile (mo); | ||
628 | return; | ||
629 | } | ||
630 | } | ||
631 | } | ||
632 | |||
633 | // | ||
634 | // P_NightmareRespawn | ||
635 | // | ||
636 | |||
637 | static void P_NightmareRespawn(mobj_t* mobj) | ||
638 | { | ||
639 | fixed_t x; | ||
640 | fixed_t y; | ||
641 | fixed_t z; | ||
642 | subsector_t* ss; | ||
643 | mobj_t* mo; | ||
644 | mapthing_t* mthing; | ||
645 | |||
646 | x = mobj->spawnpoint.x << FRACBITS; | ||
647 | y = mobj->spawnpoint.y << FRACBITS; | ||
648 | |||
649 | /* haleyjd: stupid nightmare respawning bug fix | ||
650 | * | ||
651 | * 08/09/00: compatibility added, time to ramble :) | ||
652 | * This fixes the notorious nightmare respawning bug that causes monsters | ||
653 | * that didn't spawn at level startup to respawn at the point (0,0) | ||
654 | * regardless of that point's nature. SMMU and Eternity need this for | ||
655 | * script-spawned things like Halif Swordsmythe, as well. | ||
656 | * | ||
657 | * cph - copied from eternity, except comp_respawnfix becomes comp_respawn | ||
658 | * and the logic is reversed (i.e. like the rest of comp_ it *disables* | ||
659 | * the fix) | ||
660 | */ | ||
661 | if(!comp[comp_respawn] && !x && !y) | ||
662 | { | ||
663 | // spawnpoint was zeroed out, so use point of death instead | ||
664 | x = mobj->x; | ||
665 | y = mobj->y; | ||
666 | } | ||
667 | |||
668 | // something is occupying its position? | ||
669 | |||
670 | if (!P_CheckPosition (mobj, x, y) ) | ||
671 | return; // no respwan | ||
672 | |||
673 | // spawn a teleport fog at old spot | ||
674 | // because of removal of the body? | ||
675 | |||
676 | mo = P_SpawnMobj (mobj->x, | ||
677 | mobj->y, | ||
678 | mobj->subsector->sector->floorheight, | ||
679 | MT_TFOG); | ||
680 | |||
681 | // initiate teleport sound | ||
682 | |||
683 | S_StartSound (mo, sfx_telept); | ||
684 | |||
685 | // spawn a teleport fog at the new spot | ||
686 | |||
687 | ss = R_PointInSubsector (x,y); | ||
688 | |||
689 | mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_TFOG); | ||
690 | |||
691 | S_StartSound (mo, sfx_telept); | ||
692 | |||
693 | // spawn the new monster | ||
694 | |||
695 | mthing = &mobj->spawnpoint; | ||
696 | if (mobj->info->flags & MF_SPAWNCEILING) | ||
697 | z = ONCEILINGZ; | ||
698 | else | ||
699 | z = ONFLOORZ; | ||
700 | |||
701 | // inherit attributes from deceased one | ||
702 | |||
703 | mo = P_SpawnMobj (x,y,z, mobj->type); | ||
704 | mo->spawnpoint = mobj->spawnpoint; | ||
705 | mo->angle = ANG45 * (mthing->angle/45); | ||
706 | |||
707 | if (mthing->options & MTF_AMBUSH) | ||
708 | mo->flags |= MF_AMBUSH; | ||
709 | |||
710 | /* killough 11/98: transfer friendliness from deceased */ | ||
711 | mo->flags = (mo->flags & ~MF_FRIEND) | (mobj->flags & MF_FRIEND); | ||
712 | |||
713 | mo->reactiontime = 18; | ||
714 | |||
715 | // remove the old monster, | ||
716 | |||
717 | P_RemoveMobj (mobj); | ||
718 | } | ||
719 | |||
720 | |||
721 | // | ||
722 | // P_MobjThinker | ||
723 | // | ||
724 | |||
725 | void P_MobjThinker (mobj_t* mobj) | ||
726 | { | ||
727 | // killough 11/98: | ||
728 | // removed old code which looked at target references | ||
729 | // (we use pointer reference counting now) | ||
730 | |||
731 | mobj->PrevX = mobj->x; | ||
732 | mobj->PrevY = mobj->y; | ||
733 | mobj->PrevZ = mobj->z; | ||
734 | |||
735 | // momentum movement | ||
736 | if (mobj->momx | mobj->momy || mobj->flags & MF_SKULLFLY) | ||
737 | { | ||
738 | P_XYMovement(mobj); | ||
739 | if (mobj->thinker.function != P_MobjThinker) // cph - Must've been removed | ||
740 | return; // killough - mobj was removed | ||
741 | } | ||
742 | |||
743 | if (mobj->z != mobj->floorz || mobj->momz) | ||
744 | { | ||
745 | P_ZMovement(mobj); | ||
746 | if (mobj->thinker.function != P_MobjThinker) // cph - Must've been removed | ||
747 | return; // killough - mobj was removed | ||
748 | } | ||
749 | else | ||
750 | if (!(mobj->momx | mobj->momy) && !sentient(mobj)) | ||
751 | { // non-sentient objects at rest | ||
752 | mobj->intflags |= MIF_ARMED; // arm a mine which has come to rest | ||
753 | |||
754 | // killough 9/12/98: objects fall off ledges if they are hanging off | ||
755 | // slightly push off of ledge if hanging more than halfway off | ||
756 | |||
757 | if (mobj->z > mobj->dropoffz && // Only objects contacting dropoff | ||
758 | !(mobj->flags & MF_NOGRAVITY) && // Only objects which fall | ||
759 | !comp[comp_falloff]) // Not in old demos | ||
760 | P_ApplyTorque(mobj); // Apply torque | ||
761 | else | ||
762 | mobj->intflags &= ~MIF_FALLING, mobj->gear = 0; // Reset torque | ||
763 | } | ||
764 | |||
765 | // cycle through states, | ||
766 | // calling action functions at transitions | ||
767 | |||
768 | if (mobj->tics != -1) | ||
769 | { | ||
770 | mobj->tics--; | ||
771 | |||
772 | // you can cycle through multiple states in a tic | ||
773 | |||
774 | if (!mobj->tics) | ||
775 | if (!P_SetMobjState (mobj, mobj->state->nextstate) ) | ||
776 | return; // freed itself | ||
777 | } | ||
778 | else | ||
779 | { | ||
780 | |||
781 | // check for nightmare respawn | ||
782 | |||
783 | if (! (mobj->flags & MF_COUNTKILL) ) | ||
784 | return; | ||
785 | |||
786 | if (!respawnmonsters) | ||
787 | return; | ||
788 | |||
789 | mobj->movecount++; | ||
790 | |||
791 | if (mobj->movecount < 12*35) | ||
792 | return; | ||
793 | |||
794 | if (leveltime & 31) | ||
795 | return; | ||
796 | |||
797 | if (P_Random (pr_respawn) > 4) | ||
798 | return; | ||
799 | |||
800 | P_NightmareRespawn (mobj); | ||
801 | } | ||
802 | |||
803 | } | ||
804 | |||
805 | |||
806 | // | ||
807 | // P_SpawnMobj | ||
808 | // | ||
809 | mobj_t* P_SpawnMobj(fixed_t x,fixed_t y,fixed_t z,mobjtype_t type) | ||
810 | { | ||
811 | mobj_t* mobj; | ||
812 | state_t* st; | ||
813 | mobjinfo_t* info; | ||
814 | |||
815 | mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL); | ||
816 | memset (mobj, 0, sizeof (*mobj)); | ||
817 | info = &mobjinfo[type]; | ||
818 | mobj->type = type; | ||
819 | mobj->info = info; | ||
820 | mobj->x = x; | ||
821 | mobj->y = y; | ||
822 | mobj->radius = info->radius; | ||
823 | mobj->height = info->height; // phares | ||
824 | mobj->flags = info->flags; | ||
825 | |||
826 | /* killough 8/23/98: no friends, bouncers, or touchy things in old demos */ | ||
827 | if (!mbf_features) | ||
828 | mobj->flags &= ~(MF_BOUNCES | MF_FRIEND | MF_TOUCHY); | ||
829 | else | ||
830 | if (type == MT_PLAYER) // Except in old demos, players | ||
831 | mobj->flags |= MF_FRIEND; // are always friends. | ||
832 | |||
833 | mobj->health = info->spawnhealth; | ||
834 | |||
835 | if (gameskill != sk_nightmare) | ||
836 | mobj->reactiontime = info->reactiontime; | ||
837 | |||
838 | mobj->lastlook = P_Random (pr_lastlook) % MAXPLAYERS; | ||
839 | |||
840 | // do not set the state with P_SetMobjState, | ||
841 | // because action routines can not be called yet | ||
842 | |||
843 | st = &states[info->spawnstate]; | ||
844 | |||
845 | mobj->state = st; | ||
846 | mobj->tics = st->tics; | ||
847 | mobj->sprite = st->sprite; | ||
848 | mobj->frame = st->frame; | ||
849 | mobj->touching_sectorlist = NULL; // NULL head of sector list // phares 3/13/98 | ||
850 | |||
851 | // set subsector and/or block links | ||
852 | |||
853 | P_SetThingPosition (mobj); | ||
854 | |||
855 | mobj->dropoffz = /* killough 11/98: for tracking dropoffs */ | ||
856 | mobj->floorz = mobj->subsector->sector->floorheight; | ||
857 | mobj->ceilingz = mobj->subsector->sector->ceilingheight; | ||
858 | |||
859 | mobj->z = z == ONFLOORZ ? mobj->floorz : z == ONCEILINGZ ? | ||
860 | mobj->ceilingz - mobj->height : z; | ||
861 | |||
862 | mobj->PrevX = mobj->x; | ||
863 | mobj->PrevY = mobj->y; | ||
864 | mobj->PrevZ = mobj->z; | ||
865 | |||
866 | mobj->thinker.function = P_MobjThinker; | ||
867 | |||
868 | //e6y | ||
869 | mobj->friction = ORIG_FRICTION; // phares 3/17/98 | ||
870 | |||
871 | mobj->target = mobj->tracer = mobj->lastenemy = NULL; | ||
872 | P_AddThinker (&mobj->thinker); | ||
873 | if (!((mobj->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL))) | ||
874 | totallive++; | ||
875 | return mobj; | ||
876 | } | ||
877 | |||
878 | |||
879 | static mapthing_t itemrespawnque[ITEMQUESIZE]; | ||
880 | static int itemrespawntime[ITEMQUESIZE]; | ||
881 | int iquehead; | ||
882 | int iquetail; | ||
883 | |||
884 | |||
885 | // | ||
886 | // P_RemoveMobj | ||
887 | // | ||
888 | |||
889 | void P_RemoveMobj (mobj_t* mobj) | ||
890 | { | ||
891 | if ((mobj->flags & MF_SPECIAL) | ||
892 | && !(mobj->flags & MF_DROPPED) | ||
893 | && (mobj->type != MT_INV) | ||
894 | && (mobj->type != MT_INS)) | ||
895 | { | ||
896 | itemrespawnque[iquehead] = mobj->spawnpoint; | ||
897 | itemrespawntime[iquehead] = leveltime; | ||
898 | iquehead = (iquehead+1)&(ITEMQUESIZE-1); | ||
899 | |||
900 | // lose one off the end? | ||
901 | |||
902 | if (iquehead == iquetail) | ||
903 | iquetail = (iquetail+1)&(ITEMQUESIZE-1); | ||
904 | } | ||
905 | |||
906 | // unlink from sector and block lists | ||
907 | |||
908 | P_UnsetThingPosition (mobj); | ||
909 | |||
910 | // Delete all nodes on the current sector_list phares 3/16/98 | ||
911 | |||
912 | if (sector_list) | ||
913 | { | ||
914 | P_DelSeclist(sector_list); | ||
915 | sector_list = NULL; | ||
916 | } | ||
917 | |||
918 | // stop any playing sound | ||
919 | |||
920 | S_StopSound (mobj); | ||
921 | |||
922 | // killough 11/98: | ||
923 | // | ||
924 | // Remove any references to other mobjs. | ||
925 | // | ||
926 | // Older demos might depend on the fields being left alone, however, | ||
927 | // if multiple thinkers reference each other indirectly before the | ||
928 | // end of the current tic. | ||
929 | // CPhipps - only leave dead references in old demos; I hope lxdoom_1 level | ||
930 | // demos are rare and don't rely on this. I hope. | ||
931 | |||
932 | if ((compatibility_level >= lxdoom_1_compatibility) || | ||
933 | (!demorecording && !demoplayback)) { | ||
934 | P_SetTarget(&mobj->target, NULL); | ||
935 | P_SetTarget(&mobj->tracer, NULL); | ||
936 | P_SetTarget(&mobj->lastenemy, NULL); | ||
937 | } | ||
938 | // free block | ||
939 | |||
940 | P_RemoveThinker (&mobj->thinker); | ||
941 | } | ||
942 | |||
943 | |||
944 | /* | ||
945 | * P_FindDoomedNum | ||
946 | * | ||
947 | * Finds a mobj type with a matching doomednum | ||
948 | * | ||
949 | * killough 8/24/98: rewrote to use hashing | ||
950 | */ | ||
951 | |||
952 | static PUREFUNC int P_FindDoomedNum(unsigned type) | ||
953 | { | ||
954 | static struct { int first, next; } *hash; | ||
955 | register int i; | ||
956 | |||
957 | if (!hash) | ||
958 | { | ||
959 | hash = Z_Malloc(sizeof *hash * NUMMOBJTYPES, PU_CACHE, (void **) &hash); | ||
960 | for (i=0; i<NUMMOBJTYPES; i++) | ||
961 | hash[i].first = NUMMOBJTYPES; | ||
962 | for (i=0; i<NUMMOBJTYPES; i++) | ||
963 | if (mobjinfo[i].doomednum != -1) | ||
964 | { | ||
965 | unsigned h = (unsigned) mobjinfo[i].doomednum % NUMMOBJTYPES; | ||
966 | hash[i].next = hash[h].first; | ||
967 | hash[h].first = i; | ||
968 | } | ||
969 | } | ||
970 | |||
971 | i = hash[type % NUMMOBJTYPES].first; | ||
972 | while ((i < NUMMOBJTYPES) && ((unsigned)mobjinfo[i].doomednum != type)) | ||
973 | i = hash[i].next; | ||
974 | return i; | ||
975 | } | ||
976 | |||
977 | // | ||
978 | // P_RespawnSpecials | ||
979 | // | ||
980 | |||
981 | void P_RespawnSpecials (void) | ||
982 | { | ||
983 | fixed_t x; | ||
984 | fixed_t y; | ||
985 | fixed_t z; | ||
986 | subsector_t* ss; | ||
987 | mobj_t* mo; | ||
988 | mapthing_t* mthing; | ||
989 | int i; | ||
990 | |||
991 | // only respawn items in deathmatch | ||
992 | |||
993 | if (deathmatch != 2) | ||
994 | return; | ||
995 | |||
996 | // nothing left to respawn? | ||
997 | |||
998 | if (iquehead == iquetail) | ||
999 | return; | ||
1000 | |||
1001 | // wait at least 30 seconds | ||
1002 | |||
1003 | if (leveltime - itemrespawntime[iquetail] < 30*35) | ||
1004 | return; | ||
1005 | |||
1006 | mthing = &itemrespawnque[iquetail]; | ||
1007 | |||
1008 | x = mthing->x << FRACBITS; | ||
1009 | y = mthing->y << FRACBITS; | ||
1010 | |||
1011 | // spawn a teleport fog at the new spot | ||
1012 | |||
1013 | ss = R_PointInSubsector (x,y); | ||
1014 | mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_IFOG); | ||
1015 | S_StartSound (mo, sfx_itmbk); | ||
1016 | |||
1017 | // find which type to spawn | ||
1018 | |||
1019 | /* killough 8/23/98: use table for faster lookup */ | ||
1020 | i = P_FindDoomedNum(mthing->type); | ||
1021 | |||
1022 | // spawn it | ||
1023 | |||
1024 | if (mobjinfo[i].flags & MF_SPAWNCEILING) | ||
1025 | z = ONCEILINGZ; | ||
1026 | else | ||
1027 | z = ONFLOORZ; | ||
1028 | |||
1029 | mo = P_SpawnMobj (x,y,z, i); | ||
1030 | mo->spawnpoint = *mthing; | ||
1031 | mo->angle = ANG45 * (mthing->angle/45); | ||
1032 | |||
1033 | // pull it from the queue | ||
1034 | |||
1035 | iquetail = (iquetail+1)&(ITEMQUESIZE-1); | ||
1036 | } | ||
1037 | |||
1038 | // | ||
1039 | // P_SpawnPlayer | ||
1040 | // Called when a player is spawned on the level. | ||
1041 | // Most of the player structure stays unchanged | ||
1042 | // between levels. | ||
1043 | // | ||
1044 | |||
1045 | extern byte playernumtotrans[MAXPLAYERS]; | ||
1046 | |||
1047 | void P_SpawnPlayer (int n, const mapthing_t* mthing) | ||
1048 | { | ||
1049 | player_t* p; | ||
1050 | fixed_t x; | ||
1051 | fixed_t y; | ||
1052 | fixed_t z; | ||
1053 | mobj_t* mobj; | ||
1054 | int i; | ||
1055 | |||
1056 | // not playing? | ||
1057 | |||
1058 | if (!playeringame[n]) | ||
1059 | return; | ||
1060 | |||
1061 | p = &players[n]; | ||
1062 | |||
1063 | if (p->playerstate == PST_REBORN) | ||
1064 | G_PlayerReborn (mthing->type-1); | ||
1065 | |||
1066 | /* cph 2001/08/14 - use the options field of memorised player starts to | ||
1067 | * indicate whether the start really exists in the level. | ||
1068 | */ | ||
1069 | if (!mthing->options) | ||
1070 | I_Error("P_SpawnPlayer: attempt to spawn player at unavailable start point"); | ||
1071 | |||
1072 | x = mthing->x << FRACBITS; | ||
1073 | y = mthing->y << FRACBITS; | ||
1074 | z = ONFLOORZ; | ||
1075 | mobj = P_SpawnMobj (x,y,z, MT_PLAYER); | ||
1076 | |||
1077 | // set color translations for player sprites | ||
1078 | |||
1079 | mobj->flags |= playernumtotrans[n]<<MF_TRANSSHIFT; | ||
1080 | |||
1081 | mobj->angle = ANG45 * (mthing->angle/45); | ||
1082 | mobj->player = p; | ||
1083 | mobj->health = p->health; | ||
1084 | |||
1085 | p->mo = mobj; | ||
1086 | p->playerstate = PST_LIVE; | ||
1087 | p->refire = 0; | ||
1088 | p->message = NULL; | ||
1089 | p->damagecount = 0; | ||
1090 | p->bonuscount = 0; | ||
1091 | p->extralight = 0; | ||
1092 | p->fixedcolormap = 0; | ||
1093 | p->viewheight = VIEWHEIGHT; | ||
1094 | |||
1095 | p->momx = p->momy = 0; // killough 10/98: initialize bobbing to 0. | ||
1096 | |||
1097 | // setup gun psprite | ||
1098 | |||
1099 | P_SetupPsprites (p); | ||
1100 | |||
1101 | // give all cards in death match mode | ||
1102 | |||
1103 | if (deathmatch) | ||
1104 | for (i = 0 ; i < NUMCARDS ; i++) | ||
1105 | p->cards[i] = true; | ||
1106 | |||
1107 | if (mthing->type-1 == consoleplayer) | ||
1108 | { | ||
1109 | ST_Start(); // wake up the status bar | ||
1110 | HU_Start(); // wake up the heads up text | ||
1111 | } | ||
1112 | R_SmoothPlaying_Reset(p); // e6y | ||
1113 | } | ||
1114 | |||
1115 | /* | ||
1116 | * P_IsDoomnumAllowed() | ||
1117 | * Based on code taken from P_LoadThings() in src/p_setup.c Return TRUE | ||
1118 | * if the thing in question is expected to be available in the gamemode used. | ||
1119 | */ | ||
1120 | |||
1121 | boolean P_IsDoomnumAllowed(int doomnum) | ||
1122 | { | ||
1123 | // Do not spawn cool, new monsters if !commercial | ||
1124 | if (gamemode != commercial) | ||
1125 | switch(doomnum) | ||
1126 | { | ||
1127 | case 64: // Archvile | ||
1128 | case 65: // Former Human Commando | ||
1129 | case 66: // Revenant | ||
1130 | case 67: // Mancubus | ||
1131 | case 68: // Arachnotron | ||
1132 | case 69: // Hell Knight | ||
1133 | case 71: // Pain Elemental | ||
1134 | case 84: // Wolf SS | ||
1135 | case 88: // Boss Brain | ||
1136 | case 89: // Boss Shooter | ||
1137 | return false; | ||
1138 | } | ||
1139 | |||
1140 | return true; | ||
1141 | } | ||
1142 | |||
1143 | // | ||
1144 | // P_SpawnMapThing | ||
1145 | // The fields of the mapthing should | ||
1146 | // already be in host byte order. | ||
1147 | // | ||
1148 | |||
1149 | void P_SpawnMapThing (const mapthing_t* mthing) | ||
1150 | { | ||
1151 | int i; | ||
1152 | //int bit; | ||
1153 | mobj_t* mobj; | ||
1154 | fixed_t x; | ||
1155 | fixed_t y; | ||
1156 | fixed_t z; | ||
1157 | int options = mthing->options; /* cph 2001/07/07 - make writable copy */ | ||
1158 | |||
1159 | // killough 2/26/98: Ignore type-0 things as NOPs | ||
1160 | // phares 5/14/98: Ignore Player 5-8 starts (for now) | ||
1161 | |||
1162 | switch(mthing->type) | ||
1163 | { | ||
1164 | case 0: | ||
1165 | case DEN_PLAYER5: | ||
1166 | case DEN_PLAYER6: | ||
1167 | case DEN_PLAYER7: | ||
1168 | case DEN_PLAYER8: | ||
1169 | return; | ||
1170 | } | ||
1171 | |||
1172 | // killough 11/98: clear flags unused by Doom | ||
1173 | // | ||
1174 | // We clear the flags unused in Doom if we see flag mask 256 set, since | ||
1175 | // it is reserved to be 0 under the new scheme. A 1 in this reserved bit | ||
1176 | // indicates it's a Doom wad made by a Doom editor which puts 1's in | ||
1177 | // bits that weren't used in Doom (such as HellMaker wads). So we should | ||
1178 | // then simply ignore all upper bits. | ||
1179 | |||
1180 | if (demo_compatibility || | ||
1181 | (compatibility_level >= lxdoom_1_compatibility && | ||
1182 | options & MTF_RESERVED)) { | ||
1183 | if (!demo_compatibility) // cph - Add warning about bad thing flags | ||
1184 | lprintf(LO_WARN, "P_SpawnMapThing: correcting bad flags (%u) (thing type %d)\n", | ||
1185 | options, mthing->type); | ||
1186 | options &= MTF_EASY|MTF_NORMAL|MTF_HARD|MTF_AMBUSH|MTF_NOTSINGLE; | ||
1187 | } | ||
1188 | |||
1189 | // count deathmatch start positions | ||
1190 | |||
1191 | // doom2.exe has at most 10 deathmatch starts | ||
1192 | if (mthing->type == 11) | ||
1193 | { | ||
1194 | if (!(!compatibility || deathmatch_p-deathmatchstarts < 10)) { | ||
1195 | return; | ||
1196 | } else { | ||
1197 | // 1/11/98 killough -- new code removes limit on deathmatch starts: | ||
1198 | |||
1199 | size_t offset = deathmatch_p - deathmatchstarts; | ||
1200 | |||
1201 | if (offset >= num_deathmatchstarts) | ||
1202 | { | ||
1203 | num_deathmatchstarts = num_deathmatchstarts ? | ||
1204 | num_deathmatchstarts*2 : 16; | ||
1205 | deathmatchstarts = realloc(deathmatchstarts, | ||
1206 | num_deathmatchstarts * | ||
1207 | sizeof(*deathmatchstarts)); | ||
1208 | deathmatch_p = deathmatchstarts + offset; | ||
1209 | } | ||
1210 | memcpy(deathmatch_p++, mthing, sizeof(*mthing)); | ||
1211 | (deathmatch_p-1)->options = 1; | ||
1212 | return; | ||
1213 | } | ||
1214 | } | ||
1215 | |||
1216 | // check for players specially | ||
1217 | |||
1218 | if (mthing->type <= 4 && mthing->type > 0) // killough 2/26/98 -- fix crashes | ||
1219 | { | ||
1220 | #ifdef DOGS | ||
1221 | // killough 7/19/98: Marine's best friend :) | ||
1222 | if (!netgame && mthing->type > 1 && mthing->type <= dogs+1 && | ||
1223 | !players[mthing->type-1].secretcount) | ||
1224 | { // use secretcount to avoid multiple dogs in case of multiple starts | ||
1225 | players[mthing->type-1].secretcount = 1; | ||
1226 | |||
1227 | // killough 10/98: force it to be a friend | ||
1228 | options |= MTF_FRIEND; | ||
1229 | if(HelperThing != -1) // haleyjd 9/22/99: deh substitution | ||
1230 | { | ||
1231 | int type = HelperThing - 1; | ||
1232 | if(type >= 0 && type < NUMMOBJTYPES) | ||
1233 | { | ||
1234 | i = type; | ||
1235 | } | ||
1236 | else | ||
1237 | { | ||
1238 | doom_printf("Invalid value %i for helper, ignored.", HelperThing); | ||
1239 | i = MT_DOGS; | ||
1240 | } | ||
1241 | } | ||
1242 | else { | ||
1243 | i = MT_DOGS; | ||
1244 | } | ||
1245 | goto spawnit; | ||
1246 | } | ||
1247 | #endif | ||
1248 | |||
1249 | // save spots for respawning in coop games | ||
1250 | playerstarts[mthing->type-1] = *mthing; | ||
1251 | /* cph 2006/07/24 - use the otherwise-unused options field to flag that | ||
1252 | * this start is present (so we know which elements of the array are filled | ||
1253 | * in, in effect). Also note that the call below to P_SpawnPlayer must use | ||
1254 | * the playerstarts version with this field set */ | ||
1255 | playerstarts[mthing->type-1].options = 1; | ||
1256 | |||
1257 | if (!deathmatch) | ||
1258 | P_SpawnPlayer (mthing->type-1, &playerstarts[mthing->type-1]); | ||
1259 | return; | ||
1260 | } | ||
1261 | |||
1262 | // check for apropriate skill level | ||
1263 | |||
1264 | /* jff "not single" thing flag */ | ||
1265 | if (!netgame && options & MTF_NOTSINGLE) | ||
1266 | return; | ||
1267 | |||
1268 | //jff 3/30/98 implement "not deathmatch" thing flag | ||
1269 | |||
1270 | if (netgame && deathmatch && options & MTF_NOTDM) | ||
1271 | return; | ||
1272 | |||
1273 | //jff 3/30/98 implement "not cooperative" thing flag | ||
1274 | |||
1275 | if (netgame && !deathmatch && options & MTF_NOTCOOP) | ||
1276 | return; | ||
1277 | |||
1278 | // killough 11/98: simplify | ||
1279 | if (gameskill == sk_baby || gameskill == sk_easy ? | ||
1280 | !(options & MTF_EASY) : | ||
1281 | gameskill == sk_hard || gameskill == sk_nightmare ? | ||
1282 | !(options & MTF_HARD) : !(options & MTF_NORMAL)) | ||
1283 | return; | ||
1284 | |||
1285 | // find which type to spawn | ||
1286 | |||
1287 | // killough 8/23/98: use table for faster lookup | ||
1288 | i = P_FindDoomedNum(mthing->type); | ||
1289 | |||
1290 | // phares 5/16/98: | ||
1291 | // Do not abort because of an unknown thing. Ignore it, but post a | ||
1292 | // warning message for the player. | ||
1293 | |||
1294 | if (i == NUMMOBJTYPES) | ||
1295 | { | ||
1296 | doom_printf("Unknown Thing type %i at (%i, %i)",mthing->type,mthing->x,mthing->y); | ||
1297 | return; | ||
1298 | } | ||
1299 | |||
1300 | // don't spawn keycards and players in deathmatch | ||
1301 | |||
1302 | if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH) | ||
1303 | return; | ||
1304 | |||
1305 | // don't spawn any monsters if -nomonsters | ||
1306 | |||
1307 | if (nomonsters && (i == MT_SKULL || (mobjinfo[i].flags & MF_COUNTKILL))) | ||
1308 | return; | ||
1309 | |||
1310 | // spawn it | ||
1311 | #ifdef DOGS | ||
1312 | spawnit: | ||
1313 | #endif | ||
1314 | |||
1315 | x = mthing->x << FRACBITS; | ||
1316 | y = mthing->y << FRACBITS; | ||
1317 | |||
1318 | if (mobjinfo[i].flags & MF_SPAWNCEILING) | ||
1319 | z = ONCEILINGZ; | ||
1320 | else | ||
1321 | z = ONFLOORZ; | ||
1322 | |||
1323 | mobj = P_SpawnMobj (x,y,z, i); | ||
1324 | mobj->spawnpoint = *mthing; | ||
1325 | |||
1326 | if (mobj->tics > 0) | ||
1327 | mobj->tics = 1 + (P_Random (pr_spawnthing) % mobj->tics); | ||
1328 | |||
1329 | if (!(mobj->flags & MF_FRIEND) && | ||
1330 | options & MTF_FRIEND && | ||
1331 | mbf_features) | ||
1332 | { | ||
1333 | mobj->flags |= MF_FRIEND; // killough 10/98: | ||
1334 | P_UpdateThinker(&mobj->thinker); // transfer friendliness flag | ||
1335 | } | ||
1336 | |||
1337 | /* killough 7/20/98: exclude friends */ | ||
1338 | if (!((mobj->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL))) | ||
1339 | totalkills++; | ||
1340 | |||
1341 | if (mobj->flags & MF_COUNTITEM) | ||
1342 | totalitems++; | ||
1343 | |||
1344 | mobj->angle = ANG45 * (mthing->angle/45); | ||
1345 | if (options & MTF_AMBUSH) | ||
1346 | mobj->flags |= MF_AMBUSH; | ||
1347 | } | ||
1348 | |||
1349 | |||
1350 | // | ||
1351 | // GAME SPAWN FUNCTIONS | ||
1352 | // | ||
1353 | |||
1354 | // | ||
1355 | // P_SpawnPuff | ||
1356 | // | ||
1357 | |||
1358 | extern fixed_t attackrange; | ||
1359 | |||
1360 | void P_SpawnPuff(fixed_t x,fixed_t y,fixed_t z) | ||
1361 | { | ||
1362 | mobj_t* th; | ||
1363 | // killough 5/5/98: remove dependence on order of evaluation: | ||
1364 | int t = P_Random(pr_spawnpuff); | ||
1365 | z += (t - P_Random(pr_spawnpuff))<<10; | ||
1366 | |||
1367 | th = P_SpawnMobj (x,y,z, MT_PUFF); | ||
1368 | th->momz = FRACUNIT; | ||
1369 | th->tics -= P_Random(pr_spawnpuff)&3; | ||
1370 | |||
1371 | if (th->tics < 1) | ||
1372 | th->tics = 1; | ||
1373 | |||
1374 | // don't make punches spark on the wall | ||
1375 | |||
1376 | if (attackrange == MELEERANGE) | ||
1377 | P_SetMobjState (th, S_PUFF3); | ||
1378 | } | ||
1379 | |||
1380 | |||
1381 | // | ||
1382 | // P_SpawnBlood | ||
1383 | // | ||
1384 | void P_SpawnBlood(fixed_t x,fixed_t y,fixed_t z,int damage) | ||
1385 | { | ||
1386 | mobj_t* th; | ||
1387 | // killough 5/5/98: remove dependence on order of evaluation: | ||
1388 | int t = P_Random(pr_spawnblood); | ||
1389 | z += (t - P_Random(pr_spawnblood))<<10; | ||
1390 | th = P_SpawnMobj(x,y,z, MT_BLOOD); | ||
1391 | th->momz = FRACUNIT*2; | ||
1392 | th->tics -= P_Random(pr_spawnblood)&3; | ||
1393 | |||
1394 | if (th->tics < 1) | ||
1395 | th->tics = 1; | ||
1396 | |||
1397 | if (damage <= 12 && damage >= 9) | ||
1398 | P_SetMobjState (th,S_BLOOD2); | ||
1399 | else if (damage < 9) | ||
1400 | P_SetMobjState (th,S_BLOOD3); | ||
1401 | } | ||
1402 | |||
1403 | |||
1404 | // | ||
1405 | // P_CheckMissileSpawn | ||
1406 | // Moves the missile forward a bit | ||
1407 | // and possibly explodes it right there. | ||
1408 | // | ||
1409 | |||
1410 | void P_CheckMissileSpawn (mobj_t* th) | ||
1411 | { | ||
1412 | th->tics -= P_Random(pr_missile)&3; | ||
1413 | if (th->tics < 1) | ||
1414 | th->tics = 1; | ||
1415 | |||
1416 | // move a little forward so an angle can | ||
1417 | // be computed if it immediately explodes | ||
1418 | |||
1419 | th->x += (th->momx>>1); | ||
1420 | th->y += (th->momy>>1); | ||
1421 | th->z += (th->momz>>1); | ||
1422 | |||
1423 | // killough 8/12/98: for non-missile objects (e.g. grenades) | ||
1424 | if (!(th->flags & MF_MISSILE) && mbf_features) | ||
1425 | return; | ||
1426 | |||
1427 | // killough 3/15/98: no dropoff (really = don't care for missiles) | ||
1428 | |||
1429 | if (!P_TryMove (th, th->x, th->y, false)) | ||
1430 | P_ExplodeMissile (th); | ||
1431 | } | ||
1432 | |||
1433 | |||
1434 | // | ||
1435 | // P_SpawnMissile | ||
1436 | // | ||
1437 | |||
1438 | mobj_t* P_SpawnMissile(mobj_t* source,mobj_t* dest,mobjtype_t type) | ||
1439 | { | ||
1440 | mobj_t* th; | ||
1441 | angle_t an; | ||
1442 | int dist; | ||
1443 | |||
1444 | th = P_SpawnMobj (source->x,source->y,source->z + 4*8*FRACUNIT,type); | ||
1445 | |||
1446 | if (th->info->seesound) | ||
1447 | S_StartSound (th, th->info->seesound); | ||
1448 | |||
1449 | P_SetTarget(&th->target, source); // where it came from | ||
1450 | an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y); | ||
1451 | |||
1452 | // fuzzy player | ||
1453 | |||
1454 | if (dest->flags & MF_SHADOW) | ||
1455 | { // killough 5/5/98: remove dependence on order of evaluation: | ||
1456 | int t = P_Random(pr_shadow); | ||
1457 | an += (t - P_Random(pr_shadow))<<20; | ||
1458 | } | ||
1459 | |||
1460 | th->angle = an; | ||
1461 | an >>= ANGLETOFINESHIFT; | ||
1462 | th->momx = FixedMul (th->info->speed, finecosine[an]); | ||
1463 | th->momy = FixedMul (th->info->speed, finesine[an]); | ||
1464 | |||
1465 | dist = P_AproxDistance (dest->x - source->x, dest->y - source->y); | ||
1466 | dist = dist / th->info->speed; | ||
1467 | |||
1468 | if (dist < 1) | ||
1469 | dist = 1; | ||
1470 | |||
1471 | th->momz = (dest->z - source->z) / dist; | ||
1472 | P_CheckMissileSpawn (th); | ||
1473 | |||
1474 | return th; | ||
1475 | } | ||
1476 | |||
1477 | |||
1478 | // | ||
1479 | // P_SpawnPlayerMissile | ||
1480 | // Tries to aim at a nearby monster | ||
1481 | // | ||
1482 | |||
1483 | void P_SpawnPlayerMissile(mobj_t* source,mobjtype_t type) | ||
1484 | { | ||
1485 | mobj_t *th; | ||
1486 | fixed_t x, y, z, slope = 0; | ||
1487 | |||
1488 | // see which target is to be aimed at | ||
1489 | |||
1490 | angle_t an = source->angle; | ||
1491 | |||
1492 | // killough 7/19/98: autoaiming was not in original beta | ||
1493 | { | ||
1494 | // killough 8/2/98: prefer autoaiming at enemies | ||
1495 | uint_64_t mask = mbf_features ? MF_FRIEND : 0; | ||
1496 | |||
1497 | do | ||
1498 | { | ||
1499 | slope = P_AimLineAttack(source, an, 16*64*FRACUNIT, mask); | ||
1500 | if (!linetarget) | ||
1501 | slope = P_AimLineAttack(source, an += 1<<26, 16*64*FRACUNIT, mask); | ||
1502 | if (!linetarget) | ||
1503 | slope = P_AimLineAttack(source, an -= 2<<26, 16*64*FRACUNIT, mask); | ||
1504 | if (!linetarget) | ||
1505 | an = source->angle, slope = 0; | ||
1506 | } | ||
1507 | while (mask && (mask=0, !linetarget)); // killough 8/2/98 | ||
1508 | } | ||
1509 | |||
1510 | x = source->x; | ||
1511 | y = source->y; | ||
1512 | z = source->z + 4*8*FRACUNIT; | ||
1513 | |||
1514 | th = P_SpawnMobj (x,y,z, type); | ||
1515 | |||
1516 | if (th->info->seesound) | ||
1517 | S_StartSound (th, th->info->seesound); | ||
1518 | |||
1519 | P_SetTarget(&th->target, source); | ||
1520 | th->angle = an; | ||
1521 | th->momx = FixedMul(th->info->speed,finecosine[an>>ANGLETOFINESHIFT]); | ||
1522 | th->momy = FixedMul(th->info->speed,finesine[an>>ANGLETOFINESHIFT]); | ||
1523 | th->momz = FixedMul(th->info->speed,slope); | ||
1524 | |||
1525 | P_CheckMissileSpawn(th); | ||
1526 | } | ||