Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
8547 | maxcodehac | 1 | // Emacs style mode select -*- C++ -*- |
2 | //----------------------------------------------------------------------------- |
||
3 | // |
||
4 | // $Id:$ |
||
5 | // |
||
6 | // Copyright (C) 1993-1996 by id Software, Inc. |
||
7 | // |
||
8 | // This source is available for distribution and/or modification |
||
9 | // only under the terms of the DOOM Source Code License as |
||
10 | // published by id Software. All rights reserved. |
||
11 | // |
||
12 | // The source is distributed in the hope that it will be useful, |
||
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 | // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License |
||
15 | // for more details. |
||
16 | // |
||
17 | // $Log:$ |
||
18 | // |
||
19 | // DESCRIPTION: |
||
20 | // Moving object handling. Spawn functions. |
||
21 | // |
||
22 | //----------------------------------------------------------------------------- |
||
23 | |||
24 | static const char |
||
25 | rcsid[] = "$Id: p_mobj.c,v 1.5 1997/02/03 22:45:12 b1 Exp $"; |
||
26 | |||
27 | #include "i_system.h" |
||
28 | #include "z_zone.h" |
||
29 | #include "m_random.h" |
||
30 | |||
31 | #include "doomdef.h" |
||
32 | #include "p_local.h" |
||
33 | #include "sounds.h" |
||
34 | |||
35 | #include "st_stuff.h" |
||
36 | #include "hu_stuff.h" |
||
37 | |||
38 | #include "s_sound.h" |
||
39 | |||
40 | #include "doomstat.h" |
||
41 | |||
42 | |||
43 | void G_PlayerReborn (int player); |
||
44 | void P_SpawnMapThing (mapthing_t* mthing); |
||
45 | |||
46 | |||
47 | // |
||
48 | // P_SetMobjState |
||
49 | // Returns true if the mobj is still present. |
||
50 | // |
||
51 | int test; |
||
52 | |||
53 | boolean |
||
54 | P_SetMobjState |
||
55 | ( mobj_t* mobj, |
||
56 | statenum_t state ) |
||
57 | { |
||
58 | state_t* st; |
||
59 | |||
60 | do |
||
61 | { |
||
62 | if (state == S_NULL) |
||
63 | { |
||
64 | mobj->state = (state_t *) S_NULL; |
||
65 | P_RemoveMobj (mobj); |
||
66 | return false; |
||
67 | } |
||
68 | |||
69 | st = &states[state]; |
||
70 | mobj->state = st; |
||
71 | mobj->tics = st->tics; |
||
72 | mobj->sprite = st->sprite; |
||
73 | mobj->frame = st->frame; |
||
74 | |||
75 | // Modified handling. |
||
76 | // Call action functions when the state is set |
||
77 | if (st->action.acp1) |
||
78 | st->action.acp1(mobj); |
||
79 | |||
80 | state = st->nextstate; |
||
81 | } while (!mobj->tics); |
||
82 | |||
83 | return true; |
||
84 | } |
||
85 | |||
86 | |||
87 | // |
||
88 | // P_ExplodeMissile |
||
89 | // |
||
90 | void P_ExplodeMissile (mobj_t* mo) |
||
91 | { |
||
92 | mo->momx = mo->momy = mo->momz = 0; |
||
93 | |||
94 | P_SetMobjState (mo, mobjinfo[mo->type].deathstate); |
||
95 | |||
96 | mo->tics -= P_Random()&3; |
||
97 | |||
98 | if (mo->tics < 1) |
||
99 | mo->tics = 1; |
||
100 | |||
101 | mo->flags &= ~MF_MISSILE; |
||
102 | |||
103 | if (mo->info->deathsound) |
||
104 | S_StartSound (mo, mo->info->deathsound); |
||
105 | } |
||
106 | |||
107 | |||
108 | // |
||
109 | // P_XYMovement |
||
110 | // |
||
111 | #define STOPSPEED 0x1000 |
||
112 | #define FRICTION 0xe800 |
||
113 | |||
114 | void P_XYMovement (mobj_t* mo) |
||
115 | { |
||
116 | fixed_t ptryx; |
||
117 | fixed_t ptryy; |
||
118 | player_t* player; |
||
119 | fixed_t xmove; |
||
120 | fixed_t ymove; |
||
121 | |||
122 | if (!mo->momx && !mo->momy) |
||
123 | { |
||
124 | if (mo->flags & MF_SKULLFLY) |
||
125 | { |
||
126 | // the skull slammed into something |
||
127 | mo->flags &= ~MF_SKULLFLY; |
||
128 | mo->momx = mo->momy = mo->momz = 0; |
||
129 | |||
130 | P_SetMobjState (mo, mo->info->spawnstate); |
||
131 | } |
||
132 | return; |
||
133 | } |
||
134 | |||
135 | player = mo->player; |
||
136 | |||
137 | if (mo->momx > MAXMOVE) |
||
138 | mo->momx = MAXMOVE; |
||
139 | else if (mo->momx < -MAXMOVE) |
||
140 | mo->momx = -MAXMOVE; |
||
141 | |||
142 | if (mo->momy > MAXMOVE) |
||
143 | mo->momy = MAXMOVE; |
||
144 | else if (mo->momy < -MAXMOVE) |
||
145 | mo->momy = -MAXMOVE; |
||
146 | |||
147 | xmove = mo->momx; |
||
148 | ymove = mo->momy; |
||
149 | |||
150 | do |
||
151 | { |
||
152 | if (xmove > MAXMOVE/2 || ymove > MAXMOVE/2) |
||
153 | { |
||
154 | ptryx = mo->x + xmove/2; |
||
155 | ptryy = mo->y + ymove/2; |
||
156 | xmove >>= 1; |
||
157 | ymove >>= 1; |
||
158 | } |
||
159 | else |
||
160 | { |
||
161 | ptryx = mo->x + xmove; |
||
162 | ptryy = mo->y + ymove; |
||
163 | xmove = ymove = 0; |
||
164 | } |
||
165 | |||
166 | if (!P_TryMove (mo, ptryx, ptryy)) |
||
167 | { |
||
168 | // blocked move |
||
169 | if (mo->player) |
||
170 | { // try to slide along it |
||
171 | P_SlideMove (mo); |
||
172 | } |
||
173 | else if (mo->flags & MF_MISSILE) |
||
174 | { |
||
175 | // explode a missile |
||
176 | if (ceilingline && |
||
177 | ceilingline->backsector && |
||
178 | ceilingline->backsector->ceilingpic == skyflatnum) |
||
179 | { |
||
180 | // Hack to prevent missiles exploding |
||
181 | // against the sky. |
||
182 | // Does not handle sky floors. |
||
183 | P_RemoveMobj (mo); |
||
184 | return; |
||
185 | } |
||
186 | P_ExplodeMissile (mo); |
||
187 | } |
||
188 | else |
||
189 | mo->momx = mo->momy = 0; |
||
190 | } |
||
191 | } while (xmove || ymove); |
||
192 | |||
193 | // slow down |
||
194 | if (player && player->cheats & CF_NOMOMENTUM) |
||
195 | { |
||
196 | // debug option for no sliding at all |
||
197 | mo->momx = mo->momy = 0; |
||
198 | return; |
||
199 | } |
||
200 | |||
201 | if (mo->flags & (MF_MISSILE | MF_SKULLFLY) ) |
||
202 | return; // no friction for missiles ever |
||
203 | |||
204 | if (mo->z > mo->floorz) |
||
205 | return; // no friction when airborne |
||
206 | |||
207 | if (mo->flags & MF_CORPSE) |
||
208 | { |
||
209 | // do not stop sliding |
||
210 | // if halfway off a step with some momentum |
||
211 | if (mo->momx > FRACUNIT/4 |
||
212 | || mo->momx < -FRACUNIT/4 |
||
213 | || mo->momy > FRACUNIT/4 |
||
214 | || mo->momy < -FRACUNIT/4) |
||
215 | { |
||
216 | if (mo->floorz != mo->subsector->sector->floorheight) |
||
217 | return; |
||
218 | } |
||
219 | } |
||
220 | |||
221 | if (mo->momx > -STOPSPEED |
||
222 | && mo->momx < STOPSPEED |
||
223 | && mo->momy > -STOPSPEED |
||
224 | && mo->momy < STOPSPEED |
||
225 | && (!player |
||
226 | || (player->cmd.forwardmove== 0 |
||
227 | && player->cmd.sidemove == 0 ) ) ) |
||
228 | { |
||
229 | // if in a walking frame, stop moving |
||
230 | if ( player&&(unsigned)((player->mo->state - states)- S_PLAY_RUN1) < 4) |
||
231 | P_SetMobjState (player->mo, S_PLAY); |
||
232 | |||
233 | mo->momx = 0; |
||
234 | mo->momy = 0; |
||
235 | } |
||
236 | else |
||
237 | { |
||
238 | mo->momx = FixedMul (mo->momx, FRICTION); |
||
239 | mo->momy = FixedMul (mo->momy, FRICTION); |
||
240 | } |
||
241 | } |
||
242 | |||
243 | // |
||
244 | // P_ZMovement |
||
245 | // |
||
246 | void P_ZMovement (mobj_t* mo) |
||
247 | { |
||
248 | fixed_t dist; |
||
249 | fixed_t delta; |
||
250 | |||
251 | // check for smooth step up |
||
252 | if (mo->player && mo->z < mo->floorz) |
||
253 | { |
||
254 | mo->player->viewheight -= mo->floorz-mo->z; |
||
255 | |||
256 | mo->player->deltaviewheight |
||
257 | = (VIEWHEIGHT - mo->player->viewheight)>>3; |
||
258 | } |
||
259 | |||
260 | // adjust height |
||
261 | mo->z += mo->momz; |
||
262 | |||
263 | if ( mo->flags & MF_FLOAT |
||
264 | && mo->target) |
||
265 | { |
||
266 | // float down towards target if too close |
||
267 | if ( !(mo->flags & MF_SKULLFLY) |
||
268 | && !(mo->flags & MF_INFLOAT) ) |
||
269 | { |
||
270 | dist = P_AproxDistance (mo->x - mo->target->x, |
||
271 | mo->y - mo->target->y); |
||
272 | |||
273 | delta =(mo->target->z + (mo->height>>1)) - mo->z; |
||
274 | |||
275 | if (delta<0 && dist < -(delta*3) ) |
||
276 | mo->z -= FLOATSPEED; |
||
277 | else if (delta>0 && dist < (delta*3) ) |
||
278 | mo->z += FLOATSPEED; |
||
279 | } |
||
280 | |||
281 | } |
||
282 | |||
283 | // clip movement |
||
284 | if (mo->z <= mo->floorz) |
||
285 | { |
||
286 | // hit the floor |
||
287 | |||
288 | // Note (id): |
||
289 | // somebody left this after the setting momz to 0, |
||
290 | // kinda useless there. |
||
291 | if (mo->flags & MF_SKULLFLY) |
||
292 | { |
||
293 | // the skull slammed into something |
||
294 | mo->momz = -mo->momz; |
||
295 | } |
||
296 | |||
297 | if (mo->momz < 0) |
||
298 | { |
||
299 | if (mo->player |
||
300 | && mo->momz < -GRAVITY*8) |
||
301 | { |
||
302 | // Squat down. |
||
303 | // Decrease viewheight for a moment |
||
304 | // after hitting the ground (hard), |
||
305 | // and utter appropriate sound. |
||
306 | mo->player->deltaviewheight = mo->momz>>3; |
||
307 | S_StartSound (mo, sfx_oof); |
||
308 | } |
||
309 | mo->momz = 0; |
||
310 | } |
||
311 | mo->z = mo->floorz; |
||
312 | |||
313 | if ( (mo->flags & MF_MISSILE) |
||
314 | && !(mo->flags & MF_NOCLIP) ) |
||
315 | { |
||
316 | P_ExplodeMissile (mo); |
||
317 | return; |
||
318 | } |
||
319 | } |
||
320 | else if (! (mo->flags & MF_NOGRAVITY) ) |
||
321 | { |
||
322 | if (mo->momz == 0) |
||
323 | mo->momz = -GRAVITY*2; |
||
324 | else |
||
325 | mo->momz -= GRAVITY; |
||
326 | } |
||
327 | |||
328 | if (mo->z + mo->height > mo->ceilingz) |
||
329 | { |
||
330 | // hit the ceiling |
||
331 | if (mo->momz > 0) |
||
332 | mo->momz = 0; |
||
333 | { |
||
334 | mo->z = mo->ceilingz - mo->height; |
||
335 | } |
||
336 | |||
337 | if (mo->flags & MF_SKULLFLY) |
||
338 | { // the skull slammed into something |
||
339 | mo->momz = -mo->momz; |
||
340 | } |
||
341 | |||
342 | if ( (mo->flags & MF_MISSILE) |
||
343 | && !(mo->flags & MF_NOCLIP) ) |
||
344 | { |
||
345 | P_ExplodeMissile (mo); |
||
346 | return; |
||
347 | } |
||
348 | } |
||
349 | } |
||
350 | |||
351 | |||
352 | |||
353 | // |
||
354 | // P_NightmareRespawn |
||
355 | // |
||
356 | void |
||
357 | P_NightmareRespawn (mobj_t* mobj) |
||
358 | { |
||
359 | fixed_t x; |
||
360 | fixed_t y; |
||
361 | fixed_t z; |
||
362 | subsector_t* ss; |
||
363 | mobj_t* mo; |
||
364 | mapthing_t* mthing; |
||
365 | |||
366 | x = mobj->spawnpoint.x << FRACBITS; |
||
367 | y = mobj->spawnpoint.y << FRACBITS; |
||
368 | |||
369 | // somthing is occupying it's position? |
||
370 | if (!P_CheckPosition (mobj, x, y) ) |
||
371 | return; // no respwan |
||
372 | |||
373 | // spawn a teleport fog at old spot |
||
374 | // because of removal of the body? |
||
375 | mo = P_SpawnMobj (mobj->x, |
||
376 | mobj->y, |
||
377 | mobj->subsector->sector->floorheight , MT_TFOG); |
||
378 | // initiate teleport sound |
||
379 | S_StartSound (mo, sfx_telept); |
||
380 | |||
381 | // spawn a teleport fog at the new spot |
||
382 | ss = R_PointInSubsector (x,y); |
||
383 | |||
384 | mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_TFOG); |
||
385 | |||
386 | S_StartSound (mo, sfx_telept); |
||
387 | |||
388 | // spawn the new monster |
||
389 | mthing = &mobj->spawnpoint; |
||
390 | |||
391 | // spawn it |
||
392 | if (mobj->info->flags & MF_SPAWNCEILING) |
||
393 | z = ONCEILINGZ; |
||
394 | else |
||
395 | z = ONFLOORZ; |
||
396 | |||
397 | // inherit attributes from deceased one |
||
398 | mo = P_SpawnMobj (x,y,z, mobj->type); |
||
399 | mo->spawnpoint = mobj->spawnpoint; |
||
400 | mo->angle = ANG45 * (mthing->angle/45); |
||
401 | |||
402 | if (mthing->options & MTF_AMBUSH) |
||
403 | mo->flags |= MF_AMBUSH; |
||
404 | |||
405 | mo->reactiontime = 18; |
||
406 | |||
407 | // remove the old monster, |
||
408 | P_RemoveMobj (mobj); |
||
409 | } |
||
410 | |||
411 | |||
412 | // |
||
413 | // P_MobjThinker |
||
414 | // |
||
415 | void P_MobjThinker (mobj_t* mobj) |
||
416 | { |
||
417 | // momentum movement |
||
418 | if (mobj->momx |
||
419 | || mobj->momy |
||
420 | || (mobj->flags&MF_SKULLFLY) ) |
||
421 | { |
||
422 | P_XYMovement (mobj); |
||
423 | |||
424 | // FIXME: decent NOP/NULL/Nil function pointer please. |
||
425 | if (mobj->thinker.function.acv == (actionf_v) (-1)) |
||
426 | return; // mobj was removed |
||
427 | } |
||
428 | if ( (mobj->z != mobj->floorz) |
||
429 | || mobj->momz ) |
||
430 | { |
||
431 | P_ZMovement (mobj); |
||
432 | |||
433 | // FIXME: decent NOP/NULL/Nil function pointer please. |
||
434 | if (mobj->thinker.function.acv == (actionf_v) (-1)) |
||
435 | return; // mobj was removed |
||
436 | } |
||
437 | |||
438 | |||
439 | // cycle through states, |
||
440 | // calling action functions at transitions |
||
441 | if (mobj->tics != -1) |
||
442 | { |
||
443 | mobj->tics--; |
||
444 | |||
445 | // you can cycle through multiple states in a tic |
||
446 | if (!mobj->tics) |
||
447 | if (!P_SetMobjState (mobj, mobj->state->nextstate) ) |
||
448 | return; // freed itself |
||
449 | } |
||
450 | else |
||
451 | { |
||
452 | // check for nightmare respawn |
||
453 | if (! (mobj->flags & MF_COUNTKILL) ) |
||
454 | return; |
||
455 | |||
456 | if (!respawnmonsters) |
||
457 | return; |
||
458 | |||
459 | mobj->movecount++; |
||
460 | |||
461 | if (mobj->movecount < 12*35) |
||
462 | return; |
||
463 | |||
464 | if ( leveltime&31 ) |
||
465 | return; |
||
466 | |||
467 | if (P_Random () > 4) |
||
468 | return; |
||
469 | |||
470 | P_NightmareRespawn (mobj); |
||
471 | } |
||
472 | |||
473 | } |
||
474 | |||
475 | |||
476 | // |
||
477 | // P_SpawnMobj |
||
478 | // |
||
479 | mobj_t* |
||
480 | P_SpawnMobj |
||
481 | ( fixed_t x, |
||
482 | fixed_t y, |
||
483 | fixed_t z, |
||
484 | mobjtype_t type ) |
||
485 | { |
||
486 | mobj_t* mobj; |
||
487 | state_t* st; |
||
488 | mobjinfo_t* info; |
||
489 | |||
490 | mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL); |
||
491 | memset (mobj, 0, sizeof (*mobj)); |
||
492 | info = &mobjinfo[type]; |
||
493 | |||
494 | mobj->type = type; |
||
495 | mobj->info = info; |
||
496 | mobj->x = x; |
||
497 | mobj->y = y; |
||
498 | mobj->radius = info->radius; |
||
499 | mobj->height = info->height; |
||
500 | mobj->flags = info->flags; |
||
501 | mobj->health = info->spawnhealth; |
||
502 | |||
503 | if (gameskill != sk_nightmare) |
||
504 | mobj->reactiontime = info->reactiontime; |
||
505 | |||
506 | mobj->lastlook = P_Random () % MAXPLAYERS; |
||
507 | // do not set the state with P_SetMobjState, |
||
508 | // because action routines can not be called yet |
||
509 | st = &states[info->spawnstate]; |
||
510 | |||
511 | mobj->state = st; |
||
512 | mobj->tics = st->tics; |
||
513 | mobj->sprite = st->sprite; |
||
514 | mobj->frame = st->frame; |
||
515 | |||
516 | // set subsector and/or block links |
||
517 | P_SetThingPosition (mobj); |
||
518 | |||
519 | mobj->floorz = mobj->subsector->sector->floorheight; |
||
520 | mobj->ceilingz = mobj->subsector->sector->ceilingheight; |
||
521 | |||
522 | if (z == ONFLOORZ) |
||
523 | mobj->z = mobj->floorz; |
||
524 | else if (z == ONCEILINGZ) |
||
525 | mobj->z = mobj->ceilingz - mobj->info->height; |
||
526 | else |
||
527 | mobj->z = z; |
||
528 | |||
529 | mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker; |
||
530 | |||
531 | P_AddThinker (&mobj->thinker); |
||
532 | |||
533 | return mobj; |
||
534 | } |
||
535 | |||
536 | |||
537 | // |
||
538 | // P_RemoveMobj |
||
539 | // |
||
540 | mapthing_t itemrespawnque[ITEMQUESIZE]; |
||
541 | int itemrespawntime[ITEMQUESIZE]; |
||
542 | int iquehead; |
||
543 | int iquetail; |
||
544 | |||
545 | |||
546 | void P_RemoveMobj (mobj_t* mobj) |
||
547 | { |
||
548 | if ((mobj->flags & MF_SPECIAL) |
||
549 | && !(mobj->flags & MF_DROPPED) |
||
550 | && (mobj->type != MT_INV) |
||
551 | && (mobj->type != MT_INS)) |
||
552 | { |
||
553 | itemrespawnque[iquehead] = mobj->spawnpoint; |
||
554 | itemrespawntime[iquehead] = leveltime; |
||
555 | iquehead = (iquehead+1)&(ITEMQUESIZE-1); |
||
556 | |||
557 | // lose one off the end? |
||
558 | if (iquehead == iquetail) |
||
559 | iquetail = (iquetail+1)&(ITEMQUESIZE-1); |
||
560 | } |
||
561 | |||
562 | // unlink from sector and block lists |
||
563 | P_UnsetThingPosition (mobj); |
||
564 | |||
565 | // stop any playing sound |
||
566 | S_StopSound (mobj); |
||
567 | |||
568 | // free block |
||
569 | P_RemoveThinker ((thinker_t*)mobj); |
||
570 | } |
||
571 | |||
572 | |||
573 | |||
574 | |||
575 | // |
||
576 | // P_RespawnSpecials |
||
577 | // |
||
578 | void P_RespawnSpecials (void) |
||
579 | { |
||
580 | fixed_t x; |
||
581 | fixed_t y; |
||
582 | fixed_t z; |
||
583 | |||
584 | subsector_t* ss; |
||
585 | mobj_t* mo; |
||
586 | mapthing_t* mthing; |
||
587 | |||
588 | int i; |
||
589 | |||
590 | // only respawn items in deathmatch |
||
591 | if (deathmatch != 2) |
||
592 | return; // |
||
593 | |||
594 | // nothing left to respawn? |
||
595 | if (iquehead == iquetail) |
||
596 | return; |
||
597 | |||
598 | // wait at least 30 seconds |
||
599 | if (leveltime - itemrespawntime[iquetail] < 30*35) |
||
600 | return; |
||
601 | |||
602 | mthing = &itemrespawnque[iquetail]; |
||
603 | |||
604 | x = mthing->x << FRACBITS; |
||
605 | y = mthing->y << FRACBITS; |
||
606 | |||
607 | // spawn a teleport fog at the new spot |
||
608 | ss = R_PointInSubsector (x,y); |
||
609 | mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_IFOG); |
||
610 | S_StartSound (mo, sfx_itmbk); |
||
611 | |||
612 | // find which type to spawn |
||
613 | for (i=0 ; i< NUMMOBJTYPES ; i++) |
||
614 | { |
||
615 | if (mthing->type == mobjinfo[i].doomednum) |
||
616 | break; |
||
617 | } |
||
618 | |||
619 | // spawn it |
||
620 | if (mobjinfo[i].flags & MF_SPAWNCEILING) |
||
621 | z = ONCEILINGZ; |
||
622 | else |
||
623 | z = ONFLOORZ; |
||
624 | |||
625 | mo = P_SpawnMobj (x,y,z, i); |
||
626 | mo->spawnpoint = *mthing; |
||
627 | mo->angle = ANG45 * (mthing->angle/45); |
||
628 | |||
629 | // pull it from the que |
||
630 | iquetail = (iquetail+1)&(ITEMQUESIZE-1); |
||
631 | } |
||
632 | |||
633 | |||
634 | |||
635 | |||
636 | // |
||
637 | // P_SpawnPlayer |
||
638 | // Called when a player is spawned on the level. |
||
639 | // Most of the player structure stays unchanged |
||
640 | // between levels. |
||
641 | // |
||
642 | void P_SpawnPlayer (mapthing_t* mthing) |
||
643 | { |
||
644 | player_t* p; |
||
645 | fixed_t x; |
||
646 | fixed_t y; |
||
647 | fixed_t z; |
||
648 | |||
649 | mobj_t* mobj; |
||
650 | |||
651 | int i; |
||
652 | |||
653 | // not playing? |
||
654 | if (!playeringame[mthing->type-1]) |
||
655 | return; |
||
656 | |||
657 | p = &players[mthing->type-1]; |
||
658 | |||
659 | if (p->playerstate == PST_REBORN) |
||
660 | G_PlayerReborn (mthing->type-1); |
||
661 | |||
662 | x = mthing->x << FRACBITS; |
||
663 | y = mthing->y << FRACBITS; |
||
664 | z = ONFLOORZ; |
||
665 | mobj = P_SpawnMobj (x,y,z, MT_PLAYER); |
||
666 | |||
667 | // set color translations for player sprites |
||
668 | if (mthing->type > 1) |
||
669 | mobj->flags |= (mthing->type-1)< |
||
670 | |||
671 | mobj->angle = ANG45 * (mthing->angle/45); |
||
672 | mobj->player = p; |
||
673 | mobj->health = p->health; |
||
674 | |||
675 | p->mo = mobj; |
||
676 | p->playerstate = PST_LIVE; |
||
677 | p->refire = 0; |
||
678 | p->message = NULL; |
||
679 | p->damagecount = 0; |
||
680 | p->bonuscount = 0; |
||
681 | p->extralight = 0; |
||
682 | p->fixedcolormap = 0; |
||
683 | p->viewheight = VIEWHEIGHT; |
||
684 | |||
685 | // setup gun psprite |
||
686 | P_SetupPsprites (p); |
||
687 | |||
688 | // give all cards in death match mode |
||
689 | if (deathmatch) |
||
690 | for (i=0 ; i |
||
691 | p->cards[i] = true; |
||
692 | |||
693 | if (mthing->type-1 == consoleplayer) |
||
694 | { |
||
695 | // wake up the status bar |
||
696 | ST_Start (); |
||
697 | // wake up the heads up text |
||
698 | HU_Start (); |
||
699 | } |
||
700 | } |
||
701 | |||
702 | |||
703 | // |
||
704 | // P_SpawnMapThing |
||
705 | // The fields of the mapthing should |
||
706 | // already be in host byte order. |
||
707 | // |
||
708 | void P_SpawnMapThing (mapthing_t* mthing) |
||
709 | { |
||
710 | int i; |
||
711 | int bit; |
||
712 | mobj_t* mobj; |
||
713 | fixed_t x; |
||
714 | fixed_t y; |
||
715 | fixed_t z; |
||
716 | |||
717 | // count deathmatch start positions |
||
718 | if (mthing->type == 11) |
||
719 | { |
||
720 | if (deathmatch_p < &deathmatchstarts[10]) |
||
721 | { |
||
722 | memcpy (deathmatch_p, mthing, sizeof(*mthing)); |
||
723 | deathmatch_p++; |
||
724 | } |
||
725 | return; |
||
726 | } |
||
727 | |||
728 | // check for players specially |
||
729 | if (mthing->type <= 4) |
||
730 | { |
||
731 | // save spots for respawning in network games |
||
732 | playerstarts[mthing->type-1] = *mthing; |
||
733 | if (!deathmatch) |
||
734 | P_SpawnPlayer (mthing); |
||
735 | |||
736 | return; |
||
737 | } |
||
738 | |||
739 | // check for apropriate skill level |
||
740 | if (!netgame && (mthing->options & 16) ) |
||
741 | return; |
||
742 | |||
743 | if (gameskill == sk_baby) |
||
744 | bit = 1; |
||
745 | else if (gameskill == sk_nightmare) |
||
746 | bit = 4; |
||
747 | else |
||
748 | bit = 1<<(gameskill-1); |
||
749 | |||
750 | if (!(mthing->options & bit) ) |
||
751 | return; |
||
752 | |||
753 | // find which type to spawn |
||
754 | for (i=0 ; i< NUMMOBJTYPES ; i++) |
||
755 | if (mthing->type == mobjinfo[i].doomednum) |
||
756 | break; |
||
757 | |||
758 | if (i==NUMMOBJTYPES) |
||
759 | I_Error ("P_SpawnMapThing: Unknown type %i at (%i, %i)", |
||
760 | mthing->type, |
||
761 | mthing->x, mthing->y); |
||
762 | |||
763 | // don't spawn keycards and players in deathmatch |
||
764 | if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH) |
||
765 | return; |
||
766 | |||
767 | // don't spawn any monsters if -nomonsters |
||
768 | if (nomonsters |
||
769 | && ( i == MT_SKULL |
||
770 | || (mobjinfo[i].flags & MF_COUNTKILL)) ) |
||
771 | { |
||
772 | return; |
||
773 | } |
||
774 | |||
775 | // spawn it |
||
776 | x = mthing->x << FRACBITS; |
||
777 | y = mthing->y << FRACBITS; |
||
778 | |||
779 | if (mobjinfo[i].flags & MF_SPAWNCEILING) |
||
780 | z = ONCEILINGZ; |
||
781 | else |
||
782 | z = ONFLOORZ; |
||
783 | |||
784 | mobj = P_SpawnMobj (x,y,z, i); |
||
785 | mobj->spawnpoint = *mthing; |
||
786 | |||
787 | if (mobj->tics > 0) |
||
788 | mobj->tics = 1 + (P_Random () % mobj->tics); |
||
789 | if (mobj->flags & MF_COUNTKILL) |
||
790 | totalkills++; |
||
791 | if (mobj->flags & MF_COUNTITEM) |
||
792 | totalitems++; |
||
793 | |||
794 | mobj->angle = ANG45 * (mthing->angle/45); |
||
795 | if (mthing->options & MTF_AMBUSH) |
||
796 | mobj->flags |= MF_AMBUSH; |
||
797 | } |
||
798 | |||
799 | |||
800 | |||
801 | // |
||
802 | // GAME SPAWN FUNCTIONS |
||
803 | // |
||
804 | |||
805 | |||
806 | // |
||
807 | // P_SpawnPuff |
||
808 | // |
||
809 | extern fixed_t attackrange; |
||
810 | |||
811 | void |
||
812 | P_SpawnPuff |
||
813 | ( fixed_t x, |
||
814 | fixed_t y, |
||
815 | fixed_t z ) |
||
816 | { |
||
817 | mobj_t* th; |
||
818 | |||
819 | z += ((P_Random()-P_Random())<<10); |
||
820 | |||
821 | th = P_SpawnMobj (x,y,z, MT_PUFF); |
||
822 | th->momz = FRACUNIT; |
||
823 | th->tics -= P_Random()&3; |
||
824 | |||
825 | if (th->tics < 1) |
||
826 | th->tics = 1; |
||
827 | |||
828 | // don't make punches spark on the wall |
||
829 | if (attackrange == MELEERANGE) |
||
830 | P_SetMobjState (th, S_PUFF3); |
||
831 | } |
||
832 | |||
833 | |||
834 | |||
835 | // |
||
836 | // P_SpawnBlood |
||
837 | // |
||
838 | void |
||
839 | P_SpawnBlood |
||
840 | ( fixed_t x, |
||
841 | fixed_t y, |
||
842 | fixed_t z, |
||
843 | int damage ) |
||
844 | { |
||
845 | mobj_t* th; |
||
846 | |||
847 | z += ((P_Random()-P_Random())<<10); |
||
848 | th = P_SpawnMobj (x,y,z, MT_BLOOD); |
||
849 | th->momz = FRACUNIT*2; |
||
850 | th->tics -= P_Random()&3; |
||
851 | |||
852 | if (th->tics < 1) |
||
853 | th->tics = 1; |
||
854 | |||
855 | if (damage <= 12 && damage >= 9) |
||
856 | P_SetMobjState (th,S_BLOOD2); |
||
857 | else if (damage < 9) |
||
858 | P_SetMobjState (th,S_BLOOD3); |
||
859 | } |
||
860 | |||
861 | |||
862 | |||
863 | // |
||
864 | // P_CheckMissileSpawn |
||
865 | // Moves the missile forward a bit |
||
866 | // and possibly explodes it right there. |
||
867 | // |
||
868 | void P_CheckMissileSpawn (mobj_t* th) |
||
869 | { |
||
870 | th->tics -= P_Random()&3; |
||
871 | if (th->tics < 1) |
||
872 | th->tics = 1; |
||
873 | |||
874 | // move a little forward so an angle can |
||
875 | // be computed if it immediately explodes |
||
876 | th->x += (th->momx>>1); |
||
877 | th->y += (th->momy>>1); |
||
878 | th->z += (th->momz>>1); |
||
879 | |||
880 | if (!P_TryMove (th, th->x, th->y)) |
||
881 | P_ExplodeMissile (th); |
||
882 | } |
||
883 | |||
884 | |||
885 | // |
||
886 | // P_SpawnMissile |
||
887 | // |
||
888 | mobj_t* |
||
889 | P_SpawnMissile |
||
890 | ( mobj_t* source, |
||
891 | mobj_t* dest, |
||
892 | mobjtype_t type ) |
||
893 | { |
||
894 | mobj_t* th; |
||
895 | angle_t an; |
||
896 | int dist; |
||
897 | |||
898 | th = P_SpawnMobj (source->x, |
||
899 | source->y, |
||
900 | source->z + 4*8*FRACUNIT, type); |
||
901 | |||
902 | if (th->info->seesound) |
||
903 | S_StartSound (th, th->info->seesound); |
||
904 | |||
905 | th->target = source; // where it came from |
||
906 | an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y); |
||
907 | |||
908 | // fuzzy player |
||
909 | if (dest->flags & MF_SHADOW) |
||
910 | an += (P_Random()-P_Random())<<20; |
||
911 | |||
912 | th->angle = an; |
||
913 | an >>= ANGLETOFINESHIFT; |
||
914 | th->momx = FixedMul (th->info->speed, finecosine[an]); |
||
915 | th->momy = FixedMul (th->info->speed, finesine[an]); |
||
916 | |||
917 | dist = P_AproxDistance (dest->x - source->x, dest->y - source->y); |
||
918 | dist = dist / th->info->speed; |
||
919 | |||
920 | if (dist < 1) |
||
921 | dist = 1; |
||
922 | |||
923 | th->momz = (dest->z - source->z) / dist; |
||
924 | P_CheckMissileSpawn (th); |
||
925 | |||
926 | return th; |
||
927 | } |
||
928 | |||
929 | |||
930 | // |
||
931 | // P_SpawnPlayerMissile |
||
932 | // Tries to aim at a nearby monster |
||
933 | // |
||
934 | void |
||
935 | P_SpawnPlayerMissile |
||
936 | ( mobj_t* source, |
||
937 | mobjtype_t type ) |
||
938 | { |
||
939 | mobj_t* th; |
||
940 | angle_t an; |
||
941 | |||
942 | fixed_t x; |
||
943 | fixed_t y; |
||
944 | fixed_t z; |
||
945 | fixed_t slope; |
||
946 | |||
947 | // see which target is to be aimed at |
||
948 | an = source->angle; |
||
949 | slope = P_AimLineAttack (source, an, 16*64*FRACUNIT); |
||
950 | |||
951 | if (!linetarget) |
||
952 | { |
||
953 | an += 1<<26; |
||
954 | slope = P_AimLineAttack (source, an, 16*64*FRACUNIT); |
||
955 | |||
956 | if (!linetarget) |
||
957 | { |
||
958 | an -= 2<<26; |
||
959 | slope = P_AimLineAttack (source, an, 16*64*FRACUNIT); |
||
960 | } |
||
961 | |||
962 | if (!linetarget) |
||
963 | { |
||
964 | an = source->angle; |
||
965 | slope = 0; |
||
966 | } |
||
967 | } |
||
968 | |||
969 | x = source->x; |
||
970 | y = source->y; |
||
971 | z = source->z + 4*8*FRACUNIT; |
||
972 | |||
973 | th = P_SpawnMobj (x,y,z, type); |
||
974 | |||
975 | if (th->info->seesound) |
||
976 | S_StartSound (th, th->info->seesound); |
||
977 | |||
978 | th->target = source; |
||
979 | th->angle = an; |
||
980 | th->momx = FixedMul( th->info->speed, |
||
981 | finecosine[an>>ANGLETOFINESHIFT]); |
||
982 | th->momy = FixedMul( th->info->speed, |
||
983 | finesine[an>>ANGLETOFINESHIFT]); |
||
984 | th->momz = FixedMul( th->info->speed, slope); |
||
985 | |||
986 | P_CheckMissileSpawn (th); |
||
987 | }26; |
||
988 |