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