DOOM64-RE

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

p_pspr.c (29596B)


      1 /* P_pspr.c */
      2 
      3 #include "doomdef.h"
      4 #include "p_local.h"
      5 
      6 #define	LOWERSPEED		FRACUNIT*7
      7 #define	RAISESPEED		FRACUNIT*7
      8 
      9 #define	WEAPONX		    (0)*FRACUNIT
     10 #define WEAPONBOTTOM	(96)*FRACUNIT	//old 128
     11 #define WEAPONTOP		(0)*FRACUNIT	//old 32
     12 
     13 #define RECOILPITCH     0x2AA8000
     14 
     15 #define	BFGCELLS		40			/* plasma cells for a bfg attack */
     16 
     17 #define LASERRANGE          (4096*FRACUNIT)
     18 #define LASERAIMHEIGHT      (40*FRACUNIT)
     19 #define LASERDISTANCE       (30)
     20 
     21 extern int ArtifactLookupTable[8];
     22 
     23 /*============================================================================= */
     24 
     25 int		ticremainder[MAXPLAYERS]; // 800A5E70
     26 
     27 /*
     28 ==================
     29 =
     30 = P_SetupPsprites
     31 =
     32 = Called at start of level for each player
     33 ==================
     34 */
     35 
     36 void P_SetupPsprites (int curplayer) // 8001B0D0
     37 {
     38 	int	i;
     39 	player_t *player;
     40 
     41 	ticremainder[curplayer] = 0;
     42 	player = &players[curplayer];
     43 
     44 	/* remove all psprites */
     45 
     46 	for (i=0 ; i<NUMPSPRITES ; i++)
     47     {
     48 		player->psprites[i].state = NULL;
     49 		player->psprites[i].alpha = 255;
     50     }
     51 
     52 	/* spawn the gun */
     53 	player->pendingweapon = player->readyweapon;
     54 	P_BringUpWeapon (player);
     55 }
     56 
     57 /*
     58 ==================
     59 =
     60 = P_MovePsprites
     61 =
     62 = Called every tic by player thinking routine
     63 ==================
     64 */
     65 
     66 void P_MovePsprites (player_t *player) // 8001B14C
     67 {
     68 	int			i;
     69 	pspdef_t	*psp;
     70 	state_t		*state;
     71 
     72 	ticremainder[0] += vblsinframe[0];
     73 
     74 	while (ticremainder[0] >= 2)
     75 	{
     76 		ticremainder[0] -= 2;
     77 
     78 		psp = &player->psprites[0];
     79 		for (i=0 ; i<NUMPSPRITES ; i++, psp++)
     80 		{
     81 			if ( (state = psp->state) != 0)		/* a null state means not active */
     82 			{
     83 			/* drop tic count and possibly change state */
     84 				if (psp->tics != -1)	/* a -1 tic count never changes */
     85 				{
     86 					psp->tics--;
     87 					if (!psp->tics)
     88 						P_SetPsprite (player, i, psp->state->nextstate);
     89 				}
     90 			}
     91 		}
     92 	}
     93 
     94 	player->psprites[ps_flash].sx = player->psprites[ps_flashalpha].sx = player->psprites[ps_weapon].sx;
     95 	player->psprites[ps_flash].sy = player->psprites[ps_flashalpha].sy = player->psprites[ps_weapon].sy;
     96 }
     97 
     98 /*============================================================================= */
     99 
    100 /*
    101 =================
    102 =
    103 = P_RecursiveSound
    104 =
    105 = If a monster yells at a player, it will alert other monsters to the player
    106 =
    107 =================
    108 */
    109 
    110 mobj_t *soundtarget; // 800A5E74
    111 
    112 void P_RecursiveSound (sector_t *sec, int soundblocks) // 8001B254
    113 {
    114 	int			i;
    115 	line_t		*check;
    116 	sector_t	*other;
    117 	sector_t	*front, *back;
    118 
    119 	/* wake up all monsters in this sector */
    120 	if (sec->validcount == validcount && sec->soundtraversed <= soundblocks+1)
    121 		return;		/* already flooded */
    122 
    123 	sec->validcount = validcount;
    124 	sec->soundtraversed = soundblocks+1;
    125 	sec->soundtarget = soundtarget;
    126 
    127 	for (i=0 ;i<sec->linecount ; i++)
    128 	{
    129 		check = sec->lines[i];
    130 		back = check->backsector;
    131 		if (!back)
    132 			continue;		/* single sided */
    133 
    134 		front = check->frontsector;
    135 		if (front->floorheight >= back->ceilingheight ||
    136             front->ceilingheight <= back->floorheight ||
    137             back->floorheight == back->ceilingheight) // [d64] added this check
    138 			continue;		/* closed door */
    139 
    140 		if ( front == sec)
    141 			other = back;
    142 		else
    143 			other = front;
    144 
    145 		if (check->flags & ML_SOUNDBLOCK)
    146 		{
    147 			if (!soundblocks)
    148 				P_RecursiveSound (other, 1);
    149 		}
    150 		else
    151 			P_RecursiveSound (other, soundblocks);
    152 	}
    153 }
    154 
    155 
    156 /*
    157 =================
    158 =
    159 = P_NoiseAlert
    160 =
    161 =================
    162 */
    163 
    164 void P_NoiseAlert (player_t *player) // 8001B3A4
    165 {
    166 	sector_t	*sec;
    167 
    168 	sec = player->mo->subsector->sector;
    169 
    170 	if (player->lastsoundsector == (void *)sec)
    171 		return;		/* don't bother doing it again here */
    172 
    173     soundtarget = player->mo;
    174 	player->lastsoundsector = (void *)sec;
    175 
    176 	validcount++;
    177 	P_RecursiveSound (sec, 0);
    178 }
    179 
    180 
    181 /*
    182 ==================
    183 =
    184 = P_SetPsprite
    185 =
    186 ==================
    187 */
    188 
    189 void P_SetPsprite (player_t *player, int position, statenum_t stnum) // 8001B3FC
    190 {
    191 	pspdef_t *psp;
    192 	state_t	 *state;
    193 
    194 	psp = &player->psprites[position];
    195 
    196 	do
    197 	{
    198 		if (!stnum)
    199 		{
    200 			psp->state = NULL;
    201 			break;		/* object removed itself */
    202 		}
    203 		state = &states[stnum];
    204 		psp->state = state;
    205 		psp->tics = state->tics;  /* could be 0 */
    206 
    207 		/* call action routine */
    208 		if (state->action)
    209 		{
    210 			state->action (player, psp);
    211 			if (!psp->state)
    212 				break;
    213 		}
    214 		stnum = psp->state->nextstate;
    215 	} while (!psp->tics);	/* an initial state of 0 could cycle through */
    216 }
    217 
    218 
    219 /*
    220 ===============================================================================
    221 
    222 						PSPRITE ACTIONS
    223 
    224 ===============================================================================
    225 */
    226 
    227 /*
    228 ===============================================================================
    229 
    230 PSPRITE ACTIONS
    231 
    232 ===============================================================================
    233 */
    234 
    235 weaponinfo_t	weaponinfo[NUMWEAPONS] = // 8005AD80
    236 {
    237     {	/* saw */
    238 /* ammo 		*/	am_noammo,
    239 /* upstate 		*/	S_708,//S_SAWUP,
    240 /* downstate 	*/	S_707,//S_SAWDOWN,
    241 /* readystate 	*/	S_705,//S_SAW,
    242 /* atkstate 	*/	S_709,//S_SAW1,
    243 /* flashstate 	*/	S_000 //S_NULL
    244 	},
    245 
    246 	{	/* fist */
    247 /* ammo 		*/	am_noammo,
    248 /* upstate 		*/	S_714,//S_PUNCHUP,
    249 /* downstate 	*/	S_713,//S_PUNCHDOWN,
    250 /* readystate 	*/	S_712,//S_PUNCH,
    251 /* atkstate 	*/	S_715,//S_PUNCH1,
    252 /* flashstate 	*/	S_000 //S_NULL
    253 	},
    254 
    255 	{	/* pistol */
    256 /* ammo 		*/	am_clip,
    257 /* upstate 		*/	S_722,//S_PISTOLUP,
    258 /* downstate 	*/	S_721,//S_PISTOLDOWN,
    259 /* readystate 	*/	S_720,//S_PISTOL,
    260 /* atkstate 	*/	S_724,//S_PISTOL2,
    261 /* flashstate 	*/	S_728 //S_PISTOLFLASH
    262 	},
    263 
    264 	{	/* shotgun */
    265 /* ammo 		*/	am_shell,
    266 /* upstate 		*/	S_731,//S_SGUNUP,
    267 /* downstate 	*/	S_730,//S_SGUNDOWN,
    268 /* readystate 	*/	S_729,//S_SGUN,
    269 /* atkstate 	*/	S_733,//S_SGUN2,
    270 /* flashstate 	*/	S_738 //S_SGUNFLASH1
    271 	},
    272 
    273     {	/* super shotgun */
    274 /* ammo 		*/	am_shell,
    275 /* upstate 		*/	S_741,//S_DSGUNUP,
    276 /* downstate 	*/	S_740,//S_DSGUNDOWN,
    277 /* readystate 	*/	S_739,//S_DSGUN,
    278 /* atkstate 	*/	S_742,//S_DSGUN1,
    279 /* flashstate 	*/	S_752 //S_DSGUNFLASH1
    280     },
    281 
    282 	{	/* chaingun */
    283 /* ammo 		*/	am_clip,
    284 /* upstate 		*/	S_755,//S_CHAINUP,
    285 /* downstate 	*/	S_754,//S_CHAINDOWN,
    286 /* readystate 	*/	S_753,//S_CHAIN,
    287 /* atkstate 	*/	S_756,//S_CHAIN1,
    288 /* flashstate 	*/	S_759 //S_CHAINFLASH1
    289 	},
    290 
    291 	{	/* missile */
    292 /* ammo 		*/	am_misl,
    293 /* upstate 		*/	S_763,//S_MISSILEUP,
    294 /* downstate 	*/	S_762,//S_MISSILEDOWN,
    295 /* readystate 	*/	S_761,//S_MISSILE,
    296 /* atkstate 	*/	S_764,//S_MISSILE1,
    297 /* flashstate 	*/	S_767 //S_MISSILEFLASH1
    298 	},
    299 
    300 	{	/* plasma */
    301 /* ammo 		*/	am_cell,
    302 /* upstate 		*/	S_773,//S_PLASMAUP,
    303 /* downstate 	*/	S_772,//S_PLASMADOWN,
    304 /* readystate 	*/	S_771,//S_PLASMA,
    305 /* atkstate 	*/	S_775,//S_PLASMA1,
    306 /* flashstate 	*/	S_000 //S_NULL
    307 	},
    308 
    309 	{	/* bfg */
    310 /* ammo 		*/	am_cell,
    311 /* upstate 		*/	S_783,//S_BFGUP,
    312 /* downstate 	*/	S_782,//S_BFGDOWN,
    313 /* readystate 	*/	S_781,//S_BFG,
    314 /* atkstate 	*/	S_784,//S_BFG1,
    315 /* flashstate 	*/	S_788 //S_BFGFLASH1
    316 	},
    317 
    318     {	/* laser rifle */
    319 /* ammo 		*/	am_cell,
    320 /* upstate 		*/	S_793,//S_LASERUP,
    321 /* downstate 	*/	S_792,//S_LASERDOWN,
    322 /* readystate 	*/	S_791,//S_LASER,
    323 /* atkstate 	*/	S_794,//S_LASER1,
    324 /* flashstate 	*/	S_796 //S_LASERFLASH
    325 	}
    326 };
    327 
    328 
    329 /*
    330 ================
    331 =
    332 = P_BringUpWeapon
    333 =
    334 = Starts bringing the pending weapon up from the bottom of the screen
    335 = Uses player
    336 ================
    337 */
    338 
    339 void P_BringUpWeapon (player_t *player) // 8001B4BC
    340 {
    341 	statenum_t	new;
    342 
    343 	if (player->pendingweapon == wp_nochange)
    344 		player->pendingweapon = player->readyweapon;
    345 
    346 	if (player->pendingweapon == wp_chainsaw)
    347         S_StartSound(player->mo, sfx_sawup);
    348     else if (player->pendingweapon == wp_plasma)
    349         S_StartSound(player->mo, sfx_electric);
    350 
    351 	new = weaponinfo[player->pendingweapon].upstate;
    352 
    353 	player->pendingweapon = wp_nochange;
    354 	player->psprites[ps_weapon].sx = WEAPONX;
    355 	player->psprites[ps_weapon].sy = WEAPONBOTTOM;
    356 	player->psprites[ps_flashalpha].alpha = 255;
    357 	P_SetPsprite (player, ps_weapon, new);
    358 }
    359 
    360 /*
    361 ================
    362 =
    363 = P_DropWeapon
    364 =
    365 = Player died, so put the weapon away
    366 ================
    367 */
    368 
    369 void P_DropWeapon (player_t *player) // 8001B580
    370 {
    371 	P_SetPsprite (player, ps_weapon, weaponinfo[player->readyweapon].downstate);
    372 }
    373 
    374 /*
    375 ================
    376 =
    377 = P_CheckAmmo
    378 =
    379 = returns true if there is enough ammo to shoot
    380 = if not, selects the next weapon to use
    381 ================
    382 */
    383 
    384 boolean P_CheckAmmo (player_t *player) // 8001B5BC
    385 {
    386 	ammotype_t	ammo;
    387 	int			count;
    388 
    389 	ammo = weaponinfo[player->readyweapon].ammo;
    390 
    391 	if (player->readyweapon == wp_bfg)
    392 		count = BFGCELLS;
    393     else if (player->readyweapon == wp_laser)
    394     {
    395       count = ArtifactLookupTable[player->artifacts];
    396       if (count == 0)
    397         count = 1;
    398     }
    399 	else if (player->readyweapon == wp_supershotgun)
    400 		count = 2;	// Double barrel.
    401 	else
    402 		count = 1;
    403 
    404 	if (ammo == am_noammo || player->ammo[ammo] >= count)
    405 		return true;
    406 
    407 	/* out of ammo, pick a weapon to change to */
    408 	do
    409 	{
    410 		if (player->weaponowned[wp_plasma] && player->ammo[am_cell])
    411 			player->pendingweapon = wp_plasma;
    412 		else if (player->weaponowned[wp_supershotgun] && player->ammo[am_shell] > 2)
    413 			player->pendingweapon = wp_supershotgun;
    414 		else if (player->weaponowned[wp_chaingun] && player->ammo[am_clip])
    415 			player->pendingweapon = wp_chaingun;
    416 		else if (player->weaponowned[wp_shotgun] && player->ammo[am_shell])
    417 			player->pendingweapon = wp_shotgun;
    418 		else if (player->ammo[am_clip])
    419 			player->pendingweapon = wp_pistol;
    420 		else if (player->weaponowned[wp_chainsaw])
    421 			player->pendingweapon = wp_chainsaw;
    422 		else if (player->weaponowned[wp_missile] && player->ammo[am_misl])
    423 			player->pendingweapon = wp_missile;
    424 		else if (player->weaponowned[wp_bfg] && player->ammo[am_cell]>40)
    425 			player->pendingweapon = wp_bfg;
    426 		else
    427 			player->pendingweapon = wp_fist;
    428 	} while (player->pendingweapon == wp_nochange);
    429 
    430 	P_SetPsprite (player, ps_weapon, weaponinfo[player->readyweapon].downstate);
    431 
    432 	return false;
    433 }
    434 
    435 
    436 /*
    437 ================
    438 =
    439 = P_FireWeapon
    440 =
    441 ================
    442 */
    443 
    444 void P_FireWeapon (player_t *player) // 8001B7CC
    445 {
    446 	statenum_t	new;
    447 
    448 	if (!P_CheckAmmo (player))
    449 		return;
    450 
    451 	P_SetMobjState (player->mo, S_006/*S_PLAY_ATK1*/);
    452 
    453 	player->psprites[ps_weapon].sx = WEAPONX;
    454 	player->psprites[ps_weapon].sy = WEAPONTOP;
    455 	new = weaponinfo[player->readyweapon].atkstate;
    456 	P_SetPsprite (player, ps_weapon, new);
    457 	P_NoiseAlert (player);
    458 }
    459 
    460 /*
    461 =================
    462 =
    463 = A_WeaponReady
    464 =
    465 = The player can fire the weapon or change to another weapon at this time
    466 =
    467 =================
    468 */
    469 
    470 void A_WeaponReady (player_t *player, pspdef_t *psp) // 8001B83C
    471 {
    472 	statenum_t	new;
    473 	int			angle;
    474 
    475 	/* */
    476 	/* check for change */
    477 	/*  if player is dead, put the weapon away */
    478 	/* */
    479 	if (player->pendingweapon != wp_nochange || !player->health)
    480 	{
    481 	    /* change weapon (pending weapon should allready be validated) */
    482 	    P_DropWeapon(player);
    483 		return;
    484 	}
    485 
    486 	/* */
    487 	/* check for fire */
    488 	/* */
    489 	/* the missile launcher and bfg do not auto fire */
    490 	if (ticbuttons[0] & BT_DATA[0]->BT_ATTACK)
    491 	{
    492 		P_FireWeapon (player);
    493 		return;
    494 	}
    495 
    496 	/* */
    497 	/* bob the weapon based on movement speed */
    498 	/* */
    499 	//angle = (64*gamevbls)&(FINEANGLES-1);
    500 	angle = (64*ticon)&(FINEANGLES-1); // PsxDoom/D64 use ticon no gamevbls
    501 	psp->sx = WEAPONX + FixedMul(player->bob, finecosine[angle]);
    502 	angle &= FINEANGLES/2-1;
    503 	psp->sy = WEAPONTOP + FixedMul(player->bob, finesine[angle]);
    504 }
    505 
    506 
    507 /*
    508 =================
    509 =
    510 = A_ReFire
    511 =
    512 = The player can re fire the weapon without lowering it entirely
    513 =
    514 =================
    515 */
    516 
    517 void A_ReFire (player_t *player, pspdef_t *psp) // 8001B91C
    518 {
    519 	/* */
    520 	/* check for fire (if a weaponchange is pending, let it go through instead) */
    521 	/* */
    522 	if ((ticbuttons[0] & BT_DATA[0]->BT_ATTACK)
    523 	&& player->pendingweapon == wp_nochange && player->health)
    524 	{
    525 		player->refire++;
    526 		P_FireWeapon (player);
    527 	}
    528 	else
    529 	{
    530 		player->refire = 0;
    531 		P_CheckAmmo (player);
    532 	}
    533 }
    534 
    535 /*
    536 =================
    537 =
    538 = A_CheckReload
    539 =
    540 =================
    541 */
    542 
    543 void A_CheckReload(player_t *player, pspdef_t *psp) // 8001B9A0
    544 {
    545 	P_CheckAmmo(player);
    546 }
    547 
    548 /*
    549 =================
    550 =
    551 = A_Lower
    552 =
    553 =================
    554 */
    555 
    556 void A_Lower (player_t *player, pspdef_t *psp) // 8001B9C0
    557 {
    558 	psp->sy += LOWERSPEED;
    559 	if (psp->sy < WEAPONBOTTOM )
    560 		return;
    561 
    562     /* */
    563     /* [d64] stop plasma buzz */
    564     /* */
    565     if (player->readyweapon == wp_plasma)
    566         S_StopSound(NULL, sfx_electric);
    567 
    568     /* */
    569     /* [d64] clear flash graphic drawer */
    570     /* */
    571     P_SetPsprite(player, ps_flash, S_000);
    572 
    573 	if (player->playerstate == PST_DEAD)
    574 	{
    575 		psp->sy = WEAPONBOTTOM;
    576 		return;		/* don't bring weapon back up */
    577 	}
    578 
    579 	/* */
    580 	/* The old weapon has been lowered off the screen, so change the weapon */
    581 	/* and start raising it */
    582 	/* */
    583 	if (!player->health)
    584 	{	/* player is dead, so keep the weapon off screen */
    585 		P_SetPsprite (player,  ps_weapon, S_000);
    586 		return;
    587 	}
    588 
    589 	player->readyweapon = player->pendingweapon;
    590 
    591 	P_BringUpWeapon (player);
    592 }
    593 
    594 
    595 /*
    596 =================
    597 =
    598 = A_Raise
    599 =
    600 =================
    601 */
    602 
    603 void A_Raise (player_t *player, pspdef_t *psp) // 8001BA84
    604 {
    605 	statenum_t	new;
    606 
    607 	psp->sy -= RAISESPEED;
    608 
    609 	if (psp->sy > WEAPONTOP )
    610 		return;
    611 
    612 	psp->sy = WEAPONTOP;
    613 
    614 	/* */
    615 	/* the weapon has been raised all the way, so change to the ready state */
    616 	/* */
    617 	new = weaponinfo[player->readyweapon].readystate;
    618 
    619 	P_SetPsprite (player, ps_weapon, new);
    620 }
    621 
    622 
    623 /*
    624 ================
    625 =
    626 = A_GunFlash
    627 =
    628 =================
    629 */
    630 
    631 void A_GunFlash (player_t *player, pspdef_t *psp) // 8001BAD8
    632 {
    633     /* [d64] set alpha on flash frame */
    634     if(player->readyweapon == wp_missile)
    635         player->psprites[ps_flashalpha].alpha = 100;
    636 
    637 	P_SetPsprite (player,ps_flashalpha,weaponinfo[player->readyweapon].flashstate);
    638 }
    639 
    640 
    641 /*
    642 ===============================================================================
    643 
    644 						WEAPON ATTACKS
    645 
    646 ===============================================================================
    647 */
    648 
    649 
    650 /*
    651 ==================
    652 =
    653 = A_Punch
    654 =
    655 ==================
    656 */
    657 
    658 void A_Punch (player_t *player, pspdef_t *psp) // 8001BB2C
    659 {
    660 	angle_t		angle;
    661 	int			damage;
    662 
    663 	//damage = ((P_Random ()&7)*3)+3;
    664 	damage = ((P_Random()&7)+1)*3;
    665 	if (player->powers[pw_strength])
    666 		damage *= 10;
    667 	angle = player->mo->angle;
    668 	angle += (angle_t)(P_Random()-P_Random())<<18;
    669 	P_LineAttack (player->mo, angle, 0, MELEERANGE, MAXINT, damage);
    670     /* turn to face target */
    671 	if (linetarget)
    672 	{
    673 	    S_StartSound(player->mo, sfx_punch);
    674 		player->mo->angle = R_PointToAngle2 (player->mo->x, player->mo->y, linetarget->x, linetarget->y);
    675 	}
    676 }
    677 
    678 /*
    679 ==================
    680 =
    681 = A_Saw
    682 =
    683 ==================
    684 */
    685 
    686 void A_Saw (player_t *player, pspdef_t *psp) // 8001BC1C
    687 {
    688 	angle_t		angle;
    689 	int			damage;
    690 	int         rnd1, rnd2;
    691 
    692 	//damage = ((P_Random ()&7)*3)+3;
    693 	damage = ((P_Random()&7)+1)*3;
    694 	angle = player->mo->angle;
    695 	rnd1 = P_Random();
    696 	rnd2 = P_Random();
    697 	angle += (angle_t)(rnd2-rnd1)<<18;
    698 	/* use meleerange + 1 se the puff doesn't skip the flash */
    699 	P_LineAttack (player->mo, angle, 0, MELEERANGE+1, MAXINT, damage);
    700 	if (!linetarget)
    701 	{
    702 		S_StartSound (player->mo, sfx_saw1);
    703 		return;
    704 	}
    705 	S_StartSound (player->mo, sfx_saw2);
    706 
    707 	/* turn to face target */
    708 	angle = R_PointToAngle2 (player->mo->x, player->mo->y, linetarget->x, linetarget->y);
    709 	if (angle - player->mo->angle > ANG180)
    710 	{
    711 		if (angle - player->mo->angle < -ANG90/20)
    712 			player->mo->angle = angle + ANG90/21;
    713 		else
    714 			player->mo->angle -= ANG90/20;
    715 	}
    716 	else
    717 	{
    718 		if (angle - player->mo->angle > ANG90/20)
    719 			player->mo->angle = angle - ANG90/21;
    720 		else
    721 			player->mo->angle += ANG90/20;
    722 	}
    723 	player->mo->flags |= MF_JUSTATTACKED;
    724 }
    725 
    726 /*
    727 ==================
    728 =
    729 = A_ChainSawReady
    730 =
    731 ==================
    732 */
    733 
    734 void A_ChainSawReady(player_t *player, pspdef_t *psp) // 8001BDA8
    735 {
    736     S_StartSound(player->mo, sfx_sawidle);
    737     A_WeaponReady(player, psp);
    738 }
    739 
    740 /*
    741 ==================
    742 =
    743 = A_FireMissile
    744 =
    745 ==================
    746 */
    747 
    748 void A_FireMissile (player_t *player, pspdef_t *psp) // 8001BDE4
    749 {
    750 	player->ammo[weaponinfo[player->readyweapon].ammo]--;
    751 
    752 	player->recoilpitch = RECOILPITCH;
    753 
    754 	if(player->onground)
    755         P_Thrust(player, player->mo->angle + ANG180, FRACUNIT);
    756 
    757 	P_SpawnPlayerMissile (player->mo, MT_PROJ_ROCKET);
    758 }
    759 
    760 
    761 /*
    762 ==================
    763 =
    764 = A_FireBFG
    765 =
    766 ==================
    767 */
    768 
    769 void A_FireBFG (player_t *player, pspdef_t *psp) // 8001BE78
    770 {
    771 	player->ammo[weaponinfo[player->readyweapon].ammo] -= BFGCELLS;
    772 	P_SpawnPlayerMissile (player->mo, MT_PROJ_BFG);
    773 }
    774 
    775 
    776 /*
    777 ==================
    778 =
    779 = A_PlasmaAnimate
    780 =
    781 ==================
    782 */
    783 int pls_animpic = 0; // 8005AE70
    784 
    785 void A_PlasmaAnimate(player_t *player, pspdef_t *psp) // 8001BED8
    786 {
    787     P_SetPsprite(player, ps_flash, pls_animpic + S_778);
    788 
    789     if (++pls_animpic >= 3)
    790         pls_animpic = 0;
    791 }
    792 
    793 /*
    794 ==================
    795 =
    796 = A_FirePlasma
    797 =
    798 ==================
    799 */
    800 
    801 void A_FirePlasma (player_t *player, pspdef_t *psp) // 8001BF2C
    802 {
    803 	player->ammo[weaponinfo[player->readyweapon].ammo]--;
    804 	P_SetPsprite (player,ps_flash,S_000);
    805 	P_SpawnPlayerMissile (player->mo, MT_PROJ_PLASMA);
    806 }
    807 
    808 /*
    809 ===============
    810 =
    811 = P_BulletSlope
    812 =
    813 ===============
    814 */
    815 
    816 fixed_t bulletslope; // 800A5E78
    817 
    818 void P_BulletSlope(mobj_t*	mo) // 8001BF88
    819 {
    820 	angle_t	an;
    821 
    822 	// see which target is to be aimed at
    823 	an = mo->angle;
    824 	bulletslope = P_AimLineAttack(mo, an, 0, 16 * 64 * FRACUNIT);
    825 
    826 	if (!linetarget)
    827 	{
    828 		an += 1 << 26;
    829 		bulletslope = P_AimLineAttack(mo, an, 0, 16 * 64 * FRACUNIT);
    830 		if (!linetarget)
    831 		{
    832 			an -= 2 << 26;
    833 			bulletslope = P_AimLineAttack(mo, an, 0, 16 * 64 * FRACUNIT);
    834 		}
    835 	}
    836 }
    837 
    838 /*
    839 ===============
    840 =
    841 = P_GunShot
    842 =
    843 ===============
    844 */
    845 
    846 void P_GunShot (mobj_t *mo, boolean accurate) // 8001C024
    847 {
    848 	angle_t		angle;
    849 	int			damage;
    850 	int         rnd1, rnd2;
    851 
    852 	damage = ((P_Random ()&3)*4)+4;
    853 	angle = mo->angle;
    854 	if (!accurate)
    855     {
    856         rnd1 = P_Random();
    857         rnd2 = P_Random();
    858 		angle += (rnd2-rnd1)<<18;
    859     }
    860 	P_LineAttack (mo, angle, 0, MISSILERANGE, bulletslope, damage);
    861 }
    862 
    863 /*
    864 ==================
    865 =
    866 = A_FirePistol
    867 =
    868 ==================
    869 */
    870 
    871 void A_FirePistol (player_t *player, pspdef_t *psp) // 8001C0B4
    872 {
    873 	S_StartSound (player->mo, sfx_pistol);
    874 
    875 	player->ammo[weaponinfo[player->readyweapon].ammo]--;
    876 	P_SetPsprite (player,ps_flashalpha,weaponinfo[player->readyweapon].flashstate);
    877 	P_BulletSlope(player->mo);
    878 
    879 	P_GunShot (player->mo, !player->refire);
    880 }
    881 
    882 /*
    883 ==================
    884 =
    885 = A_FireShotgun
    886 =
    887 ==================
    888 */
    889 
    890 void A_FireShotgun (player_t *player, pspdef_t *psp) // 8001C138
    891 {
    892 	angle_t		angle;
    893 	int			damage;
    894 	int			i;
    895 
    896 	S_StartSound (player->mo, sfx_shotgun);
    897 
    898 	player->ammo[weaponinfo[player->readyweapon].ammo]--;
    899 	player->recoilpitch = RECOILPITCH;
    900 
    901 	P_SetPsprite (player,ps_flashalpha,weaponinfo[player->readyweapon].flashstate);
    902 	P_BulletSlope(player->mo);
    903 
    904 	for (i=0 ; i<7 ; i++)
    905 	{
    906 	    P_GunShot(player->mo, false);
    907 	}
    908 }
    909 
    910 /*
    911 ==================
    912 =
    913 = A_FireShotgun2
    914 =
    915 ==================
    916 */
    917 
    918 void A_FireShotgun2(player_t *player, pspdef_t *psp) // 8001C210
    919 {
    920     angle_t		angle;
    921 	int			damage;
    922 	int			i;
    923 
    924 	S_StartSound(player->mo, sfx_sht2fire);
    925 	P_SetMobjState(player->mo, S_007);
    926 
    927 	player->ammo[weaponinfo[player->readyweapon].ammo] -= 2;
    928 	player->recoilpitch = RECOILPITCH;
    929 
    930 	if(player->onground)
    931         P_Thrust(player, player->mo->angle + ANG180, FRACUNIT);
    932 
    933 	P_SetPsprite(player, ps_flashalpha, weaponinfo[player->readyweapon].flashstate);
    934 	P_BulletSlope(player->mo);
    935 
    936 	for (i = 0; i<20; i++)
    937 	{
    938 		//damage = ((P_Random() % 3) * 5) + 5;
    939 		damage = 5 * (P_Random() % 3 + 1);
    940 		angle = player->mo->angle;
    941 		angle += (P_Random() - P_Random()) << 19;
    942 		P_LineAttack(player->mo, angle, 0, MISSILERANGE, bulletslope + ((P_Random() - P_Random()) << 5), damage);
    943 	}
    944 }
    945 
    946 /*
    947 ==================
    948 =
    949 = A_CockSgun
    950 =
    951 ==================
    952 */
    953 #if 0 //No Used In PSX Doom/ Doom64
    954 void A_CockSgun (player_t *player, pspdef_t *psp)
    955 {
    956 	S_StartSound (player->mo, sfx_sgcock);
    957 }
    958 #endif // 0
    959 
    960 /*
    961 ==================
    962 =
    963 = A_FireCGun
    964 =
    965 ==================
    966 */
    967 
    968 void A_FireCGun (player_t *player, pspdef_t *psp) // 8001C3F8
    969 {
    970     int ammo;
    971     int rand;
    972 
    973     ammo = player->ammo[weaponinfo[player->readyweapon].ammo];
    974 
    975 	if (!ammo)
    976 		return;
    977 
    978     S_StartSound (player->mo, sfx_pistol);
    979 
    980 	player->ammo[weaponinfo[player->readyweapon].ammo]--;
    981 
    982 	/* randomize sx */
    983     rand = (((P_Random() & 1) << 1) - 1);
    984     psp->sx = (rand * FRACUNIT);
    985 
    986     /* randomize sy */
    987     rand = ((((ammo - 1) & 1) << 1) - 1);
    988     psp->sy = WEAPONTOP - (rand * (2*FRACUNIT));
    989 
    990     player->recoilpitch = RECOILPITCH;
    991 
    992 	P_SetPsprite (player,ps_flashalpha,weaponinfo[player->readyweapon].flashstate + psp->state - &states[S_756/*S_CHAIN1*/]);
    993     P_BulletSlope(player->mo);
    994 
    995 	player->psprites[ps_flashalpha].alpha = 160;
    996 
    997 	P_GunShot (player->mo, !player->refire);
    998 }
    999 
   1000 /*
   1001 ================
   1002 =
   1003 = A_BFGFlash
   1004 =
   1005 =================
   1006 */
   1007 
   1008 void A_BFGFlash(mobj_t* actor) // 8001C548
   1009 {
   1010     players[0].bfgcount = 100;
   1011     actor->alpha = 170;
   1012 }
   1013 
   1014 /*
   1015 ================
   1016 =
   1017 = A_BFGSpray
   1018 =
   1019 = Spawn a BFG explosion on every monster in view
   1020 =
   1021 =================
   1022 */
   1023 
   1024 void A_BFGSpray (mobj_t *mo) // 8001C560
   1025 {
   1026 	int			i, j, damage;
   1027 	angle_t		an;
   1028 	int         alpha;
   1029 
   1030 	alpha = 0;
   1031 
   1032 	/* offset angles from its attack angle */
   1033 	for (i=0 ; i<40 ; i++)
   1034 	{
   1035 		an = mo->angle - ANG90/2 + ANG90/40*i;
   1036 		/* mo->target is the originator (player) of the missile */
   1037 		P_AimLineAttack (mo->target, an, 0, 16*64*FRACUNIT);
   1038 		if (!linetarget)
   1039 			continue;
   1040 		P_SpawnMobj (linetarget->x, linetarget->y, linetarget->z + (linetarget->height>>1), MT_BFGSPREAD);
   1041 		damage = 0;
   1042 		for (j=0;j<15;j++)
   1043         {
   1044 			damage += (P_Random()&7) + 1;
   1045         }
   1046 		P_DamageMobj (linetarget, mo->target,mo->target, damage);
   1047 	}
   1048 
   1049     alpha = mo->alpha * 3;
   1050     if (alpha < 0)
   1051         alpha += 3;
   1052 
   1053     mo->alpha = alpha >> 2;
   1054 }
   1055 
   1056 /*
   1057 ================
   1058 =
   1059 = A_BFGsound
   1060 =
   1061 =================
   1062 */
   1063 
   1064 void A_BFGsound (player_t *player, pspdef_t *psp) // 8001C698
   1065 {
   1066 	S_StartSound (player->mo, sfx_bfg);
   1067 }
   1068 
   1069 #if 0
   1070 /*
   1071 ================
   1072 =
   1073 = A_OpenShotgun2
   1074 =
   1075 =================
   1076 */
   1077 
   1078 void A_OpenShotgun2(player_t *player, pspdef_t *psp)//L80021AFC()
   1079 {
   1080 	S_StartSound(player->mo, sfx_dbopn);
   1081 }
   1082 #endif // 0
   1083 
   1084 /*
   1085 ================
   1086 =
   1087 = A_LoadShotgun2
   1088 =
   1089 =================
   1090 */
   1091 
   1092 void A_LoadShotgun2(player_t *player, pspdef_t *psp) // 8001C6C0
   1093 {
   1094 	S_StartSound(player->mo, sfx_sht2load1);
   1095 }
   1096 
   1097 /*
   1098 ================
   1099 =
   1100 = A_CloseShotgun2
   1101 =
   1102 =================
   1103 */
   1104 
   1105 void A_CloseShotgun2(player_t *player, pspdef_t *psp) // 8001C6E8
   1106 {
   1107 	S_StartSound(player->mo, sfx_sht2load2);
   1108 	//A_ReFire(player, psp);
   1109 }
   1110 
   1111 /*
   1112 ================
   1113 =
   1114 = P_LaserCrossBSP
   1115 =
   1116 =================
   1117 */
   1118 
   1119 void P_LaserCrossBSP(int bspnum, laserdata_t *laser) // 8001C710
   1120 {
   1121     node_t* node;
   1122     int ds1, ds2;
   1123     int s1, s2;
   1124     int dist;
   1125     int frac;
   1126     mobj_t *marker;
   1127     laserdata_t *childlaser;
   1128     laser_t *next_cl, *next_l;
   1129     fixed_t x, y, z;
   1130     fixed_t x1, y1, z1;
   1131     fixed_t x2, y2, z2;
   1132     fixed_t nx, ny, ndx, ndy;
   1133 
   1134     while(!(bspnum & NF_SUBSECTOR))
   1135     {
   1136         node = &nodes[bspnum];
   1137 
   1138         x1 = laser->x1;
   1139         y1 = laser->y1;
   1140         z1 = laser->z1;
   1141         x2 = laser->x2;
   1142         y2 = laser->y2;
   1143         z2 = laser->z2;
   1144 
   1145         nx = node->line.x;
   1146         ny = node->line.y;
   1147         ndx = (node->line.dx >> FRACBITS);
   1148         ndy = (node->line.dy >> FRACBITS);
   1149 
   1150         /* traverse nodes */
   1151         ds1 = (((x1 - nx) >> FRACBITS) * ndy) - (((y1 - ny) >> FRACBITS) * ndx);
   1152         ds2 = (((x2 - nx) >> FRACBITS) * ndy) - (((y2 - ny) >> FRACBITS) * ndx);
   1153 
   1154         s1 = (ds1 < 0);
   1155         s2 = (ds2 < 0);
   1156 
   1157         /* did the two laser points cross the node? */
   1158         if(s1 == s2)
   1159         {
   1160             bspnum = node->children[s1];
   1161             continue;
   1162         }
   1163 
   1164         /* new child laser */
   1165         childlaser = (laserdata_t *)Z_Malloc( sizeof(*childlaser), PU_LEVSPEC, 0);
   1166 
   1167         /* copy laser pointer */
   1168         *childlaser = *laser;
   1169 
   1170         /* get the intercepting point of the laser and node */
   1171         frac = FixedDiv(ds1, ds1 - ds2);
   1172 
   1173         x = (((x2 - x1) >> FRACBITS) * frac) + x1;
   1174         y = (((y2 - y1) >> FRACBITS) * frac) + y1;
   1175         z = (((z2 - z1) >> FRACBITS) * frac) + z1;
   1176 
   1177         /* update endpoint of current laser to intercept point */
   1178         laser->x2 = x;
   1179         laser->y2 = y;
   1180         laser->z2 = z;
   1181 
   1182         /* childlaser begins at intercept point */
   1183         childlaser->x1 = x;
   1184         childlaser->y1 = y;
   1185         childlaser->z1 = z;
   1186 
   1187         /* update distmax */
   1188         dist = (laser->distmax * frac) >> FRACBITS;
   1189 
   1190         childlaser->distmax = laser->distmax - dist;
   1191         laser->distmax = dist;
   1192 
   1193         /* point to child laser */
   1194         laser->next = childlaser;
   1195 
   1196         /* traverse child nodes */
   1197         P_LaserCrossBSP(node->children[s1], laser);
   1198 
   1199         laser = childlaser;
   1200         bspnum = node->children[s2];
   1201     }
   1202 
   1203     /* subsector was hit, spawn a marker between the two laser points */
   1204     x = (laser->x1 + laser->x2) >> 1;
   1205     y = (laser->y1 + laser->y2) >> 1;
   1206     z = (laser->z1 + laser->z2) >> 1;
   1207 
   1208     marker = P_SpawnMobj(x, y, z, MT_LASERMARKER);
   1209 
   1210     /* have marker point to which laser it belongs to */
   1211     marker->extradata = (laser_t*)laser;
   1212     laser->marker = marker;
   1213 }
   1214 
   1215 /*
   1216 ================
   1217 =
   1218 = T_LaserThinker
   1219 =
   1220 =================
   1221 */
   1222 
   1223 void T_LaserThinker(laser_t *laser) // 8001C9B8
   1224 {
   1225     fade_t *fade;
   1226     laserdata_t *pThisLaser;
   1227 
   1228     pThisLaser = laser->laserdata;
   1229     pThisLaser ->dist += 64;
   1230 
   1231     /* laser reached its destination? */
   1232     if(pThisLaser->dist >= pThisLaser->distmax)
   1233     {
   1234         /* reached the end? */
   1235         if (!pThisLaser->next)
   1236         {
   1237             P_RemoveThinker(&laser->thinker);
   1238 
   1239             /* fade out the laser puff */
   1240             fade = Z_Malloc (sizeof(*fade), PU_LEVSPEC, 0);
   1241             P_AddThinker (&fade->thinker);
   1242             fade->thinker.function = T_FadeThinker;
   1243             fade->amount = -24;
   1244             fade->destAlpha = 0;
   1245             fade->flagReserve = 0;
   1246             fade->mobj = laser->marker;
   1247         }
   1248         else
   1249         {
   1250             laser->laserdata = pThisLaser->next;
   1251         }
   1252 
   1253         P_RemoveMobj(pThisLaser->marker);
   1254         Z_Free(pThisLaser);
   1255     }
   1256     else
   1257     {
   1258         /* update laser's location */
   1259         pThisLaser->x1 += (pThisLaser->slopex * 32);
   1260         pThisLaser->y1 += (pThisLaser->slopey * 32);
   1261         pThisLaser->z1 += (pThisLaser->slopez * 32);
   1262     }
   1263 }
   1264 
   1265 /*
   1266 ================
   1267 =
   1268 = A_FireLaser
   1269 =
   1270 =================
   1271 */
   1272 extern fixed_t         aimfrac;        // 800A5720
   1273 
   1274 void A_FireLaser(player_t *player, pspdef_t *psp) // 8001CAC0
   1275 {
   1276     angle_t                 angleoffs;
   1277     angle_t                 spread;
   1278     mobj_t                  *mobj;
   1279     int                     lasercount;
   1280     int                     i;
   1281     fixed_t                 slopex, slopey, slopez;
   1282     fixed_t                 x, y, z;
   1283     fixed_t                 x1, y1, z1;
   1284     fixed_t                 x2, y2, z2;
   1285     byte                    type;
   1286     laserdata_t             *laser_data;
   1287     laser_t                 *laser;
   1288     fixed_t                 laserfrac;
   1289     int                     damage;
   1290 
   1291     mobj = player->mo;
   1292 
   1293     type = ArtifactLookupTable[player->artifacts];
   1294 
   1295     /* setup laser type */
   1296     switch(type)
   1297     {
   1298     case 1:     /* Rapid fire / single shot */
   1299         psp->tics = 5;
   1300         lasercount = 1;
   1301         angleoffs = mobj->angle;
   1302         break;
   1303     case 2:     /* Rapid fire / double shot */
   1304         psp->tics = 4;
   1305         lasercount = 2;
   1306         spread = 0x16C0000;
   1307         angleoffs = mobj->angle + 0xFF4A0000;
   1308         break;
   1309     case 3:     /* Spread shot */
   1310         psp->tics = 4;
   1311         lasercount = 3;
   1312         spread = 0x2220000 + (0x2220000 * (player->refire & 3));
   1313         angleoffs = mobj->angle - spread;
   1314         break;
   1315     default:    /* Normal shot */
   1316         lasercount = 1;
   1317         angleoffs = mobj->angle;
   1318         break;
   1319     }
   1320 
   1321     x1 = mobj->x + (finecosine[mobj->angle >> ANGLETOFINESHIFT] * LASERDISTANCE);
   1322     y1 = mobj->y + (finesine[mobj->angle >> ANGLETOFINESHIFT] * LASERDISTANCE);
   1323     z1 = mobj->z + LASERAIMHEIGHT;
   1324 
   1325     /* setup laser beams */
   1326     for(i = 0; i < lasercount; i++)
   1327     {
   1328         slopez = P_AimLineAttack(mobj, angleoffs, LASERAIMHEIGHT, LASERRANGE);
   1329 
   1330         if(aimfrac)
   1331             laserfrac = (aimfrac << (FRACBITS - 4)) - (4 << FRACBITS);
   1332         else
   1333             laserfrac = (2048*FRACUNIT);
   1334 
   1335         slopex = finecosine[angleoffs >> ANGLETOFINESHIFT];
   1336         slopey = finesine[angleoffs >> ANGLETOFINESHIFT];
   1337 
   1338         x2 = mobj->x + FixedMul(slopex, laserfrac);
   1339         y2 = mobj->y + FixedMul(slopey, laserfrac);
   1340         z2 = z1 + FixedMul(slopez, laserfrac);
   1341 
   1342         z = (z2 - z1) >> FRACBITS;
   1343         x = (x2 - x1) >> FRACBITS;
   1344         y = (y2 - y1) >> FRACBITS;
   1345 
   1346         /* setup laser */
   1347         laser_data = (laserdata_t *)Z_Malloc( sizeof(*laser_data), PU_LEVSPEC, 0);
   1348 
   1349         /* setup laser head point */
   1350         laser_data->x1 = x1;
   1351         laser_data->y1 = y1;
   1352         laser_data->z1 = z1;
   1353 
   1354         /* setup laser tail point */
   1355         laser_data->x2 = x2;
   1356         laser_data->y2 = y2;
   1357         laser_data->z2 = z2;
   1358 
   1359         /* setup movement slope */
   1360         laser_data->slopex = slopex;
   1361         laser_data->slopey = slopey;
   1362         laser_data->slopez = slopez;
   1363 
   1364         /* setup distance info */
   1365         laser_data->dist = 0;
   1366         laser_data->distmax = (fixed_t) sqrtf((float)((x * x) + (y * y) + (z * z)));
   1367 
   1368         laser_data->next = NULL;
   1369 
   1370         P_LaserCrossBSP(numnodes-1, laser_data);
   1371 
   1372         /* setup laser puff */
   1373         laser = (laser_t *)Z_Malloc( sizeof(*laser), PU_LEVSPEC, 0);
   1374         P_AddThinker (&laser->thinker);
   1375         laser->thinker.function = T_LaserThinker;
   1376         laser->laserdata = laser_data;
   1377         laser->marker = P_SpawnMobj(x2, y2, z2, MT_PROJ_LASER);
   1378 
   1379         player->ammo[weaponinfo[player->readyweapon].ammo]--;
   1380 
   1381         if(!linetarget)
   1382         {
   1383             angleoffs += spread;
   1384         }
   1385         else
   1386         {
   1387             damage = ((P_Random() & 7) * 10) + 10;
   1388             P_DamageMobj(linetarget, mobj, mobj, damage);
   1389         }
   1390     }
   1391 
   1392     P_SetPsprite(player, ps_flashalpha, weaponinfo[player->readyweapon].flashstate);
   1393     S_StartSound(player->mo, sfx_laser);
   1394 }