A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 905 lines 26 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 * Handling interactions (i.e., collisions). 29 * 30 *-----------------------------------------------------------------------------*/ 31 32#include "doomstat.h" 33#include "dstrings.h" 34#include "m_random.h" 35#include "am_map.h" 36#include "r_main.h" 37#include "s_sound.h" 38#include "sounds.h" 39#include "d_deh.h" // Ty 03/22/98 - externalized strings 40#include "p_tick.h" 41#include "i_system.h" 42 43#include "p_inter.h" 44#include "p_enemy.h" 45 46#ifdef __GNUG__ 47#pragma implementation "p_inter.h" 48#endif 49#include "p_inter.h" 50 51#define BONUSADD 6 52 53// Ty 03/07/98 - add deh externals 54// Maximums and such were hardcoded values. Need to externalize those for 55// dehacked support (and future flexibility). Most var names came from the key 56// strings used in dehacked. 57 58int initial_health = 100; 59int initial_bullets = 50; 60int maxhealth = 100; // was MAXHEALTH as a #define, used only in this module 61int max_armor = 200; 62int green_armor_class = 1; // these are involved with armortype below 63int blue_armor_class = 2; 64int max_soul = 200; 65int soul_health = 100; 66int mega_health = 200; 67int god_health = 100; // these are used in cheats (see st_stuff.c) 68int idfa_armor = 200; 69int idfa_armor_class = 2; 70// not actually used due to pairing of cheat_k and cheat_fa 71int idkfa_armor = 200; 72int idkfa_armor_class = 2; 73 74int bfgcells = 40; // used in p_pspr.c 75// Ty 03/07/98 - end deh externals 76 77// a weapon is found with two clip loads, 78// a big item has five clip loads 79int maxammo[NUMAMMO] = {200, 50, 300, 50}; 80int clipammo[NUMAMMO] = { 10, 4, 20, 1}; 81 82// 83// GET STUFF 84// 85 86// 87// P_GiveAmmo 88// Num is the number of clip loads, 89// not the individual count (0= 1/2 clip). 90// Returns false if the ammo can't be picked up at all 91// 92 93boolean P_GiveAmmo(player_t *player, ammotype_t ammo, int num) 94{ 95 int oldammo; 96 97 if (ammo == am_noammo) 98 return false; 99 100#ifdef RANGECHECK 101 if (ammo < 0 || ammo > NUMAMMO) 102 I_Error ("P_GiveAmmo: bad type %i", ammo); 103#endif 104 105 if ( player->ammo[ammo] == player->maxammo[ammo] ) 106 return false; 107 108 if (num) 109 num *= clipammo[ammo]; 110 else 111 num = clipammo[ammo]/2; 112 113 // give double ammo in trainer mode, you'll need in nightmare 114 if (gameskill == sk_baby || gameskill == sk_nightmare) 115 num <<= 1; 116 117 oldammo = player->ammo[ammo]; 118 player->ammo[ammo] += num; 119 120 if (player->ammo[ammo] > player->maxammo[ammo]) 121 player->ammo[ammo] = player->maxammo[ammo]; 122 123 // If non zero ammo, don't change up weapons, player was lower on purpose. 124 if (oldammo) 125 return true; 126 127 // We were down to zero, so select a new weapon. 128 // Preferences are not user selectable. 129 130 switch (ammo) 131 { 132 case am_clip: 133 if (player->readyweapon == wp_fist) { 134 if (player->weaponowned[wp_chaingun]) 135 player->pendingweapon = wp_chaingun; 136 else 137 player->pendingweapon = wp_pistol; 138 } 139 break; 140 141 case am_shell: 142 if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol) 143 if (player->weaponowned[wp_shotgun]) 144 player->pendingweapon = wp_shotgun; 145 break; 146 147 case am_cell: 148 if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol) 149 if (player->weaponowned[wp_plasma]) 150 player->pendingweapon = wp_plasma; 151 break; 152 153 case am_misl: 154 if (player->readyweapon == wp_fist) 155 if (player->weaponowned[wp_missile]) 156 player->pendingweapon = wp_missile; 157 default: 158 break; 159 } 160 return true; 161} 162 163// 164// P_GiveWeapon 165// The weapon name may have a MF_DROPPED flag ored in. 166// 167 168boolean P_GiveWeapon(player_t *player, weapontype_t weapon, boolean dropped) 169{ 170 boolean gaveammo; 171 boolean gaveweapon; 172 173 if (netgame && deathmatch!=2 && !dropped) 174 { 175 // leave placed weapons forever on net games 176 if (player->weaponowned[weapon]) 177 return false; 178 179 player->bonuscount += BONUSADD; 180 player->weaponowned[weapon] = true; 181 182 P_GiveAmmo(player, weaponinfo[weapon].ammo, deathmatch ? 5 : 2); 183 184 player->pendingweapon = weapon; 185 /* cph 20028/10 - for old-school DM addicts, allow old behavior 186 * where only consoleplayer's pickup sounds are heard */ 187 if (!comp[comp_sound] || player == &players[consoleplayer]) 188 S_StartSound (player->mo, sfx_wpnup|PICKUP_SOUND); // killough 4/25/98 189 return false; 190 } 191 192 if (weaponinfo[weapon].ammo != am_noammo) 193 { 194 // give one clip with a dropped weapon, 195 // two clips with a found weapon 196 gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, dropped ? 1 : 2); 197 } 198 else 199 gaveammo = false; 200 201 if (player->weaponowned[weapon]) 202 gaveweapon = false; 203 else 204 { 205 gaveweapon = true; 206 player->weaponowned[weapon] = true; 207 player->pendingweapon = weapon; 208 } 209 return gaveweapon || gaveammo; 210} 211 212// 213// P_GiveBody 214// Returns false if the body isn't needed at all 215// 216 217boolean P_GiveBody(player_t *player, int num) 218{ 219 if (player->health >= maxhealth) 220 return false; // Ty 03/09/98 externalized MAXHEALTH to maxhealth 221 player->health += num; 222 if (player->health > maxhealth) 223 player->health = maxhealth; 224 player->mo->health = player->health; 225 return true; 226} 227 228// 229// P_GiveArmor 230// Returns false if the armor is worse 231// than the current armor. 232// 233 234boolean P_GiveArmor(player_t *player, int armortype) 235{ 236 int hits = armortype*100; 237 if (player->armorpoints >= hits) 238 return false; // don't pick up 239 player->armortype = armortype; 240 player->armorpoints = hits; 241 return true; 242} 243 244// 245// P_GiveCard 246// 247 248void P_GiveCard(player_t *player, card_t card) 249{ 250 if (player->cards[card]) 251 return; 252 player->bonuscount = BONUSADD; 253 player->cards[card] = 1; 254} 255 256// 257// P_GivePower 258// 259// Rewritten by Lee Killough 260// 261 262boolean P_GivePower(player_t *player, int power) 263{ 264 static const int tics[NUMPOWERS] = { 265 INVULNTICS, 1 /* strength */, INVISTICS, 266 IRONTICS, 1 /* allmap */, INFRATICS, 267 }; 268 269 switch (power) 270 { 271 case pw_invisibility: 272 player->mo->flags |= MF_SHADOW; 273 break; 274 case pw_allmap: 275 if (player->powers[pw_allmap]) 276 return false; 277 break; 278 case pw_strength: 279 P_GiveBody(player,100); 280 break; 281 } 282 283 // Unless player has infinite duration cheat, set duration (killough) 284 285 if (player->powers[power] >= 0) 286 player->powers[power] = tics[power]; 287 return true; 288} 289 290// 291// P_TouchSpecialThing 292// 293 294void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) 295{ 296 player_t *player; 297 int i; 298 int sound; 299 fixed_t delta = special->z - toucher->z; 300 301 if (delta > toucher->height || delta < -8*FRACUNIT) 302 return; // out of reach 303 304 sound = sfx_itemup; 305 player = toucher->player; 306 307 // Dead thing touching. 308 // Can happen with a sliding player corpse. 309 if (toucher->health <= 0) 310 return; 311 312 // Identify by sprite. 313 switch (special->sprite) 314 { 315 // armor 316 case SPR_ARM1: 317 if (!P_GiveArmor (player, green_armor_class)) 318 return; 319 player->message = s_GOTARMOR; // Ty 03/22/98 - externalized 320 break; 321 322 case SPR_ARM2: 323 if (!P_GiveArmor (player, blue_armor_class)) 324 return; 325 player->message = s_GOTMEGA; // Ty 03/22/98 - externalized 326 break; 327 328 // bonus items 329 case SPR_BON1: 330 player->health++; // can go over 100% 331 if (player->health > (maxhealth * 2)) 332 player->health = (maxhealth * 2); 333 player->mo->health = player->health; 334 player->message = s_GOTHTHBONUS; // Ty 03/22/98 - externalized 335 break; 336 337 case SPR_BON2: 338 player->armorpoints++; // can go over 100% 339 if (player->armorpoints > max_armor) 340 player->armorpoints = max_armor; 341 if (!player->armortype) 342 player->armortype = green_armor_class; 343 player->message = s_GOTARMBONUS; // Ty 03/22/98 - externalized 344 break; 345 346 case SPR_SOUL: 347 player->health += soul_health; 348 if (player->health > max_soul) 349 player->health = max_soul; 350 player->mo->health = player->health; 351 player->message = s_GOTSUPER; // Ty 03/22/98 - externalized 352 sound = sfx_getpow; 353 break; 354 355 case SPR_MEGA: 356 if (gamemode != commercial) 357 return; 358 player->health = mega_health; 359 player->mo->health = player->health; 360 P_GiveArmor (player,blue_armor_class); 361 player->message = s_GOTMSPHERE; // Ty 03/22/98 - externalized 362 sound = sfx_getpow; 363 break; 364 365 // cards 366 // leave cards for everyone 367 case SPR_BKEY: 368 if (!player->cards[it_bluecard]) 369 player->message = s_GOTBLUECARD; // Ty 03/22/98 - externalized 370 P_GiveCard (player, it_bluecard); 371 if (!netgame) 372 break; 373 return; 374 375 case SPR_YKEY: 376 if (!player->cards[it_yellowcard]) 377 player->message = s_GOTYELWCARD; // Ty 03/22/98 - externalized 378 P_GiveCard (player, it_yellowcard); 379 if (!netgame) 380 break; 381 return; 382 383 case SPR_RKEY: 384 if (!player->cards[it_redcard]) 385 player->message = s_GOTREDCARD; // Ty 03/22/98 - externalized 386 P_GiveCard (player, it_redcard); 387 if (!netgame) 388 break; 389 return; 390 391 case SPR_BSKU: 392 if (!player->cards[it_blueskull]) 393 player->message = s_GOTBLUESKUL; // Ty 03/22/98 - externalized 394 P_GiveCard (player, it_blueskull); 395 if (!netgame) 396 break; 397 return; 398 399 case SPR_YSKU: 400 if (!player->cards[it_yellowskull]) 401 player->message = s_GOTYELWSKUL; // Ty 03/22/98 - externalized 402 P_GiveCard (player, it_yellowskull); 403 if (!netgame) 404 break; 405 return; 406 407 case SPR_RSKU: 408 if (!player->cards[it_redskull]) 409 player->message = s_GOTREDSKULL; // Ty 03/22/98 - externalized 410 P_GiveCard (player, it_redskull); 411 if (!netgame) 412 break; 413 return; 414 415 // medikits, heals 416 case SPR_STIM: 417 if (!P_GiveBody (player, 10)) 418 return; 419 player->message = s_GOTSTIM; // Ty 03/22/98 - externalized 420 break; 421 422 case SPR_MEDI: 423 if (!P_GiveBody (player, 25)) 424 return; 425 426 if (player->health < 50) // cph - 25 + the 25 just added, thanks to Quasar for reporting this bug 427 player->message = s_GOTMEDINEED; // Ty 03/22/98 - externalized 428 else 429 player->message = s_GOTMEDIKIT; // Ty 03/22/98 - externalized 430 break; 431 432 433 // power ups 434 case SPR_PINV: 435 if (!P_GivePower (player, pw_invulnerability)) 436 return; 437 player->message = s_GOTINVUL; // Ty 03/22/98 - externalized 438 sound = sfx_getpow; 439 break; 440 441 case SPR_PSTR: 442 if (!P_GivePower (player, pw_strength)) 443 return; 444 player->message = s_GOTBERSERK; // Ty 03/22/98 - externalized 445 if (player->readyweapon != wp_fist) 446 player->pendingweapon = wp_fist; 447 sound = sfx_getpow; 448 break; 449 450 case SPR_PINS: 451 if (!P_GivePower (player, pw_invisibility)) 452 return; 453 player->message = s_GOTINVIS; // Ty 03/22/98 - externalized 454 sound = sfx_getpow; 455 break; 456 457 case SPR_SUIT: 458 if (!P_GivePower (player, pw_ironfeet)) 459 return; 460 player->message = s_GOTSUIT; // Ty 03/22/98 - externalized 461 sound = sfx_getpow; 462 break; 463 464 case SPR_PMAP: 465 if (!P_GivePower (player, pw_allmap)) 466 return; 467 player->message = s_GOTMAP; // Ty 03/22/98 - externalized 468 sound = sfx_getpow; 469 break; 470 471 case SPR_PVIS: 472 if (!P_GivePower (player, pw_infrared)) 473 return; 474 player->message = s_GOTVISOR; // Ty 03/22/98 - externalized 475 sound = sfx_getpow; 476 break; 477 478 // ammo 479 case SPR_CLIP: 480 if (special->flags & MF_DROPPED) 481 { 482 if (!P_GiveAmmo (player,am_clip,0)) 483 return; 484 } 485 else 486 { 487 if (!P_GiveAmmo (player,am_clip,1)) 488 return; 489 } 490 player->message = s_GOTCLIP; // Ty 03/22/98 - externalized 491 break; 492 493 case SPR_AMMO: 494 if (!P_GiveAmmo (player, am_clip,5)) 495 return; 496 player->message = s_GOTCLIPBOX; // Ty 03/22/98 - externalized 497 break; 498 499 case SPR_ROCK: 500 if (!P_GiveAmmo (player, am_misl,1)) 501 return; 502 player->message = s_GOTROCKET; // Ty 03/22/98 - externalized 503 break; 504 505 case SPR_BROK: 506 if (!P_GiveAmmo (player, am_misl,5)) 507 return; 508 player->message = s_GOTROCKBOX; // Ty 03/22/98 - externalized 509 break; 510 511 case SPR_CELL: 512 if (!P_GiveAmmo (player, am_cell,1)) 513 return; 514 player->message = s_GOTCELL; // Ty 03/22/98 - externalized 515 break; 516 517 case SPR_CELP: 518 if (!P_GiveAmmo (player, am_cell,5)) 519 return; 520 player->message = s_GOTCELLBOX; // Ty 03/22/98 - externalized 521 break; 522 523 case SPR_SHEL: 524 if (!P_GiveAmmo (player, am_shell,1)) 525 return; 526 player->message = s_GOTSHELLS; // Ty 03/22/98 - externalized 527 break; 528 529 case SPR_SBOX: 530 if (!P_GiveAmmo (player, am_shell,5)) 531 return; 532 player->message = s_GOTSHELLBOX; // Ty 03/22/98 - externalized 533 break; 534 535 case SPR_BPAK: 536 if (!player->backpack) 537 { 538 for (i=0 ; i<NUMAMMO ; i++) 539 player->maxammo[i] *= 2; 540 player->backpack = true; 541 } 542 for (i=0 ; i<NUMAMMO ; i++) 543 P_GiveAmmo (player, i, 1); 544 player->message = s_GOTBACKPACK; // Ty 03/22/98 - externalized 545 break; 546 547 // weapons 548 case SPR_BFUG: 549 if (!P_GiveWeapon (player, wp_bfg, false) ) 550 return; 551 player->message = s_GOTBFG9000; // Ty 03/22/98 - externalized 552 sound = sfx_wpnup; 553 break; 554 555 case SPR_MGUN: 556 if (!P_GiveWeapon (player, wp_chaingun, (special->flags&MF_DROPPED)!=0) ) 557 return; 558 player->message = s_GOTCHAINGUN; // Ty 03/22/98 - externalized 559 sound = sfx_wpnup; 560 break; 561 562 case SPR_CSAW: 563 if (!P_GiveWeapon (player, wp_chainsaw, false) ) 564 return; 565 player->message = s_GOTCHAINSAW; // Ty 03/22/98 - externalized 566 sound = sfx_wpnup; 567 break; 568 569 case SPR_LAUN: 570 if (!P_GiveWeapon (player, wp_missile, false) ) 571 return; 572 player->message = s_GOTLAUNCHER; // Ty 03/22/98 - externalized 573 sound = sfx_wpnup; 574 break; 575 576 case SPR_PLAS: 577 if (!P_GiveWeapon (player, wp_plasma, false) ) 578 return; 579 player->message = s_GOTPLASMA; // Ty 03/22/98 - externalized 580 sound = sfx_wpnup; 581 break; 582 583 case SPR_SHOT: 584 if (!P_GiveWeapon (player, wp_shotgun, (special->flags&MF_DROPPED)!=0 ) ) 585 return; 586 player->message = s_GOTSHOTGUN; // Ty 03/22/98 - externalized 587 sound = sfx_wpnup; 588 break; 589 590 case SPR_SGN2: 591 if (!P_GiveWeapon(player, wp_supershotgun, (special->flags&MF_DROPPED)!=0)) 592 return; 593 player->message = s_GOTSHOTGUN2; // Ty 03/22/98 - externalized 594 sound = sfx_wpnup; 595 break; 596 597 default: 598 I_Error ("P_SpecialThing: Unknown gettable thing"); 599 } 600 601 if (special->flags & MF_COUNTITEM) 602 player->itemcount++; 603 P_RemoveMobj (special); 604 player->bonuscount += BONUSADD; 605 606 /* cph 20028/10 - for old-school DM addicts, allow old behavior 607 * where only consoleplayer's pickup sounds are heard */ 608 if (!comp[comp_sound] || player == &players[consoleplayer]) 609 S_StartSound (player->mo, sound | PICKUP_SOUND); // killough 4/25/98 610} 611 612// 613// KillMobj 614// 615// killough 11/98: make static 616static void P_KillMobj(mobj_t *source, mobj_t *target) 617{ 618 mobjtype_t item; 619 mobj_t *mo; 620 621 target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY); 622 623 if (target->type != MT_SKULL) 624 target->flags &= ~MF_NOGRAVITY; 625 626 target->flags |= MF_CORPSE|MF_DROPOFF; 627 target->height >>= 2; 628 629 if (!((target->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL))) 630 totallive--; 631 632 if (source && source->player) 633 { 634 // count for intermission 635 if (target->flags & MF_COUNTKILL) 636 source->player->killcount++; 637 if (target->player) 638 source->player->frags[target->player-players]++; 639 } 640 else 641 if (target->flags & MF_COUNTKILL) { /* Add to kills tally */ 642 if ((compatibility_level < lxdoom_1_compatibility) || !netgame) { 643 if (!netgame) 644 // count all monster deaths, 645 // even those caused by other monsters 646 players[0].killcount++; 647 } else 648 if (!deathmatch) { 649 // try and find a player to give the kill to, otherwise give the 650 // kill to a random player. this fixes the missing monsters bug 651 // in coop - rain 652 // CPhipps - not a bug as such, but certainly an inconsistency. 653 if (target->lastenemy && target->lastenemy->health > 0 654 && target->lastenemy->player) // Fighting a player 655 target->lastenemy->player->killcount++; 656 else { 657 // cph - randomely choose a player in the game to be credited 658 // and do it uniformly between the active players 659 unsigned int activeplayers = 0, player, i; 660 661 for (player = 0; player<MAXPLAYERS; player++) 662 if (playeringame[player]) 663 activeplayers++; 664 665 if (activeplayers) { 666 player = P_Random(pr_friends) % activeplayers; 667 668 for (i=0; i<MAXPLAYERS; i++) 669 if (playeringame[i]) 670 if (!player--) 671 players[i].killcount++; 672 } 673 } 674 } 675 } 676 677 if (target->player) 678 { 679 // count environment kills against you 680 if (!source) 681 target->player->frags[target->player-players]++; 682 683 target->flags &= ~MF_SOLID; 684 target->player->playerstate = PST_DEAD; 685 P_DropWeapon (target->player); 686 687 if (target->player == &players[consoleplayer] && (automapmode & am_active)) 688 AM_Stop(); // don't die in auto map; switch view prior to dying 689 } 690 691 if (target->health < -target->info->spawnhealth && target->info->xdeathstate) 692 P_SetMobjState (target, target->info->xdeathstate); 693 else 694 P_SetMobjState (target, target->info->deathstate); 695 696 target->tics -= P_Random(pr_killtics)&3; 697 698 if (target->tics < 1) 699 target->tics = 1; 700 701 // Drop stuff. 702 // This determines the kind of object spawned 703 // during the death frame of a thing. 704 705 switch (target->type) 706 { 707 case MT_WOLFSS: 708 case MT_POSSESSED: 709 item = MT_CLIP; 710 break; 711 712 case MT_SHOTGUY: 713 item = MT_SHOTGUN; 714 break; 715 716 case MT_CHAINGUY: 717 item = MT_CHAINGUN; 718 break; 719 720 default: 721 return; 722 } 723 724 mo = P_SpawnMobj (target->x,target->y,ONFLOORZ, item); 725 mo->flags |= MF_DROPPED; // special versions of items 726} 727 728// 729// P_DamageMobj 730// Damages both enemies and players 731// "inflictor" is the thing that caused the damage 732// creature or missile, can be NULL (slime, etc) 733// "source" is the thing to target after taking damage 734// creature or NULL 735// Source and inflictor are the same for melee attacks. 736// Source can be NULL for slime, barrel explosions 737// and other environmental stuff. 738// 739 740void P_DamageMobj(mobj_t *target,mobj_t *inflictor, mobj_t *source, int damage) 741{ 742 player_t *player; 743 boolean justhit; /* killough 11/98 */ 744 745 /* killough 8/31/98: allow bouncers to take damage */ 746 if (!(target->flags & (MF_SHOOTABLE | MF_BOUNCES))) 747 return; // shouldn't happen... 748 749 if (target->health <= 0) 750 return; 751 752 /* proff 11/22/98: Andy Baker's Stealth monsters */ 753 if (target->flags & MF_STEALTH) 754 P_BecomeVisible(target); 755 756 if (target->flags & MF_SKULLFLY) 757 target->momx = target->momy = target->momz = 0; 758 759 player = target->player; 760 if (player && gameskill == sk_baby) 761 damage >>= 1; // take half damage in trainer mode 762 763 // Some close combat weapons should not 764 // inflict thrust and push the victim out of reach, 765 // thus kick away unless using the chainsaw. 766 767 if (inflictor && !(target->flags & MF_NOCLIP) && 768 (!source || !source->player || 769 source->player->readyweapon != wp_chainsaw)) 770 { 771 unsigned ang = R_PointToAngle2 (inflictor->x, inflictor->y, 772 target->x, target->y); 773 774 fixed_t thrust = damage*(FRACUNIT>>3)*100/target->info->mass; 775 776 // make fall forwards sometimes 777 if ( damage < 40 && damage > target->health 778 && target->z - inflictor->z > 64*FRACUNIT 779 && P_Random(pr_damagemobj) & 1) 780 { 781 ang += ANG180; 782 thrust *= 4; 783 } 784 785 ang >>= ANGLETOFINESHIFT; 786 target->momx += FixedMul (thrust, finecosine[ang]); 787 target->momy += FixedMul (thrust, finesine[ang]); 788 789 /* killough 11/98: thrust objects hanging off ledges */ 790 if (target->intflags & MIF_FALLING && target->gear >= MAXGEAR) 791 target->gear = 0; 792 } 793 794 // player specific 795 if (player) 796 { 797 // end of game hell hack 798 if (target->subsector->sector->special == 11 && damage >= target->health) 799 damage = target->health - 1; 800 801 // Below certain threshold, 802 // ignore damage in GOD mode, or with INVUL power. 803 // killough 3/26/98: make god mode 100% god mode in non-compat mode 804 805 if ((damage < 1000 || (!comp[comp_god] && (player->cheats&CF_GODMODE))) && 806 (player->cheats&CF_GODMODE || player->powers[pw_invulnerability])) 807 return; 808 809 if (player->armortype) 810 { 811 int saved = player->armortype == 1 ? damage/3 : damage/2; 812 if (player->armorpoints <= saved) 813 { 814 // armor is used up 815 saved = player->armorpoints; 816 player->armortype = 0; 817 } 818 player->armorpoints -= saved; 819 damage -= saved; 820 } 821 822 player->health -= damage; // mirror mobj health here for Dave 823 if (player->health < 0) 824 player->health = 0; 825 826 player->attacker = source; 827 player->damagecount += damage; // add damage after armor / invuln 828 829 if (player->damagecount > 100) 830 player->damagecount = 100; // teleport stomp does 10k points... 831 } 832 833 // do the damage 834 target->health -= damage; 835 if (target->health <= 0) 836 { 837 P_KillMobj (source, target); 838 return; 839 } 840 841 // killough 9/7/98: keep track of targets so that friends can help friends 842 if (mbf_features) 843 { 844 /* If target is a player, set player's target to source, 845 * so that a friend can tell who's hurting a player 846 */ 847 if (player) 848 P_SetTarget(&target->target, source); 849 850 /* killough 9/8/98: 851 * If target's health is less than 50%, move it to the front of its list. 852 * This will slightly increase the chances that enemies will choose to 853 * "finish it off", but its main purpose is to alert friends of danger. 854 */ 855 if (target->health*2 < target->info->spawnhealth) 856 { 857 thinker_t *cap = &thinkerclasscap[target->flags & MF_FRIEND ? 858 th_friends : th_enemies]; 859 (target->thinker.cprev->cnext = target->thinker.cnext)->cprev = 860 target->thinker.cprev; 861 (target->thinker.cnext = cap->cnext)->cprev = &target->thinker; 862 (target->thinker.cprev = cap)->cnext = &target->thinker; 863 } 864 } 865 866 if ((justhit = (P_Random (pr_painchance) < target->info->painchance && 867 !(target->flags & MF_SKULLFLY)))) //killough 11/98: see below 868 P_SetMobjState(target, target->info->painstate); 869 870 target->reactiontime = 0; // we're awake now... 871 872 /* killough 9/9/98: cleaned up, made more consistent: */ 873 874 if (source && source != target && source->type != MT_VILE && 875 (!target->threshold || target->type == MT_VILE) && 876 ((source->flags ^ target->flags) & MF_FRIEND || 877 monster_infighting || 878 !mbf_features)) 879 { 880 /* if not intent on another player, chase after this one 881 * 882 * killough 2/15/98: remember last enemy, to prevent 883 * sleeping early; 2/21/98: Place priority on players 884 * killough 9/9/98: cleaned up, made more consistent: 885 */ 886 887 if (!target->lastenemy || target->lastenemy->health <= 0 || 888 (!mbf_features ? 889 !target->lastenemy->player : 890 !((target->flags ^ target->lastenemy->flags) & MF_FRIEND) && 891 target->target != source)) // remember last enemy - killough 892 P_SetTarget(&target->lastenemy, target->target); 893 894 P_SetTarget(&target->target, source); // killough 11/98 895 target->threshold = BASETHRESHOLD; 896 if (target->state == &states[target->info->spawnstate] 897 && target->info->seestate != S_NULL) 898 P_SetMobjState (target, target->info->seestate); 899 } 900 901 /* killough 11/98: Don't attack a friend, unless hit by that friend. */ 902 if (justhit && (target->target == source || !target->target || 903 !(target->flags & target->target->flags & MF_FRIEND))) 904 target->flags |= MF_JUSTHIT; // fight back! 905}