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