DOOM64-RE

DOOM 64 Reverse Engineering
Log | Files | Refs | README | LICENSE

p_inter.c (19328B)


      1 /* P_inter.c */
      2 
      3 
      4 #include "doomdef.h"
      5 #include "p_local.h"
      6 #include "st_main.h"
      7 
      8 #define	BONUSADD		4
      9 
     10 /* a weapon is found with two clip loads, a big item has five clip loads */
     11 int		maxammo[NUMAMMO] = {200, 50, 300, 50}; // 8005AD40
     12 int		clipammo[NUMAMMO] = {10, 4, 20, 1}; // 8005AD50
     13 
     14 /*
     15 ===============================================================================
     16 
     17 							GET STUFF
     18 
     19 ===============================================================================
     20 */
     21 
     22 /*
     23 ===================
     24 =
     25 = P_GiveAmmo
     26 =
     27 = Num is the number of clip loads, not the individual count (0= 1/2 clip)
     28 = Returns false if the ammo can't be picked up at all
     29 ===================
     30 */
     31 
     32 boolean P_GiveAmmo (player_t *player, ammotype_t ammo, int num) // 800143E0
     33 {
     34 	int		oldammo;
     35 
     36 	if (ammo == am_noammo)
     37 		return false;
     38 
     39 	if (ammo > NUMAMMO)
     40 		I_Error ("P_GiveAmmo: bad type %i", ammo);
     41 
     42 	if ( player->ammo[ammo] == player->maxammo[ammo]  )
     43 		return false;
     44 
     45 	if (num)
     46 		num *= clipammo[ammo];
     47 	else
     48     {
     49         //num = clipammo[ammo]/2;
     50 		num = clipammo[ammo];
     51 		if(!(num >= 0))
     52         {
     53             num = num + 1;
     54         }
     55 
     56         num = num/2;
     57     }
     58 
     59     #if ENABLE_NIGHTMARE == 1 // Like PC Doom / Doom 64 EX
     60     if (gameskill == sk_baby || gameskill == sk_nightmare)
     61 		num <<= 1;			/* give double ammo in trainer mode */
     62     #else
     63     if (gameskill == sk_baby)
     64 		num <<= 1;			/* give double ammo in trainer mode */
     65     #endif // ENABLE_NIGHTMARE
     66 
     67 	oldammo = player->ammo[ammo];
     68 	player->ammo[ammo] += num;
     69 	if (player->ammo[ammo] > player->maxammo[ammo])
     70 		player->ammo[ammo] = player->maxammo[ammo];
     71 
     72 	if (oldammo)
     73 		return true;		/* don't change up weapons, player was lower on */
     74 							/* purpose */
     75 
     76 	switch (ammo)
     77 	{
     78 	case am_clip:
     79 		if (player->readyweapon == wp_fist)
     80 		{
     81 			if (player->weaponowned[wp_chaingun])
     82 				player->pendingweapon = wp_chaingun;
     83 			else
     84 				player->pendingweapon = wp_pistol;
     85 		}
     86 		break;
     87 	case am_shell:
     88 		if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol)
     89 		{
     90 			if (player->weaponowned[wp_shotgun])
     91 				player->pendingweapon = wp_shotgun;
     92 		}
     93 		break;
     94 	case am_cell:
     95 		if (player->readyweapon == wp_fist || player->readyweapon == wp_pistol)
     96 		{
     97 			if (player->weaponowned[wp_plasma])
     98 				player->pendingweapon = wp_plasma;
     99 		}
    100 		break;
    101 	case am_misl:
    102 		if (player->readyweapon == wp_fist)
    103 		{
    104 			if (player->weaponowned[wp_missile])
    105 				player->pendingweapon = wp_missile;
    106 		}
    107 	default:
    108 		break;
    109 	}
    110 
    111 	return true;
    112 }
    113 
    114 
    115 /*
    116 ===================
    117 =
    118 = P_GiveWeapon
    119 =
    120 = The weapon name may have a MF_DROPPED flag ored in
    121 ===================
    122 */
    123 
    124 boolean P_GiveWeapon (player_t *player, weapontype_t weapon, boolean dropped) // 800145C0
    125 {
    126 	boolean		gaveammo, gaveweapon;
    127 
    128 	if (weaponinfo[weapon].ammo != am_noammo)
    129 	{	/* give one clip with a dropped weapon, two clips with a found weapon */
    130 		if (dropped)
    131 			gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 1);
    132 		else
    133 			gaveammo = P_GiveAmmo (player, weaponinfo[weapon].ammo, 2);
    134 	}
    135 	else
    136 		gaveammo = false;
    137 
    138 	if (player->weaponowned[weapon])
    139 		gaveweapon = false;
    140 	else
    141 	{
    142 		gaveweapon = true;
    143 		player->weaponowned[weapon] = true;
    144 		player->pendingweapon = weapon;
    145 	}
    146 
    147 	return gaveweapon || gaveammo;
    148 }
    149 
    150 
    151 
    152 /*
    153 ===================
    154 =
    155 = P_GiveBody
    156 =
    157 = Returns false if the body isn't needed at all
    158 ===================
    159 */
    160 
    161 boolean P_GiveBody (player_t *player, int num) // 80014680
    162 {
    163 	if (player->health >= MAXHEALTH)
    164 		return false;
    165 
    166 	player->health += num;
    167 	if (player->health > MAXHEALTH)
    168 		player->health = MAXHEALTH;
    169 	player->mo->health = player->health;
    170 
    171 	return true;
    172 }
    173 
    174 
    175 /*
    176 ===================
    177 =
    178 = P_GiveArmor
    179 =
    180 = Returns false if the armor is worse than the current armor
    181 ===================
    182 */
    183 
    184 boolean P_GiveArmor (player_t *player, int armortype) // 800146C8
    185 {
    186 	int		hits;
    187 
    188 	hits = armortype*100;
    189 	if (player->armorpoints >= hits)
    190 		return false;		/* don't pick up */
    191 
    192 	player->armortype = armortype;
    193 	player->armorpoints = hits;
    194 
    195 	return true;
    196 }
    197 
    198 
    199 /*
    200 ===================
    201 =
    202 = P_GiveCard
    203 =
    204 ===================
    205 */
    206 
    207 void P_GiveCard (player_t *player, card_t card) // 80014704
    208 {
    209 	if (player->cards[card])
    210 		return;
    211 	player->bonuscount = BONUSADD;
    212 	player->cards[card] = true;
    213 }
    214 
    215 
    216 /*
    217 ===================
    218 =
    219 = P_GivePower
    220 =
    221 ===================
    222 */
    223 
    224 boolean P_GivePower (player_t *player, powertype_t power) // 8001472C
    225 {
    226 	switch (power)
    227 	{
    228 	case pw_invulnerability:
    229 		player->powers[power] = INVULNTICS;
    230 		return true;
    231 	case pw_invisibility:
    232 		player->powers[power] = INVISTICS;
    233 		player->mo->flags |= MF_SHADOW;
    234 		return true;
    235 	case pw_infrared:
    236 		player->powers[power] = INFRATICS;
    237         infraredFactor = 300;
    238         P_RefreshBrightness();
    239 		return true;
    240 	case pw_ironfeet:
    241 		player->powers[power] = IRONTICS;
    242 		return true;
    243 	case pw_strength:
    244 		P_GiveBody(player, 100);
    245 		player->powers[power] = STRTICS;
    246 		return true;
    247 	default:
    248 		break;
    249 	}
    250     //pw_allmap
    251 	if (player->powers[power])
    252 		return false;		/* already got it */
    253 
    254 	player->powers[power] = 1;
    255 	return true;
    256 }
    257 
    258 /*
    259 ==================
    260 =
    261 = P_TouchSpecialThing
    262 =
    263 ==================
    264 */
    265 
    266 int ArtifactLookupTable[8] = {0, 1, 1, 2, 1, 2, 2, 3}; // 8005AD60
    267 
    268 void P_TouchSpecialThing (mobj_t *special, mobj_t *toucher) // 80014810
    269 {
    270 	player_t	*player;
    271 	int			i;
    272 	fixed_t		delta;
    273 	int			sound;
    274 	char        *message;
    275 	int         artflag;
    276 
    277 	delta = special->z - toucher->z;
    278 	if (delta > toucher->height || delta < -8*FRACUNIT)
    279 		return;			/* out of reach */
    280 
    281 	sound = sfx_itemup;
    282 	player = toucher->player;
    283 	if (toucher->health <= 0)
    284 		return;						/* can happen with a sliding player corpse */
    285 
    286     message = NULL;
    287 
    288 	switch (special->type)
    289 	{
    290 
    291     /* */
    292     /* bonus items */
    293     /* */
    294 	case MT_ITEM_BONUSHEALTH:
    295 		player->health+=2;		/* can go over 100% */
    296 		if (player->health > 200)
    297 			player->health = 200;
    298 		player->mo->health = player->health;
    299 		message = "You pick up a health bonus.";
    300 		break;
    301 	case MT_ITEM_BONUSARMOR:
    302 		player->armorpoints+=2;		/* can go over 100% */
    303 		if (player->armorpoints > 200)
    304 			player->armorpoints = 200;
    305 		if (!player->armortype)
    306 			player->armortype = 1;
    307 		message = "You pick up an armor bonus.";
    308 		break;
    309 	case MT_ITEM_SOULSPHERE:
    310 		player->health += 100;
    311 		if (player->health > 200)
    312 			player->health = 200;
    313 		player->mo->health = player->health;
    314 		message = "Supercharge!";
    315 		sound = sfx_powerup;
    316 		break;
    317 	case MT_ITEM_MEGASPHERE:
    318 		player->health = 200;
    319 		player->mo->health = 200;
    320 		P_GiveArmor(player, 2);
    321 		message = "Mega Sphere!";
    322 		sound = sfx_powerup;
    323 		break;
    324 
    325     /* */
    326     /* ammo */
    327     /* */
    328 	case MT_AMMO_CLIP:
    329 		if (special->flags & MF_DROPPED)
    330 		{
    331 			if (!P_GiveAmmo (player,am_clip,0))
    332 				return;
    333 		}
    334 		else
    335 		{
    336 			if (!P_GiveAmmo (player,am_clip,1))
    337 				return;
    338 		}
    339 		message = "Picked up a clip.";
    340 		break;
    341 	case MT_AMMO_CLIPBOX:
    342 		if (!P_GiveAmmo (player, am_clip,5))
    343 			return;
    344 		message = "Picked up a box of bullets.";
    345 		break;
    346 	case MT_AMMO_ROCKET:
    347 		if (!P_GiveAmmo (player, am_misl,1))
    348 			return;
    349 		message = "Picked up a rocket.";
    350 		break;
    351 	case MT_AMMO_ROCKETBOX:
    352 		if (!P_GiveAmmo (player, am_misl,5))
    353 			return;
    354 		message = "Picked up a box of rockets.";
    355 		break;
    356 	case MT_AMMO_CELL:
    357 		if (!P_GiveAmmo (player, am_cell,1))
    358 			return;
    359 		message = "Picked up an energy cell.";
    360 		break;
    361 	case MT_AMMO_CELLPACK:
    362 		if (!P_GiveAmmo (player, am_cell,5))
    363 			return;
    364 		message = "Picked up an energy cell pack.";
    365 		break;
    366 	case MT_AMMO_SHELL:
    367 		if (!P_GiveAmmo (player, am_shell,1))
    368 			return;
    369         #if ENABLE_NIGHTMARE == 1
    370         if (gameskill == sk_baby || gameskill == sk_nightmare)
    371             message = "Picked up 8 shotgun shells.";
    372         else
    373             message = "Picked up 4 shotgun shells.";
    374         #else
    375         if (gameskill == sk_baby)
    376             message = "Picked up 8 shotgun shells.";
    377         else
    378             message = "Picked up 4 shotgun shells.";
    379         #endif // ENABLE_NIGHTMARE
    380 		break;
    381 	case MT_AMMO_SHELLBOX:
    382 		if (!P_GiveAmmo (player, am_shell,5))
    383 			return;
    384 		message = "Picked up a box of shotgun shells.";
    385 		break;
    386 	case MT_AMMO_BACKPACK:
    387 		if (!player->backpack)
    388 		{
    389 			for (i=0 ; i<NUMAMMO ; i++)
    390 				player->maxammo[i] *= 2;
    391 			player->backpack = true;
    392 		}
    393 		for (i=0 ; i<NUMAMMO ; i++)
    394 			P_GiveAmmo (player, i, 1);
    395 		message = "You got the backpack!";
    396 		break;
    397 
    398 
    399 	/* */
    400 	/* weapons */
    401 	/* */
    402 	case MT_WEAP_BFG:
    403 		if (!P_GiveWeapon (player, wp_bfg, false) )
    404 			return;
    405 		message = "You got the BFG9000!  Oh, yes.";
    406 		sound = sfx_sgcock;
    407 		break;
    408 	case MT_WEAP_CHAINGUN:
    409 		if (!P_GiveWeapon (player, wp_chaingun, special->flags&MF_DROPPED) )
    410 			return;
    411 		message = "You got the chaingun!";
    412 		sound = sfx_sgcock;
    413 		break;
    414 	case MT_WEAP_CHAINSAW:
    415 		if (!P_GiveWeapon (player, wp_chainsaw, false) )
    416 			return;
    417 		message = "A chainsaw!  Find some meat!";
    418 		sound = sfx_sgcock;
    419 		break;
    420 	case MT_WEAP_LAUNCHER:
    421 		if (!P_GiveWeapon (player, wp_missile, false) )
    422 			return;
    423 		message = "You got the rocket launcher!";
    424 		sound = sfx_sgcock;
    425 		break;
    426 	case MT_WEAP_PLASMA:
    427 		if (!P_GiveWeapon (player, wp_plasma, false) )
    428 			return;
    429 		message = "You got the plasma gun!";
    430 		sound = sfx_sgcock;
    431 		break;
    432 	case MT_WEAP_SHOTGUN:
    433 		if (!P_GiveWeapon (player, wp_shotgun, special->flags&MF_DROPPED ) )
    434 			return;
    435 		message = "You got the shotgun!";
    436 		sound = sfx_sgcock;
    437 		break;
    438 	case MT_WEAP_SSHOTGUN:
    439 		if (!P_GiveWeapon(player, wp_supershotgun, special->flags&MF_DROPPED))
    440 			return;
    441 		message = "You got the super shotgun!";
    442 		sound = sfx_sgcock;
    443 		break;
    444     case MT_WEAP_LCARBINE:
    445 		if (!P_GiveWeapon(player, wp_laser, false))
    446 			return;
    447 		message = "What the !@#%* is this!";
    448 		sound = sfx_sgcock;
    449 		break;
    450 
    451 		/* */
    452 		/* armor */
    453 		/* */
    454 	case MT_ITEM_ARMOR1:
    455 		if (!P_GiveArmor(player, 1))
    456 			return;
    457 		message = "You pick up the armor.";
    458 		break;
    459 
    460 	case MT_ITEM_ARMOR2:
    461 		if (!P_GiveArmor(player, 2))
    462 			return;
    463 		message = "You got the MegaArmor!";
    464 		break;
    465 
    466     /* */
    467     /* cards */
    468     /* leave cards for everyone */
    469     /* */
    470 	case MT_ITEM_BLUECARDKEY:
    471 		if (!player->cards[it_bluecard])
    472 			message = "You pick up a blue keycard.";
    473 		P_GiveCard(player, it_bluecard);
    474 		break;
    475     case MT_ITEM_REDCARDKEY:
    476 		if (!player->cards[it_redcard])
    477 			message = "You pick up a red keycard.";
    478 		P_GiveCard(player, it_redcard);
    479 		break;
    480 	case MT_ITEM_YELLOWCARDKEY:
    481 		if (!player->cards[it_yellowcard])
    482 			message = "You pick up a yellow keycard.";
    483 		P_GiveCard(player, it_yellowcard);
    484 		break;
    485 	case MT_ITEM_BLUESKULLKEY:
    486 		if (!player->cards[it_blueskull])
    487 			message = "You pick up a blue skull key.";
    488 		P_GiveCard(player, it_blueskull);
    489 		break;
    490     case MT_ITEM_REDSKULLKEY:
    491 		if (!player->cards[it_redskull])
    492 			message = "You pick up a red skull key.";
    493 		P_GiveCard(player, it_redskull);
    494 		break;
    495 	case MT_ITEM_YELLOWSKULLKEY:
    496 		if (!player->cards[it_yellowskull])
    497 			message = "You pick up a yellow skull key.";
    498 		P_GiveCard(player, it_yellowskull);
    499 		break;
    500 
    501     /* */
    502     /* heals */
    503     /* */
    504 	case MT_ITEM_STIMPACK:
    505 		if (!P_GiveBody(player, 10))
    506 			return;
    507 		message = "You pick up a stimpack.";
    508 		break;
    509 	case MT_ITEM_MEDKIT:
    510 		if (!P_GiveBody(player, 25))
    511 			return;
    512 		if (player->health < 25)
    513 			message = "You pick up a medikit that you REALLY need!";
    514 		else
    515 			message = "You pick up a medikit.";
    516 		break;
    517 
    518     /* */
    519     /* power ups */
    520     /* */
    521 	case MT_ITEM_INVULSPHERE:
    522 		P_GivePower(player, pw_invulnerability);
    523 		message = "Invulnerability!";
    524 		sound = sfx_powerup;
    525 		break;
    526 	case MT_ITEM_BERSERK:
    527 		P_GivePower(player, pw_strength);
    528 		message = "Berserk!";
    529 		if (player->readyweapon != wp_fist)
    530 			player->pendingweapon = wp_fist;
    531 		sound = sfx_powerup;
    532 		break;
    533 	case MT_ITEM_INVISSPHERE:
    534 		P_GivePower(player, pw_invisibility);
    535 		message = "Partial Invisibility!";
    536 		sound = sfx_powerup;
    537 		break;
    538 	case MT_ITEM_RADSPHERE:
    539 		P_GivePower(player, pw_ironfeet);
    540 		message = "Radiation Shielding Suit";
    541 		sound = sfx_powerup;
    542 		break;
    543 	case MT_ITEM_AUTOMAP:
    544 		if (!P_GivePower(player, pw_allmap))
    545 			return;
    546 		message = "Computer Area Map";
    547 		sound = sfx_powerup;
    548 		break;
    549 	case MT_ITEM_PVIS:
    550 		P_GivePower(player, pw_infrared);
    551 		message = "Light Amplification Goggles";
    552 		sound = sfx_powerup;
    553 		break;
    554 
    555     /* */
    556     /* artifacts */
    557     /* */
    558     case MT_ITEM_ARTIFACT1:
    559     case MT_ITEM_ARTIFACT2:
    560     case MT_ITEM_ARTIFACT3:
    561 
    562         artflag = 1 << ((special->type + 7) & 0x1f);
    563 
    564         if ((player->artifacts & artflag))
    565             return;
    566 
    567         player->artifacts |= artflag;
    568 
    569         if (ArtifactLookupTable[player->artifacts] == 1) /* ART_FAST */
    570             message = "You have a feeling that\nit wasn't to be touched...";
    571         else if (ArtifactLookupTable[player->artifacts] == 2) /* ART_TRIPLE */
    572             message = "Whatever it is, it doesn't\nbelong in this world...";
    573         else /* ART_DOUBLE */
    574             message = "It must do something...";
    575 
    576         sound = sfx_powerup;
    577 		break;
    578 
    579     /* */
    580     /* fake item */
    581     /* */
    582     case MT_FAKEITEM:
    583         goto runtrigger;
    584         break;
    585 
    586 	default:
    587 		I_Error("P_SpecialThing: Unknown gettable thing"); // Restored
    588 		break;
    589 	}
    590 
    591     if (message)
    592     {
    593         player->message = message;
    594         player->messagetic = MSGTICS;
    595     }
    596 
    597 	if (special->flags & MF_COUNTITEM)
    598 		player->itemcount++;
    599 
    600     if (special->flags & MF_COUNTSECRET)
    601         player->secretcount++;
    602 
    603 	P_RemoveMobj (special);
    604 	player->bonuscount += BONUSADD;
    605 
    606 	if (player == &players[0])
    607 		S_StartSound(NULL, sound);
    608 
    609 	if(special->flags & MF_TRIGTOUCH)
    610     {
    611     runtrigger:
    612         if(!P_ActivateLineByTag(special->tid, toucher))
    613         {
    614             macroqueue[macroidx1].activator = toucher;
    615             macroqueue[macroidx1].tag = special->tid;
    616             macroidx1 = (macroidx1 + 1) & 3;
    617         }
    618     }
    619 }
    620 
    621 /*
    622 ==============
    623 =
    624 = KillMobj
    625 =
    626 ==============
    627 */
    628 extern int deathmocktics; // 800A56A0
    629 
    630 void P_KillMobj (mobj_t *source, mobj_t *target) // 80015080
    631 {
    632 	mobjtype_t		item;
    633 	mobj_t			*mo;
    634 	boolean         forceXdeath;
    635 
    636 	target->flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY);
    637 
    638 	if (target->type != MT_SKULL)
    639 		target->flags |= MF_GRAVITY;
    640 
    641 	target->flags |= MF_CORPSE|MF_DROPOFF;
    642 	target->height >>= 2;
    643 
    644 	forceXdeath = false;    //New PsxDoom / Doom64
    645 
    646 	if (target->player)
    647 	{	/* a frag of one sort or another */
    648 		if (!source || !source->player || source->player == target->player)
    649 		{	/* killed self somehow */
    650 			target->player->frags--;
    651 			//if (target->player->frags < 0)
    652 				//target->player->frags = 0;
    653 		}
    654 		else
    655 		{	/* killed by other player */
    656 			source->player->frags++;
    657 		}
    658 
    659 		/* else just killed by a monster */
    660 	}
    661 	else if (source && source->player && (target->flags & MF_COUNTKILL) )
    662 	{	/* a deliberate kill by a player */
    663 		source->player->killcount++;		/* count for intermission */
    664 	}
    665 	else if ((target->flags & MF_COUNTKILL) )
    666 		players[0].killcount++;			/* count all monster deaths, even */
    667 										/* those caused by other monsters */
    668 
    669 	if (target->player)
    670 	{
    671 		target->flags &= ~MF_SOLID;
    672 		target->player->playerstate = PST_DEAD;
    673 		P_DropWeapon (target->player);
    674 		if (target->health < -50)
    675 		{
    676 		    forceXdeath = true; //Force the player to the state of Xdeath
    677 
    678 			S_StartSound (target, sfx_slop);
    679 		}
    680 		else
    681 			S_StartSound (target, sfx_plrdie);
    682 
    683         deathmocktics = ticon;
    684 	}
    685 
    686 	if (forceXdeath || (target->health < -target->info->spawnhealth) && target->info->xdeathstate)
    687 		P_SetMobjState (target, target->info->xdeathstate);
    688 	else
    689 		P_SetMobjState (target, target->info->deathstate);
    690 
    691 	target->tics -= P_Random()&1;
    692 	if (target->tics < 1)
    693 		target->tics = 1;
    694 
    695 	/* */
    696 	/* drop stuff */
    697 	/* */
    698 	switch (target->type)
    699 	{
    700 	case MT_POSSESSED1: //MT_POSSESSED:
    701 		item = MT_AMMO_CLIP; //MT_CLIP;
    702 		break;
    703 	case MT_POSSESSED2: //MT_SHOTGUY:
    704 		item = MT_WEAP_SHOTGUN; //MT_SHOTGUN;
    705 		break;
    706 	/*case MT_CHAINGUY:
    707 		item = MT_WEAP_CHAINGUN; //MT_CHAINGUN;
    708 		break;*/
    709 	default:
    710 		return;
    711 	}
    712 
    713 	mo = P_SpawnMobj (target->x,target->y,ONFLOORZ, item);
    714 	mo->flags |= MF_DROPPED;		/* special versions of items */
    715 }
    716 
    717 
    718 
    719 /*
    720 =================
    721 =
    722 = P_DamageMobj
    723 =
    724 = Damages both enemies and players
    725 = inflictor is the thing that caused the damage
    726 = 		creature or missile, can be NULL (slime, etc)
    727 = source is the thing to target after taking damage
    728 =		creature or NULL
    729 = Source and inflictor are the same for melee attacks
    730 = source can be null for barrel explosions and other environmental stuff
    731 ==================
    732 */
    733 
    734 void P_DamageMobj (mobj_t *target, mobj_t *inflictor, mobj_t *source, int damage) // 800152DC
    735 {
    736 	unsigned	ang, an;
    737 	int			saved;
    738 	player_t	*player;
    739 	fixed_t		thrust;
    740 
    741 	if (!(target->flags & MF_SHOOTABLE))
    742 		return;						/* shouldn't happen... */
    743 
    744 	if (target->health <= 0)
    745 		return;
    746 
    747 	if (target->flags & MF_SKULLFLY)
    748 	{
    749 		target->momx = target->momy = target->momz = 0;
    750 	}
    751 
    752 	player = target->player;
    753 	if (player && gameskill == sk_baby)
    754 		damage >>= 1;				/* take half damage in trainer mode */
    755 
    756 	/* */
    757 	/* kick away unless using the chainsaw */
    758 	/* */
    759 	if (inflictor && (!source || !source->player || source->player->readyweapon != wp_chainsaw))
    760 	{
    761 		ang = R_PointToAngle2 (inflictor->x, inflictor->y, target->x, target->y);
    762 
    763 		thrust = (damage * ((FRACUNIT >> 2) * 100)) / target->info->mass;
    764 
    765 		/* make fall forwards sometimes */
    766 		if ( (damage < 40) && (damage > target->health) && (target->z - inflictor->z > (64*FRACUNIT)) && (P_Random ()&1))
    767 		{
    768 			ang += ANG180;
    769 			thrust *= 4;
    770 		}
    771 
    772 		an = ang >> ANGLETOFINESHIFT;
    773 		thrust >>= 16;
    774 		target->momx += thrust * finecosine[an];
    775 		target->momy += thrust * finesine[an];
    776 
    777 		// [psx/d64]: clamp thrust for players only
    778 		if (target->player)
    779 		{
    780             if (target->momx > MAXMOVE)
    781                 target->momx = MAXMOVE;
    782             else if (target->momx < -MAXMOVE)
    783                 target->momx = -MAXMOVE;
    784 
    785             if (target->momy > MAXMOVE)
    786                 target->momy = MAXMOVE;
    787             else if (target->momy < -MAXMOVE)
    788                 target->momy = -MAXMOVE;
    789 		}
    790 	}
    791 
    792 	/* */
    793 	/* player specific */
    794 	/* */
    795 	if (player)
    796 	{
    797 		if ((player->cheats&CF_GODMODE) || player->powers[pw_invulnerability])
    798 			return;
    799 
    800 		if (player->armortype)
    801 		{
    802 			if (player->armortype == 1)
    803 				saved = damage/3;
    804 			else
    805 				saved = damage/2;
    806 			if (player->armorpoints <= saved)
    807 			{	/* armor is used up */
    808 				saved = player->armorpoints;
    809 				player->armortype = 0;
    810 			}
    811 			player->armorpoints -= saved;
    812 			damage -= saved;
    813 		}
    814 		S_StartSound (target,sfx_plrpain);
    815 		player->health -= damage;		/* mirror mobj health here for Dave */
    816 		if (player->health < 0)
    817 			player->health = 0;
    818 		player->attacker = source;
    819 
    820         player->damagecount += (damage/*>>1*/);	/* add damage after armor / invuln */
    821 	}
    822 
    823 	/* */
    824 	/* do the damage */
    825 	/* */
    826 	target->health -= damage;
    827 	if (target->health <= 0)
    828 	{
    829 		P_KillMobj (source, target);
    830 		return;
    831 	}
    832 
    833 	if ( (P_Random () < target->info->painchance) && !(target->flags&MF_SKULLFLY) )
    834 	{
    835 		target->flags |= MF_JUSTHIT;		/* fight back! */
    836 		if(target->info->painstate)
    837             P_SetMobjState (target, target->info->painstate);
    838 	}
    839 
    840 	target->reactiontime = 0;		/* we're awake now...	 */
    841 	if (!target->threshold && source && (source->flags & MF_SHOOTABLE) && !(target->flags & MF_NOINFIGHTING))
    842 	{	/* if not intent on another player, chase after this one */
    843 		target->target = source;
    844 		target->threshold = BASETHRESHOLD;
    845 		if (target->state == &states[target->info->spawnstate] && target->info->seestate != S_000)
    846         {
    847 			P_SetMobjState (target, target->info->seestate);
    848         }
    849 	}
    850 }
    851