//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// DESCRIPTION:
//	Weapon sprite animation, weapon objects.
//	Action functions for weapons.
//


#include "doomdef.h"
#include "d_event.h"

#include "deh_misc.h"

#include "m_random.h"
#include "p_local.h"
#include "s_sound.h"

// State.
#include "doomstat.h"

// Data.
#include "sounds.h"

#include "p_pspr.h"

#define LOWERSPEED		FRACUNIT*6
#define RAISESPEED		FRACUNIT*6

#define WEAPONBOTTOM	128*FRACUNIT
#define WEAPONTOP		32*FRACUNIT



//
// P_SetPsprite
//
// [STRIFE]
// villsa: Removed psprite sx, sy modification via misc1/2
//
void
P_SetPsprite
( player_t*     player,
  int           position,
  statenum_t    stnum )
{
    pspdef_t*   psp;
    state_t*    state;

    psp = &player->psprites[position];

    do
    {
        if (!stnum)
        {
            // object removed itself
            psp->state = NULL;
            break;
        }

        state = &states[stnum];
        psp->state = state;
        psp->tics = state->tics;        // could be 0

        // villsa [STRIFE] unused
        /*if (state->misc1)
        {
            // coordinate set
            psp->sx = state->misc1 << FRACBITS;
            psp->sy = state->misc2 << FRACBITS;
        }*/

        // Call action routine.
        // Modified handling.
        if (state->action.acp2)
        {
            state->action.acp2(player, psp);
            if (!psp->state)
                break;
        }

        stnum = psp->state->nextstate;

    } while (!psp->tics);
    // an initial state of 0 could cycle through
}

// haleyjd 09/06/10: [STRIFE] Removed P_CalcSwing

//
// P_BringUpWeapon
// Starts bringing the pending weapon up
// from the bottom of the screen.
// Uses player
//
// villsa [STRIFE] Modifications for Strife weapons
//
void P_BringUpWeapon (player_t* player)
{
    statenum_t  newstate;

    if (player->pendingweapon == wp_nochange)
        player->pendingweapon = player->readyweapon;

    // [crispy] weapon sound source
    if (player->pendingweapon == wp_flame)
        S_StartSound (player->so, sfx_flidl);   // villsa [STRIFE] flame sounds

    newstate = weaponinfo[player->pendingweapon].upstate;

    player->psprites[ps_weapon].sy = WEAPONBOTTOM;
    P_SetPsprite (player, ps_weapon, newstate);

    // villsa [STRIFE] set various flash states
    if(player->pendingweapon == wp_elecbow)
        P_SetPsprite(player, ps_flash, S_XBOW_10); // 31
    else if(player->pendingweapon == wp_sigil && player->sigiltype)
        P_SetPsprite(player, ps_flash, S_SIGH_00 + player->sigiltype); // 117
    else
        P_SetPsprite(player, ps_flash, S_NULL);

    player->pendingweapon = wp_nochange;
}

//
// P_CheckAmmo
// Returns true if there is enough ammo to shoot.
// If not, selects the next weapon to use.
//
// villsa [STRIFE] Changes to handle Strife weapons
//
boolean P_CheckAmmo (player_t* player)
{
    ammotype_t          ammo;
    int                 count;

    ammo = weaponinfo[player->readyweapon].ammo;

    // Minimal amount for one shot varies.
    if (player->readyweapon == wp_torpedo)
        count = 30;
    else if (player->readyweapon == wp_mauler)
        count = 20;
    else
        count = 1;      // Regular.

    // Some do not need ammunition anyway.
    // Return if current ammunition sufficient.
    if (ammo == am_noammo || player->ammo[ammo] >= count)
        return true;

    // Out of ammo, pick a weapon to change to.
    // Preferences are set here.

    // villsa [STRIFE] new weapon preferences
    if (player->weaponowned[wp_mauler] && player->ammo[am_cell] >= 20)
        player->pendingweapon = wp_mauler;

    else if(player->weaponowned[wp_rifle] && player->ammo[am_bullets])
        player->pendingweapon = wp_rifle;

    else if (player->weaponowned[wp_elecbow] && player->ammo[am_elecbolts])
        player->pendingweapon = wp_elecbow;

    else if (player->weaponowned[wp_missile] && player->ammo[am_missiles])
        player->pendingweapon = wp_missile;

    else if (player->weaponowned[wp_flame] && player->ammo[am_cell])
        player->pendingweapon = wp_flame;

    else if (player->weaponowned[wp_hegrenade] && player->ammo[am_hegrenades])
        player->pendingweapon = wp_hegrenade;

    else if (player->weaponowned[wp_poisonbow] && player->ammo[am_poisonbolts])
        player->pendingweapon = wp_poisonbow;

    else if (player->weaponowned[wp_wpgrenade] && player->ammo[am_wpgrenades])
        player->pendingweapon = wp_wpgrenade;

    // BUG: This will *never* be selected for an automatic switch because the 
    // normal Mauler is higher priority and uses less ammo.
    else if (player->weaponowned[wp_torpedo] && player->ammo[am_cell] >= 30)
        player->pendingweapon = wp_torpedo; 

    else
        player->pendingweapon = wp_fist;


    // Now set appropriate weapon overlay.
    P_SetPsprite(player, ps_weapon, weaponinfo[player->readyweapon].downstate);

    return false;
}


//
// P_FireWeapon.
//
// villsa [STRIFE] Changes for player state and weapons
//
void P_FireWeapon (player_t* player)
{
    statenum_t  newstate;

    if (!P_CheckAmmo (player))
        return;

    P_SetMobjState (player->mo, S_PLAY_05); // 292
    newstate = weaponinfo[player->readyweapon].atkstate;
    P_SetPsprite (player, ps_weapon, newstate);
    
    // villsa [STRIFE] exclude these weapons from causing noise
    if(player->readyweapon > wp_elecbow && player->readyweapon != wp_poisonbow)
        P_NoiseAlert (player->mo, player->mo);
}



//
// P_DropWeapon
// Player died, so put the weapon away.
//
void P_DropWeapon (player_t* player)
{
    P_SetPsprite (player,
                  ps_weapon,
                  weaponinfo[player->readyweapon].downstate);
}



//
// A_WeaponReady
// The player can fire the weapon
// or change to another weapon at this time.
// Follows after getting weapon up,
// or after previous attack/fire sequence.
//
void A_WeaponReady( player_t* player, pspdef_t* psp)
{
    statenum_t  newstate;
    int         angle;
    
    // get out of attack state
    if (player->mo->state == &states[S_PLAY_05] || // 292
        player->mo->state == &states[S_PLAY_06])   // 293
    {
        P_SetMobjState (player->mo, S_PLAY_00); // 287
    }
    
    // villsa [STRIFE] check for wp_flame instead of chainsaw
    // haleyjd 09/06/10: fixed state (00 rather than 01)
    if (player->readyweapon == wp_flame
        && psp->state == &states[S_FLMT_00]) // 62
    {
        S_StartSound (player->so, sfx_flidl); // [crispy] weapon sound source
    }
    
    // check for change
    //  if player is dead, put the weapon away
    if (player->pendingweapon != wp_nochange || !player->health)
    {
        // change weapon
        //  (pending weapon should allready be validated)
        newstate = weaponinfo[player->readyweapon].downstate;
        P_SetPsprite (player, ps_weapon, newstate);
        return;
    }
    
    // check for fire
    //  the missile launcher and torpedo do not auto fire
    if (player->cmd.buttons & BT_ATTACK)
    {
        if ( !player->attackdown
            || (player->readyweapon != wp_missile
            && player->readyweapon != wp_torpedo)) // villsa [STRIFE] replace bfg with torpedo
        {
            player->attackdown = true;
            P_FireWeapon (player);
            return;
        }
    }
    else
        player->attackdown = false;
    
    // bob the weapon based on movement speed
    angle = (128*leveltime)&FINEMASK;
    psp->sx = FRACUNIT + FixedMul (player->bob, finecosine[angle]);
    angle &= FINEANGLES/2-1;
    psp->sy = WEAPONTOP + FixedMul (player->bob, finesine[angle]);
}



//
// A_ReFire
// The player can re-fire the weapon
// without lowering it entirely.
//
void A_ReFire
( player_t*	player,
  pspdef_t*	psp )
{
    
    // check for fire
    //  (if a weaponchange is pending, let it go through instead)
    if ( (player->cmd.buttons & BT_ATTACK) 
        && player->pendingweapon == wp_nochange
        && player->health)
    {
        player->refire++;
        P_FireWeapon (player);
    }
    else
    {
        player->refire = 0;
        P_CheckAmmo (player);
    }
}

//
// A_CheckReload
//
void A_CheckReload(player_t* player, pspdef_t* psp)
{
    P_CheckAmmo(player);

    // villsa [STRIFE] set animating sprite for crossbow
    if(player->readyweapon == wp_elecbow)
        P_SetPsprite(player, player->readyweapon, S_XBOW_10);
}



//
// A_Lower
// Lowers current weapon,
//  and changes weapon at bottom.
//
void
A_Lower
( player_t*	player,
  pspdef_t*	psp )
{	
    psp->sy += LOWERSPEED;

    // Is already down.
    if (psp->sy < WEAPONBOTTOM )
        return;

    // Player is dead.
    if (player->playerstate == PST_DEAD)
    {
        psp->sy = WEAPONBOTTOM;

        // don't bring weapon back up
        return;
    }
    
    // The old weapon has been lowered off the screen,
    // so change the weapon and start raising it
    if (!player->health)
    {
        // Player is dead, so keep the weapon off screen.
        P_SetPsprite (player,  ps_weapon, S_NULL);
        return;
    }

    player->readyweapon = player->pendingweapon; 

    P_BringUpWeapon (player);
}


//
// A_Raise
//
void
A_Raise
( player_t*	player,
  pspdef_t*	psp )
{
    statenum_t  newstate;

    psp->sy -= RAISESPEED;

    if (psp->sy > WEAPONTOP )
        return;

    psp->sy = WEAPONTOP;

    // The weapon has been raised all the way,
    //  so change to the ready state.
    newstate = weaponinfo[player->readyweapon].readystate;

    P_SetPsprite (player, ps_weapon, newstate);
}



//
// A_GunFlash
//
void
A_GunFlash
( player_t*	player,
  pspdef_t*	psp ) 
{
    P_SetMobjState (player->mo, S_PLAY_06);
    P_SetPsprite (player,ps_flash,weaponinfo[player->readyweapon].flashstate);
}



//
// WEAPON ATTACKS
//


//
// A_Punch
//

void A_Punch(player_t* player, pspdef_t* psp) 
{
    angle_t     angle;
    int         damage;
    int         slope;
    int         sound;
    int         stamina;
    int         t;

    // villsa [STRIFE] new damage formula
    // haleyjd 09/19/10: seriously corrected...
    stamina = player->stamina;
    damage = (P_Random() & ((stamina/10) + 7)) * ((stamina/10) + 2);

    if(player->powers[pw_strength])
        damage *= 10;

    angle = player->mo->angle;
    t = P_Random();
    angle += (t - P_Random()) << 18;
    slope = P_AimLineAttack (player->mo, angle, PLAYERMELEERANGE);
    P_LineAttack (player->mo, angle, PLAYERMELEERANGE, slope, damage);

    // turn to face target
    if(linetarget)
    {
        // villsa [STRIFE] check for non-flesh types
        if(linetarget->flags & MF_NOBLOOD)
            sound = sfx_mtalht;
        else
            sound = sfx_meatht;

        S_StartSound (player->so, sound); // [crispy] weapon sound source
        player->mo->angle = R_PointToAngle2 (player->mo->x,
                                             player->mo->y,
                                             linetarget->x,
                                             linetarget->y);

        // villsa [STRIFE] apply flag
        player->mo->flags |= MF_JUSTATTACKED;

        // villsa [STRIFE] do punch alert routine
        P_DoPunchAlert(player->mo, linetarget);
    }
    else
        S_StartSound (player->so, sfx_swish); // [crispy] weapon sound source
}


//
// A_FireFlameThrower
//
// villsa [STRIFE] new codepointer
//
void A_FireFlameThrower(player_t* player, pspdef_t* psp) 
{
    mobj_t* mo;
    int t;

    P_SetMobjState(player->mo, S_PLAY_06);
    player->ammo[weaponinfo[player->readyweapon].ammo]--;
    t = P_Random();
    player->mo->angle += (t - P_Random()) << 18;

    mo = P_SpawnPlayerMissile(player->mo, MT_SFIREBALL);
    mo->momz += (5*FRACUNIT);
}

//
// A_FireMissile
//
// villsa [STRIFE] completly new compared to the original
//
void A_FireMissile(player_t* player, pspdef_t* psp) 
{
    angle_t an;
    int t;

    // haleyjd 09/19/10: I previously missed an add op that meant it should be
    // accuracy * 5, not 4. Checks out with other sources.
    an = player->mo->angle;
    t = P_Random();
    player->mo->angle += (t - P_Random()) << (19 - (player->accuracy * 5 / 100));
    P_SetMobjState(player->mo, S_PLAY_06);
    player->ammo[weaponinfo[player->readyweapon].ammo]--;
    P_SpawnPlayerMissile(player->mo, MT_MINIMISSLE);
    player->mo->angle = an;
}

//
// A_FireMauler2
//
// villsa [STRIFE] - new codepointer
//
void A_FireMauler2(player_t* player, pspdef_t* pspr)
{
    P_SetMobjState(player->mo, S_PLAY_06);
    P_DamageMobj(player->mo, player->mo, NULL, 20);
    player->ammo[weaponinfo[player->readyweapon].ammo] -= 30;
    P_SpawnPlayerMissile(player->mo, MT_TORPEDO);
    P_Thrust(player, player->mo->angle + ANG180, 512000);
}

//
// A_FireGrenade
//
// villsa [STRIFE] - new codepointer
//
void A_FireGrenade(player_t* player, pspdef_t* pspr)
{
    mobjtype_t type;
    mobj_t* mo;
    state_t* st1;
    state_t* st2;
    angle_t an;
    fixed_t radius;

    // decide on what type of grenade to spawn
    if(player->readyweapon == wp_hegrenade)
    {
        type = MT_HEGRENADE;
    }
    else if(player->readyweapon == wp_wpgrenade)
    {
        type = MT_PGRENADE;
    }
    else
    {
        type = MT_HEGRENADE;
        fprintf(stderr, "Warning: A_FireGrenade used on wrong weapon!\n");
    }

    player->ammo[weaponinfo[player->readyweapon].ammo]--;

    // set flash frame
    st1 = &states[(pspr->state - states) + weaponinfo[player->readyweapon].flashstate];
    st2 = &states[weaponinfo[player->readyweapon].atkstate];
    P_SetPsprite(player, ps_flash, st1 - st2);

    player->mo->z += 32*FRACUNIT; // ugh
    mo = P_SpawnMortar(player->mo, type);
    player->mo->z -= 32*FRACUNIT; // ugh

    // change momz based on player's pitch
    mo->momz = FixedMul((player->pitch<<FRACBITS) / 160, mo->info->speed) + (8*FRACUNIT);
    S_StartSound(mo, mo->info->seesound);

    radius = mobjinfo[type].radius + player->mo->info->radius;
    an = (player->mo->angle >> ANGLETOFINESHIFT);

    mo->x += FixedMul(finecosine[an], radius + (4*FRACUNIT));
    mo->y += FixedMul(finesine[an], radius + (4*FRACUNIT));

    // shoot grenade from left or right side?
    if(&states[weaponinfo[player->readyweapon].atkstate] == pspr->state)
        an = (player->mo->angle - ANG90) >> ANGLETOFINESHIFT;
    else
        an = (player->mo->angle + ANG90) >> ANGLETOFINESHIFT;

    mo->x += FixedMul((15*FRACUNIT), finecosine[an]);
    mo->y += FixedMul((15*FRACUNIT), finesine[an]);

    // set bounce flag
    mo->flags |= MF_BOUNCE;
}

//
// A_FireElectricBolt
// villsa [STRIFE] - new codepointer
//

void A_FireElectricBolt(player_t* player, pspdef_t* pspr)
{
    angle_t an = player->mo->angle;
    int t;

    // haleyjd 09/19/10: Use 5 mul on accuracy here as well
    t = P_Random();
    player->mo->angle += (t - P_Random()) << (18 - (player->accuracy * 5 / 100));
    player->ammo[weaponinfo[player->readyweapon].ammo]--;
    P_SpawnPlayerMissile(player->mo, MT_ELECARROW);
    player->mo->angle = an;
    S_StartSound(player->so, sfx_xbow); // [crispy] weapon sound source
}

//
// A_FirePoisonBolt
// villsa [STRIFE] - new codepointer
//

void A_FirePoisonBolt(player_t* player, pspdef_t* pspr)
{
    angle_t an = player->mo->angle;
    int t;

    // haleyjd 09/19/10: Use 5 mul on accuracy here as well
    t = P_Random();
    player->mo->angle += (t - P_Random()) << (18 - (player->accuracy * 5 / 100));
    player->ammo[weaponinfo[player->readyweapon].ammo]--;
    P_SpawnPlayerMissile(player->mo, MT_POISARROW);
    player->mo->angle = an;
    S_StartSound(player->so, sfx_xbow); // [crispy] weapon sound source
}

//
// P_BulletSlope
// Sets a slope so a near miss is at aproximately
// the height of the intended target
//
// haleyjd 09/06/10 [STRIFE] Modified with a little target hack...
//
fixed_t         bulletslope;


void P_BulletSlope (mobj_t *mo)
{
    angle_t	an;
    
    // see which target is to be aimed at
    an = mo->angle;
    bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);

    if (!linetarget)
    {
        an += 1<<26;
        bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
        if (!linetarget)
        {
            an -= 2<<26;
            bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
        }
    }

    // haleyjd 09/06/10: [STRIFE] Somebody added this here, and without it, you
    // will get spurious crashing in routines such as P_LookForPlayers!
    if(linetarget)
        mo->target = linetarget;
}


//
// P_GunShot
//
// [STRIFE] Modifications to support accuracy.
//
void
P_GunShot
( mobj_t*	mo,
  boolean	accurate )
{
    angle_t     angle;
    int         damage;

    angle = mo->angle;

    // villsa [STRIFE] apply player accuracy
    // haleyjd 09/18/10: made some corrections: use 5x accuracy;
    // eliminated order-of-evaluation dependency
    if (!accurate)
    {
        int t = P_Random();
        angle += (t - P_Random()) << (20 - ((mo->player->accuracy * 5) / 100));
    }

    // haleyjd 09/18/10 [STRIFE] corrected damage formula and moved down to
    // preserve proper P_Random call order.
    damage = 4 * (P_Random() % 3 + 1);

    P_LineAttack (mo, angle, MISSILERANGE, bulletslope, damage);
}

//
// A_FireRifle
//
// villsa [STRIFE] - new codepointer
//
void A_FireRifle(player_t* player, pspdef_t* pspr)
{
    S_StartSound(player->so, sfx_rifle); // [crispy] weapon sound source

    if(player->ammo[weaponinfo[player->readyweapon].ammo])
    {
        P_SetMobjState(player->mo, S_PLAY_06); // 293
        player->ammo[weaponinfo[player->readyweapon].ammo]--;
        P_BulletSlope(player->mo);
        P_GunShot(player->mo, !player->refire);
    }
}

//
// A_FireMauler1
//
// villsa [STRIFE] - new codepointer
//
void A_FireMauler1(player_t* player, pspdef_t* pspr)
{
    int i;
    angle_t angle;
    int damage;

    // haleyjd 09/18/10: Corrected ammo check to use >=
    if(player->ammo[weaponinfo[player->readyweapon].ammo] >= 20)
    {
        player->ammo[weaponinfo[player->readyweapon].ammo] -= 20;
        P_BulletSlope(player->mo);
        S_StartSound(player->so, sfx_pgrdat); // [crispy] weapon sound source

        for(i = 0; i < 20; i++)
        {
            int t;
            damage = 5*(P_Random ()%3+1);
            angle = player->mo->angle;
            t = P_Random();
            angle += (t - P_Random()) << 19;
            t = P_Random();
            P_LineAttack(player->mo, angle, 2112*FRACUNIT,
                         bulletslope + ((t - P_Random())<<5), damage);
        }
    }
}

//
// A_SigilSound
//
// villsa [STRIFE] - new codepointer
//
void A_SigilSound(player_t* player, pspdef_t* pspr)
{
    S_StartSound(player->so, sfx_siglup); // [crispy] weapon sound source
    player->extralight = 2;

}

//
// A_FireSigil
//
// villsa [STRIFE] - new codepointer
//
void A_FireSigil(player_t* player, pspdef_t* pspr)
{
    mobj_t* mo;
    angle_t an;
    int i;

    // keep info on armor because sigil does piercing damage
    i = player->armortype;
    player->armortype = 0;

    // BUG: setting inflictor causes firing the Sigil to always push the player
    // toward the east, no matter what direction he is facing.
    P_DamageMobj(player->mo, player->mo, NULL, 4 * (player->sigiltype + 1));

    // restore armor
    player->armortype = i;

    S_StartSound(player->so, sfx_siglup); // [crispy] weapon sound source

    switch(player->sigiltype)
    {
        // falling lightning bolts from the sky
    case 0:
        P_BulletSlope(player->mo);
        if(linetarget)
        {
            // haleyjd 09/18/10: corrected z coordinate
            mo = P_SpawnMobj(linetarget->x, linetarget->y, ONFLOORZ, 
                             MT_SIGIL_A_GROUND);
            mo->tracer = linetarget;
        }
        else
        {
            an = player->mo->angle>>ANGLETOFINESHIFT;
            mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, 
                             MT_SIGIL_A_GROUND);
            mo->momx += FixedMul((28*FRACUNIT), finecosine[an]);
            mo->momy += FixedMul((28*FRACUNIT), finesine[an]);
        }
        mo->health = -1;
        mo->target = player->mo;
        break;

        // simple projectile
    case 1:
        P_SpawnPlayerMissile(player->mo, MT_SIGIL_B_SHOT)->health = -1;
        break;

        // spread shot
    case 2:
        player->mo->angle -= ANG90; // starting at 270...
        for(i = 0; i < 20; i++)     // increment by 1/10 of 90, 20 times.
        {
            player->mo->angle += (ANG90 / 10);
            mo = P_SpawnMortar(player->mo, MT_SIGIL_C_SHOT);
            mo->health = -1;
            mo->z = player->mo->z + (32*FRACUNIT);
        }
        player->mo->angle -= ANG90; // subtract off the extra 90
        break;

        // tracer attack
    case 3:
        P_BulletSlope(player->mo);
        if(linetarget)
        {
            mo = P_SpawnPlayerMissile(player->mo, MT_SIGIL_D_SHOT);
            mo->tracer = linetarget;
        }
        else
        {
            an = player->mo->angle >> ANGLETOFINESHIFT;
            mo = P_SpawnPlayerMissile(player->mo, MT_SIGIL_D_SHOT);
            mo->momx += FixedMul(mo->info->speed, finecosine[an]);
            mo->momy += FixedMul(mo->info->speed, finesine[an]);
        }
        mo->health = -1;
        break;

        // mega blast
    case 4:
        mo = P_SpawnPlayerMissile(player->mo, MT_SIGIL_E_SHOT);
        mo->health = -1;
        if(!linetarget)
        {
            an = (unsigned int)player->pitch >> ANGLETOFINESHIFT;
            mo->momz += FixedMul(finesine[an], mo->info->speed); 
        }
        break;

    default:
        break;
    }
}

//
// A_GunFlashThinker
//
// villsa [STRIFE] - new codepointer
//
void A_GunFlashThinker(player_t* player, pspdef_t* pspr)
{
    if(player->readyweapon == wp_sigil && player->sigiltype)
        P_SetPsprite(player, ps_flash, S_SIGH_00 + player->sigiltype);
    else
        P_SetPsprite(player, ps_flash, S_NULL);

}


//
// ?
//
void A_Light0 (player_t *player, pspdef_t *psp)
{
    player->extralight = 0;
}

void A_Light1 (player_t *player, pspdef_t *psp)
{
    player->extralight = 1;
}

void A_Light2 (player_t *player, pspdef_t *psp)
{
    player->extralight = 2;
}

//
// A_SigilShock
//
// villsa [STRIFE] - new codepointer
//
void A_SigilShock (player_t *player, pspdef_t *psp)
{
    player->extralight = -3;
}

//
// A_TorpedoExplode
//
// villsa [STRIFE] - new codepointer
//
void A_TorpedoExplode(mobj_t* actor)
{
    int i;

    actor->angle -= ANG180;

    for(i = 0; i < 80; i++)
    {
        actor->angle += (ANG90 / 20);
        P_SpawnMortar(actor, MT_TORPEDOSPREAD)->target = actor->target;
    }
}

//
// A_MaulerSound
//
// villsa [STRIFE] - new codepointer
//
void A_MaulerSound(player_t *player, pspdef_t *psp)
{
    int t;
    S_StartSound(player->so, sfx_proton); // [crispy] weapon sound source
    t = P_Random();
    psp->sx += (t - P_Random()) << 10;
    t = P_Random();
    psp->sy += (t - P_Random()) << 10;

}


//
// P_SetupPsprites
// Called at start of level for each player.
//
void P_SetupPsprites(player_t* player) 
{
    int	i;

    // remove all psprites
    for(i = 0; i < NUMPSPRITES; i++)
        player->psprites[i].state = NULL;

    // spawn the gun
    player->pendingweapon = player->readyweapon;
    P_BringUpWeapon(player);
}




//
// P_MovePsprites
// Called every tic by player thinking routine.
//
void P_MovePsprites (player_t* player) 
{
    int		i;
    pspdef_t*	psp;

    psp = &player->psprites[0];
    for(i = 0; i < NUMPSPRITES; i++, psp++)
    {
        // a null state means not active
        if(psp->state)
        {
            // drop tic count and possibly change state

            // a -1 tic count never changes
            if(psp->tics != -1)	
            {
                psp->tics--;
                if(!psp->tics)
                    P_SetPsprite (player, i, psp->state->nextstate);
            }
        }
    }
    
    player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx;
    player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy;

    // villsa [STRIFE] extra stuff for targeter
    player->psprites[ps_targleft].sx =
        (160*FRACUNIT) - ((100 - player->accuracy) << FRACBITS);

    player->psprites[ps_targright].sx =
        ((100 - player->accuracy) << FRACBITS) + (160*FRACUNIT);

    // [crispy] update targeter position
    player->psprites[ps_targleft].sx2 = player->psprites[ps_targleft].sx;
    player->psprites[ps_targright].sx2 = player->psprites[ps_targright].sx;

    // [crispy] apply bobbing (or centering) to the player's weapon sprite
    psp = &player->psprites[0];
    psp->sx2 = psp->sx;
    psp->sy2 = psp->sy;
    if (psp->state && (crispy->bobfactor || crispy->centerweapon || crispy->uncapped))
    {
        // [crispy] don't center vertically during lowering and raising states
        if (psp->state->action.acp2 == (actionf_p2)A_Lower ||
            psp->state->action.acp2 == (actionf_p2)A_Raise)
        {
        }
        else
        // [crispy] not attacking means idle
        if (!player->attackdown ||
            crispy->centerweapon == CENTERWEAPON_BOB)
        {
            angle_t angle = (128 * leveltime) & FINEMASK;
            psp->sx2 = FRACUNIT + FixedMul(player->bob2, finecosine[angle]);
            angle &= FINEANGLES / 2 - 1;
            psp->sy2 = WEAPONTOP + FixedMul(player->bob2, finesine[angle]);
        }
        else
        // [crispy] center the weapon sprite horizontally and push up vertically
        if (crispy->centerweapon == CENTERWEAPON_CENTER)
        {
            psp->sx2 = FRACUNIT;
            psp->sy2 = WEAPONTOP;
        }
    }

	player->psprites[ps_flash].sx2 = psp->sx2;
	player->psprites[ps_flash].sy2 = psp->sy2;
}


