mirror of
https://github.com/ZDoom/Raze.git
synced 2024-11-16 01:11:44 +00:00
7156 lines
187 KiB
C++
7156 lines
187 KiB
C++
//-------------------------------------------------------------------------
|
|
/*
|
|
Copyright (C) 1997, 2005 - 3D Realms Entertainment
|
|
|
|
This file is part of Shadow Warrior version 1.2
|
|
|
|
Shadow Warrior 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.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
Original Source: 1997 - Frank Maddin and Jim Norwood
|
|
Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
|
|
*/
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include "ns.h"
|
|
|
|
#undef MAIN
|
|
#include "build.h"
|
|
|
|
#include "names2.h"
|
|
#include "panel.h"
|
|
#include "lists.h"
|
|
#include "misc.h"
|
|
#include "network.h"
|
|
#include "pal.h"
|
|
#include "player.h"
|
|
#include "v_2ddrawer.h"
|
|
#include "gamehud.h"
|
|
|
|
#include "weapon.h"
|
|
#include "razemenu.h"
|
|
#include "raze_sound.h"
|
|
|
|
BEGIN_SW_NS
|
|
|
|
|
|
int InitSwordAttack(PLAYERp pp);
|
|
PANEL_SPRITEp InitWeaponUziSecondaryReload(PANEL_SPRITEp);
|
|
PANEL_SPRITEp InitWeaponUzi2(PANEL_SPRITEp);
|
|
int InitShotgun(PLAYERp pp);
|
|
int InitRail(PLAYERp pp);
|
|
int InitMicro(PLAYERp pp);
|
|
int InitRocket(PLAYERp pp);
|
|
int InitNuke(PLAYERp pp);
|
|
int InitGrenade(PLAYERp pp);
|
|
int InitMine(PLAYERp pp);
|
|
int InitFistAttack(PLAYERp pp);
|
|
|
|
#define PANF_UZI_XFLIP (BIT(21))
|
|
|
|
#define XDIM 320
|
|
#define YDIM 200
|
|
|
|
typedef struct
|
|
{
|
|
short xoff, yoff, skip;
|
|
int lo_jump_speed, hi_jump_speed, lo_xspeed, hi_xspeed;
|
|
PANEL_STATEp state[2];
|
|
} PANEL_SHRAP, *PANEL_SHRAPp;
|
|
|
|
void PanelInvTestSuicide(PANEL_SPRITEp psp);
|
|
|
|
void InsertPanelSprite(PLAYERp pp, PANEL_SPRITEp psp);
|
|
void pKillSprite(PANEL_SPRITEp psp);
|
|
void pWeaponBob(PANEL_SPRITEp psp, short condition);
|
|
void pSuicide(PANEL_SPRITEp psp);
|
|
void pNextState(PANEL_SPRITEp psp);
|
|
void pStatePlusOne(PANEL_SPRITEp psp);
|
|
void pSetState(PANEL_SPRITEp psp, PANEL_STATEp panel_state);
|
|
void pStateControl(PANEL_SPRITEp psp);
|
|
|
|
int DoPanelFall(PANEL_SPRITEp psp);
|
|
int DoBeginPanelFall(PANEL_SPRITEp psp);
|
|
int DoPanelJump(PANEL_SPRITEp psp);
|
|
int DoBeginPanelJump(PANEL_SPRITEp psp);
|
|
void SpawnHeartBlood(PANEL_SPRITEp psp);
|
|
void SpawnUziShell(PANEL_SPRITEp psp);
|
|
|
|
bool pWeaponUnHideKeys(PANEL_SPRITEp psp, PANEL_STATEp state);
|
|
bool pWeaponHideKeys(PANEL_SPRITEp psp, PANEL_STATEp state);
|
|
void pHotHeadOverlays(PANEL_SPRITEp psp, short mode);
|
|
|
|
uint8_t UziRecoilYadj = 0;
|
|
|
|
extern short screenpeek;
|
|
|
|
pANIMATOR pNullAnimator;
|
|
int InitStar(PLAYERp);
|
|
int ChangeWeapon(PLAYERp);
|
|
|
|
ANIMATOR InitFire;
|
|
|
|
int
|
|
NullAnimator(DSWActor*)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void pNullAnimator(PANEL_SPRITEp)
|
|
{
|
|
return;
|
|
}
|
|
|
|
PANEL_SPRITEp pFindMatchingSprite(PLAYERp pp, int x, int y, short pri)
|
|
{
|
|
PANEL_SPRITEp next;
|
|
|
|
auto list = pp->GetPanelSpriteList();
|
|
for (auto psp = list->Next; next = psp->Next, psp != list; psp = next)
|
|
{
|
|
// early out
|
|
if (psp->priority > pri)
|
|
return nullptr;
|
|
|
|
if (psp->x == x && psp->y == y && psp->priority == pri)
|
|
{
|
|
return psp;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
PANEL_SPRITEp pFindMatchingSpriteID(PLAYERp pp, short id, int x, int y, short pri)
|
|
{
|
|
PANEL_SPRITEp next;
|
|
|
|
auto list = pp->GetPanelSpriteList();
|
|
for (auto psp = list->Next; next = psp->Next, psp != list; psp = next)
|
|
{
|
|
// early out
|
|
if (psp->priority > pri)
|
|
return nullptr;
|
|
|
|
if (psp->ID == id && psp->x == x && psp->y == y && psp->priority == pri)
|
|
{
|
|
return psp;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
bool pKillScreenSpiteIDs(PLAYERp pp, short id)
|
|
{
|
|
PANEL_SPRITEp next;
|
|
bool found = false;
|
|
|
|
// Kill ALL sprites with the correct id
|
|
auto list = pp->GetPanelSpriteList();
|
|
for (auto psp = list->Next; next = psp->Next, psp != list; psp = next)
|
|
{
|
|
if (psp->ID == id)
|
|
{
|
|
pKillSprite(psp);
|
|
found = true;
|
|
}
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
|
|
// Used to sprites in the view at correct aspect ratio and x,y location.
|
|
|
|
void pSetSuicide(PANEL_SPRITEp psp)
|
|
{
|
|
//SET(psp->flags, PANF_SUICIDE);
|
|
//psp->State = nullptr;
|
|
psp->PanelSpriteFunc = pSuicide;
|
|
}
|
|
|
|
void pToggleCrosshair(void)
|
|
{
|
|
cl_crosshair = !cl_crosshair;
|
|
}
|
|
|
|
// Player has a chance of yelling out during combat, when firing a weapon.
|
|
void DoPlayerChooseYell(PLAYERp pp)
|
|
{
|
|
int choose_snd = 0;
|
|
|
|
if (RandomRange(1000) < 990) return;
|
|
|
|
choose_snd = STD_RANDOM_RANGE(MAX_YELLSOUNDS);
|
|
|
|
if (pp == Player+myconnectindex)
|
|
PlayerSound(PlayerYellVocs[choose_snd], v3df_follow|v3df_dontpan,pp);
|
|
}
|
|
|
|
void ArmorCalc(int damage_amt, int *armor_damage, int *player_damage)
|
|
{
|
|
int damage_percent;
|
|
|
|
if (damage_amt == 1)
|
|
{
|
|
*player_damage = RANDOM_P2(2<<8)>>8;
|
|
*armor_damage = 1;
|
|
return;
|
|
}
|
|
|
|
// note: this could easily be converted to a mulscale and save a
|
|
// bit of processing for floats
|
|
damage_percent = int((0.6 * damage_amt)+0.5);
|
|
|
|
*player_damage = damage_amt - damage_percent;
|
|
*armor_damage = damage_percent;
|
|
}
|
|
|
|
|
|
void PlayerUpdateHealth(PLAYERp pp, short value)
|
|
{
|
|
USERp u = pp->Actor()->u();
|
|
short x,y;
|
|
|
|
if (Prediction)
|
|
return;
|
|
|
|
if (GodMode)
|
|
{
|
|
if (value < 0)
|
|
return;
|
|
}
|
|
|
|
if (TEST(pp->Flags, PF_DEAD))
|
|
return;
|
|
|
|
if (value < 0)
|
|
{
|
|
bool IsChem = false;
|
|
bool NoArmor = false;
|
|
|
|
if (value <= -2000)
|
|
{
|
|
value += 2000;
|
|
NoArmor = true;
|
|
}
|
|
else if (value <= -1000)
|
|
{
|
|
//DSPRINTF(ds,"value = %d\n",value);
|
|
MONO_PRINT(ds);
|
|
|
|
value += 1000;
|
|
IsChem = true;
|
|
}
|
|
|
|
// TAKE SOME DAMAGE
|
|
u->LastDamage = -value;
|
|
|
|
// adjust for armor
|
|
if (pp->Armor && !NoArmor)
|
|
{
|
|
int armor_damage, player_damage;
|
|
ArmorCalc(labs(value), &armor_damage, &player_damage);
|
|
PlayerUpdateArmor(pp, -armor_damage);
|
|
value = -player_damage;
|
|
}
|
|
|
|
u->Health += value;
|
|
|
|
if (value < 0)
|
|
{
|
|
int choosesnd = 0;
|
|
|
|
choosesnd = RandomRange(MAX_PAIN);
|
|
|
|
if (u->Health > 50)
|
|
{
|
|
PlayerSound(PlayerPainVocs[choosesnd],v3df_dontpan|v3df_doppler|v3df_follow,pp);
|
|
}
|
|
else
|
|
{
|
|
PlayerSound(PlayerLowHealthPainVocs[choosesnd],v3df_dontpan|v3df_doppler|v3df_follow,pp);
|
|
}
|
|
|
|
}
|
|
// Do redness based on damage taken.
|
|
if (pp == Player + screenpeek)
|
|
{
|
|
if (IsChem)
|
|
SetFadeAmt(pp,-40,144); // ChemBomb green color
|
|
else
|
|
{
|
|
if (value <= -10)
|
|
SetFadeAmt(pp,value,112);
|
|
else if (value > -10 && value < 0)
|
|
SetFadeAmt(pp,-20,112);
|
|
}
|
|
}
|
|
if (u->Health <= 100)
|
|
pp->MaxHealth = 100; // Reset max health if sank below 100
|
|
}
|
|
else
|
|
{
|
|
// ADD SOME HEALTH
|
|
if (value > 1000)
|
|
u->Health += (value-1000);
|
|
else
|
|
{
|
|
if (u->Health < pp->MaxHealth)
|
|
{
|
|
u->Health+=value;
|
|
}
|
|
}
|
|
|
|
|
|
if (value >= 1000)
|
|
value -= 1000; // Strip out high value
|
|
}
|
|
|
|
if (u->Health < 0)
|
|
u->Health = 0;
|
|
|
|
if (u->Health > pp->MaxHealth)
|
|
u->Health = pp->MaxHealth;
|
|
}
|
|
|
|
void PlayerUpdateAmmo(PLAYERp pp, short UpdateWeaponNum, short value)
|
|
{
|
|
short x,y;
|
|
short WeaponNum;
|
|
|
|
if (Prediction)
|
|
return;
|
|
|
|
if (DamageData[UpdateWeaponNum].max_ammo == -1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
WeaponNum = UpdateWeaponNum;
|
|
|
|
// get the WeaponNum of the ammo
|
|
if (DamageData[UpdateWeaponNum].with_weapon != -1)
|
|
{
|
|
WeaponNum = DamageData[UpdateWeaponNum].with_weapon;
|
|
}
|
|
|
|
pp->WpnAmmo[WeaponNum] += value;
|
|
|
|
if (pp->WpnAmmo[WeaponNum] <= 0)
|
|
{
|
|
// star and mine
|
|
if (TEST(WeaponIsAmmo, BIT(WeaponNum)))
|
|
RESET(pp->WpnFlags, BIT(WeaponNum));
|
|
|
|
pp->WpnAmmo[WeaponNum] = 0;
|
|
}
|
|
|
|
if (pp->WpnAmmo[WeaponNum] > DamageData[WeaponNum].max_ammo)
|
|
{
|
|
pp->WpnAmmo[WeaponNum] = DamageData[WeaponNum].max_ammo;
|
|
}
|
|
}
|
|
|
|
void PlayerUpdateWeapon(PLAYERp pp, short WeaponNum)
|
|
{
|
|
USERp u = pp->Actor()->u();
|
|
|
|
// weapon Change
|
|
if (Prediction)
|
|
return;
|
|
|
|
u->WeaponNum = int8_t(WeaponNum);
|
|
}
|
|
|
|
void PlayerUpdateKills(PLAYERp pp, short value)
|
|
{
|
|
if (Prediction)
|
|
return;
|
|
|
|
if (gNet.MultiGameType == MULTI_GAME_COOPERATIVE)
|
|
return;
|
|
|
|
// Team play
|
|
if (gNet.MultiGameType == MULTI_GAME_COMMBAT && gNet.TeamPlay)
|
|
{
|
|
short pnum;
|
|
PLAYERp opp;
|
|
|
|
TRAVERSE_CONNECT(pnum)
|
|
{
|
|
opp = Player + pnum;
|
|
|
|
// for everyone on the same team
|
|
if (opp != pp && opp->Actor()->u()->spal == pp->Actor()->u()->spal)
|
|
{
|
|
opp->Kills += value;
|
|
if (opp->Kills > 999)
|
|
opp->Kills = 0;
|
|
if (opp->Kills < -99)
|
|
opp->Kills = -99;
|
|
}
|
|
}
|
|
}
|
|
|
|
pp->Kills += value;
|
|
if (pp->Kills > 999)
|
|
pp->Kills = 0;
|
|
if (pp->Kills < -99)
|
|
pp->Kills = -99;
|
|
}
|
|
|
|
void PlayerUpdateArmor(PLAYERp pp, short value)
|
|
{
|
|
if (Prediction)
|
|
return;
|
|
|
|
if (value >= 1000)
|
|
pp->Armor = value-1000;
|
|
else
|
|
pp->Armor += value;
|
|
|
|
if (pp->Armor > 100)
|
|
pp->Armor = 100;
|
|
if (pp->Armor < 0)
|
|
pp->Armor = 0;
|
|
}
|
|
|
|
|
|
int WeaponOperate(PLAYERp pp)
|
|
{
|
|
short weapon;
|
|
USERp u = pp->Actor()->u();
|
|
|
|
|
|
InventoryKeys(pp);
|
|
|
|
// UziType >= 3 means they are reloading
|
|
if (pp->WpnUziType >= 3) return true;
|
|
|
|
//if (CheatInputMode)
|
|
// return (0);
|
|
|
|
if (pp->FirePause != 0)
|
|
{
|
|
pp->FirePause -= synctics;
|
|
if (pp->FirePause <= 0)
|
|
pp->FirePause = 0;
|
|
}
|
|
|
|
if (pp->sop)
|
|
{
|
|
switch (pp->sop->track)
|
|
{
|
|
case SO_VEHICLE:
|
|
case SO_TURRET:
|
|
case SO_TURRET_MGUN:
|
|
// case SO_SPEED_BOAT:
|
|
|
|
if (!TEST(pp->sop->flags, SOBJ_HAS_WEAPON))
|
|
break;
|
|
|
|
if (pp->input.actions & SB_FIRE)
|
|
{
|
|
if (pp->KeyPressBits & SB_FIRE)
|
|
{
|
|
if (!pp->FirePause)
|
|
{
|
|
InitSobjGun(pp);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
weapon = pp->input.getNewWeapon();
|
|
|
|
if (weapon)
|
|
{
|
|
if (pp->KeyPressBits & SB_FIRST_WEAPON_BIT)
|
|
{
|
|
pp->KeyPressBits &= ~SB_FIRST_WEAPON_BIT;
|
|
|
|
weapon -= 1;
|
|
|
|
// Special uzi crap
|
|
if (weapon != WPN_UZI) pp->WpnUziType = 2; // This means we aren't on uzi
|
|
|
|
switch (weapon)
|
|
{
|
|
case WPN_FIST:
|
|
//case WPN_SWORD:
|
|
if (u->WeaponNum == WPN_FIST
|
|
|| u->WeaponNum == WPN_SWORD)
|
|
{
|
|
// toggle
|
|
if (pp->WpnFirstType == WPN_FIST)
|
|
pp->WpnFirstType = WPN_SWORD;
|
|
else if (pp->WpnFirstType == WPN_SWORD)
|
|
pp->WpnFirstType = WPN_FIST;
|
|
}
|
|
|
|
switch (pp->WpnFirstType)
|
|
{
|
|
case WPN_SWORD:
|
|
InitWeaponSword(pp);
|
|
break;
|
|
case WPN_FIST:
|
|
InitWeaponFist(pp);
|
|
break;
|
|
}
|
|
break;
|
|
case WPN_STAR:
|
|
InitWeaponStar(pp);
|
|
break;
|
|
case WPN_UZI:
|
|
if (u->WeaponNum == WPN_UZI)
|
|
{
|
|
if (TEST(pp->Flags, PF_TWO_UZI))
|
|
{
|
|
pp->WpnUziType++;
|
|
PlaySound(DIGI_UZI_UP, pp, v3df_follow);
|
|
if (pp->WpnUziType > 1)
|
|
pp->WpnUziType = 0;
|
|
}
|
|
else
|
|
pp->WpnUziType = 1; // Use retracted state for single uzi
|
|
}
|
|
InitWeaponUzi(pp);
|
|
break;
|
|
case WPN_MICRO:
|
|
if (u->WeaponNum == WPN_MICRO)
|
|
{
|
|
pp->WpnRocketType++;
|
|
PlaySound(DIGI_ROCKET_UP, pp, v3df_follow);
|
|
if (pp->WpnRocketType > 2)
|
|
pp->WpnRocketType = 0;
|
|
if (pp->WpnRocketType == 2 && pp->WpnRocketNuke == 0)
|
|
pp->WpnRocketType = 0;
|
|
if (pp->WpnRocketType == 2)
|
|
pp->TestNukeInit = true; // Init the nuke
|
|
else
|
|
pp->TestNukeInit = false;
|
|
}
|
|
InitWeaponMicro(pp);
|
|
break;
|
|
case WPN_SHOTGUN:
|
|
if (u->WeaponNum == WPN_SHOTGUN)
|
|
{
|
|
pp->WpnShotgunType++;
|
|
if (pp->WpnShotgunType > 1)
|
|
pp->WpnShotgunType = 0;
|
|
PlaySound(DIGI_SHOTGUN_UP, pp, v3df_follow);
|
|
}
|
|
InitWeaponShotgun(pp);
|
|
break;
|
|
case WPN_RAIL:
|
|
if (!SW_SHAREWARE)
|
|
{
|
|
#if 0
|
|
if (u->WeaponNum == WPN_RAIL)
|
|
{
|
|
pp->WpnRailType++;
|
|
if (pp->WpnRailType > 1)
|
|
pp->WpnRailType = 0;
|
|
}
|
|
if (pp->WpnRailType == 1)
|
|
PlaySound(DIGI_RAIL_UP, pp, v3df_follow);
|
|
#endif
|
|
InitWeaponRail(pp);
|
|
}
|
|
else
|
|
{
|
|
PutStringInfo(pp,"Order the full version");
|
|
}
|
|
break;
|
|
case WPN_HOTHEAD:
|
|
if (!SW_SHAREWARE)
|
|
{
|
|
if (u->WeaponNum == WPN_HOTHEAD
|
|
|| u->WeaponNum == WPN_RING
|
|
|| u->WeaponNum == WPN_NAPALM)
|
|
{
|
|
pp->WpnFlameType++;
|
|
if (pp->WpnFlameType > 2)
|
|
pp->WpnFlameType = 0;
|
|
// if(pp->Wpn[WPN_HOTHEAD])
|
|
pHotHeadOverlays(pp->Wpn[WPN_HOTHEAD], pp->WpnFlameType);
|
|
PlaySound(DIGI_HOTHEADSWITCH, pp, v3df_dontpan|v3df_follow);
|
|
}
|
|
|
|
InitWeaponHothead(pp);
|
|
}
|
|
else
|
|
{
|
|
PutStringInfo(pp,"Order the full version");
|
|
}
|
|
break;
|
|
case WPN_HEART:
|
|
if (!SW_SHAREWARE)
|
|
{
|
|
InitWeaponHeart(pp);
|
|
}
|
|
else
|
|
{
|
|
PutStringInfo(pp,"Order the full version");
|
|
}
|
|
break;
|
|
case WPN_GRENADE:
|
|
InitWeaponGrenade(pp);
|
|
break;
|
|
case WPN_MINE:
|
|
//InitChops(pp);
|
|
InitWeaponMine(pp);
|
|
break;
|
|
case 13:
|
|
pp->WpnFirstType = WPN_FIST;
|
|
InitWeaponFist(pp);
|
|
break;
|
|
case 14:
|
|
pp->WpnFirstType = WPN_SWORD;
|
|
InitWeaponSword(pp);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pp->KeyPressBits |= SB_FIRST_WEAPON_BIT;
|
|
}
|
|
|
|
// Shut that computer chick up if weapon has changed!
|
|
// This really should be handled better, but since there's no usable tracking state for the sounds, the easiest way to handle them is to play on otherwise unused channels.
|
|
if (pp->WpnRocketType != 2 || pp->CurWpn != pp->Wpn[WPN_MICRO])
|
|
{
|
|
pp->InitingNuke = false;
|
|
soundEngine->StopSound(SOURCE_Player, pp, CHAN_WEAPON);
|
|
}
|
|
if (pp->CurWpn != pp->Wpn[WPN_RAIL])
|
|
{
|
|
soundEngine->StopSound(SOURCE_Player, pp, CHAN_ITEM);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool
|
|
WeaponOK(PLAYERp pp)
|
|
{
|
|
USERp u;
|
|
short min_ammo, WeaponNum, FindWeaponNum;
|
|
static const uint8_t wpn_order[] = {2,3,4,5,6,7,8,9,1,0};
|
|
unsigned wpn_ndx=0;
|
|
|
|
if (!pp->Actor())
|
|
return(false);
|
|
|
|
if (!pp->Actor()->hasU())
|
|
return(false);
|
|
|
|
u = pp->Actor()->u();
|
|
|
|
// sword
|
|
if (DamageData[u->WeaponNum].max_ammo == -1)
|
|
return true;
|
|
|
|
WeaponNum = u->WeaponNum;
|
|
FindWeaponNum = u->WeaponNum;
|
|
|
|
min_ammo = DamageData[WeaponNum].min_ammo;
|
|
|
|
// if ran out of ammo switch to something else
|
|
if (pp->WpnAmmo[WeaponNum] < min_ammo)
|
|
{
|
|
if (u->WeaponNum == WPN_UZI) pp->WpnUziType = 2; // Set it for retract
|
|
|
|
// Still got a nuke, it's ok.
|
|
if (WeaponNum == WPN_MICRO && pp->WpnRocketNuke)
|
|
{
|
|
//pp->WpnRocketType = 2; // Set it to Nuke
|
|
if (!pp->NukeInitialized) pp->TestNukeInit = true;
|
|
|
|
u->WeaponNum = WPN_MICRO;
|
|
(*DamageData[u->WeaponNum].Init)(pp);
|
|
|
|
return true;
|
|
}
|
|
|
|
pp->KeyPressBits &= ~SB_FIRE;
|
|
|
|
FindWeaponNum = WPN_SHOTGUN; // Start at the top
|
|
|
|
while (true)
|
|
{
|
|
// ran out of weapons - choose SWORD
|
|
if (wpn_ndx > sizeof(wpn_order))
|
|
{
|
|
FindWeaponNum = WPN_SWORD;
|
|
break;
|
|
}
|
|
|
|
// if you have the weapon and the ammo is greater than 0
|
|
if (TEST(pp->WpnFlags, BIT(FindWeaponNum)) && pp->WpnAmmo[FindWeaponNum] >= min_ammo)
|
|
break;
|
|
|
|
wpn_ndx++;
|
|
FindWeaponNum = wpn_order[wpn_ndx];
|
|
}
|
|
|
|
u->WeaponNum = int8_t(FindWeaponNum);
|
|
|
|
if (u->WeaponNum == WPN_HOTHEAD)
|
|
{
|
|
pp->WeaponType = WPN_HOTHEAD;
|
|
pp->WpnFlameType = 0;
|
|
}
|
|
|
|
(*DamageData[u->WeaponNum].Init)(pp);
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// X/Y POSITION INLINES
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
inline double pspSinVel(PANEL_SPRITEp const psp, int const ang = INT_MAX)
|
|
{
|
|
return psp->vel * synctics * bsinf(ang == INT_MAX ? psp->ang : ang, -22);
|
|
}
|
|
|
|
inline double pspCosVel(PANEL_SPRITEp const psp, int const ang = INT_MAX)
|
|
{
|
|
return psp->vel * synctics * bcosf(ang == INT_MAX ? psp->ang : ang, -22);
|
|
}
|
|
|
|
inline double pspPresentRetractScale(int const picnum, double const defaultheight)
|
|
{
|
|
double const picheight = tileHeight(picnum);
|
|
return picheight == defaultheight ? 1 : picheight / defaultheight;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SWORD
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static short SwordAngTable[] =
|
|
{
|
|
82,
|
|
168,
|
|
256+64
|
|
};
|
|
|
|
short SwordAng = 0;
|
|
|
|
void
|
|
SwordBlur(PANEL_SPRITEp psp)
|
|
{
|
|
psp->kill_tics -= synctics;
|
|
if (psp->kill_tics <= 0)
|
|
{
|
|
pKillSprite(psp);
|
|
return;
|
|
}
|
|
else if (psp->kill_tics <= 6)
|
|
{
|
|
SET(psp->flags, PANF_TRANS_FLIP);
|
|
}
|
|
|
|
psp->shade += 10;
|
|
// change sprites priority
|
|
REMOVE(psp);
|
|
psp->priority--;
|
|
InsertPanelSprite(psp->PlayerP, psp);
|
|
}
|
|
|
|
void
|
|
SpawnSwordBlur(PANEL_SPRITEp psp)
|
|
{
|
|
if (cl_nomeleeblur) return;
|
|
|
|
PANEL_SPRITEp nsp;
|
|
//PICITEMp pip;
|
|
|
|
if (psp->PlayerP->SwordAng > 200)
|
|
return;
|
|
|
|
nsp = pSpawnSprite(psp->PlayerP, nullptr, PRI_BACK, psp->x, psp->y);
|
|
|
|
SET(nsp->flags, PANF_WEAPON_SPRITE);
|
|
nsp->ang = psp->ang;
|
|
nsp->vel = psp->vel;
|
|
nsp->PanelSpriteFunc = SwordBlur;
|
|
nsp->kill_tics = 9;
|
|
nsp->shade = psp->shade + 10;
|
|
|
|
nsp->picndx = -1;
|
|
nsp->picnum = psp->picndx;
|
|
|
|
if (TEST(psp->State->flags, psf_Xflip))
|
|
SET(nsp->flags, PANF_XFLIP);
|
|
|
|
nsp->rotate_ang = psp->rotate_ang;
|
|
nsp->scale = psp->scale;
|
|
|
|
SET(nsp->flags, PANF_TRANSLUCENT);
|
|
}
|
|
|
|
void pSwordPresent(PANEL_SPRITEp psp);
|
|
void pSwordRetract(PANEL_SPRITEp psp);
|
|
void pSwordAction(PANEL_SPRITEp psp);
|
|
void pSwordRest(PANEL_SPRITEp psp);
|
|
void pSwordAttack(PANEL_SPRITEp psp);
|
|
void pSwordSlide(PANEL_SPRITEp psp);
|
|
void pSwordSlideDown(PANEL_SPRITEp psp);
|
|
void pSwordHide(PANEL_SPRITEp psp);
|
|
void pSwordUnHide(PANEL_SPRITEp psp);
|
|
|
|
void pSwordSlideR(PANEL_SPRITEp psp);
|
|
void pSwordSlideDownR(PANEL_SPRITEp psp);
|
|
|
|
extern PANEL_STATE ps_SwordSwing[];
|
|
extern PANEL_STATE ps_ReloadSword[];
|
|
|
|
#define Sword_BEAT_RATE 24
|
|
#define Sword_ACTION_RATE 10
|
|
|
|
PANEL_STATE ps_PresentSword[] =
|
|
{
|
|
{ID_SwordPresent0, Sword_BEAT_RATE, pSwordPresent, &ps_PresentSword[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_SwordRest[] =
|
|
{
|
|
{ID_SwordPresent0, Sword_BEAT_RATE, pSwordRest, &ps_SwordRest[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_SwordHide[] =
|
|
{
|
|
{ID_SwordPresent0, Sword_BEAT_RATE, pSwordHide, &ps_SwordHide[0], 0,0,0}
|
|
};
|
|
|
|
#define SWORD_PAUSE_TICS 10
|
|
//#define SWORD_SLIDE_TICS 14
|
|
#define SWORD_SLIDE_TICS 10
|
|
#define SWORD_MID_SLIDE_TICS 14
|
|
|
|
PANEL_STATE ps_SwordSwing[] =
|
|
{
|
|
{ID_SwordSwing0, SWORD_PAUSE_TICS, pNullAnimator, &ps_SwordSwing[1], 0,0,0},
|
|
{ID_SwordSwing1, SWORD_SLIDE_TICS, /* start slide */ pSwordSlide, &ps_SwordSwing[2], 0,0,0},
|
|
{ID_SwordSwing1, 0, /* damage */ pSwordAttack, &ps_SwordSwing[3], psf_QuickCall, 0,0},
|
|
{ID_SwordSwing2, SWORD_MID_SLIDE_TICS, /* mid slide */ pSwordSlideDown, &ps_SwordSwing[4], 0,0,0},
|
|
|
|
{ID_SwordSwing2, 99, /* end slide */ pSwordSlideDown, &ps_SwordSwing[4], 0,0,0},
|
|
|
|
{ID_SwordSwingR1, SWORD_SLIDE_TICS, /* start slide */ pSwordSlideR, &ps_SwordSwing[6], psf_Xflip, 0,0},
|
|
{ID_SwordSwingR2, 0, /* damage */ pSwordAttack, &ps_SwordSwing[7], psf_QuickCall|psf_Xflip, 0,0},
|
|
{ID_SwordSwingR2, SWORD_MID_SLIDE_TICS, /* mid slide */ pSwordSlideDownR, &ps_SwordSwing[8], psf_Xflip, 0,0},
|
|
|
|
{ID_SwordSwingR2, 99, /* end slide */ pSwordSlideDownR, &ps_SwordSwing[8], psf_Xflip, 0,0},
|
|
{ID_SwordSwingR2, 2, /* end slide */ pNullAnimator, &ps_SwordSwing[1], psf_Xflip, 0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_RetractSword[] =
|
|
{
|
|
{ID_SwordPresent0, Sword_BEAT_RATE, pSwordRetract, &ps_RetractSword[0], 0,0,0}
|
|
};
|
|
|
|
#define SWORD_SWAY_AMT 12
|
|
|
|
// left swing
|
|
#define SWORD_XOFF (320 + SWORD_SWAY_AMT)
|
|
#define SWORD_YOFF 200
|
|
|
|
// right swing
|
|
#define SWORDR_XOFF (0 - 80)
|
|
|
|
#define SWORD_VEL 1700
|
|
#define SWORD_POWER_VEL 2500
|
|
|
|
|
|
void SpecialUziRetractFunc(PANEL_SPRITEp psp)
|
|
{
|
|
psp->backupy();
|
|
psp->y += 4 * synctics;
|
|
|
|
if (psp->y >= 200 + tileHeight(psp->picnum))
|
|
{
|
|
pKillSprite(psp);
|
|
}
|
|
}
|
|
|
|
void RetractCurWpn(PLAYERp pp)
|
|
{
|
|
// Retract old weapon
|
|
if (pp->CurWpn)
|
|
{
|
|
PANEL_SPRITEp cur,nxt;
|
|
|
|
if ((pp->CurWpn == pp->Wpn[WPN_UZI] && pp->WpnUziType == 2) || pp->CurWpn != pp->Wpn[WPN_UZI])
|
|
{
|
|
pSetState(pp->CurWpn, pp->CurWpn->RetractState);
|
|
SET(pp->Flags, PF_WEAPON_RETRACT);
|
|
}
|
|
|
|
if (pp->CurWpn->sibling)
|
|
{
|
|
// primarily for double uzi to take down the second uzi
|
|
pSetState(pp->CurWpn->sibling, pp->CurWpn->sibling->RetractState);
|
|
}
|
|
else
|
|
{
|
|
// check for any outstanding siblings that need to go away also
|
|
auto list = pp->GetPanelSpriteList();
|
|
for (auto cur = list->Next; nxt = cur->Next, cur != list; cur = nxt)
|
|
{
|
|
if (cur->sibling && cur->sibling == pp->CurWpn)
|
|
{
|
|
// special case for uzi reload pieces
|
|
cur->picnum = cur->picndx;
|
|
cur->State = nullptr;
|
|
cur->PanelSpriteFunc = SpecialUziRetractFunc;
|
|
cur->sibling = nullptr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
InitWeaponSword(PLAYERp pp)
|
|
{
|
|
PANEL_SPRITEp psp;
|
|
short rnd_num;
|
|
|
|
|
|
if (Prediction)
|
|
return;
|
|
|
|
if (!TEST(pp->WpnFlags, BIT(WPN_SWORD)) ||
|
|
TEST(pp->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
// needed for death sequence when the SWORD was your weapon when you died
|
|
if (pp->Wpn[WPN_SWORD] && TEST(pp->Wpn[WPN_SWORD]->flags, PANF_DEATH_HIDE))
|
|
{
|
|
RESET(pp->Wpn[WPN_SWORD]->flags, PANF_DEATH_HIDE);
|
|
RESET(pp->Flags, PF_WEAPON_RETRACT|PF_WEAPON_DOWN);
|
|
pSetState(pp->CurWpn, pp->CurWpn->PresentState);
|
|
return;
|
|
}
|
|
|
|
|
|
if (!pp->Wpn[WPN_SWORD])
|
|
{
|
|
psp = pp->Wpn[WPN_SWORD] = pSpawnSprite(pp, ps_PresentSword, PRI_MID, SWORD_XOFF, SWORD_YOFF);
|
|
psp->y += tileHeight(psp->picndx);
|
|
psp->backupy();
|
|
}
|
|
|
|
if (pp->CurWpn == pp->Wpn[WPN_SWORD])
|
|
{
|
|
return;
|
|
}
|
|
|
|
PlayerUpdateWeapon(pp, WPN_SWORD);
|
|
|
|
pp->WpnUziType = 2; // Make uzi's go away!
|
|
RetractCurWpn(pp);
|
|
|
|
// Set up the new weapon variables
|
|
psp = pp->CurWpn = pp->Wpn[WPN_SWORD];
|
|
SET(psp->flags, PANF_WEAPON_SPRITE);
|
|
psp->ActionState = ps_SwordSwing;
|
|
psp->RetractState = ps_RetractSword;
|
|
psp->PresentState = ps_PresentSword;
|
|
psp->RestState = ps_SwordRest;
|
|
pSetState(psp, psp->PresentState);
|
|
|
|
PlaySound(DIGI_SWORD_UP, pp, v3df_follow|v3df_dontpan);
|
|
|
|
if (pp == Player+myconnectindex && PlayClock > 0)
|
|
{
|
|
rnd_num = STD_RANDOM_RANGE(1024);
|
|
if (rnd_num > 900)
|
|
PlaySound(DIGI_TAUNTAI2, pp, v3df_follow|v3df_dontpan);
|
|
else if (rnd_num > 800)
|
|
PlaySound(DIGI_PLAYERYELL1, pp, v3df_follow|v3df_dontpan);
|
|
else if (rnd_num > 700)
|
|
PlaySound(DIGI_PLAYERYELL2, pp, v3df_follow|v3df_dontpan);
|
|
else if (rnd_num > 600)
|
|
PlayerSound(DIGI_ILIKESWORD, v3df_follow|v3df_dontpan,pp);
|
|
}
|
|
|
|
psp->PlayerP->KeyPressBits |= SB_FIRE;
|
|
}
|
|
|
|
|
|
void
|
|
pSwordPresent(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->PlayerP->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
psp->backupy();
|
|
psp->y -= 3 * synctics * pspPresentRetractScale(psp->picndx, 136);
|
|
|
|
if (psp->y < SWORD_YOFF)
|
|
{
|
|
psp->oy = psp->y = SWORD_YOFF;
|
|
psp->backupboby();
|
|
pSetState(psp, psp->RestState);
|
|
}
|
|
}
|
|
|
|
//
|
|
// LEFT SWING
|
|
//
|
|
|
|
void
|
|
pSwordSlide(PANEL_SPRITEp psp)
|
|
{
|
|
SpawnSwordBlur(psp);
|
|
|
|
psp->backupcoords();
|
|
|
|
psp->x += pspCosVel(psp);
|
|
psp->y -= pspSinVel(psp);
|
|
|
|
psp->vel += 24 * synctics;
|
|
}
|
|
|
|
void
|
|
pSwordSlideDown(PANEL_SPRITEp psp)
|
|
{
|
|
SpawnSwordBlur(psp);
|
|
|
|
auto ang = SwordAng + psp->ang + psp->PlayerP->SwordAng;
|
|
|
|
psp->backupcoords();
|
|
|
|
psp->x += pspCosVel(psp, ang);
|
|
psp->y -= pspSinVel(psp, ang);
|
|
|
|
psp->vel += 20 * synctics;
|
|
|
|
if (psp->x < -40)
|
|
{
|
|
// if still holding down the fire key - continue swinging
|
|
if (psp->PlayerP->input.actions & SB_FIRE)
|
|
{
|
|
if (psp->PlayerP->KeyPressBits & SB_FIRE)
|
|
{
|
|
DoPlayerChooseYell(psp->PlayerP);
|
|
// continue to next state to swing right
|
|
pStatePlusOne(psp);
|
|
psp->ox = psp->x = SWORDR_XOFF;
|
|
psp->oy = psp->y = SWORD_YOFF;
|
|
psp->backupboby();
|
|
psp->ang = 1024;
|
|
psp->PlayerP->SwordAng = SwordAngTable[RandomRange(SIZ(SwordAngTable))];
|
|
psp->vel = 2500;
|
|
DoPlayerSpriteThrow(psp->PlayerP);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// NOT still holding down the fire key - stop swinging
|
|
pSetState(psp, psp->PresentState);
|
|
psp->ox = psp->x = SWORD_XOFF;
|
|
psp->oy = psp->y = SWORD_YOFF + tileHeight(psp->picndx);
|
|
psp->backupboby();
|
|
}
|
|
}
|
|
|
|
//
|
|
// RIGHT SWING
|
|
//
|
|
|
|
void
|
|
pSwordSlideR(PANEL_SPRITEp psp)
|
|
{
|
|
SpawnSwordBlur(psp);
|
|
|
|
psp->backupcoords();
|
|
|
|
psp->x -= pspCosVel(psp);
|
|
psp->y += pspSinVel(psp);
|
|
|
|
psp->vel += 24 * synctics;
|
|
}
|
|
|
|
void
|
|
pSwordSlideDownR(PANEL_SPRITEp psp)
|
|
{
|
|
SpawnSwordBlur(psp);
|
|
|
|
auto ang = SwordAng + psp->ang - psp->PlayerP->SwordAng;
|
|
|
|
psp->backupcoords();
|
|
|
|
psp->x -= pspCosVel(psp, ang);
|
|
psp->y += pspSinVel(psp, ang);
|
|
|
|
psp->vel += 24 * synctics;
|
|
|
|
if (psp->x > 350)
|
|
{
|
|
// if still holding down the fire key - continue swinging
|
|
if (psp->PlayerP->input.actions & SB_FIRE)
|
|
{
|
|
if (psp->PlayerP->KeyPressBits & SB_FIRE)
|
|
{
|
|
DoPlayerChooseYell(psp->PlayerP);
|
|
// back to action state
|
|
pStatePlusOne(psp);
|
|
psp->ox = psp->x = SWORD_XOFF + 80;
|
|
psp->oy = psp->y = SWORD_YOFF;
|
|
psp->backupboby();
|
|
psp->PlayerP->SwordAng = SwordAngTable[RandomRange(SIZ(SwordAngTable))];
|
|
psp->ang = 1024;
|
|
psp->vel = 2500;
|
|
DoPlayerSpriteThrow(psp->PlayerP);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// NOT still holding down the fire key - stop swinging
|
|
pSetState(psp, psp->PresentState);
|
|
psp->ox = psp->x = SWORD_XOFF;
|
|
psp->oy = psp->y = SWORD_YOFF + tileHeight(psp->picndx);
|
|
psp->backupboby();
|
|
}
|
|
}
|
|
|
|
void
|
|
pSwordBobSetup(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->flags, PANF_BOB))
|
|
return;
|
|
|
|
psp->backupbobcoords();
|
|
|
|
psp->sin_amt = SWORD_SWAY_AMT;
|
|
psp->sin_ndx = 0;
|
|
psp->bob_height_divider = 8;
|
|
}
|
|
|
|
void
|
|
pSwordHide(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= SWORD_YOFF + tileHeight(picnum))
|
|
{
|
|
psp->oy = psp->y = SWORD_YOFF + tileHeight(picnum);
|
|
psp->ox = psp->x = SWORD_XOFF;
|
|
|
|
pWeaponUnHideKeys(psp, psp->PresentState);
|
|
}
|
|
}
|
|
|
|
void
|
|
pSwordRest(PANEL_SPRITEp psp)
|
|
{
|
|
bool force = !!TEST(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (pWeaponHideKeys(psp, ps_SwordHide))
|
|
return;
|
|
|
|
psp->yorig += synctics;
|
|
|
|
if (psp->yorig > SWORD_YOFF)
|
|
{
|
|
psp->yorig = SWORD_YOFF;
|
|
}
|
|
|
|
pSwordBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
|
|
force = !!TEST(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if ((psp->PlayerP->input.actions & SB_FIRE) || force)
|
|
{
|
|
if ((psp->PlayerP->KeyPressBits & SB_FIRE) || force)
|
|
{
|
|
RESET(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
pSetState(psp, psp->ActionState);
|
|
|
|
psp->vel = 2500;
|
|
|
|
psp->ang = 1024;
|
|
psp->PlayerP->SwordAng = SwordAngTable[RandomRange(SIZ(SwordAngTable))];
|
|
DoPlayerSpriteThrow(psp->PlayerP);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
pSwordAction(PANEL_SPRITEp psp)
|
|
{
|
|
pSwordBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
}
|
|
|
|
|
|
void
|
|
pSwordAttack(PANEL_SPRITEp psp)
|
|
{
|
|
|
|
InitSwordAttack(psp->PlayerP);
|
|
}
|
|
|
|
void
|
|
pSwordRetract(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics * pspPresentRetractScale(picnum, 136);
|
|
|
|
if (psp->y >= SWORD_YOFF + tileHeight(picnum))
|
|
{
|
|
RESET(psp->PlayerP->Flags, PF_WEAPON_RETRACT);
|
|
psp->PlayerP->Wpn[WPN_SWORD] = nullptr;
|
|
pKillSprite(psp);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// STAR
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void pStarPresent(PANEL_SPRITEp psp);
|
|
void pStarRetract(PANEL_SPRITEp psp);
|
|
void pStarAction(PANEL_SPRITEp psp);
|
|
void pStarRest(PANEL_SPRITEp psp);
|
|
void pStarThrow(PANEL_SPRITEp psp);
|
|
|
|
void pStarGrab(PANEL_SPRITEp psp);
|
|
void pStarDone(PANEL_SPRITEp psp);
|
|
void pStarFollowThru(PANEL_SPRITEp psp);
|
|
void pStarFollowThru2(PANEL_SPRITEp psp);
|
|
void pStarStartThrow(PANEL_SPRITEp psp);
|
|
|
|
void pStarFollowUp(PANEL_SPRITEp psp);
|
|
void pStarFollowDown(PANEL_SPRITEp psp);
|
|
|
|
void pStarHide(PANEL_SPRITEp psp);
|
|
void pStarRestTest(PANEL_SPRITEp psp);
|
|
|
|
extern PANEL_STATE ps_StarThrow[];
|
|
|
|
#define PRESENT_STAR_RATE 5
|
|
|
|
PANEL_STATE ps_PresentStar[] =
|
|
{
|
|
{ID_StarPresent0, PRESENT_STAR_RATE, pStarPresent, &ps_PresentStar[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_StarHide[] =
|
|
{
|
|
{ID_StarPresent0, PRESENT_STAR_RATE, pStarHide, &ps_StarHide[0], 0,0,0}
|
|
};
|
|
|
|
#define Star_RATE 2 // was 5
|
|
|
|
PANEL_STATE ps_StarRest[] =
|
|
{
|
|
{ID_StarPresent0, Star_RATE, pStarRest, &ps_StarRest[0], 0,0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_ThrowStar[] =
|
|
{
|
|
{ID_StarDown0, Star_RATE+3, pNullAnimator, &ps_ThrowStar[1], 0,0,0},
|
|
{ID_StarDown1, Star_RATE+3, pNullAnimator, &ps_ThrowStar[2], 0,0,0},
|
|
{ID_StarDown1, Star_RATE*2, pNullAnimator, &ps_ThrowStar[3], psf_Invisible, 0,0},
|
|
{ID_StarDown1, Star_RATE, pNullAnimator, &ps_ThrowStar[4], 0,0,0},
|
|
{ID_StarDown0, Star_RATE, pNullAnimator, &ps_ThrowStar[5], 0,0,0},
|
|
{ID_ThrowStar0, 1, pNullAnimator, &ps_ThrowStar[6], 0,0,0},
|
|
{ID_ThrowStar0, Star_RATE, pStarThrow, &ps_ThrowStar[7], psf_QuickCall, 0,0},
|
|
{ID_ThrowStar0, Star_RATE, pNullAnimator, &ps_ThrowStar[8], 0,0,0},
|
|
{ID_ThrowStar1, Star_RATE, pNullAnimator, &ps_ThrowStar[9], 0,0,0},
|
|
{ID_ThrowStar2, Star_RATE*2, pNullAnimator, &ps_ThrowStar[10], 0,0,0},
|
|
{ID_ThrowStar3, Star_RATE*2, pNullAnimator, &ps_ThrowStar[11], 0,0,0},
|
|
{ID_ThrowStar4, Star_RATE*2, pNullAnimator, &ps_ThrowStar[12], 0,0,0},
|
|
// start up
|
|
{ID_StarDown1, Star_RATE+3, pNullAnimator, &ps_ThrowStar[13], 0,0,0},
|
|
{ID_StarDown0, Star_RATE+3, pNullAnimator, &ps_ThrowStar[14], 0,0,0},
|
|
{ID_StarPresent0, Star_RATE+3, pNullAnimator, &ps_ThrowStar[15], 0,0,0},
|
|
// maybe to directly to rest state
|
|
{ID_StarDown0, 3, pStarRestTest, &ps_ThrowStar[16], psf_QuickCall, 0,0},
|
|
// if holding the fire key we get to here
|
|
{ID_ThrowStar4, 3, pNullAnimator, &ps_ThrowStar[5], 0,0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_RetractStar[] =
|
|
{
|
|
{ID_StarPresent0, PRESENT_STAR_RATE, pStarRetract, &ps_RetractStar[0], 0,0,0}
|
|
};
|
|
|
|
//
|
|
// Right hand star routines
|
|
//
|
|
|
|
//#define STAR_YOFF 220
|
|
//#define STAR_XOFF (160+25)
|
|
#define STAR_YOFF 208
|
|
#define STAR_XOFF (160+80)
|
|
|
|
void
|
|
pStarRestTest(PANEL_SPRITEp psp)
|
|
{
|
|
if (psp->PlayerP->input.actions & SB_FIRE)
|
|
{
|
|
if (psp->PlayerP->KeyPressBits & SB_FIRE)
|
|
{
|
|
if (!WeaponOK(psp->PlayerP))
|
|
return;
|
|
|
|
// continue to next state to swing right
|
|
DoPlayerChooseYell(psp->PlayerP);
|
|
pStatePlusOne(psp);
|
|
return;
|
|
}
|
|
}
|
|
|
|
pSetState(psp, psp->RestState);
|
|
}
|
|
|
|
void
|
|
InitWeaponStar(PLAYERp pp)
|
|
{
|
|
PANEL_SPRITEp psp = nullptr;
|
|
|
|
if (Prediction)
|
|
return;
|
|
|
|
if (!TEST(pp->WpnFlags, BIT(WPN_STAR)) ||
|
|
pp->WpnAmmo[WPN_STAR] < 3 ||
|
|
TEST(pp->Flags, PF_WEAPON_RETRACT))
|
|
{
|
|
//pp->WpnFirstType = WPN_SWORD;
|
|
//InitWeaponSword(pp);
|
|
return;
|
|
}
|
|
|
|
// needed for death sequence when the STAR was your weapon when you died
|
|
if (pp->Wpn[WPN_STAR] && TEST(pp->Wpn[WPN_STAR]->flags, PANF_DEATH_HIDE))
|
|
{
|
|
RESET(pp->Wpn[WPN_STAR]->flags, PANF_DEATH_HIDE);
|
|
RESET(pp->Flags, PF_WEAPON_RETRACT);
|
|
pSetState(pp->CurWpn, pp->CurWpn->PresentState);
|
|
return;
|
|
}
|
|
|
|
if (!pp->Wpn[WPN_STAR])
|
|
{
|
|
psp = pp->Wpn[WPN_STAR] = pSpawnSprite(pp, ps_PresentStar, PRI_MID, STAR_XOFF, STAR_YOFF);
|
|
psp->y += tileHeight(psp->picndx);
|
|
psp->backupy();
|
|
}
|
|
|
|
if (pp->CurWpn == pp->Wpn[WPN_STAR])
|
|
{
|
|
return;
|
|
}
|
|
|
|
PlayerUpdateWeapon(pp, WPN_STAR);
|
|
|
|
pp->WpnUziType = 2; // Make uzi's go away!
|
|
RetractCurWpn(pp);
|
|
|
|
// Set up the new weapon variables
|
|
pp->CurWpn = pp->Wpn[WPN_STAR];
|
|
SET(psp->flags, PANF_WEAPON_SPRITE);
|
|
psp->ActionState = ps_ThrowStar;
|
|
//psp->ActionState = &ps_ThrowStar[1];
|
|
psp->RetractState = ps_RetractStar;
|
|
psp->PresentState = ps_PresentStar;
|
|
psp->RestState = ps_StarRest;
|
|
//psp->RestState = ps_ThrowStar;
|
|
pSetState(psp, psp->PresentState);
|
|
|
|
PlaySound(DIGI_PULL, pp, v3df_follow|v3df_dontpan);
|
|
if (STD_RANDOM_RANGE(1000) > 900 && pp == Player+myconnectindex)
|
|
{
|
|
if (!sw_darts)
|
|
PlayerSound(DIGI_ILIKESHURIKEN, v3df_follow|v3df_dontpan,pp);
|
|
}
|
|
|
|
psp->PlayerP->KeyPressBits |= SB_FIRE;
|
|
}
|
|
|
|
void
|
|
pStarPresent(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->PlayerP->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
psp->backupy();
|
|
psp->y -= 3 * synctics;
|
|
|
|
if (psp->y < STAR_YOFF)
|
|
{
|
|
psp->oy = psp->y = STAR_YOFF;
|
|
}
|
|
|
|
if (psp->y <= STAR_YOFF)
|
|
{
|
|
pSetState(psp, psp->RestState);
|
|
}
|
|
}
|
|
|
|
void
|
|
pStarBobSetup(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->flags, PANF_BOB))
|
|
return;
|
|
|
|
psp->backupbobcoords();
|
|
|
|
psp->sin_amt = 10;
|
|
psp->sin_ndx = 0;
|
|
psp->bob_height_divider = 8;
|
|
}
|
|
|
|
void
|
|
pLStarBobSetup(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->flags, PANF_BOB))
|
|
return;
|
|
|
|
psp->backupbobcoords();
|
|
|
|
psp->sin_amt = 6;
|
|
psp->sin_ndx = 0;
|
|
psp->bob_height_divider = 16;
|
|
}
|
|
|
|
void
|
|
pStarHide(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= STAR_YOFF + tileHeight(picnum))
|
|
{
|
|
psp->oy = psp->y = STAR_YOFF + tileHeight(picnum);
|
|
|
|
pWeaponUnHideKeys(psp, psp->PresentState);
|
|
}
|
|
}
|
|
|
|
void
|
|
pStarRest(PANEL_SPRITEp psp)
|
|
{
|
|
bool force = !!TEST(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (pWeaponHideKeys(psp, ps_StarHide))
|
|
return;
|
|
|
|
pStarBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
|
|
if ((psp->PlayerP->input.actions & SB_FIRE) || force)
|
|
{
|
|
if ((psp->PlayerP->KeyPressBits & SB_FIRE) || force)
|
|
{
|
|
RESET(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (!WeaponOK(psp->PlayerP))
|
|
return;
|
|
|
|
// //DSPRINTF(ds,"StarFire");
|
|
// MONO_PRINT(ds);
|
|
|
|
DoPlayerChooseYell(psp->PlayerP);
|
|
|
|
pSetState(psp, psp->ActionState);
|
|
DoPlayerSpriteThrow(psp->PlayerP);
|
|
}
|
|
}
|
|
else
|
|
WeaponOK(psp->PlayerP);
|
|
}
|
|
|
|
|
|
void
|
|
pStarAction(PANEL_SPRITEp psp)
|
|
{
|
|
pStarBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
}
|
|
|
|
|
|
void
|
|
pStarThrow(PANEL_SPRITEp psp)
|
|
{
|
|
InitStar(psp->PlayerP);
|
|
}
|
|
|
|
void
|
|
pStarRetract(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= STAR_YOFF + tileHeight(picnum))
|
|
{
|
|
RESET(psp->PlayerP->Flags, PF_WEAPON_RETRACT);
|
|
|
|
// kill only in its own routine
|
|
psp->PlayerP->Wpn[WPN_STAR] = nullptr;
|
|
pKillSprite(psp);
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UZI
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void pUziPresent(PANEL_SPRITEp);
|
|
void pUziFire(PANEL_SPRITEp);
|
|
void pUziRetract(PANEL_SPRITEp);
|
|
void pUziAction(PANEL_SPRITEp);
|
|
void pUziRest(PANEL_SPRITEp);
|
|
void pUziHide(PANEL_SPRITEp);
|
|
void pUziPresentReload(PANEL_SPRITEp);
|
|
|
|
void pSpawnUziClip(PANEL_SPRITEp);
|
|
void pSpawnUziReload(PANEL_SPRITEp);
|
|
void pUziReload(PANEL_SPRITEp);
|
|
void pUziReloadRetract(PANEL_SPRITEp);
|
|
void pUziClip(PANEL_SPRITEp);
|
|
void pUziDoneReload(PANEL_SPRITEp);
|
|
|
|
void pUziEjectDown(PANEL_SPRITEp);
|
|
void pUziEjectUp(PANEL_SPRITEp);
|
|
|
|
// CTW MODIFICATION
|
|
//void SetVisNorm(void);
|
|
int SetVisNorm(void);
|
|
// CTW MODIFICATION END
|
|
pANIMATOR pSetVisNorm;
|
|
|
|
// Right Uzi
|
|
PANEL_STATE ps_FireUzi[] =
|
|
{
|
|
{ID_UziPresent0, 3, pUziRest, &ps_FireUzi[0], 0,0,0},
|
|
{ID_UziFire0, 1, pUziAction, &ps_FireUzi[2], psf_ShadeHalf, 0,0},
|
|
|
|
{ID_UziFire1, 0, pUziFire, &ps_FireUzi[3], psf_ShadeNone|psf_QuickCall, 0,0},
|
|
{ID_UziFire1, 4, pUziAction, &ps_FireUzi[4], psf_ShadeNone, 0,0},
|
|
{ID_UziFire1, 0, pSetVisNorm, &ps_FireUzi[5], psf_ShadeNone|psf_QuickCall, 0,0},
|
|
{ID_UziFire1, 4, pUziAction, &ps_FireUzi[6], psf_ShadeNone, 0,0},
|
|
{ID_UziFire1, 0, pUziFire, &ps_FireUzi[7], psf_ShadeNone|psf_QuickCall, 0,0},
|
|
{ID_UziFire1, 4, pUziAction, &ps_FireUzi[8], psf_ShadeNone, 0,0},
|
|
{ID_UziFire1, 0, pSetVisNorm, &ps_FireUzi[9], psf_ShadeNone, 0,0},
|
|
|
|
{ID_UziFire0, 4, pUziAction, &ps_FireUzi[10], psf_ShadeHalf, 0,0},
|
|
{ID_UziFire0, 0, pUziFire, &ps_FireUzi[11], psf_QuickCall, 0,0},
|
|
{ID_UziFire0, 4, pUziAction, &ps_FireUzi[12], psf_ShadeHalf, 0,0},
|
|
{ID_UziFire0, 4, pUziAction, &ps_FireUzi[13], psf_ShadeHalf, 0,0},
|
|
|
|
{ID_UziFire1, 5, pUziRest, &ps_FireUzi[0], psf_ShadeNone|psf_QuickCall, 0,0},
|
|
};
|
|
|
|
#define PRESENT_UZI_RATE 6
|
|
#define RELOAD_UZI_RATE 1
|
|
|
|
PANEL_STATE ps_UziNull[] =
|
|
{
|
|
{ID_UziPresent0, PRESENT_UZI_RATE, pNullAnimator, &ps_UziNull[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_UziHide[] =
|
|
{
|
|
{ID_UziPresent0, PRESENT_UZI_RATE, pUziHide, &ps_UziHide[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_PresentUzi[] =
|
|
{
|
|
{ID_UziPresent0, PRESENT_UZI_RATE, pUziPresent, &ps_PresentUzi[0], 0,0,0},
|
|
};
|
|
|
|
// present of secondary uzi for reload needs to be faster
|
|
PANEL_STATE ps_PresentUziReload[] =
|
|
{
|
|
{ID_UziPresent0, RELOAD_UZI_RATE, pUziPresentReload, &ps_PresentUziReload[0], 0,0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_RetractUzi[] =
|
|
{
|
|
{ID_UziPresent0, PRESENT_UZI_RATE, pUziRetract, &ps_RetractUzi[0], 0,0,0},
|
|
};
|
|
|
|
// Left Uzi
|
|
|
|
PANEL_STATE ps_FireUzi2[] =
|
|
{
|
|
{ID_Uzi2Present0, 3, pUziRest, &ps_FireUzi2[0], psf_Xflip, 0,0},
|
|
{ID_Uzi2Fire0, 1, pUziAction, &ps_FireUzi2[2], psf_ShadeHalf|psf_Xflip, 0,0},
|
|
|
|
{ID_Uzi2Fire1, 0, pUziFire, &ps_FireUzi2[3], psf_ShadeNone|psf_QuickCall|psf_Xflip, 0,0},
|
|
{ID_Uzi2Fire1, 4, pUziAction, &ps_FireUzi2[4], psf_ShadeNone|psf_Xflip, 0,0},
|
|
{ID_Uzi2Fire1, 4, pUziAction, &ps_FireUzi2[5], psf_ShadeNone|psf_Xflip, 0,0},
|
|
{ID_Uzi2Fire1, 0, pUziFire, &ps_FireUzi2[6], psf_ShadeNone|psf_QuickCall|psf_Xflip, 0,0},
|
|
{ID_Uzi2Fire1, 4, pUziAction, &ps_FireUzi2[7], psf_ShadeNone|psf_Xflip, 0,0},
|
|
|
|
{ID_Uzi2Fire0, 4, pUziAction, &ps_FireUzi2[8], psf_ShadeHalf|psf_Xflip, 0,0},
|
|
{ID_Uzi2Fire0, 0, pUziFire, &ps_FireUzi2[9], psf_ShadeHalf|psf_QuickCall|psf_Xflip, 0,0},
|
|
{ID_Uzi2Fire0, 4, pUziAction, &ps_FireUzi2[10], psf_ShadeHalf|psf_Xflip, 0,0},
|
|
{ID_Uzi2Fire0, 4, pUziAction, &ps_FireUzi2[11], psf_ShadeHalf|psf_Xflip, 0,0},
|
|
|
|
{ID_Uzi2Fire1, 5, pUziRest, &ps_FireUzi2[0], psf_QuickCall, 0,0},
|
|
};
|
|
|
|
|
|
PANEL_STATE ps_PresentUzi2[] =
|
|
{
|
|
{ID_Uzi2Present0, PRESENT_UZI_RATE, pUziPresent, &ps_PresentUzi2[0], psf_Xflip, 0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_Uzi2Hide[] =
|
|
{
|
|
{ID_Uzi2Present0, PRESENT_UZI_RATE, pUziHide, &ps_Uzi2Hide[0], psf_Xflip, 0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_RetractUzi2[] =
|
|
{
|
|
{ID_Uzi2Present0, PRESENT_UZI_RATE, pUziRetract, &ps_RetractUzi2[0], psf_Xflip, 0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_Uzi2Suicide[] =
|
|
{
|
|
{ID_Uzi2Present0, PRESENT_UZI_RATE, pSuicide, &ps_Uzi2Suicide[0], psf_Xflip, 0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_Uzi2Null[] =
|
|
{
|
|
{ID_Uzi2Present0, PRESENT_UZI_RATE, pNullAnimator, &ps_Uzi2Null[0], psf_Xflip, 0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_UziEject[] =
|
|
{
|
|
{ID_UziPresent0, 1, pNullAnimator, &ps_UziEject[1], 0,0,0},
|
|
{ID_UziPresent0, RELOAD_UZI_RATE, pUziEjectDown, &ps_UziEject[1], 0,0,0},
|
|
{ID_UziEject0, RELOAD_UZI_RATE, pUziEjectUp, &ps_UziEject[2], 0,0,0},
|
|
{ID_UziEject0, 1, pNullAnimator, &ps_UziEject[4], 0,0,0},
|
|
{ID_UziEject0, RELOAD_UZI_RATE, pSpawnUziClip, &ps_UziEject[5], psf_QuickCall, 0,0},
|
|
{ID_UziEject0, RELOAD_UZI_RATE, pNullAnimator, &ps_UziEject[5], 0,0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_UziClip[] =
|
|
{
|
|
{ID_UziClip0, RELOAD_UZI_RATE, pUziClip, &ps_UziClip[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_UziReload[] =
|
|
{
|
|
{ID_UziReload0, RELOAD_UZI_RATE, pUziReload, &ps_UziReload[0], 0,0,0},
|
|
{ID_UziReload0, RELOAD_UZI_RATE, pUziReloadRetract, &ps_UziReload[1], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_UziDoneReload[] =
|
|
{
|
|
{ID_UziEject0, RELOAD_UZI_RATE, pUziDoneReload, &ps_UziDoneReload[0], 0,0,0}
|
|
};
|
|
|
|
#define CHAMBER_REST 0
|
|
#define CHAMBER_FIRE 1
|
|
#define CHAMBER_RELOAD 2
|
|
void
|
|
pUziOverlays(PANEL_SPRITEp psp, short mode)
|
|
{
|
|
#define UZI_CHAMBER_XOFF 32
|
|
#define UZI_CHAMBER_YOFF -73
|
|
|
|
#define UZI_CHAMBERRELOAD_XOFF 14
|
|
#define UZI_CHAMBERRELOAD_YOFF -100
|
|
|
|
if (!TEST(psp->flags, PANF_SECONDARY)) return;
|
|
|
|
if (psp->over[0].xoff == -1)
|
|
{
|
|
psp->over[0].xoff = UZI_CHAMBER_XOFF;
|
|
psp->over[0].yoff = UZI_CHAMBER_YOFF;
|
|
}
|
|
|
|
switch (mode)
|
|
{
|
|
case 0: // At rest
|
|
psp->over[0].pic = UZI_COPEN;
|
|
break;
|
|
case 1: // Firing
|
|
psp->over[0].pic = UZI_CLIT;
|
|
break;
|
|
case 2: // Reloading
|
|
psp->over[0].pic = UZI_CRELOAD;
|
|
psp->over[0].xoff = UZI_CHAMBERRELOAD_XOFF;
|
|
psp->over[0].yoff = UZI_CHAMBERRELOAD_YOFF;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#define UZI_CLIP_XOFF 16
|
|
#define UZI_CLIP_YOFF (-84)
|
|
|
|
//#define UZI_XOFF (80)
|
|
#define UZI_XOFF (100)
|
|
#define UZI_YOFF 208
|
|
|
|
#define UZI_RELOAD_YOFF 200
|
|
|
|
|
|
//
|
|
// Uzi Reload
|
|
//
|
|
|
|
void
|
|
pUziEjectDown(PANEL_SPRITEp gun)
|
|
{
|
|
gun->oy = gun->y;
|
|
gun->y += 5 * synctics;
|
|
|
|
if (gun->y > 260)
|
|
{
|
|
gun->oy = gun->y = 260;
|
|
pStatePlusOne(gun);
|
|
}
|
|
}
|
|
|
|
void
|
|
pUziEjectUp(PANEL_SPRITEp gun)
|
|
{
|
|
|
|
pUziOverlays(gun, CHAMBER_RELOAD);
|
|
|
|
gun->oy = gun->y;
|
|
gun->y -= 5 * synctics;
|
|
|
|
if (gun->y < UZI_RELOAD_YOFF)
|
|
{
|
|
gun->oy = gun->y = UZI_RELOAD_YOFF;
|
|
pStatePlusOne(gun);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
pSpawnUziClip(PANEL_SPRITEp gun)
|
|
{
|
|
PANEL_SPRITEp New;
|
|
|
|
PlaySound(DIGI_REMOVECLIP, gun->PlayerP,v3df_follow|v3df_dontpan|v3df_doppler|v3df_follow);
|
|
|
|
if (TEST(gun->flags, PANF_XFLIP))
|
|
{
|
|
New = pSpawnSprite(gun->PlayerP, ps_UziClip, PRI_BACK, gun->x - UZI_CLIP_XOFF, gun->y + UZI_CLIP_YOFF);
|
|
SET(New->flags, PANF_XFLIP);
|
|
New->ang = NORM_ANGLE(1024 + 256 + 22);
|
|
New->ang = NORM_ANGLE(New->ang + 512);
|
|
}
|
|
else
|
|
{
|
|
New = pSpawnSprite(gun->PlayerP, ps_UziClip, PRI_BACK, gun->x + UZI_CLIP_XOFF, gun->y + UZI_CLIP_YOFF);
|
|
New->ang = NORM_ANGLE(1024 + 256 - 22);
|
|
}
|
|
|
|
New->vel = 1050;
|
|
SET(New->flags, PANF_WEAPON_SPRITE);
|
|
|
|
|
|
// carry Eject sprite with clip
|
|
New->sibling = gun;
|
|
}
|
|
|
|
void
|
|
pSpawnUziReload(PANEL_SPRITEp oclip)
|
|
{
|
|
PANEL_SPRITEp nclip;
|
|
|
|
nclip = pSpawnSprite(oclip->PlayerP, ps_UziReload, PRI_BACK, oclip->x, UZI_RELOAD_YOFF);
|
|
SET(nclip->flags, PANF_WEAPON_SPRITE);
|
|
|
|
if (TEST(oclip->flags, PANF_XFLIP))
|
|
SET(nclip->flags, PANF_XFLIP);
|
|
|
|
// move Reload in oposite direction of clip
|
|
nclip->ang = NORM_ANGLE(oclip->ang + 1024);
|
|
nclip->vel = 900;
|
|
|
|
// move gun sprite from clip to reload
|
|
nclip->sibling = oclip->sibling;
|
|
}
|
|
|
|
void
|
|
pUziReload(PANEL_SPRITEp nclip)
|
|
{
|
|
PANEL_SPRITEp gun = nclip->sibling;
|
|
|
|
nclip->vel += 14 * synctics;
|
|
|
|
nclip->ox = nclip->x;
|
|
nclip->oy = nclip->y;
|
|
|
|
nclip->x += pspCosVel(nclip);
|
|
nclip->y -= pspSinVel(nclip);
|
|
|
|
gun->ox = gun->x;
|
|
gun->oy = gun->y;
|
|
|
|
gun->x -= pspCosVel(gun);
|
|
gun->y += pspSinVel(gun);
|
|
|
|
if (TEST(nclip->flags, PANF_XFLIP))
|
|
{
|
|
if (nclip->x < gun->x)
|
|
{
|
|
PlaySound(DIGI_REPLACECLIP, nclip->PlayerP,v3df_follow|v3df_dontpan|v3df_doppler);
|
|
|
|
nclip->ox = nclip->x = gun->x - UZI_CLIP_XOFF;
|
|
nclip->oy = nclip->y = gun->y + UZI_CLIP_YOFF;
|
|
nclip->vel = 680;
|
|
nclip->ang = NORM_ANGLE(nclip->ang - 128 - 64);
|
|
// go to retract phase
|
|
pSetState(nclip, &ps_UziReload[1]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (nclip->x > gun->x)
|
|
{
|
|
PlaySound(DIGI_REPLACECLIP, nclip->PlayerP,v3df_follow|v3df_dontpan|v3df_doppler);
|
|
|
|
nclip->ox = nclip->x = gun->x + UZI_CLIP_XOFF;
|
|
nclip->oy = nclip->y = gun->y + UZI_CLIP_YOFF;
|
|
nclip->vel = 680;
|
|
nclip->ang = NORM_ANGLE(nclip->ang + 128 + 64);
|
|
// go to retract phase
|
|
pSetState(nclip, &ps_UziReload[1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
pUziReloadRetract(PANEL_SPRITEp nclip)
|
|
{
|
|
PANEL_SPRITEp gun = nclip->sibling;
|
|
|
|
double xadj = pspCosVel(nclip);
|
|
double yadj = pspSinVel(nclip);
|
|
|
|
nclip->vel += 18 * synctics;
|
|
|
|
nclip->backupcoords();
|
|
|
|
nclip->x -= xadj;
|
|
nclip->y += yadj;
|
|
|
|
gun->backupcoords();
|
|
|
|
gun->x -= xadj;
|
|
gun->y += yadj;
|
|
|
|
if (gun->y > UZI_RELOAD_YOFF + tileHeight(gun->picndx))
|
|
{
|
|
pSetState(gun, ps_UziDoneReload);
|
|
pKillSprite(nclip);
|
|
}
|
|
}
|
|
|
|
void
|
|
pUziDoneReload(PANEL_SPRITEp psp)
|
|
{
|
|
PLAYERp pp = psp->PlayerP;
|
|
|
|
|
|
if (TEST(psp->flags, PANF_PRIMARY) && pp->WpnUziType == 3)
|
|
{
|
|
// if 2 uzi's and the first one has been reloaded
|
|
// kill the first one and make the second one the CurWeapon
|
|
// Set uzi's back to previous state
|
|
PANEL_SPRITEp New;
|
|
|
|
|
|
if (pp->WpnUziType > 2)
|
|
pp->WpnUziType -= 3;
|
|
|
|
New = InitWeaponUziSecondaryReload(psp);
|
|
pp->Wpn[WPN_UZI] = New;
|
|
pp->CurWpn = New;
|
|
pp->CurWpn->sibling = nullptr;
|
|
|
|
pKillSprite(psp);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// Reset everything
|
|
|
|
// Set uzi's back to previous state
|
|
if (pp->WpnUziType > 2)
|
|
pp->WpnUziType -= 3;
|
|
|
|
// reset uzi variable
|
|
pp->Wpn[WPN_UZI] = nullptr;
|
|
pp->CurWpn = nullptr;
|
|
|
|
// kill uzi eject sequence for good
|
|
pKillSprite(psp);
|
|
|
|
// give the uzi back
|
|
InitWeaponUzi(pp);
|
|
}
|
|
}
|
|
|
|
void
|
|
pUziClip(PANEL_SPRITEp oclip)
|
|
{
|
|
|
|
oclip->ox = oclip->x;
|
|
oclip->oy = oclip->y;
|
|
|
|
oclip->x += pspCosVel(oclip);
|
|
oclip->y -= pspSinVel(oclip);
|
|
|
|
if (oclip->y > UZI_RELOAD_YOFF)
|
|
{
|
|
PANEL_SPRITEp gun = oclip->sibling;
|
|
|
|
// as synctics gets bigger, oclip->x can be way off
|
|
// when clip goes off the screen - recalc oclip->x from scratch
|
|
// so it will end up the same for all synctic values
|
|
for (oclip->x = oclip->ox, oclip->y = oclip->oy; oclip->y < UZI_RELOAD_YOFF; )
|
|
{
|
|
oclip->x += oclip->vel * bcosf(oclip->ang, -22);
|
|
oclip->y -= oclip->vel * bsinf(oclip->ang, -22);
|
|
}
|
|
|
|
oclip->ox = oclip->x;
|
|
oclip->oy = oclip->y = UZI_RELOAD_YOFF;
|
|
|
|
gun->vel = 800;
|
|
gun->ang = NORM_ANGLE(oclip->ang + 1024);
|
|
|
|
pSpawnUziReload(oclip);
|
|
pKillSprite(oclip);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Uzi Basic Stuff
|
|
//
|
|
|
|
void
|
|
InitWeaponUzi(PLAYERp pp)
|
|
{
|
|
PANEL_SPRITEp psp = nullptr;
|
|
|
|
if (Prediction)
|
|
return;
|
|
|
|
pp->WeaponType = WPN_UZI;
|
|
|
|
// make sure you have the uzi, uzi ammo, and not retracting another
|
|
// weapon
|
|
if (!TEST(pp->WpnFlags, BIT(WPN_UZI)) ||
|
|
// pp->WpnAmmo[WPN_UZI] <= 0 ||
|
|
TEST(pp->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
// if players uzi is null
|
|
if (!pp->Wpn[WPN_UZI])
|
|
{
|
|
psp = pp->Wpn[WPN_UZI] = pSpawnSprite(pp, ps_PresentUzi, PRI_MID, 160 + UZI_XOFF, UZI_YOFF);
|
|
psp->y += tileHeight(psp->picndx);
|
|
psp->backupy();
|
|
}
|
|
|
|
// if Current weapon is uzi
|
|
if (pp->CurWpn == pp->Wpn[WPN_UZI])
|
|
{
|
|
// Retracting other uzi?
|
|
if (pp->CurWpn->sibling && pp->WpnUziType == 1)
|
|
{
|
|
RetractCurWpn(pp);
|
|
}
|
|
else
|
|
// Is player toggling between one and two uzi's?
|
|
if (pp->CurWpn->sibling && TEST(pp->Wpn[WPN_UZI]->flags, PANF_PRIMARY) && pp->WpnUziType == 0)
|
|
{
|
|
if (!TEST(pp->CurWpn->flags, PANF_RELOAD))
|
|
InitWeaponUzi2(pp->Wpn[WPN_UZI]);
|
|
}
|
|
|
|
// if actually picked an uzi up and don't currently have double uzi
|
|
if (TEST(pp->Flags, PF_PICKED_UP_AN_UZI) && !TEST(pp->Wpn[WPN_UZI]->flags, PANF_PRIMARY))
|
|
{
|
|
RESET(pp->Flags, PF_PICKED_UP_AN_UZI);
|
|
|
|
if (!TEST(pp->CurWpn->flags, PANF_RELOAD))
|
|
InitWeaponUzi2(pp->Wpn[WPN_UZI]);
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
RESET(pp->Flags, PF_PICKED_UP_AN_UZI);
|
|
}
|
|
|
|
PlayerUpdateWeapon(pp, WPN_UZI);
|
|
|
|
RetractCurWpn(pp);
|
|
|
|
// Set up the new weapon variables
|
|
pp->CurWpn = pp->Wpn[WPN_UZI];
|
|
SET(psp->flags, PANF_WEAPON_SPRITE);
|
|
psp->ActionState = &ps_FireUzi[1];
|
|
psp->RetractState = ps_RetractUzi;
|
|
psp->PresentState = ps_PresentUzi;
|
|
psp->RestState = ps_FireUzi;
|
|
pSetState(psp, psp->PresentState);
|
|
|
|
// power up
|
|
// NOTE: PRIMARY is ONLY set when there is a powerup
|
|
if (TEST(pp->Flags, PF_TWO_UZI))
|
|
{
|
|
InitWeaponUzi2(psp);
|
|
}
|
|
|
|
PlaySound(DIGI_UZI_UP, pp, v3df_follow);
|
|
|
|
psp->PlayerP->KeyPressBits |= SB_FIRE;
|
|
}
|
|
|
|
PANEL_SPRITEp
|
|
InitWeaponUzi2(PANEL_SPRITEp uzi_orig)
|
|
{
|
|
PANEL_SPRITEp New;
|
|
PLAYERp pp = uzi_orig->PlayerP;
|
|
|
|
|
|
// There is already a second uzi, or it's retracting
|
|
if (pp->WpnUziType == 1 || pp->CurWpn->sibling || TEST(pp->Flags, PF_WEAPON_RETRACT)) return nullptr;
|
|
|
|
// NOTE: PRIMARY is ONLY set when there is a powerup
|
|
SET(uzi_orig->flags, PANF_PRIMARY);
|
|
|
|
// Spawning a 2nd uzi, set weapon mode
|
|
pp->WpnUziType = 0; // 0 is up, 1 is retract
|
|
|
|
New = pSpawnSprite(pp, ps_PresentUzi2, PRI_MID, 160 - UZI_XOFF, UZI_YOFF);
|
|
New->y += tileHeight(New->picndx);
|
|
New->oy = New->y;
|
|
uzi_orig->sibling = New;
|
|
|
|
// Set up the New weapon variables
|
|
SET(New->flags, PANF_WEAPON_SPRITE);
|
|
New->ActionState = &ps_FireUzi2[1];
|
|
New->RetractState = ps_RetractUzi2;
|
|
New->PresentState = ps_PresentUzi2;
|
|
New->RestState = ps_FireUzi2;
|
|
pSetState(New, New->PresentState);
|
|
|
|
New->sibling = uzi_orig;
|
|
SET(New->flags, PANF_SECONDARY);
|
|
pUziOverlays(New, CHAMBER_REST);
|
|
|
|
return New;
|
|
}
|
|
|
|
PANEL_SPRITEp
|
|
InitWeaponUziSecondaryReload(PANEL_SPRITEp uzi_orig)
|
|
{
|
|
PANEL_SPRITEp New;
|
|
PLAYERp pp = uzi_orig->PlayerP;
|
|
|
|
New = pSpawnSprite(pp, ps_PresentUzi, PRI_MID, 160 - UZI_XOFF, UZI_YOFF);
|
|
New->y += tileHeight(New->picndx);
|
|
New->oy = New->y;
|
|
|
|
SET(New->flags, PANF_XFLIP);
|
|
|
|
// Set up the New weapon variables
|
|
SET(New->flags, PANF_WEAPON_SPRITE);
|
|
New->ActionState = ps_UziEject;
|
|
New->RetractState = ps_RetractUzi;
|
|
New->PresentState = ps_PresentUzi;
|
|
New->RestState = ps_UziEject;
|
|
// pSetState(New, New->PresentState);
|
|
pSetState(New, ps_PresentUziReload);
|
|
|
|
New->sibling = uzi_orig;
|
|
SET(New->flags, PANF_SECONDARY|PANF_RELOAD);
|
|
|
|
return New;
|
|
}
|
|
|
|
void
|
|
pUziPresent(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->PlayerP->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
psp->backupy();
|
|
psp->y -= 3 * synctics;
|
|
|
|
if (psp->PlayerP->WpnUziType)
|
|
{
|
|
psp->PlayerP->WpnReloadState = 2;
|
|
}
|
|
|
|
if (psp->y < UZI_YOFF)
|
|
{
|
|
RESET(psp->flags, PANF_RELOAD);
|
|
|
|
psp->oy = psp->y = UZI_YOFF;
|
|
psp->backupx();
|
|
psp->backupbobcoords();
|
|
pSetState(psp, psp->RestState);
|
|
}
|
|
}
|
|
|
|
// same as pUziPresent only faster for reload sequence
|
|
void
|
|
pUziPresentReload(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->PlayerP->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
psp->backupy();
|
|
psp->y -= 5 * synctics;
|
|
|
|
psp->PlayerP->WpnReloadState = 2;
|
|
|
|
if (psp->y < UZI_YOFF)
|
|
{
|
|
psp->oy = psp->y = UZI_YOFF;
|
|
psp->backupx();
|
|
psp->backupbobcoords();
|
|
pSetState(psp, psp->RestState);
|
|
}
|
|
}
|
|
|
|
void
|
|
pUziBobSetup(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->flags, PANF_BOB))
|
|
return;
|
|
|
|
psp->backupbobcoords();
|
|
|
|
psp->sin_amt = 12;
|
|
psp->sin_ndx = 0;
|
|
psp->bob_height_divider = 8;
|
|
}
|
|
|
|
void
|
|
pUziStartReload(PANEL_SPRITEp psp)
|
|
{
|
|
SetVisNorm();
|
|
|
|
psp->backupx();
|
|
|
|
// Set uzi's to reload state
|
|
if (psp->PlayerP->WpnUziType < 3)
|
|
psp->PlayerP->WpnUziType += 3;
|
|
|
|
// Uzi #1 reload - starting from a full up position
|
|
pSetState(psp, ps_UziEject);
|
|
|
|
SET(psp->flags, PANF_RELOAD);
|
|
|
|
if (TEST(psp->flags, PANF_PRIMARY) && psp->sibling)
|
|
{
|
|
// this is going to KILL Uzi #2 !!!
|
|
pSetState(psp->sibling, psp->sibling->RetractState);
|
|
}
|
|
}
|
|
|
|
void
|
|
pUziHide(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= 200 + tileHeight(picnum))
|
|
{
|
|
psp->oy = psp->y = 200 + tileHeight(picnum);
|
|
|
|
if (TEST(psp->flags, PANF_PRIMARY) && psp->PlayerP->WpnUziType != 1)
|
|
{
|
|
if (pWeaponUnHideKeys(psp, psp->PresentState))
|
|
pSetState(psp->sibling, psp->sibling->PresentState);
|
|
}
|
|
else if (!TEST(psp->flags, PANF_SECONDARY))
|
|
{
|
|
pWeaponUnHideKeys(psp, psp->PresentState);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
pUziRest(PANEL_SPRITEp psp)
|
|
{
|
|
bool shooting;
|
|
bool force = !!TEST(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
|
|
// If you have two uzi's, but one didn't come up, spawn it
|
|
if (TEST(psp->PlayerP->Flags, PF_TWO_UZI) && psp->sibling == nullptr)
|
|
{
|
|
InitWeaponUzi2(psp);
|
|
}
|
|
|
|
if (TEST(psp->flags, PANF_PRIMARY) && psp->sibling)
|
|
{
|
|
if (pWeaponHideKeys(psp, ps_UziHide))
|
|
{
|
|
if (psp->sibling != nullptr) // !JIM! Without this line, will ASSERT if reloading here
|
|
pSetState(psp->sibling, ps_Uzi2Hide);
|
|
return;
|
|
}
|
|
}
|
|
else if (!TEST(psp->flags, PANF_SECONDARY))
|
|
{
|
|
if (pWeaponHideKeys(psp, ps_UziHide))
|
|
return;
|
|
}
|
|
|
|
if (TEST(psp->flags, PANF_SECONDARY))
|
|
pUziOverlays(psp, CHAMBER_REST);
|
|
|
|
SetVisNorm();
|
|
|
|
shooting = (psp->PlayerP->input.actions & SB_FIRE) && (psp->PlayerP->KeyPressBits & SB_FIRE);
|
|
shooting |= force;
|
|
|
|
pUziBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP) || shooting);
|
|
|
|
if (shooting)
|
|
{
|
|
if (!WeaponOK(psp->PlayerP))
|
|
return;
|
|
|
|
RESET(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
pSetState(psp, psp->ActionState);
|
|
}
|
|
else
|
|
WeaponOK(psp->PlayerP);
|
|
}
|
|
|
|
void
|
|
pUziAction(PANEL_SPRITEp psp)
|
|
{
|
|
static int alternate = 0;
|
|
|
|
bool shooting = (psp->PlayerP->input.actions & SB_FIRE) && (psp->PlayerP->KeyPressBits & SB_FIRE);
|
|
|
|
if (shooting)
|
|
{
|
|
if (TEST(psp->flags, PANF_SECONDARY))
|
|
{
|
|
alternate++;
|
|
if (alternate > 6) alternate = 0;
|
|
if (alternate <= 3)
|
|
pUziOverlays(psp, CHAMBER_FIRE);
|
|
else
|
|
pUziOverlays(psp, CHAMBER_REST);
|
|
}
|
|
// Only Recoil if shooting
|
|
pUziBobSetup(psp);
|
|
UziRecoilYadj = (RANDOM_P2(1024)) >> 8; // global hack for
|
|
// weapon Bob
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP) || shooting);
|
|
UziRecoilYadj = 0; // reset my global hack
|
|
if (RANDOM_P2(1024) > 990)
|
|
DoPlayerChooseYell(psp->PlayerP);
|
|
}
|
|
else
|
|
{
|
|
if (TEST(psp->flags, PANF_SECONDARY))
|
|
pUziOverlays(psp, CHAMBER_REST);
|
|
pUziBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP) || shooting);
|
|
}
|
|
}
|
|
|
|
void
|
|
pUziFire(PANEL_SPRITEp psp)
|
|
{
|
|
PLAYERp pp = psp->PlayerP;
|
|
|
|
if (!WeaponOK(psp->PlayerP))
|
|
return;
|
|
|
|
if (TEST(psp->flags, PANF_SECONDARY) && pp->WpnUziType > 0) return;
|
|
|
|
InitUzi(psp->PlayerP);
|
|
SpawnUziShell(psp);
|
|
|
|
// If its the second Uzi, give the shell back only if it's a reload count to keep #'s even
|
|
if (TEST(psp->flags, PANF_SECONDARY))
|
|
{
|
|
if (TEST(pp->Flags, PF_TWO_UZI) && psp->sibling)
|
|
{
|
|
if ((pp->WpnAmmo[WPN_UZI] % 100) == 0)
|
|
pp->WpnAmmo[WPN_UZI]++;
|
|
}
|
|
else if ((pp->WpnAmmo[WPN_UZI] % 50) == 0)
|
|
pp->WpnAmmo[WPN_UZI]++;
|
|
}
|
|
else
|
|
{
|
|
SpawnVis(psp->PlayerP->Actor(), -1, -1, -1, -1, 32);
|
|
|
|
if (!WeaponOK(psp->PlayerP))
|
|
return;
|
|
|
|
// Reload if done with clip
|
|
if (TEST(pp->Flags, PF_TWO_UZI) && psp->sibling)
|
|
{
|
|
if ((pp->WpnAmmo[WPN_UZI] % 100) == 0)
|
|
pUziStartReload(psp);
|
|
}
|
|
else if ((pp->WpnAmmo[WPN_UZI] % 50) == 0)
|
|
{
|
|
// clip has run out
|
|
pUziStartReload(psp);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
pUziRetract(PANEL_SPRITEp psp)
|
|
{
|
|
// PANEL_SPRITEp sib = psp->sibling;
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= 200 + tileHeight(picnum))
|
|
{
|
|
// if in the reload phase and its retracting then get rid of uzi
|
|
// no matter whether it is PRIMARY/SECONDARY/neither.
|
|
if (TEST(psp->flags, PANF_RELOAD))
|
|
{
|
|
RESET(psp->PlayerP->Flags, PF_WEAPON_RETRACT);
|
|
psp->PlayerP->Wpn[WPN_UZI] = nullptr;
|
|
}
|
|
else
|
|
{
|
|
// NOT reloading here
|
|
if (TEST(psp->flags, PANF_PRIMARY))
|
|
{
|
|
// only reset when primary goes off the screen
|
|
RESET(psp->PlayerP->Flags, PF_WEAPON_RETRACT);
|
|
psp->PlayerP->Wpn[WPN_UZI] = nullptr;
|
|
}
|
|
else if (TEST(psp->flags, PANF_SECONDARY))
|
|
{
|
|
// primarily for beginning of reload sequence where seconary
|
|
// is taken off of the screen. Lets the primary know that
|
|
// he is alone.
|
|
if (psp->sibling && psp->sibling->sibling == psp)
|
|
psp->sibling->sibling = nullptr;
|
|
}
|
|
else
|
|
{
|
|
// only one uzi here is retracting
|
|
RESET(psp->PlayerP->Flags, PF_WEAPON_RETRACT);
|
|
psp->PlayerP->Wpn[WPN_UZI] = nullptr;
|
|
}
|
|
}
|
|
|
|
|
|
pKillSprite(psp);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UZI SHELL
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void pUziShell(PANEL_SPRITEp);
|
|
|
|
#define UZI_SHELL_RATE 10
|
|
|
|
PANEL_STATE ps_UziShell[] =
|
|
{
|
|
{ID_UziShell0, UZI_SHELL_RATE, pUziShell, &ps_UziShell[1], 0,0,0},
|
|
{ID_UziShell1, UZI_SHELL_RATE, pUziShell, &ps_UziShell[2], 0,0,0},
|
|
{ID_UziShell2, UZI_SHELL_RATE, pUziShell, &ps_UziShell[3], 0,0,0},
|
|
{ID_UziShell3, UZI_SHELL_RATE, pUziShell, &ps_UziShell[4], 0,0,0},
|
|
{ID_UziShell4, UZI_SHELL_RATE, pUziShell, &ps_UziShell[5], 0,0,0},
|
|
{ID_UziShell5, UZI_SHELL_RATE, pUziShell, &ps_UziShell[0], 0,0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_Uzi2Shell[] =
|
|
{
|
|
{ID_Uzi2Shell0, UZI_SHELL_RATE, pUziShell, &ps_Uzi2Shell[1], psf_Xflip, 0,0},
|
|
{ID_Uzi2Shell1, UZI_SHELL_RATE, pUziShell, &ps_Uzi2Shell[2], psf_Xflip, 0,0},
|
|
{ID_Uzi2Shell2, UZI_SHELL_RATE, pUziShell, &ps_Uzi2Shell[3], psf_Xflip, 0,0},
|
|
{ID_Uzi2Shell3, UZI_SHELL_RATE, pUziShell, &ps_Uzi2Shell[4], psf_Xflip, 0,0},
|
|
{ID_Uzi2Shell4, UZI_SHELL_RATE, pUziShell, &ps_Uzi2Shell[5], psf_Xflip, 0,0},
|
|
{ID_Uzi2Shell5, UZI_SHELL_RATE, pUziShell, &ps_Uzi2Shell[0], psf_Xflip, 0,0},
|
|
};
|
|
|
|
void
|
|
SpawnUziShell(PANEL_SPRITEp psp)
|
|
{
|
|
PLAYERp pp = psp->PlayerP;
|
|
|
|
if (psp->State && TEST(psp->State->flags, psf_Xflip))
|
|
{
|
|
// LEFT side
|
|
pp->UziShellLeftAlt = !pp->UziShellLeftAlt;
|
|
if (pp->UziShellLeftAlt)
|
|
SpawnShell(pp->Actor(),-3);
|
|
}
|
|
else
|
|
{
|
|
// RIGHT side
|
|
pp->UziShellRightAlt = !pp->UziShellRightAlt;
|
|
if (pp->UziShellRightAlt)
|
|
SpawnShell(pp->Actor(),-2);
|
|
}
|
|
}
|
|
|
|
void
|
|
pUziShell(PANEL_SPRITEp psp)
|
|
{
|
|
psp->backupx();
|
|
|
|
if (psp->State && TEST(psp->State->flags, psf_Xflip))
|
|
{
|
|
psp->x -= 3 * synctics;
|
|
}
|
|
else
|
|
{
|
|
psp->x += 3 * synctics;
|
|
}
|
|
|
|
// increment the ndx into the sin table and wrap at 1024
|
|
psp->sin_ndx = (psp->sin_ndx + (synctics << psp->sin_arc_speed) + 1024) & 1023;
|
|
|
|
// get height
|
|
psp->oy = psp->y = psp->yorig;
|
|
psp->y += psp->sin_amt * -bsinf(psp->sin_ndx, -14);
|
|
|
|
// if off of the screen kill them
|
|
if (psp->x > 330 || psp->x < -10)
|
|
{
|
|
pKillSprite(psp);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SHOTGUN SHELL
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void pShotgunShell(PANEL_SPRITEp);
|
|
|
|
#define SHOTGUN_SHELL_RATE 7
|
|
|
|
PANEL_STATE ps_ShotgunShell[] =
|
|
{
|
|
{ID_ShotgunShell0, SHOTGUN_SHELL_RATE, pShotgunShell, &ps_ShotgunShell[1], 0,0,0},
|
|
{ID_ShotgunShell1, SHOTGUN_SHELL_RATE, pShotgunShell, &ps_ShotgunShell[2], 0,0,0},
|
|
{ID_ShotgunShell2, SHOTGUN_SHELL_RATE, pShotgunShell, &ps_ShotgunShell[3], 0,0,0},
|
|
{ID_ShotgunShell3, SHOTGUN_SHELL_RATE, pShotgunShell, &ps_ShotgunShell[4], 0,0,0},
|
|
{ID_ShotgunShell4, SHOTGUN_SHELL_RATE, pShotgunShell, &ps_ShotgunShell[5], 0,0,0},
|
|
{ID_ShotgunShell5, SHOTGUN_SHELL_RATE, pShotgunShell, &ps_ShotgunShell[6], 0,0,0},
|
|
{ID_ShotgunShell6, SHOTGUN_SHELL_RATE, pShotgunShell, &ps_ShotgunShell[7], 0,0,0},
|
|
{ID_ShotgunShell6, SHOTGUN_SHELL_RATE, pShotgunShell, &ps_ShotgunShell[0], 0,0,0},
|
|
};
|
|
|
|
void
|
|
SpawnShotgunShell(PANEL_SPRITEp psp)
|
|
{
|
|
PLAYERp pp = psp->PlayerP;
|
|
SpawnShell(pp->Actor(),-4);
|
|
}
|
|
|
|
void
|
|
pShotgunShell(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->flags, PANF_JUMPING))
|
|
{
|
|
DoPanelJump(psp);
|
|
}
|
|
else if (TEST(psp->flags, PANF_FALLING))
|
|
{
|
|
DoPanelFall(psp);
|
|
}
|
|
|
|
psp->backupx();
|
|
|
|
psp->x += psp->xspeed * (1. / FRACUNIT);
|
|
|
|
if (psp->x > 320 || psp->x < 0 || psp->y > 200)
|
|
{
|
|
pKillSprite(psp);
|
|
return;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// SHOTGUN
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void pShotgunPresent(PANEL_SPRITEp psp);
|
|
void pShotgunRetract(PANEL_SPRITEp psp);
|
|
void pShotgunAction(PANEL_SPRITEp psp);
|
|
void pShotgunRest(PANEL_SPRITEp psp);
|
|
void pShotgunFire(PANEL_SPRITEp psp);
|
|
void pShotgunHide(PANEL_SPRITEp psp);
|
|
void pShotgunRestTest(PANEL_SPRITEp psp);
|
|
|
|
void pShotgunReloadDown(PANEL_SPRITEp psp);
|
|
void pShotgunReloadUp(PANEL_SPRITEp psp);
|
|
void pShotgunBobSetup(PANEL_SPRITEp psp);
|
|
void pShotgunRecoilUp(PANEL_SPRITEp psp);
|
|
void pShotgunRecoilDown(PANEL_SPRITEp psp);
|
|
|
|
bool pShotgunReloadTest(PANEL_SPRITEp psp);
|
|
|
|
extern PANEL_STATE ps_ShotgunReload[];
|
|
|
|
#define Shotgun_BEAT_RATE 24
|
|
#define Shotgun_ACTION_RATE 4
|
|
|
|
PANEL_STATE ps_PresentShotgun[] =
|
|
{
|
|
{ID_ShotgunPresent0, Shotgun_BEAT_RATE, pShotgunPresent, &ps_PresentShotgun[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_ShotgunRest[] =
|
|
{
|
|
{ID_ShotgunPresent0, Shotgun_BEAT_RATE, pShotgunRest, &ps_ShotgunRest[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_ShotgunHide[] =
|
|
{
|
|
{ID_ShotgunPresent0, Shotgun_BEAT_RATE, pShotgunHide, &ps_ShotgunHide[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_ShotgunRecoil[] =
|
|
{
|
|
// recoil
|
|
{ID_ShotgunReload0, Shotgun_ACTION_RATE, pShotgunRecoilDown, &ps_ShotgunRecoil[0], 0,0,0},
|
|
{ID_ShotgunReload0, Shotgun_ACTION_RATE, pShotgunRecoilUp, &ps_ShotgunRecoil[1], 0,0,0},
|
|
// reload
|
|
{ID_ShotgunReload0, Shotgun_ACTION_RATE*5, pNullAnimator, &ps_ShotgunRecoil[3], 0,0,0},
|
|
{ID_ShotgunReload1, Shotgun_ACTION_RATE, pNullAnimator, &ps_ShotgunRecoil[4], 0,0,0},
|
|
{ID_ShotgunReload2, Shotgun_ACTION_RATE*5, pNullAnimator, &ps_ShotgunRecoil[5], 0,0,0},
|
|
{ID_ShotgunPresent0,Shotgun_ACTION_RATE, pShotgunRestTest, &ps_ShotgunRecoil[6], 0,0,0},
|
|
{ID_ShotgunPresent0,Shotgun_ACTION_RATE/2, pShotgunAction, &ps_ShotgunRecoil[7], 0,0,0},
|
|
{ID_ShotgunPresent0,Shotgun_ACTION_RATE/2, pShotgunAction, &ps_ShotgunRecoil[8], 0,0,0},
|
|
// ready to fire again
|
|
{ID_ShotgunPresent0, 3, pNullAnimator, &ps_ShotgunRest[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_ShotgunRecoilAuto[] =
|
|
{
|
|
// recoil
|
|
{ID_ShotgunReload0, 1, pShotgunRecoilDown, &ps_ShotgunRecoilAuto[0], 0,0,0},
|
|
{ID_ShotgunReload0, 1, pShotgunRecoilUp, &ps_ShotgunRecoilAuto[1], 0,0,0},
|
|
// Reload
|
|
{ID_ShotgunReload0, 1, pNullAnimator, &ps_ShotgunRecoilAuto[3], 0,0,0},
|
|
{ID_ShotgunReload0, 1, pNullAnimator, &ps_ShotgunRecoilAuto[4], 0,0,0},
|
|
{ID_ShotgunReload0, 1, pNullAnimator, &ps_ShotgunRecoilAuto[5], 0,0,0},
|
|
|
|
{ID_ShotgunPresent0,1, pShotgunRestTest, &ps_ShotgunRecoilAuto[6], 0,0,0},
|
|
{ID_ShotgunPresent0,1, pShotgunAction, &ps_ShotgunRecoilAuto[7], 0,0,0},
|
|
{ID_ShotgunPresent0,1, pShotgunRest, &ps_ShotgunRest[0],psf_QuickCall, 0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_ShotgunFire[] =
|
|
{
|
|
{ID_ShotgunFire0, Shotgun_ACTION_RATE, pShotgunAction, &ps_ShotgunFire[1], psf_ShadeHalf, 0,0},
|
|
{ID_ShotgunFire1, Shotgun_ACTION_RATE, pShotgunFire, &ps_ShotgunFire[2], psf_ShadeNone|psf_QuickCall, 0,0},
|
|
{ID_ShotgunFire1, Shotgun_ACTION_RATE, pShotgunAction, &ps_ShotgunFire[3], psf_ShadeNone, 0,0},
|
|
{ID_ShotgunReload0, 0, SpawnShotgunShell, &ps_ShotgunFire[4], psf_QuickCall, 0,0},
|
|
{ID_ShotgunReload0, Shotgun_ACTION_RATE, pShotgunAction, &ps_ShotgunRecoil[0], 0,0,0}
|
|
};
|
|
|
|
|
|
#if 1
|
|
PANEL_STATE ps_ShotgunAutoFire[] =
|
|
{
|
|
{ID_ShotgunFire1, 2, pShotgunAction, &ps_ShotgunAutoFire[1], psf_ShadeHalf, 0,0},
|
|
{ID_ShotgunFire1, 2, pShotgunFire, &ps_ShotgunAutoFire[2], psf_ShadeNone, 0,0},
|
|
{ID_ShotgunFire1, 2, pShotgunAction, &ps_ShotgunAutoFire[3], psf_ShadeNone, 0,0},
|
|
{ID_ShotgunReload0, 0, SpawnShotgunShell, &ps_ShotgunAutoFire[4], psf_QuickCall, 0,0},
|
|
{ID_ShotgunReload0, 1, pShotgunAction, &ps_ShotgunRecoilAuto[0], 0,0,0}
|
|
};
|
|
#endif
|
|
|
|
#if 1
|
|
PANEL_STATE ps_ShotgunReload[] =
|
|
{
|
|
{ID_ShotgunPresent0, Shotgun_BEAT_RATE, pShotgunReloadDown, &ps_ShotgunReload[0], 0,0,0},
|
|
{ID_ShotgunPresent0, 30, pNullAnimator, &ps_ShotgunReload[2], 0,0,0},
|
|
// make reload sound here
|
|
{ID_ShotgunPresent0, Shotgun_BEAT_RATE, pNullAnimator, &ps_ShotgunReload[3], psf_QuickCall, 0,0},
|
|
{ID_ShotgunPresent0, 30, pNullAnimator, &ps_ShotgunReload[4], 0,0,0},
|
|
{ID_ShotgunPresent0, Shotgun_BEAT_RATE, pShotgunReloadUp, &ps_ShotgunReload[4], 0,0,0},
|
|
{ID_ShotgunPresent0, 3, pNullAnimator, &ps_ShotgunRest[0], 0,0,0}
|
|
};
|
|
#endif
|
|
|
|
PANEL_STATE ps_RetractShotgun[] =
|
|
{
|
|
{ID_ShotgunPresent0, Shotgun_BEAT_RATE, pShotgunRetract, &ps_RetractShotgun[0], 0,0,0}
|
|
};
|
|
|
|
#define SHOTGUN_YOFF 200
|
|
#define SHOTGUN_XOFF (160+42)
|
|
|
|
void
|
|
InitWeaponShotgun(PLAYERp pp)
|
|
{
|
|
PANEL_SPRITEp psp = nullptr;
|
|
|
|
if (Prediction)
|
|
return;
|
|
|
|
pp->WeaponType = WPN_SHOTGUN;
|
|
|
|
if (!TEST(pp->WpnFlags, BIT(pp->WeaponType)) ||
|
|
// pp->WpnAmmo[pp->WeaponType] <= 0 ||
|
|
TEST(pp->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
if (!pp->Wpn[pp->WeaponType])
|
|
{
|
|
psp = pp->Wpn[pp->WeaponType] = pSpawnSprite(pp, ps_PresentShotgun, PRI_MID, SHOTGUN_XOFF, SHOTGUN_YOFF);
|
|
psp->y += tileHeight(psp->picndx);
|
|
psp->backupy();
|
|
}
|
|
|
|
if (pp->CurWpn == pp->Wpn[pp->WeaponType])
|
|
{
|
|
return;
|
|
}
|
|
|
|
psp->WeaponType = pp->WeaponType;
|
|
PlayerUpdateWeapon(pp, pp->WeaponType);
|
|
|
|
pp->WpnUziType = 2; // Make uzi's go away!
|
|
RetractCurWpn(pp);
|
|
|
|
// Set up the new weapon variables
|
|
psp = pp->CurWpn = pp->Wpn[pp->WeaponType];
|
|
SET(psp->flags, PANF_WEAPON_SPRITE);
|
|
psp->ActionState = ps_ShotgunFire;
|
|
//psp->ActionState = ps_ShotgunAutoFire;
|
|
psp->RetractState = ps_RetractShotgun;
|
|
psp->PresentState = ps_PresentShotgun;
|
|
psp->RestState = ps_ShotgunRest;
|
|
pSetState(psp, psp->PresentState);
|
|
|
|
PlaySound(DIGI_SHOTGUN_UP, pp, v3df_follow);
|
|
|
|
psp->PlayerP->KeyPressBits |= SB_FIRE;
|
|
}
|
|
|
|
void
|
|
pShotgunSetRecoil(PANEL_SPRITEp psp)
|
|
{
|
|
psp->vel = 900;
|
|
psp->ang = NORM_ANGLE(-256);
|
|
}
|
|
|
|
void
|
|
pShotgunRecoilDown(PANEL_SPRITEp psp)
|
|
{
|
|
int targetvel = psp->PlayerP->WpnShotgunType == 1 ? 890 : 780;
|
|
|
|
psp->backupcoords();
|
|
|
|
psp->x += pspCosVel(psp);
|
|
psp->y -= pspSinVel(psp);
|
|
|
|
psp->vel -= 24 * synctics;
|
|
|
|
if (psp->vel < targetvel)
|
|
{
|
|
psp->vel = targetvel;
|
|
psp->ang = NORM_ANGLE(psp->ang + 1024);
|
|
|
|
pStatePlusOne(psp);
|
|
}
|
|
}
|
|
|
|
void
|
|
pShotgunRecoilUp(PANEL_SPRITEp psp)
|
|
{
|
|
psp->backupcoords();
|
|
|
|
psp->x += pspCosVel(psp);
|
|
psp->y -= pspSinVel(psp);
|
|
|
|
psp->vel += 15 * synctics;
|
|
|
|
if (psp->y < SHOTGUN_YOFF)
|
|
{
|
|
psp->oy = psp->y = SHOTGUN_YOFF;
|
|
psp->ox = psp->x = SHOTGUN_XOFF;
|
|
|
|
pShotgunSetRecoil(psp);
|
|
|
|
pStatePlusOne(psp);
|
|
RESET(psp->flags, PANF_BOB);
|
|
}
|
|
}
|
|
|
|
#if 1
|
|
void
|
|
pShotgunReloadDown(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= SHOTGUN_YOFF + (tileHeight(picnum)/2))
|
|
{
|
|
PlaySound(DIGI_ROCKET_UP, psp->PlayerP,v3df_follow|v3df_dontpan|v3df_doppler);
|
|
|
|
psp->oy = psp->y = SHOTGUN_YOFF + (tileHeight(picnum)/2);
|
|
|
|
pStatePlusOne(psp);
|
|
}
|
|
}
|
|
|
|
void
|
|
pShotgunReloadUp(PANEL_SPRITEp psp)
|
|
{
|
|
psp->ox = psp->x = SHOTGUN_XOFF;
|
|
psp->backupy();
|
|
psp->y -= 3 * synctics;
|
|
|
|
psp->PlayerP->WpnReloadState = 2;
|
|
|
|
if (psp->y < SHOTGUN_YOFF)
|
|
{
|
|
PlaySound(DIGI_SHOTGUN_UP, psp->PlayerP,v3df_follow|v3df_dontpan|v3df_doppler);
|
|
|
|
psp->oy = psp->y = SHOTGUN_YOFF;
|
|
|
|
pStatePlusOne(psp);
|
|
RESET(psp->flags, PANF_BOB);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void
|
|
pShotgunPresent(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->PlayerP->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
// Needed for recoil
|
|
psp->ang = NORM_ANGLE(256 + 128);
|
|
pShotgunSetRecoil(psp);
|
|
///
|
|
|
|
psp->backupy();
|
|
psp->y -= 3 * synctics;
|
|
|
|
if (psp->y < SHOTGUN_YOFF)
|
|
{
|
|
psp->oy = psp->y = SHOTGUN_YOFF;
|
|
psp->backupboby();
|
|
pSetState(psp, psp->RestState);
|
|
}
|
|
}
|
|
|
|
void
|
|
pShotgunBobSetup(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->flags, PANF_BOB))
|
|
return;
|
|
|
|
psp->backupbobcoords();
|
|
|
|
psp->sin_amt = 12;
|
|
psp->sin_ndx = 0;
|
|
psp->bob_height_divider = 8;
|
|
}
|
|
|
|
bool
|
|
pShotgunOverlays(PANEL_SPRITEp psp)
|
|
{
|
|
#define SHOTGUN_AUTO_XOFF 28
|
|
#define SHOTGUN_AUTO_YOFF -17
|
|
|
|
if (psp->over[SHOTGUN_AUTO_NUM].xoff == -1)
|
|
{
|
|
psp->over[SHOTGUN_AUTO_NUM].xoff = SHOTGUN_AUTO_XOFF;
|
|
psp->over[SHOTGUN_AUTO_NUM].yoff = SHOTGUN_AUTO_YOFF;
|
|
}
|
|
|
|
//if(psp->PlayerP->WpnShotgunAuto == 0 && psp->PlayerP->WpnRocketType == 1)
|
|
//psp->PlayerP->WpnShotgunType--;
|
|
|
|
switch (psp->PlayerP->WpnShotgunType)
|
|
{
|
|
case 0:
|
|
psp->over[SHOTGUN_AUTO_NUM].pic = -1;
|
|
SET(psp->over[SHOTGUN_AUTO_NUM].flags, psf_ShadeNone);
|
|
return false;
|
|
case 1:
|
|
psp->over[SHOTGUN_AUTO_NUM].pic = SHOTGUN_AUTO;
|
|
SET(psp->over[SHOTGUN_AUTO_NUM].flags, psf_ShadeNone);
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
PANEL_STATE ps_ShotgunFlash[] =
|
|
{
|
|
{SHOTGUN_AUTO, 30, nullptr, &ps_ShotgunFlash[1], 0,0,0},
|
|
{0, 30, nullptr, &ps_ShotgunFlash[2], 0,0,0},
|
|
{SHOTGUN_AUTO, 30, nullptr, &ps_ShotgunFlash[3], 0,0,0},
|
|
{0, 30, nullptr, &ps_ShotgunFlash[4], 0,0,0},
|
|
{SHOTGUN_AUTO, 30, nullptr, &ps_ShotgunFlash[5], 0,0,0},
|
|
{0, 30, nullptr, &ps_ShotgunFlash[6], 0,0,0},
|
|
{SHOTGUN_AUTO, 30, nullptr, &ps_ShotgunFlash[7], 0,0,0},
|
|
{0, 30, nullptr, &ps_ShotgunFlash[8], 0,0,0},
|
|
{SHOTGUN_AUTO, 30, nullptr, &ps_ShotgunFlash[9], 0,0,0},
|
|
{0, 0, nullptr, nullptr, 0,0,0}
|
|
};
|
|
|
|
|
|
void
|
|
pShotgunHide(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= SHOTGUN_YOFF + tileHeight(picnum))
|
|
{
|
|
psp->oy = psp->y = SHOTGUN_YOFF + tileHeight(picnum);
|
|
|
|
pWeaponUnHideKeys(psp, psp->PresentState);
|
|
}
|
|
}
|
|
|
|
#if 1
|
|
bool
|
|
pShotgunReloadTest(PANEL_SPRITEp psp)
|
|
{
|
|
//short ammo = psp->PlayerP->WpnAmmo[psp->PlayerP->WeaponType];
|
|
short ammo = psp->PlayerP->WpnAmmo[WPN_SHOTGUN];
|
|
|
|
// Reload if done with clip
|
|
if (ammo > 0 && (ammo % 4) == 0)
|
|
{
|
|
// clip has run out
|
|
RESET(psp->flags, PANF_REST_POS);
|
|
pSetState(psp, ps_ShotgunReload);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
void
|
|
pShotgunRest(PANEL_SPRITEp psp)
|
|
{
|
|
bool force = !!TEST(psp->flags, PANF_UNHIDE_SHOOT);
|
|
//short ammo = psp->PlayerP->WpnAmmo[psp->PlayerP->WeaponType];
|
|
int ammo = psp->PlayerP->WpnAmmo[WPN_SHOTGUN];
|
|
int lastammo = psp->PlayerP->WpnShotgunLastShell;
|
|
|
|
if (pWeaponHideKeys(psp, ps_ShotgunHide))
|
|
return;
|
|
|
|
if (psp->PlayerP->WpnShotgunType == 1 && ammo > 0 && ((ammo % 4) != 0) && lastammo != ammo && TEST(psp->flags, PANF_REST_POS))
|
|
{
|
|
force = true;
|
|
}
|
|
|
|
pShotgunOverlays(psp);
|
|
|
|
pShotgunBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
|
|
|
|
if ((psp->PlayerP->input.actions & SB_FIRE) || force)
|
|
{
|
|
if ((psp->PlayerP->KeyPressBits & SB_FIRE) || force)
|
|
{
|
|
RESET(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (!WeaponOK(psp->PlayerP))
|
|
return;
|
|
|
|
SET(psp->flags, PANF_REST_POS); // Used for reload checking in autofire
|
|
|
|
if (psp->PlayerP->WpnShotgunType == 0)
|
|
psp->PlayerP->WpnShotgunLastShell = ammo-1;
|
|
|
|
DoPlayerChooseYell(psp->PlayerP);
|
|
if (psp->PlayerP->WpnShotgunType==0)
|
|
pSetState(psp, ps_ShotgunFire);
|
|
else
|
|
pSetState(psp, ps_ShotgunAutoFire);
|
|
}
|
|
if (!WeaponOK(psp->PlayerP))
|
|
return;
|
|
}
|
|
else
|
|
WeaponOK(psp->PlayerP);
|
|
}
|
|
|
|
void
|
|
pShotgunRestTest(PANEL_SPRITEp psp)
|
|
{
|
|
bool force = !!TEST(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (psp->PlayerP->WpnShotgunType == 1 && !pShotgunReloadTest(psp))
|
|
force = true;
|
|
|
|
if (pShotgunReloadTest(psp))
|
|
return;
|
|
|
|
if (pWeaponHideKeys(psp, ps_ShotgunHide))
|
|
return;
|
|
|
|
pShotgunBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
|
|
if ((psp->PlayerP->input.actions & SB_FIRE) || force)
|
|
{
|
|
if ((psp->PlayerP->KeyPressBits & SB_FIRE) || force)
|
|
{
|
|
RESET(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (!WeaponOK(psp->PlayerP))
|
|
return;
|
|
|
|
DoPlayerChooseYell(psp->PlayerP);
|
|
return;
|
|
}
|
|
}
|
|
|
|
pSetState(psp, psp->RestState);
|
|
}
|
|
|
|
void
|
|
pShotgunAction(PANEL_SPRITEp psp)
|
|
{
|
|
pShotgunBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
}
|
|
|
|
|
|
void
|
|
pShotgunFire(PANEL_SPRITEp psp)
|
|
{
|
|
SpawnVis(psp->PlayerP->Actor(), -1, -1, -1, -1, 32);
|
|
InitShotgun(psp->PlayerP);
|
|
//SpawnShotgunShell(psp);
|
|
}
|
|
|
|
void
|
|
pShotgunRetract(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= SHOTGUN_YOFF + tileHeight(picnum) + 50)
|
|
{
|
|
RESET(psp->PlayerP->Flags, PF_WEAPON_RETRACT);
|
|
psp->PlayerP->Wpn[psp->WeaponType] = nullptr;
|
|
pKillSprite(psp);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// RAIL
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void pRailPresent(PANEL_SPRITEp psp);
|
|
void pRailRetract(PANEL_SPRITEp psp);
|
|
void pRailAction(PANEL_SPRITEp psp);
|
|
void pRailRest(PANEL_SPRITEp psp);
|
|
void pRailFire(PANEL_SPRITEp psp);
|
|
void pRailHide(PANEL_SPRITEp psp);
|
|
void pRailRestTest(PANEL_SPRITEp psp);
|
|
void pRailOkTest(PANEL_SPRITEp psp);
|
|
void pRailRecoilUp(PANEL_SPRITEp psp);
|
|
void pRailRecoilDown(PANEL_SPRITEp psp);
|
|
|
|
void pRailBobSetup(PANEL_SPRITEp psp);
|
|
|
|
bool pRailReloadTest(PANEL_SPRITEp psp);
|
|
|
|
#define Rail_BEAT_RATE 24
|
|
#define Rail_ACTION_RATE 3 // !JIM! Was 10
|
|
#define Rail_CHARGE_RATE 3
|
|
|
|
PANEL_STATE ps_PresentRail[] =
|
|
{
|
|
{ID_RailPresent0, Rail_BEAT_RATE, pRailPresent, &ps_PresentRail[0], psf_ShadeNone, 0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_RailRest[] =
|
|
{
|
|
{ID_RailRest0, Rail_BEAT_RATE, pRailRest, &ps_RailRest[1], psf_ShadeNone, 0,0},
|
|
{ID_RailRest1, Rail_BEAT_RATE, pRailRest, &ps_RailRest[2], psf_ShadeNone, 0,0},
|
|
{ID_RailRest2, Rail_BEAT_RATE, pRailRest, &ps_RailRest[3], psf_ShadeNone, 0,0},
|
|
{ID_RailRest3, Rail_BEAT_RATE, pRailRest, &ps_RailRest[4], psf_ShadeNone, 0,0},
|
|
{ID_RailRest4, Rail_BEAT_RATE, pRailRest, &ps_RailRest[0], psf_ShadeNone, 0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_RailHide[] =
|
|
{
|
|
{ID_RailPresent0, Rail_BEAT_RATE, pRailHide, &ps_RailHide[0], psf_ShadeNone, 0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_RailRecoil[] =
|
|
{
|
|
// recoil
|
|
{ID_RailPresent0, Rail_BEAT_RATE, pRailRecoilDown, &ps_RailRecoil[0], 0,0,0},
|
|
{ID_RailPresent0, Rail_BEAT_RATE, pRailRecoilUp, &ps_RailRecoil[1], 0,0,0},
|
|
// ready to fire again
|
|
{ID_RailPresent0, 3, pNullAnimator, &ps_RailRest[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_RailFire[] =
|
|
{
|
|
{ID_RailCharge0, Rail_CHARGE_RATE, pRailAction, &ps_RailFire[1], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge1, Rail_CHARGE_RATE, pRailAction, &ps_RailFire[2], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge2, Rail_CHARGE_RATE, pRailAction, &ps_RailFire[3], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge1, Rail_CHARGE_RATE, pRailAction, &ps_RailFire[4], psf_ShadeNone, 0,0},
|
|
|
|
{ID_RailFire0, Rail_ACTION_RATE, pRailAction, &ps_RailFire[5], psf_ShadeNone, 0,0},
|
|
{ID_RailFire1, Rail_ACTION_RATE, pRailAction, &ps_RailFire[6], psf_ShadeNone, 0,0},
|
|
{ID_RailFire1, Rail_ACTION_RATE, pRailAction, &ps_RailFire[7], psf_ShadeNone, 0,0},
|
|
{ID_RailFire1, 0, pRailFire, &ps_RailFire[8], psf_ShadeNone|psf_QuickCall, 0,0},
|
|
|
|
// recoil
|
|
{ID_RailPresent0, Rail_BEAT_RATE, pRailRecoilDown, &ps_RailFire[8], psf_ShadeNone, 0,0},
|
|
{ID_RailPresent0, Rail_BEAT_RATE, pRailRecoilUp, &ps_RailFire[9], psf_ShadeNone, 0,0},
|
|
// !JIM! I added these to introduce firing delay, that looks like a charge down.
|
|
{ID_RailCharge0, Rail_CHARGE_RATE, pRailOkTest, &ps_RailFire[11], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge1, Rail_CHARGE_RATE, pRailAction, &ps_RailFire[12], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge2, Rail_CHARGE_RATE, pRailOkTest, &ps_RailFire[13], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge1, Rail_CHARGE_RATE, pRailAction, &ps_RailFire[14], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge0, Rail_CHARGE_RATE+1, pRailAction, &ps_RailFire[15], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge1, Rail_CHARGE_RATE+1, pRailAction, &ps_RailFire[16], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge2, Rail_CHARGE_RATE+1, pRailAction, &ps_RailFire[17], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge1, Rail_CHARGE_RATE+2, pRailAction, &ps_RailFire[18], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge0, Rail_CHARGE_RATE+2, pRailAction, &ps_RailFire[19], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge1, Rail_CHARGE_RATE+2, pRailAction, &ps_RailFire[20], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge2, Rail_CHARGE_RATE+3, pRailAction, &ps_RailFire[21], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge1, Rail_CHARGE_RATE+3, pRailAction, &ps_RailFire[22], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge0, Rail_CHARGE_RATE+4, pRailAction, &ps_RailFire[23], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge1, Rail_CHARGE_RATE+4, pRailAction, &ps_RailFire[24], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge2, Rail_CHARGE_RATE+4, pRailAction, &ps_RailFire[25], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge0, Rail_CHARGE_RATE+5, pRailAction, &ps_RailFire[26], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge1, Rail_CHARGE_RATE+5, pRailAction, &ps_RailFire[27], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge2, Rail_CHARGE_RATE+5, pRailAction, &ps_RailFire[28], psf_ShadeNone, 0,0},
|
|
|
|
{ID_RailCharge0, Rail_ACTION_RATE, pRailRestTest, &ps_RailFire[29], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge1, Rail_ACTION_RATE, pRailRest, &ps_RailRest[0], psf_ShadeNone, 0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_RailFireEMP[] =
|
|
{
|
|
{ID_RailCharge0, Rail_CHARGE_RATE, pRailAction, &ps_RailFireEMP[1], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge1, Rail_CHARGE_RATE, pRailAction, &ps_RailFireEMP[2], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge2, Rail_CHARGE_RATE, pRailAction, &ps_RailFireEMP[3], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge1, Rail_CHARGE_RATE, pRailAction, &ps_RailFireEMP[4], psf_ShadeNone, 0,0},
|
|
|
|
{ID_RailFire0, Rail_ACTION_RATE, pRailAction, &ps_RailFireEMP[5], psf_ShadeNone, 0,0},
|
|
{ID_RailFire1, Rail_ACTION_RATE, pRailAction, &ps_RailFireEMP[6], psf_ShadeNone, 0,0},
|
|
{ID_RailFire1, Rail_ACTION_RATE, pRailAction, &ps_RailFireEMP[7], psf_ShadeNone, 0,0},
|
|
{ID_RailFire1, 0, pRailFire, &ps_RailFireEMP[8], psf_ShadeNone|psf_QuickCall, 0,0},
|
|
|
|
{ID_RailCharge0, Rail_ACTION_RATE, pRailRestTest, &ps_RailFireEMP[9], psf_ShadeNone, 0,0},
|
|
{ID_RailCharge1, Rail_ACTION_RATE, pRailRest, &ps_RailRest[0], psf_ShadeNone, 0,0},
|
|
};
|
|
|
|
|
|
PANEL_STATE ps_RetractRail[] =
|
|
{
|
|
{ID_RailPresent0, Rail_BEAT_RATE, pRailRetract, &ps_RetractRail[0], psf_ShadeNone, 0,0}
|
|
};
|
|
|
|
#define RAIL_YOFF 200
|
|
//#define RAIL_XOFF (160+60)
|
|
#define RAIL_XOFF (160+6)
|
|
|
|
void
|
|
InitWeaponRail(PLAYERp pp)
|
|
{
|
|
PANEL_SPRITEp psp = nullptr;
|
|
|
|
if (SW_SHAREWARE) return;
|
|
|
|
if (Prediction)
|
|
return;
|
|
|
|
pp->WeaponType = WPN_RAIL;
|
|
|
|
if (!TEST(pp->WpnFlags, BIT(pp->WeaponType)) ||
|
|
// pp->WpnAmmo[pp->WeaponType] <= 0 ||
|
|
TEST(pp->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
if (!pp->Wpn[pp->WeaponType])
|
|
{
|
|
psp = pp->Wpn[pp->WeaponType] = pSpawnSprite(pp, ps_PresentRail, PRI_MID, RAIL_XOFF, RAIL_YOFF);
|
|
psp->y += tileHeight(psp->picndx);
|
|
psp->backupy();
|
|
}
|
|
|
|
if (pp->CurWpn == pp->Wpn[pp->WeaponType])
|
|
{
|
|
return;
|
|
}
|
|
|
|
psp->WeaponType = pp->WeaponType;
|
|
PlayerUpdateWeapon(pp, pp->WeaponType);
|
|
|
|
pp->WpnUziType = 2; // Make uzi's go away!
|
|
RetractCurWpn(pp);
|
|
|
|
// Set up the new weapon variables
|
|
psp = pp->CurWpn = pp->Wpn[pp->WeaponType];
|
|
SET(psp->flags, PANF_WEAPON_SPRITE);
|
|
psp->ActionState = ps_RailFire;
|
|
psp->RetractState = ps_RetractRail;
|
|
psp->PresentState = ps_PresentRail;
|
|
psp->RestState = ps_RailRest;
|
|
pSetState(psp, psp->PresentState);
|
|
|
|
PlaySound(DIGI_RAIL_UP, pp, v3df_follow);
|
|
PlaySound(DIGI_RAILREADY, pp, v3df_follow | v3df_dontpan, CHAN_ITEM); // this one needs to be on a dedicated channel to allow switching it off without too many checks.
|
|
|
|
psp->PlayerP->KeyPressBits |= SB_FIRE;
|
|
}
|
|
|
|
void
|
|
pRailSetRecoil(PANEL_SPRITEp psp)
|
|
{
|
|
psp->vel = 900;
|
|
psp->ang = NORM_ANGLE(-256);
|
|
}
|
|
|
|
void
|
|
pRailRecoilDown(PANEL_SPRITEp psp)
|
|
{
|
|
psp->backupcoords();
|
|
|
|
psp->x += pspCosVel(psp);
|
|
psp->y -= pspSinVel(psp);
|
|
|
|
psp->vel -= 24 * synctics;
|
|
|
|
if (psp->vel < 800)
|
|
{
|
|
psp->vel = 800;
|
|
psp->ang = NORM_ANGLE(psp->ang + 1024);
|
|
|
|
pStatePlusOne(psp);
|
|
}
|
|
}
|
|
|
|
void
|
|
pRailRecoilUp(PANEL_SPRITEp psp)
|
|
{
|
|
psp->backupcoords();
|
|
|
|
psp->x += pspCosVel(psp);
|
|
psp->y -= pspSinVel(psp);
|
|
|
|
psp->vel += 15 * synctics;
|
|
|
|
if (psp->y < RAIL_YOFF)
|
|
{
|
|
psp->oy = psp->y = RAIL_YOFF;
|
|
psp->ox = psp->x = RAIL_XOFF;
|
|
|
|
pRailSetRecoil(psp);
|
|
|
|
pStatePlusOne(psp);
|
|
RESET(psp->flags, PANF_BOB);
|
|
}
|
|
}
|
|
|
|
void
|
|
pRailPresent(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->PlayerP->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
// Needed for recoil
|
|
psp->ang = NORM_ANGLE(256 + 128);
|
|
pRailSetRecoil(psp);
|
|
///
|
|
|
|
psp->backupy();
|
|
psp->y -= 3 * synctics;
|
|
|
|
if (psp->y < RAIL_YOFF)
|
|
{
|
|
psp->oy = psp->y = RAIL_YOFF;
|
|
psp->backupboby();
|
|
pSetState(psp, psp->RestState);
|
|
}
|
|
}
|
|
|
|
void
|
|
pRailBobSetup(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->flags, PANF_BOB))
|
|
return;
|
|
|
|
psp->backupbobcoords();
|
|
|
|
psp->sin_amt = 12;
|
|
psp->sin_ndx = 0;
|
|
psp->bob_height_divider = 8;
|
|
}
|
|
|
|
void
|
|
pRailHide(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= RAIL_YOFF + tileHeight(picnum))
|
|
{
|
|
psp->oy = psp->y = RAIL_YOFF + tileHeight(picnum);
|
|
|
|
pWeaponUnHideKeys(psp, psp->PresentState);
|
|
}
|
|
}
|
|
|
|
void
|
|
pRailOkTest(PANEL_SPRITEp psp)
|
|
{
|
|
if (pWeaponHideKeys(psp, ps_RailHide))
|
|
return;
|
|
|
|
WeaponOK(psp->PlayerP);
|
|
}
|
|
|
|
void
|
|
pRailRest(PANEL_SPRITEp psp)
|
|
{
|
|
bool force = !!TEST(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (SW_SHAREWARE) return;
|
|
|
|
if (pWeaponHideKeys(psp, ps_RailHide))
|
|
return;
|
|
|
|
pRailBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
|
|
if ((psp->PlayerP->input.actions & SB_FIRE) || force)
|
|
{
|
|
if ((psp->PlayerP->KeyPressBits & SB_FIRE) || force)
|
|
{
|
|
RESET(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (!WeaponOK(psp->PlayerP))
|
|
return;
|
|
|
|
//PlaySound(DIGI_RAILPWRUP, &psp->PlayerP->posx, &psp->PlayerP->posy, &psp->PlayerP->posz, v3df_follow);
|
|
|
|
DoPlayerChooseYell(psp->PlayerP);
|
|
if (psp->PlayerP->WpnRailType == 0)
|
|
pSetState(psp, ps_RailFire);
|
|
else
|
|
pSetState(psp, ps_RailFireEMP);
|
|
}
|
|
}
|
|
else
|
|
WeaponOK(psp->PlayerP);
|
|
}
|
|
|
|
void
|
|
pRailRestTest(PANEL_SPRITEp psp)
|
|
{
|
|
bool force = !!TEST(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (pWeaponHideKeys(psp, ps_RailHide))
|
|
return;
|
|
|
|
pRailBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
|
|
if ((psp->PlayerP->input.actions & SB_FIRE) || force)
|
|
{
|
|
if ((psp->PlayerP->KeyPressBits & SB_FIRE) || force)
|
|
{
|
|
RESET(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (!WeaponOK(psp->PlayerP))
|
|
return;
|
|
|
|
DoPlayerChooseYell(psp->PlayerP);
|
|
return;
|
|
}
|
|
}
|
|
|
|
pSetState(psp, psp->RestState);
|
|
}
|
|
|
|
void
|
|
pRailAction(PANEL_SPRITEp psp)
|
|
{
|
|
pRailBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
}
|
|
|
|
|
|
void
|
|
pRailFire(PANEL_SPRITEp psp)
|
|
{
|
|
SpawnVis(psp->PlayerP->Actor(), -1, -1, -1, -1, 16);
|
|
InitRail(psp->PlayerP);
|
|
}
|
|
|
|
void
|
|
pRailRetract(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= RAIL_YOFF + tileHeight(picnum) + 50)
|
|
{
|
|
RESET(psp->PlayerP->Flags, PF_WEAPON_RETRACT);
|
|
psp->PlayerP->Wpn[psp->WeaponType] = nullptr;
|
|
DeleteNoSoundOwner(psp->PlayerP->Actor());
|
|
pKillSprite(psp);
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// HOTHEAD
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void pHotheadPresent(PANEL_SPRITEp psp);
|
|
void pHotheadRetract(PANEL_SPRITEp psp);
|
|
void pHotheadAction(PANEL_SPRITEp psp);
|
|
void pHotheadActionCenter(PANEL_SPRITEp psp);
|
|
void pHotheadRest(PANEL_SPRITEp psp);
|
|
void pHotheadRestCenter(PANEL_SPRITEp psp);
|
|
void pHotheadAttack(PANEL_SPRITEp psp);
|
|
void pHotheadRing(PANEL_SPRITEp psp);
|
|
void pHotheadNapalm(PANEL_SPRITEp psp);
|
|
void pHotheadHide(PANEL_SPRITEp psp);
|
|
void pHotheadRestTest(PANEL_SPRITEp psp);
|
|
|
|
extern PANEL_STATE ps_HotheadAttack[];
|
|
extern PANEL_STATE ps_ReloadHothead[];
|
|
extern PANEL_STATE ps_HotheadTurn[];
|
|
|
|
|
|
#define Hothead_BEAT_RATE 24
|
|
#define Hothead_ACTION_RATE_PRE 2 // !JIM! Was 1
|
|
#define Hothead_ACTION_RATE_POST 7
|
|
|
|
PANEL_STATE ps_PresentHothead[] =
|
|
{
|
|
{ID_HotheadPresent0, Hothead_BEAT_RATE, pHotheadPresent, &ps_PresentHothead[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_HotheadHide[] =
|
|
{
|
|
{ID_HotheadRest0, Hothead_BEAT_RATE, pHotheadHide, &ps_HotheadHide[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_RetractHothead[] =
|
|
{
|
|
{ID_HotheadPresent0, Hothead_BEAT_RATE, pHotheadRetract, &ps_RetractHothead[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_HotheadRest[] =
|
|
{
|
|
{ID_HotheadRest0, Hothead_BEAT_RATE, pHotheadRest, &ps_HotheadRest[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_HotheadRestRing[] =
|
|
{
|
|
{ID_HotheadRest0, Hothead_BEAT_RATE, pHotheadRest, &ps_HotheadRest[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_HotheadRestNapalm[] =
|
|
{
|
|
{ID_HotheadRest0, Hothead_BEAT_RATE, pHotheadRest, &ps_HotheadRest[0], 0,0,0}
|
|
};
|
|
// Turns - attacks
|
|
|
|
PANEL_STATE ps_HotheadAttack[] =
|
|
{
|
|
{ID_HotheadAttack0, Hothead_ACTION_RATE_PRE, pHotheadAction, &ps_HotheadAttack[1], psf_ShadeHalf, 0,0},
|
|
{ID_HotheadAttack0, 3, pHotheadAction, &ps_HotheadAttack[2], psf_ShadeHalf, 0,0},
|
|
{ID_HotheadAttack0, 0, pHotheadAttack, &ps_HotheadAttack[3], psf_QuickCall, 0,0},
|
|
{ID_HotheadAttack0, 3, pHotheadAction, &ps_HotheadAttack[4], psf_ShadeHalf, 0,0},
|
|
{ID_HotheadAttack0, 0, pHotheadRestTest, &ps_HotheadAttack[4], psf_QuickCall, 0,0},
|
|
{ID_HotheadAttack0, 0, pHotheadAction, &ps_HotheadAttack[0], psf_ShadeHalf, 0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_HotheadRing[] =
|
|
{
|
|
{ID_HotheadAttack0, Hothead_ACTION_RATE_PRE, pHotheadAction, &ps_HotheadRing[1], psf_ShadeHalf, 0,0},
|
|
{ID_HotheadAttack0, 10, pHotheadAction, &ps_HotheadRing[2], psf_ShadeHalf, 0,0},
|
|
{ID_HotheadAttack0, 0, pHotheadAttack, &ps_HotheadRing[3], psf_QuickCall, 0,0},
|
|
{ID_HotheadAttack0, 40, pHotheadAction, &ps_HotheadRing[4], psf_ShadeHalf, 0,0},
|
|
{ID_HotheadAttack0, 0, pHotheadRestTest, &ps_HotheadRing[4], psf_QuickCall, 0,0},
|
|
{ID_HotheadAttack0, 3, pHotheadAction, &ps_HotheadRing[0], psf_ShadeHalf, 0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_HotheadNapalm[] =
|
|
{
|
|
{ID_HotheadAttack0, Hothead_ACTION_RATE_PRE, pHotheadAction, &ps_HotheadNapalm[1], psf_ShadeHalf, 0,0},
|
|
{ID_HotheadAttack0, 3, pHotheadAction, &ps_HotheadNapalm[2], psf_ShadeHalf, 0,0},
|
|
{ID_HotheadAttack0, 0, pHotheadAttack, &ps_HotheadNapalm[3], psf_QuickCall, 0,0},
|
|
{ID_HotheadAttack0, 50, pHotheadAction, &ps_HotheadNapalm[4], psf_ShadeHalf, 0,0},
|
|
{ID_HotheadAttack0, 0, pHotheadRestTest, &ps_HotheadNapalm[4], psf_QuickCall, 0,0},
|
|
{ID_HotheadAttack0, 3, pHotheadAction, &ps_HotheadNapalm[0], psf_ShadeHalf, 0,0}
|
|
};
|
|
|
|
// Turns - can do three different turns
|
|
|
|
PANEL_STATE ps_HotheadTurn[] =
|
|
{
|
|
{ID_HotheadTurn0, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurn[1], 0,0,0},
|
|
{ID_HotheadTurn1, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurn[2], 0,0,0},
|
|
{ID_HotheadTurn2, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurn[3], 0,0,0},
|
|
{ID_HotheadTurn3, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurn[4], 0,0,0},
|
|
{ID_HotheadChomp0, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurn[5], 0,0,0},
|
|
{ID_HotheadTurn3, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurn[6], 0,0,0},
|
|
{ID_HotheadChomp0, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurn[7], 0,0,0},
|
|
{ID_HotheadTurn3, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurn[8], 0,0,0},
|
|
{ID_HotheadTurn2, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurn[9], 0,0,0},
|
|
{ID_HotheadTurn1, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurn[10], 0,0,0},
|
|
{ID_HotheadTurn0, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurn[11], 0,0,0},
|
|
{ID_HotheadTurn0, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadRest[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_HotheadTurnRing[] =
|
|
{
|
|
{ID_HotheadTurn0, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurnRing[1], 0,0,0},
|
|
{ID_HotheadTurn1, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurnRing[2], 0,0,0},
|
|
{ID_HotheadTurn2, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurnRing[3], 0,0,0},
|
|
{ID_HotheadTurn3, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurnRing[4], 0,0,0},
|
|
{ID_HotheadChomp0, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurnRing[5], 0,0,0},
|
|
{ID_HotheadTurn3, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurnRing[6], 0,0,0},
|
|
{ID_HotheadTurn2, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurnRing[7], 0,0,0},
|
|
{ID_HotheadTurn1, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurnRing[8], 0,0,0},
|
|
{ID_HotheadTurn0, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurnRing[9], 0,0,0},
|
|
{ID_HotheadTurn0, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadRestRing[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_HotheadTurnNapalm[] =
|
|
{
|
|
{ID_HotheadTurn0, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurnNapalm[1], 0,0,0},
|
|
{ID_HotheadTurn1, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurnNapalm[2], 0,0,0},
|
|
{ID_HotheadTurn2, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurnNapalm[3], 0,0,0},
|
|
{ID_HotheadTurn3, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurnNapalm[4], 0,0,0},
|
|
{ID_HotheadTurn3, Hothead_BEAT_RATE*2, pNullAnimator, &ps_HotheadTurnNapalm[5], 0,0,0},
|
|
{ID_HotheadTurn2, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurnNapalm[6], 0,0,0},
|
|
{ID_HotheadTurn1, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurnNapalm[7], 0,0,0},
|
|
{ID_HotheadTurn0, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadTurnNapalm[8], 0,0,0},
|
|
{ID_HotheadTurn0, Hothead_BEAT_RATE, pNullAnimator, &ps_HotheadRestNapalm[0], 0,0,0}
|
|
};
|
|
|
|
|
|
PANEL_STATEp HotheadAttackStates[] =
|
|
{
|
|
ps_HotheadAttack,
|
|
ps_HotheadRing,
|
|
ps_HotheadNapalm
|
|
};
|
|
|
|
PANEL_STATEp HotheadRestStates[] =
|
|
{
|
|
ps_HotheadRest,
|
|
ps_HotheadRestRing,
|
|
ps_HotheadRestNapalm
|
|
};
|
|
|
|
PANEL_STATEp HotheadTurnStates[] =
|
|
{
|
|
ps_HotheadTurn,
|
|
ps_HotheadTurnRing,
|
|
ps_HotheadTurnNapalm
|
|
};
|
|
|
|
#define FIREBALL_MODE 0
|
|
#define RING_MODE 1
|
|
#define NAPALM_MODE 2
|
|
void
|
|
pHotHeadOverlays(PANEL_SPRITEp psp, short mode)
|
|
{
|
|
#define HOTHEAD_FINGER_XOFF 0
|
|
#define HOTHEAD_FINGER_YOFF 0
|
|
|
|
switch (mode)
|
|
{
|
|
case 0: // Great balls o' fire
|
|
psp->over[0].pic = HEAD_MODE1;
|
|
break;
|
|
case 1: // Ring of fire
|
|
psp->over[0].pic = HEAD_MODE2;
|
|
break;
|
|
case 2: // I love the smell of napalm in the morning
|
|
psp->over[0].pic = HEAD_MODE3;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#define HOTHEAD_BOB_X_AMT 10
|
|
|
|
#define HOTHEAD_XOFF (200 + HOTHEAD_BOB_X_AMT + 6)
|
|
#define HOTHEAD_YOFF 200
|
|
|
|
void
|
|
InitWeaponHothead(PLAYERp pp)
|
|
{
|
|
PANEL_SPRITEp psp = nullptr;
|
|
|
|
if (SW_SHAREWARE) return;
|
|
|
|
if (Prediction)
|
|
return;
|
|
|
|
if (!TEST(pp->WpnFlags, BIT(WPN_HOTHEAD)) ||
|
|
// pp->WpnAmmo[WPN_HOTHEAD] <= 0 ||
|
|
TEST(pp->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
if (!pp->Wpn[WPN_HOTHEAD])
|
|
{
|
|
psp = pp->Wpn[WPN_HOTHEAD] = pSpawnSprite(pp, ps_PresentHothead, PRI_MID, HOTHEAD_XOFF, HOTHEAD_YOFF);
|
|
psp->y += tileHeight(psp->picndx);
|
|
psp->backupy();
|
|
}
|
|
|
|
if (pp->CurWpn == pp->Wpn[WPN_HOTHEAD])
|
|
{
|
|
return;
|
|
}
|
|
|
|
psp->WeaponType = WPN_HOTHEAD;
|
|
PlayerUpdateWeapon(pp, WPN_HOTHEAD);
|
|
|
|
pp->WpnUziType = 2; // Make uzi's go away!
|
|
RetractCurWpn(pp);
|
|
|
|
// Set up the new weapon variables
|
|
psp = pp->CurWpn = pp->Wpn[WPN_HOTHEAD];
|
|
SET(psp->flags, PANF_WEAPON_SPRITE);
|
|
psp->ActionState = ps_HotheadAttack;
|
|
psp->PresentState = ps_PresentHothead;
|
|
psp->RestState = HotheadRestStates[psp->PlayerP->WpnFlameType];
|
|
psp->RetractState = ps_RetractHothead;
|
|
pSetState(psp, psp->PresentState);
|
|
psp->ang = 768;
|
|
psp->vel = 512;
|
|
|
|
psp->PlayerP->KeyPressBits |= SB_FIRE;
|
|
pHotHeadOverlays(psp, pp->WpnFlameType);
|
|
psp->over[0].xoff = HOTHEAD_FINGER_XOFF;
|
|
psp->over[0].yoff = HOTHEAD_FINGER_YOFF;
|
|
|
|
PlaySound(DIGI_GRDALERT, pp, v3df_follow|v3df_dontpan);
|
|
}
|
|
|
|
void
|
|
pHotheadRestTest(PANEL_SPRITEp psp)
|
|
{
|
|
if (psp->PlayerP->input.actions & SB_FIRE)
|
|
{
|
|
if (psp->PlayerP->KeyPressBits & SB_FIRE)
|
|
{
|
|
//if (!TEST(psp->PlayerP->Flags,PF_DIVING))
|
|
{
|
|
if (!WeaponOK(psp->PlayerP))
|
|
return;
|
|
|
|
if (psp->PlayerP->WpnAmmo[WPN_HOTHEAD] < 10)
|
|
{
|
|
psp->PlayerP->WpnFlameType = 0;
|
|
WeaponOK(psp->PlayerP);
|
|
}
|
|
|
|
DoPlayerChooseYell(psp->PlayerP);
|
|
}
|
|
|
|
pStatePlusOne(psp);
|
|
return;
|
|
}
|
|
}
|
|
|
|
pSetState(psp, HotheadRestStates[psp->PlayerP->WpnFlameType]);
|
|
psp->over[0].xoff = HOTHEAD_FINGER_XOFF;
|
|
psp->over[0].yoff = HOTHEAD_FINGER_YOFF;
|
|
}
|
|
|
|
void
|
|
pHotheadPresent(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->PlayerP->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
psp->backupy();
|
|
psp->y -= 3 * synctics;
|
|
|
|
if (psp->y < HOTHEAD_YOFF)
|
|
{
|
|
psp->oy = psp->y = HOTHEAD_YOFF;
|
|
psp->backupboby();
|
|
pSetState(psp, psp->RestState);
|
|
//pSetState(psp, HotheadTurnStates[psp->PlayerP->WpnFlameType]);
|
|
}
|
|
}
|
|
|
|
void
|
|
pHotheadBobSetup(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->flags, PANF_BOB))
|
|
return;
|
|
|
|
psp->backupbobcoords();
|
|
|
|
psp->sin_amt = HOTHEAD_BOB_X_AMT;
|
|
psp->sin_ndx = 0;
|
|
psp->bob_height_divider = 4;
|
|
}
|
|
|
|
void
|
|
pHotheadHide(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupx();
|
|
psp->x += 3 * synctics;
|
|
|
|
if (psp->x >= HOTHEAD_XOFF + tileWidth(picnum) || psp->y >= HOTHEAD_YOFF + tileHeight(picnum))
|
|
{
|
|
psp->ox = psp->x = HOTHEAD_XOFF;
|
|
psp->oy = psp->y = HOTHEAD_YOFF + tileHeight(picnum);
|
|
|
|
pWeaponUnHideKeys(psp, psp->PresentState);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
pHotheadRest(PANEL_SPRITEp psp)
|
|
{
|
|
bool force = !!TEST(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (SW_SHAREWARE) return;
|
|
|
|
if (pWeaponHideKeys(psp, ps_HotheadHide))
|
|
return;
|
|
|
|
if (HotheadRestStates[psp->PlayerP->WpnFlameType] != psp->RestState)
|
|
{
|
|
psp->RestState = HotheadRestStates[psp->PlayerP->WpnFlameType];
|
|
pSetState(psp, HotheadRestStates[psp->PlayerP->WpnFlameType]);
|
|
}
|
|
|
|
// in rest position - only bob when in rest pos
|
|
pHotheadBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
|
|
if ((psp->PlayerP->input.actions & SB_FIRE) || force)
|
|
{
|
|
if ((psp->PlayerP->KeyPressBits & SB_FIRE) || force)
|
|
{
|
|
RESET(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
//if (TEST(psp->PlayerP->Flags,PF_DIVING))
|
|
// return;
|
|
|
|
if (!WeaponOK(psp->PlayerP))
|
|
return;
|
|
|
|
if (psp->PlayerP->WpnAmmo[WPN_HOTHEAD] < 10)
|
|
{
|
|
psp->PlayerP->WpnFlameType = 0;
|
|
WeaponOK(psp->PlayerP);
|
|
}
|
|
|
|
DoPlayerChooseYell(psp->PlayerP);
|
|
//pSetState(psp, psp->ActionState);
|
|
pSetState(psp, HotheadAttackStates[psp->PlayerP->WpnFlameType]);
|
|
psp->over[0].xoff = HOTHEAD_FINGER_XOFF-1;
|
|
psp->over[0].yoff = HOTHEAD_FINGER_YOFF-10;
|
|
}
|
|
}
|
|
else
|
|
WeaponOK(psp->PlayerP);
|
|
}
|
|
|
|
void
|
|
pHotheadAction(PANEL_SPRITEp psp)
|
|
{
|
|
bool shooting = (psp->PlayerP->input.actions & SB_FIRE) && (psp->PlayerP->KeyPressBits & SB_FIRE);
|
|
|
|
if (shooting)
|
|
{
|
|
pUziBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP) || shooting);
|
|
}
|
|
}
|
|
|
|
void
|
|
pHotheadAttack(PANEL_SPRITEp psp)
|
|
{
|
|
switch (psp->PlayerP->WpnFlameType)
|
|
{
|
|
case 0:
|
|
SpawnVis(psp->PlayerP->Actor(), -1, -1, -1, -1, 32);
|
|
InitFireball(psp->PlayerP);
|
|
break;
|
|
case 1:
|
|
SpawnVis(psp->PlayerP->Actor(), -1, -1, -1, -1, 20);
|
|
InitSpellRing(psp->PlayerP);
|
|
break;
|
|
case 2:
|
|
SpawnVis(psp->PlayerP->Actor(), -1, -1, -1, -1, 16);
|
|
InitSpellNapalm(psp->PlayerP);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
pHotheadRetract(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= HOTHEAD_YOFF + tileHeight(picnum))
|
|
{
|
|
RESET(psp->PlayerP->Flags, PF_WEAPON_RETRACT);
|
|
psp->PlayerP->Wpn[WPN_HOTHEAD] = nullptr;
|
|
pKillSprite(psp);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// HOTHEAD ON_FIRE
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void pOnFire(PANEL_SPRITEp);
|
|
|
|
#define ON_FIRE_RATE 10
|
|
|
|
PANEL_STATE ps_OnFire[] =
|
|
{
|
|
{ID_OnFire0, ON_FIRE_RATE, pOnFire, &ps_OnFire[1], 0,0,0},
|
|
{ID_OnFire1, ON_FIRE_RATE, pOnFire, &ps_OnFire[2], 0,0,0},
|
|
{ID_OnFire2, ON_FIRE_RATE, pOnFire, &ps_OnFire[3], 0,0,0},
|
|
{ID_OnFire3, ON_FIRE_RATE, pOnFire, &ps_OnFire[4], 0,0,0},
|
|
{ID_OnFire4, ON_FIRE_RATE, pOnFire, &ps_OnFire[5], 0,0,0},
|
|
{ID_OnFire5, ON_FIRE_RATE, pOnFire, &ps_OnFire[6], 0,0,0},
|
|
{ID_OnFire6, ON_FIRE_RATE, pOnFire, &ps_OnFire[7], 0,0,0},
|
|
{ID_OnFire7, ON_FIRE_RATE, pOnFire, &ps_OnFire[8], 0,0,0},
|
|
{ID_OnFire8, ON_FIRE_RATE, pOnFire, &ps_OnFire[9], 0,0,0},
|
|
{ID_OnFire9, ON_FIRE_RATE, pOnFire, &ps_OnFire[10], 0,0,0},
|
|
{ID_OnFire10, ON_FIRE_RATE, pOnFire, &ps_OnFire[11], 0,0,0},
|
|
{ID_OnFire11, ON_FIRE_RATE, pOnFire, &ps_OnFire[12], 0,0,0},
|
|
{ID_OnFire12, ON_FIRE_RATE, pOnFire, &ps_OnFire[0], 0,0,0},
|
|
};
|
|
|
|
#define ON_FIRE_Y_TOP 190
|
|
#define ON_FIRE_Y_BOT 230
|
|
|
|
void
|
|
SpawnOnFire(PLAYERp pp)
|
|
{
|
|
PANEL_SPRITEp fire;
|
|
short x = 50;
|
|
|
|
while (x < 320)
|
|
{
|
|
fire = pSpawnSprite(pp, &ps_OnFire[RANDOM_P2(8<<8)>>8], PRI_FRONT, x, ON_FIRE_Y_BOT);
|
|
SET(fire->flags, PANF_WEAPON_SPRITE);
|
|
x += tileWidth(fire->picndx);
|
|
}
|
|
}
|
|
|
|
void
|
|
pOnFire(PANEL_SPRITEp psp)
|
|
{
|
|
auto actor = psp->PlayerP->Actor();
|
|
auto u = actor->u();
|
|
// Kill immediately - in case of death/water
|
|
if (u->flameActor == nullptr && u->Flags2 & SPR2_FLAMEDIE)
|
|
{
|
|
pKillSprite(psp);
|
|
return;
|
|
}
|
|
|
|
psp->backupy();
|
|
|
|
if (u->flameActor == nullptr)
|
|
{
|
|
// take flames down and kill them
|
|
psp->y += 1;
|
|
if (psp->y > ON_FIRE_Y_BOT)
|
|
{
|
|
pKillSprite(psp);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// bring flames up
|
|
psp->y -= 2;
|
|
if (psp->y < ON_FIRE_Y_TOP)
|
|
psp->oy = psp->y = ON_FIRE_Y_TOP;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// MICRO
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void pMicroPresent(PANEL_SPRITEp psp);
|
|
void pMicroRetract(PANEL_SPRITEp psp);
|
|
void pMicroAction(PANEL_SPRITEp psp);
|
|
void pMicroRest(PANEL_SPRITEp psp);
|
|
void pMicroFire(PANEL_SPRITEp psp);
|
|
void pMicroHide(PANEL_SPRITEp psp);
|
|
void pMicroUnHide(PANEL_SPRITEp psp);
|
|
void pMicroRecoilDown(PANEL_SPRITEp psp);
|
|
void pMicroRecoilUp(PANEL_SPRITEp psp);
|
|
void pMicroBobSetup(PANEL_SPRITEp psp);
|
|
void pMicroReloadUp(PANEL_SPRITEp psp);
|
|
void pMicroReloadDown(PANEL_SPRITEp psp);
|
|
void pMicroStandBy(PANEL_SPRITEp psp);
|
|
void pMicroCount(PANEL_SPRITEp psp);
|
|
void pMicroReady(PANEL_SPRITEp psp);
|
|
void pNukeAction(PANEL_SPRITEp psp);
|
|
|
|
extern PANEL_STATE ps_MicroReload[];
|
|
|
|
#define Micro_REST_RATE 24
|
|
#define Micro_ACTION_RATE 6 // !JIM! was 9
|
|
|
|
PANEL_STATE ps_PresentMicro[] =
|
|
{
|
|
{ID_MicroPresent0, Micro_REST_RATE, pMicroPresent, &ps_PresentMicro[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_MicroRest[] =
|
|
{
|
|
{ID_MicroPresent0, Micro_REST_RATE, pMicroRest, &ps_MicroRest[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_MicroHide[] =
|
|
{
|
|
{ID_MicroPresent0, Micro_REST_RATE, pMicroHide, &ps_MicroHide[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_InitNuke[] =
|
|
{
|
|
{ID_MicroPresent0, Micro_ACTION_RATE,pNukeAction, &ps_InitNuke[1], 0,0,0},
|
|
{ID_MicroPresent0, 0, pMicroStandBy, &ps_InitNuke[2], psf_QuickCall, 0,0},
|
|
{ID_MicroPresent0, 120*2, pNukeAction, &ps_InitNuke[3], 0,0,0},
|
|
{ID_MicroPresent0, 0, pMicroCount, &ps_InitNuke[4], psf_QuickCall, 0,0},
|
|
{ID_MicroPresent0, 120*3, pNukeAction, &ps_InitNuke[5], 0,0,0},
|
|
{ID_MicroPresent0, 0, pMicroReady, &ps_InitNuke[6], psf_QuickCall, 0,0},
|
|
{ID_MicroPresent0, 120*2, pNukeAction, &ps_InitNuke[7], 0,0,0},
|
|
{ID_MicroPresent0, 3, pNukeAction, &ps_MicroRest[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_MicroRecoil[] =
|
|
{
|
|
// recoil
|
|
{ID_MicroPresent0, Micro_ACTION_RATE, pMicroRecoilDown, &ps_MicroRecoil[0], 0,0,0},
|
|
{ID_MicroPresent0, Micro_ACTION_RATE, pMicroRecoilUp, &ps_MicroRecoil[1], 0,0,0},
|
|
|
|
// Firing delay.
|
|
{ID_MicroPresent0, 30, pNullAnimator, &ps_MicroRecoil[3], 0,0,0},
|
|
// ready to fire again
|
|
{ID_MicroPresent0, 3, pNullAnimator, &ps_MicroRest[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_MicroFire[] =
|
|
{
|
|
{ID_MicroFire0, Micro_ACTION_RATE, pMicroAction, &ps_MicroFire[1], psf_ShadeNone, 0,0},
|
|
{ID_MicroFire1, Micro_ACTION_RATE, pMicroAction, &ps_MicroFire[2], psf_ShadeNone, 0,0},
|
|
{ID_MicroFire2, Micro_ACTION_RATE, pMicroAction, &ps_MicroFire[3], psf_ShadeHalf, 0,0},
|
|
{ID_MicroFire3, Micro_ACTION_RATE, pMicroAction, &ps_MicroFire[4], psf_ShadeHalf, 0,0},
|
|
{ID_MicroPresent0, 0, pMicroFire, &ps_MicroFire[5], psf_ShadeNone|psf_QuickCall, 0,0},
|
|
|
|
|
|
// !JIM! After firing delay so rockets can't fire so fast!
|
|
// Putting a BIG blast radius for rockets, this is better than small and fast for this weap.
|
|
{ID_MicroPresent0, 120, pMicroAction, &ps_MicroFire[6], 0,0,0},
|
|
|
|
{ID_MicroPresent0, 3, pMicroAction, &ps_MicroRecoil[0], 0,0,0}
|
|
};
|
|
|
|
#define Micro_SINGLE_RATE 8
|
|
#define Micro_DISSIPATE_RATE 6
|
|
|
|
PANEL_STATE ps_MicroSingleFire[] =
|
|
{
|
|
{ID_MicroSingleFire0, Micro_SINGLE_RATE, pMicroAction, &ps_MicroSingleFire[1], psf_ShadeHalf, 0,0},
|
|
{ID_MicroSingleFire1, Micro_SINGLE_RATE, pMicroAction, &ps_MicroSingleFire[2], psf_ShadeNone, 0,0},
|
|
{ID_MicroSingleFire1, 0, pMicroFire, &ps_MicroSingleFire[3], psf_ShadeNone|psf_QuickCall, 0,0},
|
|
{ID_MicroSingleFire2, Micro_DISSIPATE_RATE, pMicroAction, &ps_MicroSingleFire[4], psf_ShadeNone, 0,0},
|
|
{ID_MicroSingleFire3, Micro_DISSIPATE_RATE, pMicroAction, &ps_MicroSingleFire[5], psf_ShadeHalf, 0,0},
|
|
|
|
// !JIM! Put in firing delay.
|
|
//{ID_MicroPresent0, 60, pMicroAction, &ps_MicroSingleFire[6]},
|
|
|
|
{ID_MicroPresent0, 3, pMicroAction, &ps_MicroRecoil[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_RetractMicro[] =
|
|
{
|
|
{ID_MicroPresent0, Micro_REST_RATE, pMicroRetract, &ps_RetractMicro[0], 0,0,0}
|
|
};
|
|
|
|
#define MICRO_BOB_X_AMT 10
|
|
#define MICRO_YOFF 205
|
|
#define MICRO_XOFF (150+MICRO_BOB_X_AMT)
|
|
|
|
void
|
|
pMicroSetRecoil(PANEL_SPRITEp psp)
|
|
{
|
|
psp->vel = 900;
|
|
psp->ang = NORM_ANGLE(-256);
|
|
}
|
|
|
|
void
|
|
InitWeaponMicro(PLAYERp pp)
|
|
{
|
|
PANEL_SPRITEp psp;
|
|
|
|
if (Prediction)
|
|
return;
|
|
|
|
if (!TEST(pp->WpnFlags, BIT(WPN_MICRO)) ||
|
|
// pp->WpnAmmo[WPN_MICRO] <= 0 ||
|
|
TEST(pp->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
if (!pp->Wpn[WPN_MICRO])
|
|
{
|
|
psp = pp->Wpn[WPN_MICRO] = pSpawnSprite(pp, ps_PresentMicro, PRI_MID, MICRO_XOFF, MICRO_YOFF);
|
|
psp->y += tileHeight(psp->picndx);
|
|
psp->backupy();
|
|
}
|
|
|
|
if (pp->CurWpn == pp->Wpn[WPN_MICRO])
|
|
{
|
|
if (pp->TestNukeInit && pp->WpnRocketType == 2 && !pp->InitingNuke && pp->WpnRocketNuke && !pp->NukeInitialized)
|
|
{
|
|
pp->TestNukeInit = false;
|
|
pp->InitingNuke = true;
|
|
psp = pp->Wpn[WPN_MICRO];
|
|
pSetState(psp, ps_InitNuke);
|
|
}
|
|
return;
|
|
}
|
|
|
|
PlayerUpdateWeapon(pp, WPN_MICRO);
|
|
|
|
pp->WpnUziType = 2; // Make uzi's go away!
|
|
RetractCurWpn(pp);
|
|
|
|
// Set up the new weapon variables
|
|
psp = pp->CurWpn = pp->Wpn[WPN_MICRO];
|
|
SET(psp->flags, PANF_WEAPON_SPRITE);
|
|
psp->ActionState = ps_MicroFire;
|
|
psp->RetractState = ps_RetractMicro;
|
|
psp->RestState = ps_MicroRest;
|
|
psp->PresentState = ps_PresentMicro;
|
|
pSetState(psp, psp->PresentState);
|
|
|
|
if (pp->WpnRocketType == 2 && !pp->InitingNuke && !pp->NukeInitialized)
|
|
pp->TestNukeInit = pp->InitingNuke = true;
|
|
|
|
PlaySound(DIGI_ROCKET_UP, pp, v3df_follow);
|
|
|
|
psp->PlayerP->KeyPressBits |= SB_FIRE;
|
|
|
|
}
|
|
|
|
|
|
void
|
|
pMicroRecoilDown(PANEL_SPRITEp psp)
|
|
{
|
|
psp->backupcoords();
|
|
|
|
psp->x += pspCosVel(psp);
|
|
psp->y -= pspSinVel(psp);
|
|
|
|
psp->vel -= 24 * synctics;
|
|
|
|
if (psp->vel < 550)
|
|
{
|
|
psp->vel = 550;
|
|
psp->ang = NORM_ANGLE(psp->ang + 1024);
|
|
|
|
pStatePlusOne(psp);
|
|
}
|
|
}
|
|
|
|
void
|
|
pMicroRecoilUp(PANEL_SPRITEp psp)
|
|
{
|
|
psp->backupcoords();
|
|
|
|
psp->x += pspCosVel(psp);
|
|
psp->y -= pspSinVel(psp);
|
|
|
|
psp->vel += 15 * synctics;
|
|
|
|
if (psp->y < MICRO_YOFF)
|
|
{
|
|
psp->oy = psp->y = MICRO_YOFF;
|
|
psp->ox = psp->x = MICRO_XOFF;
|
|
|
|
pMicroSetRecoil(psp);
|
|
|
|
pStatePlusOne(psp);
|
|
RESET(psp->flags, PANF_BOB);
|
|
}
|
|
}
|
|
|
|
void
|
|
pMicroPresent(PANEL_SPRITEp psp)
|
|
{
|
|
PLAYERp pp = psp->PlayerP;
|
|
|
|
if (TEST(psp->PlayerP->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
// Needed for recoil
|
|
psp->ang = NORM_ANGLE(256 + 96);
|
|
pMicroSetRecoil(psp);
|
|
///
|
|
|
|
psp->backupy();
|
|
psp->y -= 3 * synctics;
|
|
|
|
if (psp->y < MICRO_YOFF)
|
|
{
|
|
psp->oy = psp->y = MICRO_YOFF;
|
|
psp->backupboby();
|
|
if (pp->WpnRocketType == 2 && !pp->NukeInitialized)
|
|
{
|
|
pp->TestNukeInit = false;
|
|
pSetState(psp, ps_InitNuke);
|
|
}
|
|
else
|
|
pSetState(psp, psp->RestState);
|
|
}
|
|
}
|
|
|
|
void
|
|
pMicroBobSetup(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->flags, PANF_BOB))
|
|
return;
|
|
|
|
psp->backupbobcoords();
|
|
|
|
psp->sin_amt = MICRO_BOB_X_AMT;
|
|
psp->sin_ndx = 0;
|
|
psp->bob_height_divider = 8;
|
|
}
|
|
|
|
void
|
|
pMicroHide(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= MICRO_YOFF + tileHeight(picnum) + 20)
|
|
{
|
|
psp->oy = psp->y = MICRO_YOFF + tileHeight(picnum) + 20;
|
|
psp->ox = psp->x = MICRO_XOFF;
|
|
|
|
pWeaponUnHideKeys(psp, psp->PresentState);
|
|
}
|
|
}
|
|
|
|
bool
|
|
pMicroOverlays(PANEL_SPRITEp psp)
|
|
{
|
|
#define MICRO_SIGHT_XOFF 29
|
|
#define MICRO_SIGHT_YOFF -58
|
|
|
|
#define MICRO_SHOT_XOFF 65
|
|
#define MICRO_SHOT_YOFF -41
|
|
|
|
#define MICRO_HEAT_XOFF 78
|
|
#define MICRO_HEAT_YOFF -51
|
|
|
|
if (psp->over[MICRO_SIGHT_NUM].xoff == -1)
|
|
{
|
|
psp->over[MICRO_SIGHT_NUM].xoff = MICRO_SIGHT_XOFF;
|
|
psp->over[MICRO_SIGHT_NUM].yoff = MICRO_SIGHT_YOFF;
|
|
psp->over[MICRO_SHOT_NUM].xoff = MICRO_SHOT_XOFF;
|
|
psp->over[MICRO_SHOT_NUM].yoff = MICRO_SHOT_YOFF;
|
|
psp->over[MICRO_HEAT_NUM].xoff = MICRO_HEAT_XOFF;
|
|
psp->over[MICRO_HEAT_NUM].yoff = MICRO_HEAT_YOFF;
|
|
|
|
}
|
|
|
|
if (psp->PlayerP->WpnRocketNuke == 0 && psp->PlayerP->WpnRocketType == 2)
|
|
psp->PlayerP->WpnRocketType=0;
|
|
|
|
switch (psp->PlayerP->WpnRocketType)
|
|
{
|
|
case 0:
|
|
psp->over[MICRO_SIGHT_NUM].pic = MICRO_SIGHT;
|
|
psp->over[MICRO_SHOT_NUM].pic = MICRO_SHOT_1;
|
|
SET(psp->over[MICRO_SHOT_NUM].flags, psf_ShadeNone);
|
|
psp->over[MICRO_HEAT_NUM].pic = -1;
|
|
return false;
|
|
case 1:
|
|
if (psp->PlayerP->WpnRocketHeat)
|
|
{
|
|
psp->over[MICRO_SIGHT_NUM].pic = MICRO_SIGHT;
|
|
psp->over[MICRO_SHOT_NUM].pic = MICRO_SHOT_1;
|
|
SET(psp->over[MICRO_SHOT_NUM].flags, psf_ShadeNone);
|
|
|
|
ASSERT(psp->PlayerP->WpnRocketHeat < 6);
|
|
|
|
psp->over[MICRO_HEAT_NUM].pic = MICRO_HEAT + (5 - psp->PlayerP->WpnRocketHeat);
|
|
}
|
|
else
|
|
{
|
|
psp->over[MICRO_SIGHT_NUM].pic = MICRO_SIGHT;
|
|
psp->over[MICRO_SHOT_NUM].pic = MICRO_SHOT_1;
|
|
SET(psp->over[MICRO_SHOT_NUM].flags, psf_ShadeNone);
|
|
psp->over[MICRO_HEAT_NUM].pic = -1;
|
|
}
|
|
|
|
return false;
|
|
case 2:
|
|
psp->over[MICRO_SIGHT_NUM].pic = -1;
|
|
psp->over[MICRO_HEAT_NUM].pic = -1;
|
|
|
|
psp->over[MICRO_SHOT_NUM].pic = MICRO_SHOT_20;
|
|
SET(psp->over[MICRO_SHOT_NUM].flags, psf_ShadeNone);
|
|
SET(psp->over[MICRO_HEAT_NUM].flags, psf_ShadeNone);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
PANEL_STATE ps_MicroHeatFlash[] =
|
|
{
|
|
{MICRO_HEAT, 30, nullptr, &ps_MicroHeatFlash[1], 0,0,0},
|
|
{0, 30, nullptr, &ps_MicroHeatFlash[2], 0,0,0},
|
|
{MICRO_HEAT, 30, nullptr, &ps_MicroHeatFlash[3], 0,0,0},
|
|
{0, 30, nullptr, &ps_MicroHeatFlash[4], 0,0,0},
|
|
{MICRO_HEAT, 30, nullptr, &ps_MicroHeatFlash[5], 0,0,0},
|
|
{0, 30, nullptr, &ps_MicroHeatFlash[6], 0,0,0},
|
|
{MICRO_HEAT, 30, nullptr, &ps_MicroHeatFlash[7], 0,0,0},
|
|
{0, 30, nullptr, &ps_MicroHeatFlash[8], 0,0,0},
|
|
{MICRO_HEAT, 30, nullptr, &ps_MicroHeatFlash[9], 0,0,0},
|
|
{0, 0, nullptr, nullptr, 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_MicroNukeFlash[] =
|
|
{
|
|
{MICRO_SHOT_20, 30, nullptr, &ps_MicroNukeFlash[1], 0,0,0},
|
|
{0, 30, nullptr, &ps_MicroNukeFlash[2], 0,0,0},
|
|
{MICRO_SHOT_20, 30, nullptr, &ps_MicroNukeFlash[3], 0,0,0},
|
|
{0, 30, nullptr, &ps_MicroNukeFlash[4], 0,0,0},
|
|
{MICRO_SHOT_20, 30, nullptr, &ps_MicroNukeFlash[5], 0,0,0},
|
|
{0, 30, nullptr, &ps_MicroNukeFlash[6], 0,0,0},
|
|
{MICRO_SHOT_20, 30, nullptr, &ps_MicroNukeFlash[7], 0,0,0},
|
|
{0, 30, nullptr, &ps_MicroNukeFlash[8], 0,0,0},
|
|
{MICRO_SHOT_20, 30, nullptr, &ps_MicroNukeFlash[9], 0,0,0},
|
|
{0, 0, nullptr, nullptr, 0,0,0}
|
|
};
|
|
|
|
void
|
|
pMicroRest(PANEL_SPRITEp psp)
|
|
{
|
|
PLAYERp pp = psp->PlayerP;
|
|
bool force = !!TEST(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (pWeaponHideKeys(psp, ps_MicroHide))
|
|
return;
|
|
|
|
pMicroOverlays(psp);
|
|
|
|
pMicroBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
|
|
if (pp->InitingNuke)
|
|
{
|
|
int choose_voc=0;
|
|
|
|
pp->InitingNuke = false;
|
|
pp->NukeInitialized = true;
|
|
|
|
if (pp == Player+myconnectindex)
|
|
{
|
|
choose_voc = STD_RANDOM_RANGE(1024);
|
|
if (choose_voc > 600)
|
|
PlayerSound(DIGI_TAUNTAI2,v3df_dontpan|v3df_follow,psp->PlayerP);
|
|
else if (choose_voc > 300)
|
|
PlayerSound(DIGI_TAUNTAI4,v3df_dontpan|v3df_follow,psp->PlayerP);
|
|
}
|
|
}
|
|
|
|
if ((psp->PlayerP->input.actions & SB_FIRE) || force)
|
|
{
|
|
if ((psp->PlayerP->KeyPressBits & SB_FIRE) || force)
|
|
{
|
|
RESET(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (!WeaponOK(psp->PlayerP))
|
|
return;
|
|
|
|
if (psp->PlayerP->WpnAmmo[WPN_MICRO] <= 0 && psp->PlayerP->WpnRocketType != 2)
|
|
{
|
|
psp->PlayerP->WpnRocketNuke = 0;
|
|
WeaponOK(psp->PlayerP);
|
|
psp->PlayerP->WpnRocketNuke = 1;
|
|
return;
|
|
}
|
|
|
|
switch (psp->PlayerP->WpnRocketType)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
pSetState(psp, ps_MicroSingleFire);
|
|
DoPlayerChooseYell(psp->PlayerP);
|
|
break;
|
|
case 2:
|
|
if (psp->PlayerP->WpnRocketNuke > 0)
|
|
pSetState(psp, ps_MicroSingleFire);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
WeaponOK(psp->PlayerP);
|
|
}
|
|
|
|
void
|
|
pMicroAction(PANEL_SPRITEp psp)
|
|
{
|
|
pMicroBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
}
|
|
|
|
|
|
void
|
|
pMicroFire(PANEL_SPRITEp psp)
|
|
{
|
|
SpawnVis(psp->PlayerP->Actor(), -1, -1, -1, -1, 20);
|
|
switch (psp->PlayerP->WpnRocketType)
|
|
{
|
|
case 0:
|
|
if (sw_bunnyrockets)
|
|
InitBunnyRocket(psp->PlayerP);
|
|
else
|
|
InitRocket(psp->PlayerP);
|
|
break;
|
|
case 1:
|
|
if (sw_bunnyrockets)
|
|
InitBunnyRocket(psp->PlayerP);
|
|
else
|
|
InitRocket(psp->PlayerP);
|
|
break;
|
|
case 2:
|
|
PlaySound(DIGI_WARNING,psp->PlayerP,v3df_dontpan|v3df_follow);
|
|
InitNuke(psp->PlayerP);
|
|
psp->PlayerP->NukeInitialized = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
pMicroRetract(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= MICRO_YOFF + tileHeight(picnum))
|
|
{
|
|
RESET(psp->PlayerP->Flags, PF_WEAPON_RETRACT);
|
|
psp->PlayerP->Wpn[WPN_MICRO] = nullptr;
|
|
pKillSprite(psp);
|
|
}
|
|
}
|
|
|
|
void
|
|
pNukeAction(PANEL_SPRITEp psp)
|
|
{
|
|
PLAYERp pp = psp->PlayerP;
|
|
|
|
#if 0 // Code commented out as it's causing interpolation issues when initialising a nuke.
|
|
psp->backupy();
|
|
psp->y -= 3 * synctics;
|
|
|
|
if (psp->y < MICRO_YOFF)
|
|
{
|
|
psp->oy = psp->y = MICRO_YOFF;
|
|
psp->backupboby();
|
|
}
|
|
#endif
|
|
|
|
pMicroBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
if (!pp->InitingNuke)
|
|
pSetState(psp, psp->PresentState);
|
|
}
|
|
|
|
void
|
|
pMicroStandBy(PANEL_SPRITEp psp)
|
|
{
|
|
PLAYERp pp = psp->PlayerP;
|
|
|
|
pMicroOverlays(psp);
|
|
PlaySound(DIGI_NUKESTDBY, pp, v3df_follow|v3df_dontpan, CHAN_WEAPON);
|
|
}
|
|
|
|
void
|
|
pMicroCount(PANEL_SPRITEp psp)
|
|
{
|
|
PLAYERp pp = psp->PlayerP;
|
|
|
|
PlaySound(DIGI_NUKECDOWN, pp, v3df_follow|v3df_dontpan, CHAN_WEAPON);
|
|
}
|
|
|
|
void
|
|
pMicroReady(PANEL_SPRITEp psp)
|
|
{
|
|
PLAYERp pp = psp->PlayerP;
|
|
|
|
PlaySound(DIGI_NUKEREADY, pp, v3df_follow|v3df_dontpan, CHAN_WEAPON);
|
|
pp->NukeInitialized = true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// HEART
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void pHeartPresent(PANEL_SPRITEp psp);
|
|
void pHeartRetract(PANEL_SPRITEp psp);
|
|
void pHeartAction(PANEL_SPRITEp psp);
|
|
void pHeartRest(PANEL_SPRITEp psp);
|
|
void pHeartAttack(PANEL_SPRITEp psp);
|
|
void pHeartHide(PANEL_SPRITEp psp);
|
|
void pHeartActionBlood(PANEL_SPRITEp psp);
|
|
void SpawnSmallHeartBlood(PANEL_SPRITEp psp);
|
|
|
|
extern PANEL_STATE ps_HeartAttack[];
|
|
extern PANEL_STATE ps_ReloadHeart[];
|
|
|
|
|
|
#define Heart_BEAT_RATE 60
|
|
#define Heart_ACTION_RATE 10
|
|
|
|
PANEL_STATE ps_PresentHeart[] =
|
|
{
|
|
{ID_HeartPresent0, Heart_BEAT_RATE, pHeartPresent, &ps_PresentHeart[1], 0,0,0},
|
|
{ID_HeartPresent1, Heart_BEAT_RATE, pHeartPresent, &ps_PresentHeart[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_HeartRest[] =
|
|
{
|
|
{ID_HeartPresent0, Heart_BEAT_RATE, pHeartRest, &ps_HeartRest[1], 0,0,0},
|
|
{ID_HeartPresent1, Heart_BEAT_RATE, pHeartRest, &ps_HeartRest[2], 0,0,0},
|
|
{ID_HeartPresent1, Heart_BEAT_RATE, SpawnSmallHeartBlood, &ps_HeartRest[3], psf_QuickCall, 0,0},
|
|
{ID_HeartPresent1, 0, pHeartRest, &ps_HeartRest[0], 0,0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_HeartHide[] =
|
|
{
|
|
{ID_HeartPresent0, Heart_BEAT_RATE, pHeartHide, &ps_HeartHide[1], 0,0,0},
|
|
{ID_HeartPresent1, Heart_BEAT_RATE, pHeartHide, &ps_HeartHide[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_HeartAttack[] =
|
|
{
|
|
// squeeze
|
|
{ID_HeartAttack0, Heart_ACTION_RATE, pHeartActionBlood, &ps_HeartAttack[1], psf_ShadeHalf, 0,0},
|
|
{ID_HeartAttack1, Heart_ACTION_RATE, pHeartActionBlood, &ps_HeartAttack[2], psf_ShadeNone, 0,0},
|
|
{ID_HeartAttack1, Heart_ACTION_RATE, pHeartActionBlood, &ps_HeartAttack[3], psf_ShadeNone, 0,0},
|
|
// attack
|
|
{ID_HeartAttack1, Heart_ACTION_RATE, pHeartAttack, &ps_HeartAttack[4], psf_QuickCall, 0,0},
|
|
// unsqueeze
|
|
{ID_HeartAttack1, Heart_ACTION_RATE, pHeartAction, &ps_HeartAttack[5], psf_ShadeNone, 0,0},
|
|
{ID_HeartAttack1, Heart_ACTION_RATE, pHeartAction, &ps_HeartAttack[6], psf_ShadeNone, 0,0},
|
|
{ID_HeartAttack0, Heart_ACTION_RATE, pHeartAction, &ps_HeartAttack[7], psf_ShadeHalf, 0,0},
|
|
|
|
{ID_HeartAttack0, Heart_ACTION_RATE, pHeartAction, &ps_HeartRest[0], psf_ShadeHalf, 0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_RetractHeart[] =
|
|
{
|
|
{ID_HeartPresent0, Heart_BEAT_RATE, pHeartRetract, &ps_RetractHeart[1], 0,0,0},
|
|
{ID_HeartPresent1, Heart_BEAT_RATE, pHeartRetract, &ps_RetractHeart[0], 0,0,0}
|
|
};
|
|
|
|
#define HEART_YOFF 212
|
|
|
|
void
|
|
InitWeaponHeart(PLAYERp pp)
|
|
{
|
|
PANEL_SPRITEp psp;
|
|
|
|
if (SW_SHAREWARE) return;
|
|
|
|
if (Prediction)
|
|
return;
|
|
|
|
if (!TEST(pp->WpnFlags, BIT(WPN_HEART)) ||
|
|
// pp->WpnAmmo[WPN_HEART] <= 0 ||
|
|
TEST(pp->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
if (!pp->Wpn[WPN_HEART])
|
|
{
|
|
psp = pp->Wpn[WPN_HEART] = pSpawnSprite(pp, ps_PresentHeart, PRI_MID, 160 + 10, HEART_YOFF);
|
|
psp->y += tileHeight(psp->picndx);
|
|
psp->backupy();
|
|
}
|
|
|
|
if (pp->CurWpn == pp->Wpn[WPN_HEART])
|
|
{
|
|
return;
|
|
}
|
|
|
|
PlayerUpdateWeapon(pp, WPN_HEART);
|
|
|
|
pp->WpnUziType = 2; // Make uzi's go away!
|
|
RetractCurWpn(pp);
|
|
|
|
PlaySound(DIGI_HEARTBEAT, pp, v3df_follow|v3df_dontpan|v3df_doppler);
|
|
|
|
// Set up the new weapon variables
|
|
psp = pp->CurWpn = pp->Wpn[WPN_HEART];
|
|
SET(psp->flags, PANF_WEAPON_SPRITE);
|
|
psp->ActionState = ps_HeartAttack;
|
|
psp->RetractState = ps_RetractHeart;
|
|
psp->PresentState = ps_PresentHeart;
|
|
psp->RestState = ps_HeartRest;
|
|
pSetState(psp, psp->PresentState);
|
|
|
|
psp->PlayerP->KeyPressBits |= SB_FIRE;
|
|
}
|
|
|
|
void
|
|
pHeartPresent(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->PlayerP->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
psp->backupy();
|
|
psp->y -= 3 * synctics;
|
|
|
|
if (psp->y < HEART_YOFF)
|
|
{
|
|
psp->oy = psp->y = HEART_YOFF;
|
|
psp->backupboby();
|
|
pSetState(psp, psp->RestState);
|
|
}
|
|
}
|
|
|
|
void
|
|
pHeartBobSetup(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->flags, PANF_BOB))
|
|
return;
|
|
|
|
psp->backupbobcoords();
|
|
|
|
psp->sin_amt = 12;
|
|
psp->sin_ndx = 0;
|
|
psp->bob_height_divider = 8;
|
|
}
|
|
|
|
void
|
|
pHeartHide(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= HEART_YOFF + tileHeight(picnum))
|
|
{
|
|
psp->oy = psp->y = HEART_YOFF + tileHeight(picnum);
|
|
|
|
pWeaponUnHideKeys(psp, psp->PresentState);
|
|
}
|
|
}
|
|
|
|
void
|
|
pHeartRest(PANEL_SPRITEp psp)
|
|
{
|
|
bool force = !!TEST(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (pWeaponHideKeys(psp, ps_HeartHide))
|
|
return;
|
|
|
|
psp->yorig += synctics;
|
|
|
|
if (psp->yorig > HEART_YOFF)
|
|
{
|
|
psp->yorig = HEART_YOFF;
|
|
}
|
|
|
|
pHeartBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
|
|
if ((psp->PlayerP->input.actions & SB_FIRE) || force)
|
|
{
|
|
if ((psp->PlayerP->KeyPressBits & SB_FIRE) || force)
|
|
{
|
|
psp->PlayerP->KeyPressBits &= ~SB_FIRE;
|
|
RESET(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (!WeaponOK(psp->PlayerP))
|
|
return;
|
|
|
|
DoPlayerChooseYell(psp->PlayerP);
|
|
pSetState(psp, psp->ActionState);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
psp->PlayerP->KeyPressBits |= SB_FIRE;
|
|
WeaponOK(psp->PlayerP);
|
|
}
|
|
}
|
|
|
|
void
|
|
pHeartAction(PANEL_SPRITEp psp)
|
|
{
|
|
psp->yorig -= synctics;
|
|
|
|
if (psp->yorig < 200)
|
|
{
|
|
psp->yorig = 200;
|
|
}
|
|
|
|
pHeartBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
}
|
|
|
|
void
|
|
pHeartActionBlood(PANEL_SPRITEp psp)
|
|
{
|
|
psp->yorig -= synctics;
|
|
|
|
if (psp->yorig < 200)
|
|
{
|
|
psp->yorig = 200;
|
|
}
|
|
|
|
psp->backupy();
|
|
psp->y = psp->yorig;
|
|
|
|
pHeartBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
|
|
SpawnHeartBlood(psp);
|
|
}
|
|
|
|
void InitHeartAttack(PLAYERp pp);
|
|
|
|
void
|
|
pHeartAttack(PANEL_SPRITEp psp)
|
|
{
|
|
PLAYERp pp = psp->PlayerP;
|
|
// CTW MODIFICATION
|
|
//int InitHeartAttack(PLAYERp pp);
|
|
// CTW MODIFICATION END
|
|
|
|
PlaySound(DIGI_HEARTFIRE, pp, v3df_follow|v3df_dontpan);
|
|
if (RandomRange(1000) > 800)
|
|
PlayerSound(DIGI_JG9009, v3df_follow|v3df_dontpan,pp);
|
|
InitHeartAttack(psp->PlayerP);
|
|
}
|
|
|
|
void
|
|
pHeartRetract(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= HEART_YOFF + tileHeight(picnum))
|
|
{
|
|
RESET(psp->PlayerP->Flags, PF_WEAPON_RETRACT);
|
|
psp->PlayerP->Wpn[WPN_HEART] = nullptr;
|
|
pKillSprite(psp);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// HEART BLOOD
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void pHeartBlood(PANEL_SPRITEp);
|
|
|
|
#define HEART_BLOOD_RATE 10
|
|
|
|
PANEL_STATE ps_HeartBlood[] =
|
|
{
|
|
{ID_HeartBlood0, HEART_BLOOD_RATE, pHeartBlood, &ps_HeartBlood[1], 0,0,0},
|
|
{ID_HeartBlood1, HEART_BLOOD_RATE, pHeartBlood, &ps_HeartBlood[2], 0,0,0},
|
|
{ID_HeartBlood2, HEART_BLOOD_RATE, pHeartBlood, &ps_HeartBlood[3], 0,0,0},
|
|
{ID_HeartBlood3, HEART_BLOOD_RATE, pHeartBlood, &ps_HeartBlood[4], 0,0,0},
|
|
{ID_HeartBlood4, HEART_BLOOD_RATE, pHeartBlood, &ps_HeartBlood[5], 0,0,0},
|
|
{ID_HeartBlood5, HEART_BLOOD_RATE, pHeartBlood, &ps_HeartBlood[6], 0,0,0},
|
|
{ID_HeartBlood5, HEART_BLOOD_RATE, pSuicide, &ps_HeartBlood[6], 0,0,0},
|
|
};
|
|
|
|
#define HEART_BLOOD_SMALL_RATE 7
|
|
|
|
PANEL_STATE ps_HeartBloodSmall[] =
|
|
{
|
|
{ID_HeartBlood0, HEART_BLOOD_SMALL_RATE, pHeartBlood, &ps_HeartBlood[1], 0,0,0},
|
|
{ID_HeartBlood1, HEART_BLOOD_SMALL_RATE, pHeartBlood, &ps_HeartBlood[2], 0,0,0},
|
|
{ID_HeartBlood2, HEART_BLOOD_SMALL_RATE, pHeartBlood, &ps_HeartBlood[3], 0,0,0},
|
|
{ID_HeartBlood3, HEART_BLOOD_SMALL_RATE, pHeartBlood, &ps_HeartBlood[4], 0,0,0},
|
|
{ID_HeartBlood4, HEART_BLOOD_SMALL_RATE, pHeartBlood, &ps_HeartBlood[5], 0,0,0},
|
|
{ID_HeartBlood5, HEART_BLOOD_SMALL_RATE, pHeartBlood, &ps_HeartBlood[6], 0,0,0},
|
|
{ID_HeartBlood5, HEART_BLOOD_SMALL_RATE, pSuicide, &ps_HeartBlood[6], 0,0,0},
|
|
};
|
|
|
|
void
|
|
SpawnHeartBlood(PANEL_SPRITEp psp)
|
|
{
|
|
PLAYERp pp = psp->PlayerP;
|
|
PANEL_SPRITEp blood;
|
|
PANEL_SHRAPp hsp;
|
|
|
|
static PANEL_SHRAP HeartShrap[] =
|
|
{
|
|
{-10, -80, 2, -FIXED(1,32000), -FIXED(2,32000), -FIXED(5,32000), -FIXED(3,32000), {ps_HeartBlood, ps_HeartBlood}},
|
|
{0, -85, 0, -FIXED(3,32000), -FIXED(8,32000), -FIXED(3,32000), -FIXED(1,32000), {ps_HeartBlood, ps_HeartBlood}},
|
|
{10, -85, 2, -FIXED(1,32000), -FIXED(2,32000), FIXED(2,32000), FIXED(3,32000), {ps_HeartBlood, ps_HeartBlood}},
|
|
{25, -80, 2, -FIXED(1,32000), -FIXED(2,32000), FIXED(5,32000), FIXED(6,32000), {ps_HeartBlood, ps_HeartBlood}},
|
|
{0, 0, 0, 0, 0, 0, 0, {0, 0}},
|
|
};
|
|
|
|
for (hsp = HeartShrap; hsp->lo_jump_speed; hsp++)
|
|
{
|
|
if (hsp->skip == 2)
|
|
{
|
|
if (MoveSkip2 != 0)
|
|
continue;
|
|
}
|
|
|
|
// RIGHT side
|
|
blood = pSpawnSprite(pp, hsp->state[RANDOM_P2(2<<8)>>8], PRI_BACK, 0, 0);
|
|
blood->x = psp->x + hsp->xoff;
|
|
blood->ox = blood->x;
|
|
blood->y = psp->y + hsp->yoff;
|
|
blood->oy = blood->y;
|
|
blood->xspeed = hsp->lo_xspeed + (RandomRange((hsp->hi_xspeed - hsp->lo_xspeed)>>4) << 4);
|
|
SET(blood->flags, PANF_WEAPON_SPRITE);
|
|
|
|
blood->scale = 20000 + RandomRange(50000 - 20000);
|
|
|
|
blood->jump_speed = hsp->lo_jump_speed + (RandomRange((hsp->hi_jump_speed + hsp->lo_jump_speed)>>4) << 4);
|
|
DoBeginPanelJump(blood);
|
|
}
|
|
}
|
|
|
|
void
|
|
SpawnSmallHeartBlood(PANEL_SPRITEp psp)
|
|
{
|
|
PLAYERp pp = psp->PlayerP;
|
|
PANEL_SPRITEp blood;
|
|
PANEL_SHRAPp hsp;
|
|
|
|
static PANEL_SHRAP HeartShrap[] =
|
|
{
|
|
{-10, -80, 0, -FIXED(1,0), -FIXED(2,0), -FIXED(1,0), -FIXED(3,0), {ps_HeartBloodSmall, ps_HeartBloodSmall}},
|
|
{0, -85, 0, -FIXED(1,0), -FIXED(5,0), -FIXED(1,0), -FIXED(1,0), {ps_HeartBloodSmall, ps_HeartBloodSmall}},
|
|
{10, -85, 0, -FIXED(1,0), -FIXED(2,0), FIXED(1,0), FIXED(2,0), {ps_HeartBloodSmall, ps_HeartBloodSmall}},
|
|
{25, -80, 0, -FIXED(1,0), -FIXED(2,0), FIXED(3,0), FIXED(4,0), {ps_HeartBloodSmall, ps_HeartBloodSmall}},
|
|
{0, 0, 0, 0, 0, 0, 0, {0,0}},
|
|
};
|
|
|
|
PlaySound(DIGI_HEARTBEAT, pp, v3df_follow|v3df_dontpan|v3df_doppler);
|
|
|
|
for (hsp = HeartShrap; hsp->lo_jump_speed; hsp++)
|
|
{
|
|
// RIGHT side
|
|
blood = pSpawnSprite(pp, hsp->state[RANDOM_P2(2<<8)>>8], PRI_BACK, 0, 0);
|
|
blood->x = psp->x + hsp->xoff;
|
|
blood->ox = blood->x;
|
|
blood->y = psp->y + hsp->yoff;
|
|
blood->oy = blood->y;
|
|
blood->xspeed = hsp->lo_xspeed + (RandomRange((hsp->hi_xspeed - hsp->lo_xspeed)>>4) << 4);
|
|
SET(blood->flags, PANF_WEAPON_SPRITE);
|
|
|
|
blood->scale = 10000 + RandomRange(30000 - 10000);
|
|
|
|
blood->jump_speed = hsp->lo_jump_speed + (RandomRange((hsp->hi_jump_speed + hsp->lo_jump_speed)>>4) << 4);
|
|
DoBeginPanelJump(blood);
|
|
}
|
|
}
|
|
|
|
void
|
|
pHeartBlood(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->flags, PANF_JUMPING))
|
|
{
|
|
DoPanelJump(psp);
|
|
}
|
|
else if (TEST(psp->flags, PANF_FALLING))
|
|
{
|
|
DoPanelFall(psp);
|
|
}
|
|
|
|
psp->backupx();
|
|
psp->x += psp->xspeed * (1. / FRACUNIT);
|
|
|
|
if (psp->x > 320 || psp->x < 0 || psp->y > 200)
|
|
{
|
|
pKillSprite(psp);
|
|
return;
|
|
}
|
|
}
|
|
|
|
int
|
|
DoBeginPanelJump(PANEL_SPRITEp psp)
|
|
{
|
|
#define PANEL_JUMP_GRAVITY FIXED(0,8000)
|
|
|
|
SET(psp->flags, PANF_JUMPING);
|
|
RESET(psp->flags, PANF_FALLING);
|
|
|
|
// set up individual actor jump gravity
|
|
psp->jump_grav = PANEL_JUMP_GRAVITY;
|
|
|
|
DoPanelJump(psp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
DoPanelJump(PANEL_SPRITEp psp)
|
|
{
|
|
// adjust jump speed by gravity - if jump speed greater than 0 player
|
|
// have started falling
|
|
if ((psp->jump_speed += psp->jump_grav) > 0)
|
|
{
|
|
// Start falling
|
|
DoBeginPanelFall(psp);
|
|
return 0;
|
|
}
|
|
|
|
// adjust height by jump speed
|
|
psp->backupy();
|
|
psp->y += psp->jump_speed * synctics * (1. / FRACUNIT);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
DoBeginPanelFall(PANEL_SPRITEp psp)
|
|
{
|
|
SET(psp->flags, PANF_FALLING);
|
|
RESET(psp->flags, PANF_JUMPING);
|
|
|
|
psp->jump_grav = PANEL_JUMP_GRAVITY;
|
|
|
|
DoPanelFall(psp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
DoPanelFall(PANEL_SPRITEp psp)
|
|
{
|
|
// adjust jump speed by gravity
|
|
psp->jump_speed += psp->jump_grav;
|
|
|
|
// adjust player height by jump speed
|
|
psp->backupy();
|
|
psp->y += psp->jump_speed * synctics * (1. / FRACUNIT);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GRENADE
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void pGrenadePresent(PANEL_SPRITEp psp);
|
|
void pGrenadeRetract(PANEL_SPRITEp psp);
|
|
void pGrenadeAction(PANEL_SPRITEp psp);
|
|
void pGrenadeRest(PANEL_SPRITEp psp);
|
|
void pGrenadeFire(PANEL_SPRITEp psp);
|
|
void pGrenadeHide(PANEL_SPRITEp psp);
|
|
void pGrenadeUnHide(PANEL_SPRITEp psp);
|
|
void pGrenadeRecoilDown(PANEL_SPRITEp psp);
|
|
void pGrenadeRecoilUp(PANEL_SPRITEp psp);
|
|
void pGrenadeBobSetup(PANEL_SPRITEp psp);
|
|
|
|
extern PANEL_STATE ps_GrenadeRecoil[];
|
|
|
|
#define Grenade_REST_RATE 24
|
|
#define Grenade_ACTION_RATE 6
|
|
|
|
PANEL_STATE ps_PresentGrenade[] =
|
|
{
|
|
{ID_GrenadePresent0, Grenade_REST_RATE, pGrenadePresent, &ps_PresentGrenade[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_GrenadeRest[] =
|
|
{
|
|
{ID_GrenadePresent0, Grenade_REST_RATE, pGrenadeRest, &ps_GrenadeRest[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_GrenadeHide[] =
|
|
{
|
|
{ID_GrenadePresent0, Grenade_REST_RATE, pGrenadeHide, &ps_GrenadeHide[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_GrenadeFire[] =
|
|
{
|
|
{ID_GrenadeFire0, Grenade_ACTION_RATE, pGrenadeAction, &ps_GrenadeFire[1], psf_ShadeHalf, 0,0},
|
|
{ID_GrenadeFire1, Grenade_ACTION_RATE, pGrenadeAction, &ps_GrenadeFire[2], psf_ShadeNone, 0,0},
|
|
{ID_GrenadeFire2, Grenade_ACTION_RATE, pGrenadeAction, &ps_GrenadeFire[3], psf_ShadeNone, 0,0},
|
|
|
|
{ID_GrenadePresent0, 0, pGrenadeFire, &ps_GrenadeFire[4], psf_QuickCall, 0,0},
|
|
{ID_GrenadePresent0, 3, pGrenadeAction, &ps_GrenadeRecoil[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_GrenadeRecoil[] =
|
|
{
|
|
// recoil
|
|
{ID_GrenadePresent0, Grenade_REST_RATE, pGrenadeRecoilDown, &ps_GrenadeRecoil[0], 0,0,0},
|
|
{ID_GrenadePresent0, Grenade_REST_RATE, pGrenadeRecoilUp, &ps_GrenadeRecoil[1], 0,0,0},
|
|
// reload
|
|
{ID_GrenadeReload0, Grenade_REST_RATE/2, pNullAnimator, &ps_GrenadeRecoil[3], 0,0,0},
|
|
{ID_GrenadeReload1, Grenade_REST_RATE/2, pNullAnimator, &ps_GrenadeRecoil[4], 0,0,0},
|
|
// ready to fire again
|
|
{ID_GrenadePresent0, 3, pNullAnimator, &ps_GrenadeRest[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_RetractGrenade[] =
|
|
{
|
|
{ID_GrenadePresent0, Grenade_REST_RATE, pGrenadeRetract, &ps_RetractGrenade[0], 0,0,0}
|
|
};
|
|
|
|
#define GRENADE_YOFF 200
|
|
#define GRENADE_XOFF (160+20)
|
|
|
|
void
|
|
pGrenadeSetRecoil(PANEL_SPRITEp psp)
|
|
{
|
|
psp->vel = 900;
|
|
psp->ang = NORM_ANGLE(-256);
|
|
}
|
|
|
|
void
|
|
pGrenadePresentSetup(PANEL_SPRITEp psp)
|
|
{
|
|
psp->rotate_ang = 1800;
|
|
psp->backupcoords();
|
|
psp->y += 34;
|
|
psp->x -= 45;
|
|
psp->ang = 256 + 128;
|
|
psp->vel = 680;
|
|
}
|
|
|
|
void
|
|
InitWeaponGrenade(PLAYERp pp)
|
|
{
|
|
PANEL_SPRITEp psp;
|
|
|
|
if (Prediction)
|
|
return;
|
|
|
|
if (!TEST(pp->WpnFlags, BIT(WPN_GRENADE)) ||
|
|
// pp->WpnAmmo[WPN_GRENADE] <= 0 ||
|
|
TEST(pp->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
if (!pp->Wpn[WPN_GRENADE])
|
|
{
|
|
psp = pp->Wpn[WPN_GRENADE] = pSpawnSprite(pp, ps_PresentGrenade, PRI_MID, GRENADE_XOFF, GRENADE_YOFF);
|
|
psp->y += tileHeight(psp->picndx);
|
|
psp->backupy();
|
|
}
|
|
|
|
if (pp->CurWpn == pp->Wpn[WPN_GRENADE])
|
|
{
|
|
return;
|
|
}
|
|
|
|
PlayerUpdateWeapon(pp, WPN_GRENADE);
|
|
|
|
pp->WpnUziType = 2; // Make uzi's go away!
|
|
RetractCurWpn(pp);
|
|
|
|
// Set up the new weapon variables
|
|
psp = pp->CurWpn = pp->Wpn[WPN_GRENADE];
|
|
psp = pp->CurWpn = pp->Wpn[WPN_GRENADE];
|
|
SET(psp->flags, PANF_WEAPON_SPRITE);
|
|
psp->ActionState = ps_GrenadeFire;
|
|
psp->RetractState = ps_RetractGrenade;
|
|
psp->PresentState = ps_PresentGrenade;
|
|
psp->RestState = ps_GrenadeRest;
|
|
pSetState(psp, psp->PresentState);
|
|
|
|
pGrenadePresentSetup(psp);
|
|
|
|
PlaySound(DIGI_GRENADE_UP, pp, v3df_follow);
|
|
|
|
psp->PlayerP->KeyPressBits |= SB_FIRE;
|
|
}
|
|
|
|
void
|
|
pGrenadeRecoilDown(PANEL_SPRITEp psp)
|
|
{
|
|
// int picnum = psp->picndx;
|
|
|
|
psp->backupcoords();
|
|
|
|
psp->x += pspCosVel(psp);
|
|
psp->y -= pspSinVel(psp);
|
|
|
|
psp->vel -= 24 * synctics;
|
|
|
|
// if (psp->y >= GRENADE_YOFF + tileHeight(picnum))
|
|
if (psp->vel < 400)
|
|
{
|
|
// psp->ox = psp->y = GRENADE_YOFF + tileHeight(picnum);
|
|
|
|
psp->vel = 400;
|
|
psp->ang = NORM_ANGLE(psp->ang + 1024);
|
|
|
|
pStatePlusOne(psp);
|
|
}
|
|
}
|
|
|
|
void
|
|
pGrenadeRecoilUp(PANEL_SPRITEp psp)
|
|
{
|
|
psp->backupcoords();
|
|
|
|
psp->x += pspCosVel(psp);
|
|
psp->y -= pspSinVel(psp);
|
|
|
|
psp->vel += 15 * synctics;
|
|
|
|
if (psp->y < GRENADE_YOFF)
|
|
{
|
|
psp->oy = psp->y = GRENADE_YOFF;
|
|
psp->ox = psp->x = GRENADE_XOFF;
|
|
|
|
pGrenadeSetRecoil(psp);
|
|
|
|
pStatePlusOne(psp);
|
|
RESET(psp->flags, PANF_BOB);
|
|
}
|
|
}
|
|
|
|
void
|
|
pGrenadePresent(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->PlayerP->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
psp->backupcoords();
|
|
|
|
psp->x += pspCosVel(psp);
|
|
psp->y -= pspSinVel(psp);
|
|
|
|
psp->rotate_ang = NORM_ANGLE(psp->rotate_ang + (6 * synctics));
|
|
|
|
if (psp->rotate_ang < 1024)
|
|
psp->rotate_ang = 0;
|
|
|
|
if (psp->y < GRENADE_YOFF)
|
|
{
|
|
pGrenadeSetRecoil(psp);
|
|
psp->ox = psp->x = GRENADE_XOFF;
|
|
psp->oy = psp->y = GRENADE_YOFF;
|
|
psp->rotate_ang = 0;
|
|
psp->backupboby();
|
|
pSetState(psp, psp->RestState);
|
|
}
|
|
}
|
|
|
|
void
|
|
pGrenadeBobSetup(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->flags, PANF_BOB))
|
|
return;
|
|
|
|
psp->backupbobcoords();
|
|
|
|
psp->sin_amt = 12;
|
|
psp->sin_ndx = 0;
|
|
psp->bob_height_divider = 8;
|
|
}
|
|
|
|
void
|
|
pGrenadeHide(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= GRENADE_YOFF + tileHeight(picnum))
|
|
{
|
|
psp->oy = psp->y = GRENADE_YOFF + tileHeight(picnum);
|
|
psp->ox = psp->x = GRENADE_XOFF;
|
|
|
|
pGrenadePresentSetup(psp);
|
|
|
|
pWeaponUnHideKeys(psp, psp->PresentState);
|
|
}
|
|
}
|
|
|
|
void
|
|
pGrenadeRest(PANEL_SPRITEp psp)
|
|
{
|
|
bool force = !!TEST(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (pWeaponHideKeys(psp, ps_GrenadeHide))
|
|
return;
|
|
|
|
pGrenadeBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
|
|
if ((psp->PlayerP->input.actions & SB_FIRE) || force)
|
|
{
|
|
if ((psp->PlayerP->KeyPressBits & SB_FIRE) || force)
|
|
{
|
|
RESET(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (!WeaponOK(psp->PlayerP))
|
|
return;
|
|
|
|
DoPlayerChooseYell(psp->PlayerP);
|
|
pSetState(psp, psp->ActionState);
|
|
}
|
|
}
|
|
else
|
|
WeaponOK(psp->PlayerP);
|
|
}
|
|
|
|
void
|
|
pGrenadeAction(PANEL_SPRITEp psp)
|
|
{
|
|
pGrenadeBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
}
|
|
|
|
|
|
void
|
|
pGrenadeFire(PANEL_SPRITEp psp)
|
|
{
|
|
SpawnVis(psp->PlayerP->Actor(), -1, -1, -1, -1, 32);
|
|
InitGrenade(psp->PlayerP);
|
|
}
|
|
|
|
void
|
|
pGrenadeRetract(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= GRENADE_YOFF + tileHeight(picnum))
|
|
{
|
|
RESET(psp->PlayerP->Flags, PF_WEAPON_RETRACT);
|
|
psp->PlayerP->Wpn[WPN_GRENADE] = nullptr;
|
|
pKillSprite(psp);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// MINE
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void pMinePresent(PANEL_SPRITEp psp);
|
|
void pMineRetract(PANEL_SPRITEp psp);
|
|
void pMineAction(PANEL_SPRITEp psp);
|
|
void pMineRest(PANEL_SPRITEp psp);
|
|
void pMineThrow(PANEL_SPRITEp psp);
|
|
void pMineLower(PANEL_SPRITEp psp);
|
|
void pMineRaise(PANEL_SPRITEp psp);
|
|
void pMineHide(PANEL_SPRITEp psp);
|
|
void pMineUnHide(PANEL_SPRITEp psp);
|
|
void pMineBobSetup(PANEL_SPRITEp psp);
|
|
void pMineUpSound(PANEL_SPRITEp psp);
|
|
|
|
#define Mine_REST_RATE 24
|
|
#define Mine_ACTION_RATE 6
|
|
|
|
PANEL_STATE ps_PresentMine[] =
|
|
{
|
|
{ID_MinePresent0, Mine_REST_RATE, pMinePresent, &ps_PresentMine[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_MineRest[] =
|
|
{
|
|
{ID_MinePresent0, 36, pMineRest, &ps_MineRest[1], 0,0,0},
|
|
{ID_MinePresent0, 0, pMineUpSound, &ps_MineRest[2], psf_QuickCall, 0,0},
|
|
{ID_MinePresent1, Mine_REST_RATE, pMineRest, &ps_MineRest[2], 0,0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_MineHide[] =
|
|
{
|
|
{ID_MinePresent0, Mine_REST_RATE, pMineHide, &ps_MineHide[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_MineThrow[] =
|
|
{
|
|
{ID_MineThrow0, 3, pNullAnimator, &ps_MineThrow[1], 0,0,0},
|
|
{ID_MineThrow0, Mine_ACTION_RATE, pMineThrow, &ps_MineThrow[2],psf_QuickCall, 0,0},
|
|
{ID_MineThrow0, Mine_ACTION_RATE, pMineLower, &ps_MineThrow[2], 0,0,0},
|
|
{ID_MineThrow0, Mine_ACTION_RATE*5, pNullAnimator, &ps_MineThrow[4], 0,0,0},
|
|
{ID_MinePresent0, Mine_ACTION_RATE, pMineRaise, &ps_MineThrow[4], 0,0,0},
|
|
{ID_MinePresent0, Mine_ACTION_RATE, pNullAnimator, &ps_MineThrow[6], 0,0,0},
|
|
{ID_MinePresent0, 3, pMineAction, &ps_MineRest[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_RetractMine[] =
|
|
{
|
|
{ID_MinePresent0, Mine_REST_RATE, pMineRetract, &ps_RetractMine[0], 0,0,0}
|
|
};
|
|
|
|
#define MINE_YOFF 200
|
|
//#define MINE_XOFF (160+20)
|
|
#define MINE_XOFF (160+50)
|
|
|
|
void
|
|
InitWeaponMine(PLAYERp pp)
|
|
{
|
|
PANEL_SPRITEp psp;
|
|
|
|
if (Prediction)
|
|
return;
|
|
|
|
if (pp->WpnAmmo[WPN_MINE] <= 0)
|
|
PutStringInfo(pp,"Out of Sticky Bombs!");
|
|
|
|
if (!TEST(pp->WpnFlags, BIT(WPN_MINE)) ||
|
|
pp->WpnAmmo[WPN_MINE] <= 0 ||
|
|
TEST(pp->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
if (!pp->Wpn[WPN_MINE])
|
|
{
|
|
psp = pp->Wpn[WPN_MINE] = pSpawnSprite(pp, ps_PresentMine, PRI_MID, MINE_XOFF, MINE_YOFF);
|
|
psp->y += tileHeight(psp->picndx);
|
|
psp->backupy();
|
|
}
|
|
|
|
if (pp->CurWpn == pp->Wpn[WPN_MINE])
|
|
{
|
|
return;
|
|
}
|
|
|
|
PlayerUpdateWeapon(pp, WPN_MINE);
|
|
|
|
pp->WpnUziType = 2; // Make uzi's go away!
|
|
RetractCurWpn(pp);
|
|
|
|
// Set up the new weapon variables
|
|
psp = pp->CurWpn = pp->Wpn[WPN_MINE];
|
|
SET(psp->flags, PANF_WEAPON_SPRITE);
|
|
psp->ActionState = ps_MineThrow;
|
|
psp->RetractState = ps_RetractMine;
|
|
psp->PresentState = ps_PresentMine;
|
|
psp->RestState = ps_MineRest;
|
|
pSetState(psp, psp->PresentState);
|
|
|
|
PlaySound(DIGI_PULL, pp, v3df_follow|v3df_dontpan);
|
|
|
|
psp->PlayerP->KeyPressBits |= SB_FIRE;
|
|
}
|
|
|
|
void
|
|
pMineUpSound(PANEL_SPRITEp psp)
|
|
{
|
|
PLAYERp pp = psp->PlayerP;
|
|
|
|
PlaySound(DIGI_MINE_UP, pp, v3df_follow);
|
|
}
|
|
|
|
void
|
|
pMineLower(PANEL_SPRITEp psp)
|
|
{
|
|
psp->backupy();
|
|
psp->y += 4 * synctics;
|
|
|
|
if (psp->y > MINE_YOFF + tileHeight(psp->picndx))
|
|
{
|
|
if (!WeaponOK(psp->PlayerP))
|
|
return;
|
|
psp->oy = psp->y = MINE_YOFF + tileHeight(psp->picndx);
|
|
pStatePlusOne(psp);
|
|
}
|
|
}
|
|
|
|
void
|
|
pMineRaise(PANEL_SPRITEp psp)
|
|
{
|
|
psp->backupy();
|
|
psp->y -= 4 * synctics;
|
|
|
|
if (psp->y < MINE_YOFF)
|
|
{
|
|
psp->oy = psp->y = MINE_YOFF;
|
|
pStatePlusOne(psp);
|
|
}
|
|
}
|
|
|
|
void
|
|
pMinePresent(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->PlayerP->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
psp->backupy();
|
|
psp->y -= 3 * synctics;
|
|
|
|
if (psp->y < MINE_YOFF)
|
|
{
|
|
psp->oy = psp->y = MINE_YOFF;
|
|
psp->rotate_ang = 0;
|
|
psp->backupboby();
|
|
pSetState(psp, psp->RestState);
|
|
}
|
|
}
|
|
|
|
void
|
|
pMineBobSetup(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->flags, PANF_BOB))
|
|
return;
|
|
|
|
psp->backupbobcoords();
|
|
|
|
psp->sin_amt = 12;
|
|
psp->sin_ndx = 0;
|
|
psp->bob_height_divider = 8;
|
|
}
|
|
|
|
void
|
|
pMineHide(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= MINE_YOFF + tileHeight(picnum))
|
|
{
|
|
psp->oy = psp->y = MINE_YOFF + tileHeight(picnum);
|
|
psp->ox = psp->x = MINE_XOFF;
|
|
|
|
pWeaponUnHideKeys(psp, psp->PresentState);
|
|
}
|
|
}
|
|
|
|
void
|
|
pMineRest(PANEL_SPRITEp psp)
|
|
{
|
|
bool force = !!TEST(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (pWeaponHideKeys(psp, ps_MineHide))
|
|
return;
|
|
|
|
pMineBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
|
|
if ((psp->PlayerP->input.actions & SB_FIRE) || force)
|
|
{
|
|
if ((psp->PlayerP->KeyPressBits & SB_FIRE) || force)
|
|
{
|
|
RESET(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
// if (!WeaponOK(psp->PlayerP))
|
|
// return;
|
|
|
|
DoPlayerChooseYell(psp->PlayerP);
|
|
pSetState(psp, psp->ActionState);
|
|
}
|
|
}
|
|
else
|
|
WeaponOK(psp->PlayerP);
|
|
}
|
|
|
|
void
|
|
pMineAction(PANEL_SPRITEp psp)
|
|
{
|
|
pMineBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
}
|
|
|
|
|
|
void
|
|
pMineThrow(PANEL_SPRITEp psp)
|
|
{
|
|
InitMine(psp->PlayerP);
|
|
}
|
|
|
|
void
|
|
pMineRetract(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= MINE_YOFF + tileHeight(picnum))
|
|
{
|
|
RESET(psp->PlayerP->Flags, PF_WEAPON_RETRACT);
|
|
psp->PlayerP->Wpn[WPN_MINE] = nullptr;
|
|
pKillSprite(psp);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CHOP STICKS
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void pChopsUp(PANEL_SPRITEp psp);
|
|
void pChopsDown(PANEL_SPRITEp psp);
|
|
void pChopsDownSlow(PANEL_SPRITEp psp);
|
|
void pChopsWait(PANEL_SPRITEp psp);
|
|
void pChopsShake(PANEL_SPRITEp psp);
|
|
void pChopsClick(PANEL_SPRITEp psp);
|
|
|
|
void pChopsRetract(PANEL_SPRITEp psp);
|
|
|
|
#define Chops_REST_RATE 24
|
|
#define Chops_ACTION_RATE 6
|
|
|
|
#define ID_ChopsRest 2000
|
|
#define ID_ChopsOpen 2001
|
|
#define ID_ChopsClose 2002
|
|
|
|
PANEL_STATE ps_ChopsAttack1[] =
|
|
{
|
|
{ID_ChopsRest, Chops_REST_RATE*3, pNullAnimator, &ps_ChopsAttack1[1], 0,0,0},
|
|
{ID_ChopsRest, Chops_REST_RATE, pChopsUp, &ps_ChopsAttack1[1], 0,0,0},
|
|
{ID_ChopsOpen, Chops_REST_RATE/3, pNullAnimator, &ps_ChopsAttack1[3], 0,0,0},
|
|
{ID_ChopsClose, 0, pChopsClick, &ps_ChopsAttack1[4], psf_QuickCall, 0,0},
|
|
{ID_ChopsClose, Chops_REST_RATE/3, pNullAnimator, &ps_ChopsAttack1[5], 0,0,0},
|
|
{ID_ChopsClose, Chops_REST_RATE, pChopsDown, &ps_ChopsAttack1[5], 0,0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_ChopsAttack2[] =
|
|
{
|
|
{ID_ChopsOpen, Chops_REST_RATE*3, pNullAnimator, &ps_ChopsAttack2[1], 0,0,0},
|
|
{ID_ChopsOpen, Chops_REST_RATE, pChopsUp, &ps_ChopsAttack2[1], 0,0,0},
|
|
{ID_ChopsOpen, 0, pChopsClick, &ps_ChopsAttack2[3], psf_QuickCall, 0,0},
|
|
{ID_ChopsOpen, 8, pNullAnimator, &ps_ChopsAttack2[4], 0,0,0},
|
|
{ID_ChopsRest, Chops_REST_RATE, pNullAnimator, &ps_ChopsAttack2[5], 0,0,0},
|
|
{ID_ChopsRest, Chops_REST_RATE, pChopsDown, &ps_ChopsAttack2[5], 0,0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_ChopsAttack3[] =
|
|
{
|
|
{ID_ChopsOpen, Chops_REST_RATE*3, pNullAnimator, &ps_ChopsAttack3[1], 0,0,0},
|
|
{ID_ChopsOpen, Chops_REST_RATE, pChopsUp, &ps_ChopsAttack3[1], 0,0,0},
|
|
|
|
{ID_ChopsRest, 0, pNullAnimator, &ps_ChopsAttack3[3], 0,0,0},
|
|
{ID_ChopsRest, 0, pChopsClick, &ps_ChopsAttack3[4], psf_QuickCall, 0,0},
|
|
|
|
{ID_ChopsRest, Chops_REST_RATE, pNullAnimator, &ps_ChopsAttack3[5], 0,0,0},
|
|
{ID_ChopsRest, 24, pNullAnimator, &ps_ChopsAttack3[6], 0,0,0},
|
|
{ID_ChopsOpen, 16, pNullAnimator, &ps_ChopsAttack3[7], 0,0,0},
|
|
|
|
{ID_ChopsRest, 0, pChopsClick, &ps_ChopsAttack3[8], psf_QuickCall, 0,0},
|
|
{ID_ChopsRest, 16, pNullAnimator, &ps_ChopsAttack3[9], 0,0,0},
|
|
{ID_ChopsOpen, 16, pNullAnimator, &ps_ChopsAttack3[10], 0,0,0},
|
|
|
|
{ID_ChopsOpen, 8, pChopsDownSlow, &ps_ChopsAttack3[11], 0,0,0},
|
|
{ID_ChopsRest, 10, pChopsDownSlow, &ps_ChopsAttack3[12], 0,0,0},
|
|
{ID_ChopsRest, 0, pChopsClick, &ps_ChopsAttack3[13], psf_QuickCall, 0,0},
|
|
{ID_ChopsRest, 10, pChopsDownSlow, &ps_ChopsAttack3[14], 0,0,0},
|
|
{ID_ChopsOpen, 10, pChopsDownSlow, &ps_ChopsAttack3[11], 0,0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_ChopsAttack4[] =
|
|
{
|
|
{ID_ChopsOpen, Chops_REST_RATE*3, pNullAnimator, &ps_ChopsAttack4[1], 0,0,0},
|
|
{ID_ChopsOpen, Chops_REST_RATE, pChopsUp, &ps_ChopsAttack4[1], 0,0,0},
|
|
|
|
{ID_ChopsOpen, 0, pChopsClick, &ps_ChopsAttack4[3], psf_QuickCall, 0,0},
|
|
{ID_ChopsOpen, 8, pNullAnimator, &ps_ChopsAttack4[4], 0,0,0},
|
|
|
|
{ID_ChopsRest, Chops_REST_RATE, pNullAnimator, &ps_ChopsAttack4[5], 0,0,0},
|
|
{ID_ChopsRest, Chops_REST_RATE*4, pChopsShake, &ps_ChopsAttack4[6], 0,0,0},
|
|
{ID_ChopsRest, Chops_REST_RATE, pChopsDown, &ps_ChopsAttack4[6], 0,0,0},
|
|
};
|
|
|
|
PANEL_STATEp psp_ChopsAttack[] = {ps_ChopsAttack1, ps_ChopsAttack2, ps_ChopsAttack3, ps_ChopsAttack4};
|
|
|
|
PANEL_STATE ps_ChopsWait[] =
|
|
{
|
|
{ID_ChopsRest, Chops_REST_RATE, pChopsWait, &ps_ChopsWait[0], 0,0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_ChopsRetract[] =
|
|
{
|
|
{ID_ChopsRest, Chops_REST_RATE, pChopsRetract, &ps_ChopsRetract[0], 0,0,0}
|
|
};
|
|
|
|
#define CHOPS_YOFF 200
|
|
#define CHOPS_XOFF (160+20)
|
|
|
|
void
|
|
InitChops(PLAYERp pp)
|
|
{
|
|
PANEL_SPRITEp psp;
|
|
|
|
if (!pp->Chops)
|
|
{
|
|
psp = pp->Chops = pSpawnSprite(pp, ps_ChopsAttack1, PRI_MID, CHOPS_XOFF, CHOPS_YOFF);
|
|
psp->y += tileHeight(psp->picndx);
|
|
psp->backupy();
|
|
}
|
|
|
|
if (Prediction)
|
|
return;
|
|
|
|
// Set up the new weapon variables
|
|
psp = pp->Chops;
|
|
|
|
SET(psp->flags, PANF_WEAPON_SPRITE);
|
|
psp->ActionState = ps_ChopsAttack1;
|
|
psp->PresentState = ps_ChopsAttack1;
|
|
psp->RetractState = ps_ChopsRetract;
|
|
psp->RestState = ps_ChopsAttack1;
|
|
|
|
PlaySound(DIGI_BUZZZ, psp->PlayerP,v3df_none);
|
|
|
|
if (RandomRange(1000) > 750)
|
|
PlayerSound(DIGI_MRFLY,v3df_follow|v3df_dontpan,psp->PlayerP);
|
|
|
|
}
|
|
|
|
void
|
|
pChopsClick(PANEL_SPRITEp psp)
|
|
{
|
|
int16_t rnd_rng;
|
|
PlaySound(DIGI_CHOP_CLICK,psp->PlayerP,v3df_none);
|
|
|
|
rnd_rng = RandomRange(1000);
|
|
if (rnd_rng > 950)
|
|
PlayerSound(DIGI_SEARCHWALL,v3df_follow|v3df_dontpan,psp->PlayerP);
|
|
else if (rnd_rng > 900)
|
|
PlayerSound(DIGI_EVADEFOREVER,v3df_follow|v3df_dontpan,psp->PlayerP);
|
|
else if (rnd_rng > 800)
|
|
PlayerSound(DIGI_SHISEISI,v3df_follow|v3df_dontpan,psp->PlayerP);
|
|
}
|
|
|
|
void
|
|
pChopsUp(PANEL_SPRITEp psp)
|
|
{
|
|
psp->backupy();
|
|
psp->y -= 3 * synctics;
|
|
|
|
if (psp->y < CHOPS_YOFF)
|
|
{
|
|
psp->oy = psp->y = CHOPS_YOFF;
|
|
pStatePlusOne(psp);
|
|
}
|
|
}
|
|
|
|
void
|
|
pChopsDown(PANEL_SPRITEp psp)
|
|
{
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y > CHOPS_YOFF+110)
|
|
{
|
|
psp->oy = psp->y = CHOPS_YOFF+110;
|
|
pSetState(psp, ps_ChopsWait);
|
|
}
|
|
}
|
|
|
|
void
|
|
pChopsDownSlow(PANEL_SPRITEp psp)
|
|
{
|
|
psp->backupy();
|
|
psp->y += 1 * synctics;
|
|
|
|
if (psp->y > CHOPS_YOFF+110)
|
|
{
|
|
psp->oy = psp->y = CHOPS_YOFF+110;
|
|
pSetState(psp, ps_ChopsWait);
|
|
}
|
|
}
|
|
|
|
void
|
|
pChopsShake(PANEL_SPRITEp psp)
|
|
{
|
|
psp->backupcoords();
|
|
|
|
psp->x += (RANDOM_P2(4<<8) * (1. / 256.)) - 2;
|
|
psp->y += (RANDOM_P2(4<<8) * (1. / 256.)) - 2;
|
|
|
|
if (psp->y < CHOPS_YOFF)
|
|
{
|
|
psp->oy = psp->y = CHOPS_YOFF;
|
|
}
|
|
}
|
|
|
|
void
|
|
pChopsWait(PANEL_SPRITEp psp)
|
|
{
|
|
//if (!paused && RANDOM_P2(1024) < 10)
|
|
if (RANDOM_P2(1024) < 10)
|
|
{
|
|
// random x position
|
|
// do a random attack here
|
|
psp->ox = psp->x = CHOPS_XOFF + (RANDOM_P2(128) - 64);
|
|
|
|
PlaySound(DIGI_BUZZZ,psp->PlayerP,v3df_none);
|
|
pSetState(psp, psp_ChopsAttack[RandomRange(SIZ(psp_ChopsAttack))]);
|
|
}
|
|
}
|
|
|
|
void ChopsSetRetract(PLAYERp pp)
|
|
{
|
|
if (pp == nullptr || pp->Chops == nullptr)
|
|
return;
|
|
|
|
pSetState(pp->Chops, pp->Chops->RetractState);
|
|
}
|
|
|
|
void
|
|
pChopsRetract(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 6 * synctics;
|
|
|
|
if (psp->y >= CHOPS_YOFF + tileHeight(picnum))
|
|
{
|
|
if (RandomRange(1000) > 800)
|
|
PlayerSound(DIGI_GETTINGSTIFF,v3df_follow|v3df_dontpan,psp->PlayerP);
|
|
psp->PlayerP->Chops = nullptr;
|
|
pKillSprite(psp);
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FIST
|
|
//
|
|
// KungFu Move Numbers: (Used to calculate damages, etc....
|
|
// 0: Normal Punch
|
|
// 1: Palm Heel Strike
|
|
// 2: Kick
|
|
// 3: Block
|
|
// 4: FISTS OF FURY - (Flury of fast punches) DUCK, then BLOCK and ATTACK
|
|
// 5: CHI STRIKE - (Devastating Palm Heel) DUCK 2 secs, then ATTACK
|
|
// 6: DEATH TOUCH - (Make enemy bleed and does alot of damage) JUMP, DUCK, BLOCK, ATTACK
|
|
// 7: FIREBALL - BLOCK 4 secs, then ATTACK
|
|
// 8: HAMMER KICK - Run forward while holding BLOCK, JUMP, ATTACK
|
|
// 9: CYCLONE KICK - (Spin 5 circles with leg out to hit multiples)
|
|
// 180 KEY, BLOCK, JUMP, ATTACK
|
|
// 10: DESPERATION - Finish Move (Cling to enemy like sticky bomb and beat the crap out of him)
|
|
// Player is invincible until he unattaches
|
|
// LOW HEALTH < 20, TOUCH ENEMY, BLOCK then ATTACK
|
|
// 11: SUPER NOVA - Become a human nuclear bomb!
|
|
// SUPER SECRET MOVE
|
|
// >150 Health + >50 Armor + Shadow Spell ACTIVE, DUCK + BLOCK 3 secs, JUMP, ATTACK
|
|
// Player will die, so it's only useful if you get more than 1 frag in the deal.
|
|
// 12: TOTAL INVISIBILITY - Worse than shadow spell, you go 100% invisible for 10 secs!
|
|
// SUPER SECRET MOVE
|
|
// >180 Health + Shadow Spell ACTIVE, BLOCK 4 secs, JUMP, ATTACK
|
|
// 13: FREEZE - Turn all enemies in your view to ice for 10 secs
|
|
// SUPER SECRET MOVE
|
|
// 100 Armor + Shadow Spell ACTIVE, BLOCK 5 secs, DUCK, ATTACK
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static short FistAngTable[] =
|
|
{
|
|
82,
|
|
168,
|
|
256+64
|
|
};
|
|
|
|
short FistAng = 0;
|
|
|
|
void
|
|
FistBlur(PANEL_SPRITEp psp)
|
|
{
|
|
psp->kill_tics -= synctics;
|
|
if (psp->kill_tics <= 0)
|
|
{
|
|
pKillSprite(psp);
|
|
return;
|
|
}
|
|
else if (psp->kill_tics <= 6)
|
|
{
|
|
SET(psp->flags, PANF_TRANS_FLIP);
|
|
}
|
|
|
|
psp->shade += 10;
|
|
// change sprites priority
|
|
REMOVE(psp);
|
|
psp->priority--;
|
|
InsertPanelSprite(psp->PlayerP, psp);
|
|
}
|
|
|
|
void
|
|
SpawnFistBlur(PANEL_SPRITEp psp)
|
|
{
|
|
if (cl_nomeleeblur) return;
|
|
|
|
PANEL_SPRITEp nsp;
|
|
//PICITEMp pip;
|
|
|
|
if (psp->PlayerP->FistAng > 200)
|
|
return;
|
|
|
|
nsp = pSpawnSprite(psp->PlayerP, nullptr, PRI_BACK, psp->x, psp->y);
|
|
|
|
SET(nsp->flags, PANF_WEAPON_SPRITE);
|
|
nsp->ang = psp->ang;
|
|
nsp->vel = psp->vel;
|
|
nsp->PanelSpriteFunc = FistBlur;
|
|
nsp->kill_tics = 9;
|
|
nsp->shade = psp->shade + 10;
|
|
|
|
nsp->picndx = -1;
|
|
nsp->picnum = psp->picndx;
|
|
|
|
if (TEST(psp->State->flags, psf_Xflip))
|
|
SET(nsp->flags, PANF_XFLIP);
|
|
|
|
nsp->rotate_ang = psp->rotate_ang;
|
|
nsp->scale = psp->scale;
|
|
|
|
SET(nsp->flags, PANF_TRANSLUCENT);
|
|
}
|
|
|
|
void pFistPresent(PANEL_SPRITEp psp);
|
|
void pFistRetract(PANEL_SPRITEp psp);
|
|
void pFistAction(PANEL_SPRITEp psp);
|
|
void pFistRest(PANEL_SPRITEp psp);
|
|
void pFistAttack(PANEL_SPRITEp psp);
|
|
void pFistSlide(PANEL_SPRITEp psp);
|
|
void pFistSlideDown(PANEL_SPRITEp psp);
|
|
void pFistHide(PANEL_SPRITEp psp);
|
|
void pFistUnHide(PANEL_SPRITEp psp);
|
|
|
|
void pFistSlideR(PANEL_SPRITEp psp);
|
|
void pFistSlideDownR(PANEL_SPRITEp psp);
|
|
void pFistBlock(PANEL_SPRITEp psp);
|
|
|
|
extern PANEL_STATE ps_FistSwing[];
|
|
extern PANEL_STATE ps_ReloadFist[];
|
|
|
|
#define Fist_BEAT_RATE 16
|
|
#define Fist_ACTION_RATE 5
|
|
|
|
PANEL_STATE ps_PresentFist[] =
|
|
{
|
|
{ID_FistPresent0, Fist_BEAT_RATE, pFistPresent, &ps_PresentFist[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_FistRest[] =
|
|
{
|
|
{ID_FistPresent0, Fist_BEAT_RATE, pFistRest, &ps_FistRest[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_FistHide[] =
|
|
{
|
|
{ID_FistPresent0, Fist_BEAT_RATE, pFistHide, &ps_FistHide[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_PresentFist2[] =
|
|
{
|
|
{ID_Fist2Present0, Fist_BEAT_RATE, pFistPresent, &ps_PresentFist2[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_Fist2Rest[] =
|
|
{
|
|
{ID_Fist2Present0, Fist_BEAT_RATE, pFistRest, &ps_Fist2Rest[0], 0,0,0}
|
|
};
|
|
|
|
PANEL_STATE ps_Fist2Hide[] =
|
|
{
|
|
{ID_Fist2Present0, Fist_BEAT_RATE, pFistHide, &ps_Fist2Hide[0], 0,0,0}
|
|
};
|
|
|
|
|
|
#define FIST_PAUSE_TICS 6
|
|
#define FIST_SLIDE_TICS 6
|
|
#define FIST_MID_SLIDE_TICS 16
|
|
|
|
PANEL_STATE ps_FistSwing[] =
|
|
{
|
|
{ID_FistSwing0, FIST_PAUSE_TICS, pNullAnimator, &ps_FistSwing[1], 0,0,0},
|
|
{ID_FistSwing1, FIST_SLIDE_TICS, /* start slide */ pNullAnimator, &ps_FistSwing[2], 0,0,0},
|
|
{ID_FistSwing2, 0, /* damage */ pFistAttack, &ps_FistSwing[3], psf_QuickCall, 0,0},
|
|
{ID_FistSwing2, FIST_MID_SLIDE_TICS, /* mid slide */ pFistSlideDown, &ps_FistSwing[4], 0,0,0},
|
|
|
|
{ID_FistSwing2, 2, /* end slide */ pFistSlideDown, &ps_FistSwing[4], 0,0,0},
|
|
|
|
{ID_FistSwing1, FIST_SLIDE_TICS, /* start slide */ pFistSlideR, &ps_FistSwing[6], psf_Xflip, 0,0},
|
|
{ID_FistSwing2, 0, /* damage */ pFistAttack, &ps_FistSwing[7], psf_QuickCall|psf_Xflip, 0,0},
|
|
{ID_FistSwing2, FIST_MID_SLIDE_TICS, /* mid slide */ pFistSlideDownR, &ps_FistSwing[8], psf_Xflip, 0,0},
|
|
|
|
{ID_FistSwing2, 2, /* end slide */ pFistSlideDownR, &ps_FistSwing[8], psf_Xflip, 0,0},
|
|
{ID_FistSwing2, 2, /* end slide */ pNullAnimator, &ps_FistSwing[1], psf_Xflip, 0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_Fist2Swing[] =
|
|
{
|
|
{4058, FIST_PAUSE_TICS, pNullAnimator, &ps_Fist2Swing[1], 0,0,0},
|
|
{4058, FIST_SLIDE_TICS, /* start slide */ pNullAnimator, &ps_Fist2Swing[2], 0,0,0},
|
|
{4058, 0, /* damage */ pFistBlock, &ps_Fist2Swing[0], psf_QuickCall, 0,0},
|
|
{4058, FIST_MID_SLIDE_TICS+5, /* mid slide */ pFistSlideDown, &ps_Fist2Swing[4], 0,0,0},
|
|
|
|
{4058, 2, /* end slide */ pFistSlideDown, &ps_Fist2Swing[4], 0,0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_Fist3Swing[] =
|
|
{
|
|
{ID_Fist3Swing0, FIST_PAUSE_TICS+25, pNullAnimator, &ps_Fist3Swing[1], 0,0,0},
|
|
{ID_Fist3Swing1, 0, /* damage */ pFistAttack, &ps_Fist3Swing[2], psf_QuickCall, 0,0},
|
|
{ID_Fist3Swing2, FIST_PAUSE_TICS+10, pNullAnimator, &ps_Fist3Swing[3], 0,0,0},
|
|
{ID_Fist3Swing2, FIST_MID_SLIDE_TICS+3, /* mid slide */ pFistSlideDown, &ps_Fist3Swing[4], 0,0,0},
|
|
|
|
{ID_Fist3Swing2, 8, /* end slide */ pFistSlideDown, &ps_Fist3Swing[4], 0,0,0},
|
|
|
|
{ID_Fist3Swing1, FIST_SLIDE_TICS+20, /* start slide */ pFistSlideR, &ps_Fist3Swing[6], psf_Xflip, 0,0},
|
|
{ID_Fist3Swing2, 0, /* damage */ pFistAttack, &ps_Fist3Swing[7], psf_QuickCall|psf_Xflip, 0,0},
|
|
{ID_Fist3Swing2, FIST_MID_SLIDE_TICS+3, /* mid slide */ pFistSlideDownR, &ps_Fist3Swing[8], psf_Xflip, 0,0},
|
|
|
|
{ID_Fist3Swing2, 8, /* end slide */ pFistSlideDownR, &ps_Fist3Swing[8], psf_Xflip, 0,0},
|
|
{ID_Fist3Swing2, 8, /* end slide */ pNullAnimator, &ps_Fist3Swing[1], psf_Xflip, 0,0},
|
|
};
|
|
|
|
#define KICK_PAUSE_TICS 40
|
|
#define KICK_SLIDE_TICS 30
|
|
#define KICK_MID_SLIDE_TICS 20
|
|
|
|
PANEL_STATE ps_Kick[] =
|
|
{
|
|
{ID_Kick0, KICK_PAUSE_TICS, pNullAnimator, &ps_Kick[1], 0,0,0},
|
|
{ID_Kick1, 0, /* damage */ pFistAttack, &ps_Kick[2], psf_QuickCall, 0,0},
|
|
{ID_Kick1, KICK_SLIDE_TICS, /* start slide */ pNullAnimator, &ps_Kick[3], 0,0,0},
|
|
{ID_Kick1, KICK_MID_SLIDE_TICS, /* mid slide */ pFistSlideDown, &ps_Kick[4], 0,0,0},
|
|
|
|
{ID_Kick1, 30, /* end slide */ pFistSlideDown, &ps_Kick[4], 0,0,0},
|
|
|
|
{ID_Kick0, KICK_SLIDE_TICS, /* start slide */ pNullAnimator, &ps_Kick[6], psf_Xflip, 0,0},
|
|
{ID_Kick1, 0, /* damage */ pFistAttack, &ps_Kick[7], psf_QuickCall|psf_Xflip, 0,0},
|
|
{ID_Kick1, KICK_MID_SLIDE_TICS,/* mid slide */ pFistSlideDownR, &ps_Kick[8], psf_Xflip, 0, 0},
|
|
|
|
{ID_Kick1, 30, /* end slide */ pFistSlideDownR, &ps_Kick[8], psf_Xflip, 0,0},
|
|
{ID_Kick1, 30, /* end slide */ pNullAnimator, &ps_Kick[1], psf_Xflip, 0,0},
|
|
};
|
|
|
|
PANEL_STATE ps_RetractFist[] =
|
|
{
|
|
{ID_FistPresent0, Fist_BEAT_RATE, pFistRetract, &ps_RetractFist[0], 0,0,0}
|
|
};
|
|
|
|
#define FIST_SWAY_AMT 12
|
|
|
|
// left swing
|
|
#define FIST_XOFF (290 + FIST_SWAY_AMT)
|
|
#define FIST_YOFF 200
|
|
|
|
// right swing
|
|
#define FISTR_XOFF (0 - 80)
|
|
|
|
#define FIST_VEL 3000
|
|
#define FIST_POWER_VEL 3000
|
|
|
|
void
|
|
InitWeaponFist(PLAYERp pp)
|
|
{
|
|
PANEL_SPRITEp psp;
|
|
short rnd_num;
|
|
|
|
|
|
if (Prediction)
|
|
return;
|
|
|
|
if (!TEST(pp->WpnFlags, BIT(WPN_FIST)) ||
|
|
//pp->WpnAmmo[WPN_FIST] <= 0 ||
|
|
TEST(pp->Flags, PF_WEAPON_RETRACT))
|
|
{
|
|
pp->WpnFirstType = WPN_SWORD;
|
|
InitWeaponSword(pp);
|
|
return;
|
|
}
|
|
|
|
if (!pp->Wpn[WPN_FIST])
|
|
{
|
|
psp = pp->Wpn[WPN_FIST] = pSpawnSprite(pp, ps_PresentFist, PRI_MID, FIST_XOFF, FIST_YOFF);
|
|
psp->y += tileHeight(psp->picndx);
|
|
psp->backupy();
|
|
}
|
|
|
|
if (pp->CurWpn == pp->Wpn[WPN_FIST])
|
|
{
|
|
return;
|
|
}
|
|
|
|
PlayerUpdateWeapon(pp, WPN_FIST);
|
|
|
|
pp->WpnUziType = 2; // Make uzi's go away!
|
|
RetractCurWpn(pp);
|
|
|
|
// Set up the new weapon variables
|
|
psp = pp->CurWpn = pp->Wpn[WPN_FIST];
|
|
SET(psp->flags, PANF_WEAPON_SPRITE);
|
|
psp->ActionState = ps_FistSwing;
|
|
psp->RetractState = ps_RetractFist;
|
|
psp->PresentState = ps_PresentFist;
|
|
psp->RestState = ps_FistRest;
|
|
pSetState(psp, psp->PresentState);
|
|
|
|
pp->WpnKungFuMove = 0; // Set to default strike
|
|
|
|
rnd_num = RANDOM_P2(1024);
|
|
if (rnd_num > 900)
|
|
PlaySound(DIGI_TAUNTAI2, pp, v3df_follow|v3df_dontpan);
|
|
else if (rnd_num > 800)
|
|
PlaySound(DIGI_PLAYERYELL1, pp, v3df_follow|v3df_dontpan);
|
|
else if (rnd_num > 700)
|
|
PlaySound(DIGI_PLAYERYELL2, pp, v3df_follow|v3df_dontpan);
|
|
|
|
psp->PlayerP->KeyPressBits |= SB_FIRE;
|
|
}
|
|
|
|
|
|
void
|
|
pFistPresent(PANEL_SPRITEp psp)
|
|
{
|
|
int rnd;
|
|
|
|
if (TEST(psp->PlayerP->Flags, PF_WEAPON_RETRACT))
|
|
return;
|
|
|
|
psp->backupy();
|
|
psp->y -= 3 * synctics;
|
|
|
|
if (psp->y < FIST_YOFF)
|
|
{
|
|
psp->oy = psp->y = FIST_YOFF;
|
|
psp->backupboby();
|
|
|
|
rnd = RandomRange(1000);
|
|
if (rnd > 500)
|
|
{
|
|
psp->PresentState = ps_PresentFist;
|
|
psp->RestState = ps_FistRest;
|
|
}
|
|
else
|
|
{
|
|
psp->PresentState = ps_PresentFist2;
|
|
psp->RestState = ps_Fist2Rest;
|
|
}
|
|
pSetState(psp, psp->RestState);
|
|
}
|
|
}
|
|
|
|
//
|
|
// LEFT SWING
|
|
//
|
|
|
|
void
|
|
pFistSlide(PANEL_SPRITEp psp)
|
|
{
|
|
SpawnFistBlur(psp);
|
|
|
|
//psp->backupx();
|
|
psp->backupy();
|
|
|
|
//psp->x += pspSinVel(psp);
|
|
psp->y -= pspSinVel(psp);
|
|
|
|
psp->vel += 68 * synctics;
|
|
}
|
|
|
|
void
|
|
pFistSlideDown(PANEL_SPRITEp psp)
|
|
{
|
|
SpawnFistBlur(psp);
|
|
|
|
short vel = 3500;
|
|
auto ang = FistAng + psp->ang + psp->PlayerP->FistAng;
|
|
|
|
psp->backupcoords();
|
|
|
|
if (psp->ActionState == ps_Kick || psp->PlayerP->WpnKungFuMove == 3)
|
|
{
|
|
psp->y -= pspSinVel(psp, ang);
|
|
}
|
|
else
|
|
{
|
|
psp->x -= pspSinVel(psp, ang);
|
|
psp->y -= pspSinVel(psp, ang) * synctics;
|
|
}
|
|
|
|
psp->vel += 48 * synctics;
|
|
|
|
if (psp->y > 440)
|
|
{
|
|
// if still holding down the fire key - continue swinging
|
|
if (psp->PlayerP->input.actions & SB_FIRE)
|
|
{
|
|
if (psp->PlayerP->KeyPressBits & SB_FIRE)
|
|
{
|
|
DoPlayerChooseYell(psp->PlayerP);
|
|
|
|
if (RandomRange(1000) > 500)
|
|
{
|
|
//if(RandomRange(1000) > 300)
|
|
// {
|
|
psp->ActionState = ps_FistSwing;
|
|
psp->PlayerP->WpnKungFuMove = 0;
|
|
// } else
|
|
// {
|
|
// psp->ActionState = ps_Fist3Swing;
|
|
// psp->PlayerP->WpnKungFuMove = 1;
|
|
// }
|
|
pSetState(psp, psp->ActionState);
|
|
|
|
psp->ox = psp->x = FIST_XOFF;
|
|
psp->oy = psp->y = FIST_YOFF;
|
|
psp->backupboby();
|
|
psp->PlayerP->FistAng = FistAngTable[RandomRange(SIZ(FistAngTable))];
|
|
psp->ang = 1024;
|
|
psp->vel = vel;
|
|
DoPlayerSpriteThrow(psp->PlayerP);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
pSetState(psp, ps_FistSwing+(psp->State - psp->ActionState)+1);
|
|
psp->ActionState = ps_FistSwing;
|
|
psp->PlayerP->WpnKungFuMove = 0;
|
|
}
|
|
|
|
psp->ox = psp->x = FISTR_XOFF+100;
|
|
psp->oy = psp->y = FIST_YOFF;
|
|
psp->backupboby();
|
|
psp->ang = 1024;
|
|
psp->PlayerP->FistAng = FistAngTable[RandomRange(SIZ(FistAngTable))];
|
|
psp->vel = vel;
|
|
DoPlayerSpriteThrow(psp->PlayerP);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// NOT still holding down the fire key - stop swinging
|
|
pSetState(psp, psp->PresentState);
|
|
psp->ox = psp->x = FIST_XOFF;
|
|
psp->oy = psp->y = FIST_YOFF + tileHeight(psp->picndx);
|
|
psp->backupboby();
|
|
}
|
|
}
|
|
|
|
//
|
|
// RIGHT SWING
|
|
//
|
|
|
|
void
|
|
pFistSlideR(PANEL_SPRITEp psp)
|
|
{
|
|
SpawnFistBlur(psp);
|
|
|
|
//psp->backupx();
|
|
psp->backupy();
|
|
|
|
//psp->x += pspSinVel(psp);
|
|
psp->y += pspSinVel(psp);
|
|
|
|
psp->vel += 68 * synctics;
|
|
}
|
|
|
|
void
|
|
pFistSlideDownR(PANEL_SPRITEp psp)
|
|
{
|
|
SpawnFistBlur(psp);
|
|
|
|
short vel = 3500;
|
|
auto ang = FistAng + psp->ang + psp->PlayerP->FistAng;
|
|
|
|
psp->backupcoords();
|
|
|
|
if (psp->ActionState == ps_Kick || psp->PlayerP->WpnKungFuMove == 3)
|
|
{
|
|
psp->y -= pspSinVel(psp, ang);
|
|
}
|
|
else
|
|
{
|
|
psp->x -= pspSinVel(psp, ang);
|
|
psp->y -= pspSinVel(psp, ang) * synctics;
|
|
}
|
|
|
|
psp->vel += 48 * synctics;
|
|
|
|
if (psp->y > 440)
|
|
{
|
|
// if still holding down the fire key - continue swinging
|
|
if (psp->PlayerP->input.actions & SB_FIRE)
|
|
{
|
|
if (psp->PlayerP->KeyPressBits & SB_FIRE)
|
|
{
|
|
DoPlayerChooseYell(psp->PlayerP);
|
|
|
|
if (RandomRange(1000) > 500)
|
|
{
|
|
psp->ActionState = ps_FistSwing+5;
|
|
psp->PlayerP->WpnKungFuMove = 0;
|
|
pSetState(psp, psp->ActionState);
|
|
|
|
psp->ox = psp->x = FISTR_XOFF+100;
|
|
psp->oy = psp->y = FIST_YOFF;
|
|
psp->backupboby();
|
|
psp->ang = 1024;
|
|
psp->PlayerP->FistAng = FistAngTable[RandomRange(SIZ(FistAngTable))];
|
|
psp->vel = vel;
|
|
DoPlayerSpriteThrow(psp->PlayerP);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
pSetState(psp, ps_FistSwing+(psp->State - psp->ActionState)+1);
|
|
psp->ActionState = ps_FistSwing;
|
|
psp->PlayerP->WpnKungFuMove = 0;
|
|
}
|
|
|
|
psp->ox = psp->x = FIST_XOFF;
|
|
psp->oy = psp->y = FIST_YOFF;
|
|
psp->backupboby();
|
|
psp->PlayerP->FistAng = FistAngTable[RandomRange(SIZ(FistAngTable))];
|
|
psp->ang = 1024;
|
|
psp->vel = vel;
|
|
DoPlayerSpriteThrow(psp->PlayerP);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// NOT still holding down the fire key - stop swinging
|
|
pSetState(psp, psp->PresentState);
|
|
psp->ox = psp->x = FIST_XOFF;
|
|
psp->oy = psp->y = FIST_YOFF + tileHeight(psp->picndx);
|
|
psp->backupboby();
|
|
}
|
|
}
|
|
|
|
void
|
|
pFistBobSetup(PANEL_SPRITEp psp)
|
|
{
|
|
if (TEST(psp->flags, PANF_BOB))
|
|
return;
|
|
|
|
psp->backupbobcoords();
|
|
|
|
psp->sin_amt = FIST_SWAY_AMT;
|
|
psp->sin_ndx = 0;
|
|
psp->bob_height_divider = 8;
|
|
}
|
|
|
|
void
|
|
pFistHide(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= FIST_YOFF + tileHeight(picnum))
|
|
{
|
|
psp->oy = psp->y = FIST_YOFF + tileHeight(picnum);
|
|
|
|
pWeaponUnHideKeys(psp, psp->PresentState);
|
|
}
|
|
}
|
|
|
|
void
|
|
pFistRest(PANEL_SPRITEp psp)
|
|
{
|
|
bool force = !!TEST(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (pWeaponHideKeys(psp, ps_FistHide))
|
|
return;
|
|
|
|
psp->yorig += synctics;
|
|
|
|
if (psp->yorig > FIST_YOFF)
|
|
{
|
|
psp->yorig = FIST_YOFF;
|
|
}
|
|
|
|
pFistBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
|
|
force = !!TEST(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
if (psp->ActionState == ps_Kick)
|
|
psp->ActionState = ps_FistSwing;
|
|
|
|
// Reset move to default
|
|
psp->PlayerP->WpnKungFuMove = 0;
|
|
|
|
if ((psp->PlayerP->input.actions & SB_FIRE) || force)
|
|
{
|
|
if ((psp->PlayerP->KeyPressBits & SB_FIRE) || force)
|
|
{
|
|
RESET(psp->flags, PANF_UNHIDE_SHOOT);
|
|
|
|
psp->ActionState = ps_FistSwing;
|
|
psp->PlayerP->WpnKungFuMove = 0;
|
|
|
|
pSetState(psp, psp->ActionState);
|
|
|
|
psp->vel = 5500;
|
|
|
|
psp->ang = 1024;
|
|
psp->PlayerP->FistAng = FistAngTable[RandomRange(SIZ(FistAngTable))];
|
|
DoPlayerSpriteThrow(psp->PlayerP);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
pFistAction(PANEL_SPRITEp psp)
|
|
{
|
|
pFistBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
}
|
|
|
|
|
|
void
|
|
pFistAttack(PANEL_SPRITEp psp)
|
|
{
|
|
InitFistAttack(psp->PlayerP);
|
|
}
|
|
|
|
void
|
|
pFistRetract(PANEL_SPRITEp psp)
|
|
{
|
|
int picnum = psp->picndx;
|
|
|
|
psp->backupy();
|
|
psp->y += 3 * synctics;
|
|
|
|
if (psp->y >= FIST_YOFF + tileHeight(picnum))
|
|
{
|
|
RESET(psp->PlayerP->Flags, PF_WEAPON_RETRACT);
|
|
psp->PlayerP->Wpn[WPN_FIST] = nullptr;
|
|
pKillSprite(psp);
|
|
}
|
|
}
|
|
|
|
void
|
|
pFistBlock(PANEL_SPRITEp psp)
|
|
{
|
|
psp->yorig += synctics;
|
|
|
|
if (psp->yorig > FIST_YOFF)
|
|
{
|
|
psp->yorig = FIST_YOFF;
|
|
}
|
|
|
|
pFistBobSetup(psp);
|
|
pWeaponBob(psp, PLAYER_MOVING(psp->PlayerP));
|
|
|
|
if (!(psp->PlayerP->input.actions & SB_OPEN))
|
|
{
|
|
pStatePlusOne(psp);
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANEL SPRITE GENERAL ROUTINES
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void
|
|
pWeaponForceRest(PLAYERp pp)
|
|
{
|
|
pSetState(pp->CurWpn, pp->CurWpn->RestState);
|
|
}
|
|
|
|
bool
|
|
pWeaponUnHideKeys(PANEL_SPRITEp psp, PANEL_STATEp state)
|
|
{
|
|
// initing the other weapon will take care of this
|
|
if (TEST(psp->flags, PANF_DEATH_HIDE))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (TEST(psp->flags, PANF_WEAPON_HIDE))
|
|
{
|
|
if (!TEST(psp->PlayerP->Flags, PF_WEAPON_DOWN))
|
|
{
|
|
RESET(psp->flags, PANF_WEAPON_HIDE);
|
|
pSetState(psp, state);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
if (psp->PlayerP->input.actions & SB_HOLSTER)
|
|
{
|
|
if (psp->PlayerP->KeyPressBits & SB_HOLSTER)
|
|
{
|
|
psp->PlayerP->KeyPressBits &= ~SB_HOLSTER;
|
|
pSetState(psp, state);
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
psp->PlayerP->KeyPressBits |= SB_HOLSTER;
|
|
}
|
|
|
|
if (psp->PlayerP->input.actions & SB_FIRE)
|
|
{
|
|
if (psp->PlayerP->KeyPressBits & SB_FIRE)
|
|
{
|
|
SET(psp->flags, PANF_UNHIDE_SHOOT);
|
|
pSetState(psp, state);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
pWeaponHideKeys(PANEL_SPRITEp psp, PANEL_STATEp state)
|
|
{
|
|
if (TEST(psp->PlayerP->Flags, PF_DEAD))
|
|
{
|
|
SET(psp->flags, PANF_DEATH_HIDE);
|
|
pSetState(psp, state);
|
|
return true;
|
|
}
|
|
|
|
if (TEST(psp->PlayerP->Flags, PF_WEAPON_DOWN))
|
|
{
|
|
SET(psp->flags, PANF_WEAPON_HIDE);
|
|
pSetState(psp, state);
|
|
return true;
|
|
}
|
|
|
|
if (psp->PlayerP->input.actions & SB_HOLSTER)
|
|
{
|
|
if (psp->PlayerP->KeyPressBits & SB_HOLSTER)
|
|
{
|
|
psp->PlayerP->KeyPressBits &= ~SB_HOLSTER;
|
|
PutStringInfo(psp->PlayerP,"Weapon Holstered");
|
|
pSetState(psp, state);
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
psp->PlayerP->KeyPressBits |= SB_HOLSTER;
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
void
|
|
InsertPanelSprite(PLAYERp pp, PANEL_SPRITEp psp)
|
|
{
|
|
PANEL_SPRITEp cur, nxt;
|
|
|
|
ASSERT(psp);
|
|
|
|
// if list is empty, insert at front
|
|
if (EMPTY(&pp->PanelSpriteList))
|
|
{
|
|
INSERT(&pp->PanelSpriteList, psp);
|
|
return;
|
|
}
|
|
|
|
// if new pri is <= first pri in list, insert at front
|
|
if (psp->priority <= pp->PanelSpriteList.Next->priority)
|
|
{
|
|
INSERT(&pp->PanelSpriteList, psp);
|
|
return;
|
|
}
|
|
|
|
// search for first pri in list thats less than the new pri
|
|
auto list = pp->GetPanelSpriteList();
|
|
for (auto cur = list->Next; nxt = cur->Next, cur != list; cur = nxt)
|
|
{
|
|
// if the next pointer is the end of the list, insert it
|
|
if ((LIST) cur->Next == (LIST) &pp->PanelSpriteList)
|
|
{
|
|
INSERT(cur, psp);
|
|
return;
|
|
}
|
|
|
|
|
|
// if between cur and next, insert here
|
|
if (psp->priority >= cur->priority && psp->priority <= cur->Next->priority)
|
|
{
|
|
INSERT(cur, psp);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
PANEL_SPRITEp
|
|
pSpawnSprite(PLAYERp pp, PANEL_STATEp state, uint8_t priority, double x, double y)
|
|
{
|
|
unsigned i;
|
|
PANEL_SPRITEp psp;
|
|
|
|
|
|
ASSERT(pp);
|
|
|
|
psp = (PANEL_SPRITEp)CallocMem(sizeof(PANEL_SPRITE), 1);
|
|
|
|
PRODUCTION_ASSERT(psp);
|
|
|
|
psp->priority = priority;
|
|
InsertPanelSprite(pp, psp);
|
|
// INSERT(&pp->PanelSpriteList, psp);
|
|
|
|
psp->PlayerP = pp;
|
|
|
|
psp->ox = psp->x = x;
|
|
psp->oy = psp->y = y;
|
|
pSetState(psp, state);
|
|
if (state == nullptr)
|
|
psp->picndx = -1;
|
|
else
|
|
psp->picndx = state->picndx;
|
|
psp->ang = 0;
|
|
psp->vel = 0;
|
|
psp->rotate_ang = 0;
|
|
psp->scale = FRACUNIT;
|
|
psp->ID = 0;
|
|
|
|
for (i = 0; i < SIZ(psp->over); i++)
|
|
{
|
|
psp->over[i].State = nullptr;
|
|
psp->over[i].pic = -1;
|
|
psp->over[i].xoff = -1;
|
|
psp->over[i].yoff = -1;
|
|
}
|
|
|
|
return psp;
|
|
}
|
|
|
|
void
|
|
pSuicide(PANEL_SPRITEp psp)
|
|
{
|
|
pKillSprite(psp);
|
|
}
|
|
|
|
void
|
|
pKillSprite(PANEL_SPRITEp psp)
|
|
{
|
|
PRODUCTION_ASSERT(psp);
|
|
|
|
REMOVE(psp);
|
|
|
|
FreeMem(psp);
|
|
}
|
|
|
|
void
|
|
pClearSpriteList(PLAYERp pp)
|
|
{
|
|
PANEL_SPRITEp psp=nullptr, next_psp=nullptr;
|
|
auto l = &pp->PanelSpriteList;
|
|
|
|
for (psp = l->Next; next_psp = psp->Next, (LIST)psp != (LIST)l; psp = next_psp)
|
|
{
|
|
if (psp->Next == nullptr || psp->Prev == nullptr) return; // this can happen when cleaning up a fatal error.
|
|
pKillSprite(psp);
|
|
}
|
|
}
|
|
|
|
void
|
|
pWeaponBob(PANEL_SPRITEp psp, short condition)
|
|
{
|
|
double xdiff = 0, ydiff = 0;
|
|
|
|
double bobvel = fFindDistance2D(psp->PlayerP->xvect, psp->PlayerP->yvect) * (1. / 32768.);
|
|
bobvel = bobvel + (bobvel * (1. / 4.));
|
|
bobvel = min(bobvel, 128.);
|
|
|
|
if (condition)
|
|
{
|
|
SET(psp->flags, PANF_BOB);
|
|
}
|
|
else
|
|
{
|
|
if (labs((psp->sin_ndx & 1023) - 0) < 70)
|
|
{
|
|
RESET(psp->flags, PANF_BOB);
|
|
psp->sin_ndx = (RANDOM_P2(1024) < 512) ? 1024 : 0;
|
|
}
|
|
}
|
|
|
|
if (cl_weaponsway && TEST(psp->flags, PANF_BOB))
|
|
{
|
|
// //
|
|
// sin_xxx moves the weapon left-right
|
|
// //
|
|
|
|
// increment the ndx into the sin table
|
|
psp->sin_ndx = (psp->sin_ndx + (synctics << 3) + (cl_swsmoothsway ? (synctics << 2) : RANDOM_P2(8) * synctics)) & 2047;
|
|
|
|
// get height
|
|
xdiff = psp->sin_amt * bsinf(psp->sin_ndx, -14);
|
|
|
|
// //
|
|
// bob_xxx moves the weapon up-down
|
|
// //
|
|
|
|
// as the weapon moves left-right move the weapon up-down in the same
|
|
// proportion
|
|
double bob_ndx = (psp->sin_ndx + 512) & 1023;
|
|
|
|
// base bob_amt on the players velocity - Max of 128
|
|
double bob_amt = bobvel / psp->bob_height_divider;
|
|
ydiff = bob_amt * bsinf(bob_ndx, -14);
|
|
}
|
|
|
|
// Back up current coordinates for interpolating.
|
|
psp->backupcoords();
|
|
|
|
psp->x = psp->xorig + xdiff;
|
|
psp->y = psp->yorig + ydiff + UziRecoilYadj;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANEL SPRITE CONTROL ROUTINES
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
bool DrawBeforeView = false;
|
|
void
|
|
pDisplaySprites(PLAYERp pp, double smoothratio)
|
|
{
|
|
USERp u = pp->Actor()->u();
|
|
PANEL_SPRITEp next=nullptr;
|
|
short shade, picnum, overlay_shade = 0;
|
|
double x, y;
|
|
unsigned i;
|
|
|
|
uint8_t pal = 0;
|
|
short ang;
|
|
int flags;
|
|
|
|
double const look_anghalf = pp->angle.look_anghalf(smoothratio);
|
|
double const looking_arc = pp->angle.looking_arc(smoothratio);
|
|
|
|
auto list = pp->GetPanelSpriteList();
|
|
for (auto psp = list->Next; next = psp->Next, psp != list; psp = next)
|
|
{
|
|
ang = psp->rotate_ang;
|
|
shade = 0;
|
|
flags = 0;
|
|
if (cl_hudinterpolation)
|
|
{
|
|
x = interpolatedvaluef(psp->ox, psp->x, smoothratio);
|
|
y = interpolatedvaluef(psp->oy, psp->y, smoothratio);
|
|
|
|
}
|
|
else
|
|
{
|
|
x = psp->x;
|
|
y = psp->y;
|
|
}
|
|
|
|
x -= look_anghalf;
|
|
y += looking_arc;
|
|
|
|
// initilize pal here - jack with it below
|
|
pal = uint8_t(psp->pal);
|
|
|
|
if (DrawBeforeView)
|
|
if (!TEST(psp->flags, PANF_DRAW_BEFORE_VIEW))
|
|
continue;
|
|
|
|
if (TEST(psp->flags, PANF_SUICIDE))
|
|
{
|
|
//pKillSprite(psp);
|
|
continue;
|
|
}
|
|
|
|
// if the state is null get the picnum for other than picndx
|
|
if (psp->picndx == -1 || !psp->State)
|
|
picnum = psp->picnum;
|
|
else
|
|
picnum = psp->picndx;
|
|
|
|
// UK panzies have to have darts instead of shurikens.
|
|
if (sw_darts)
|
|
switch (picnum)
|
|
{
|
|
case STAR_REST:
|
|
picnum = 2510;
|
|
break;
|
|
case STAR_REST + 1:
|
|
picnum = 2511;
|
|
break;
|
|
case STAR_REST + 2:
|
|
picnum = 2512;
|
|
break;
|
|
case STAR_REST + 3:
|
|
picnum = 2513;
|
|
break;
|
|
case STAR_REST + 4:
|
|
picnum = 2514;
|
|
break;
|
|
case STAR_REST + 5:
|
|
picnum = 2515;
|
|
break;
|
|
case STAR_REST + 6:
|
|
picnum = 2516;
|
|
break;
|
|
case STAR_REST + 7:
|
|
picnum = 2517;
|
|
break;
|
|
}
|
|
|
|
if (pp->Bloody)
|
|
{
|
|
switch (picnum)
|
|
{
|
|
case SWORD_REST:
|
|
picnum = BLOODYSWORD_REST;
|
|
break;
|
|
case SWORD_SWING0:
|
|
picnum = BLOODYSWORD_SWING0;
|
|
break;
|
|
case SWORD_SWING1:
|
|
picnum = BLOODYSWORD_SWING1;
|
|
break;
|
|
case SWORD_SWING2:
|
|
picnum = BLOODYSWORD_SWING2;
|
|
break;
|
|
|
|
case FIST_REST:
|
|
picnum = 4077;
|
|
break;
|
|
case FIST2_REST:
|
|
picnum = 4051;
|
|
break;
|
|
case FIST_SWING0:
|
|
picnum = 4074;
|
|
break;
|
|
case FIST_SWING1:
|
|
picnum = 4075;
|
|
break;
|
|
case FIST_SWING2:
|
|
picnum = 4076;
|
|
break;
|
|
|
|
case STAR_REST:
|
|
case 2510:
|
|
if (!sw_darts)
|
|
picnum = 2138;
|
|
else
|
|
picnum = 2518; // Bloody Dart Hand
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pp->WpnShotgunType == 1)
|
|
{
|
|
switch (picnum)
|
|
{
|
|
case SHOTGUN_REST:
|
|
case SHOTGUN_RELOAD0:
|
|
picnum = 2227;
|
|
break;
|
|
case SHOTGUN_RELOAD1:
|
|
picnum = 2226;
|
|
break;
|
|
case SHOTGUN_RELOAD2:
|
|
picnum = 2225;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// don't draw
|
|
if (TEST(psp->flags, PANF_INVISIBLE))
|
|
continue;
|
|
|
|
if (psp->State && TEST(psp->State->flags, psf_Invisible))
|
|
continue;
|
|
|
|
// if its a weapon sprite and the view is set to the outside don't draw the sprite
|
|
if (TEST(psp->flags, PANF_WEAPON_SPRITE))
|
|
{
|
|
sectortype* sectp = nullptr;
|
|
int16_t floorshade = 0;
|
|
if (pp->cursectnum >= 0)
|
|
{
|
|
sectp = pp->cursector();
|
|
pal = sectp->floorpal;
|
|
floorshade = sectp->floorshade;
|
|
|
|
if (pal != PALETTE_DEFAULT)
|
|
{
|
|
if (sectp->hasU() && TEST(sectp->flags, SECTFU_DONT_COPY_PALETTE))
|
|
pal = PALETTE_DEFAULT;
|
|
}
|
|
|
|
if (pal == PALETTE_FOG || pal == PALETTE_DIVE || pal == PALETTE_DIVE_LAVA)
|
|
pal = uint8_t(psp->pal); // Set it back
|
|
}
|
|
|
|
///////////
|
|
|
|
if (pp->InventoryActive[INVENTORY_CLOAK])
|
|
{
|
|
SET(flags, RS_TRANS1);
|
|
}
|
|
|
|
//shade = overlay_shade = DIV2(pp->cursector()->floorshade + pp->cursector()->ceilingshade);
|
|
shade = overlay_shade = floorshade - 10;
|
|
|
|
if (TEST(psp->PlayerP->Flags, PF_VIEW_FROM_OUTSIDE))
|
|
{
|
|
if (!TEST(psp->PlayerP->Flags, PF_VIEW_OUTSIDE_WEAPON))
|
|
continue;
|
|
}
|
|
|
|
if (TEST(psp->PlayerP->Flags, PF_VIEW_FROM_CAMERA))
|
|
continue;
|
|
|
|
// !FRANK - this was moved from BELOW this IF statement
|
|
// if it doesn't have a picflag or its in the view
|
|
if (sectp && sectp->hasU() && TEST(sectp->flags, SECTFU_DONT_COPY_PALETTE))
|
|
pal = 0;
|
|
}
|
|
|
|
if (TEST(psp->flags, PANF_TRANSLUCENT))
|
|
SET(flags, RS_TRANS1);
|
|
|
|
SET(flags, TEST(psp->flags, PANF_TRANS_FLIP));
|
|
|
|
if (TEST(psp->flags, PANF_CORNER))
|
|
SET(flags, RS_TOPLEFT);
|
|
|
|
if ((psp->State && TEST(psp->State->flags, psf_Xflip)) || TEST(psp->flags, PANF_XFLIP))
|
|
{
|
|
SET(flags, RS_XFLIPHUD);
|
|
}
|
|
|
|
// shading
|
|
if (psp->State && TEST(psp->State->flags, psf_ShadeHalf|psf_ShadeNone))
|
|
{
|
|
if (TEST(psp->State->flags, psf_ShadeNone))
|
|
shade = 0;
|
|
else if (TEST(psp->State->flags, psf_ShadeHalf))
|
|
shade /= 2;
|
|
}
|
|
|
|
if (pal == PALETTE_DEFAULT)
|
|
{
|
|
switch (picnum)
|
|
{
|
|
case 4080:
|
|
case 4081:
|
|
case 2220:
|
|
case 2221:
|
|
pal = u->spal;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// temporary hack to fix fist artifacts until a solution is found in the panel system itself
|
|
switch (picnum)
|
|
{
|
|
case FIST_SWING0:
|
|
case FIST_SWING1:
|
|
case FIST_SWING2:
|
|
case FIST2_SWING0:
|
|
case FIST2_SWING1:
|
|
case FIST2_SWING2:
|
|
case FIST3_SWING0:
|
|
case FIST3_SWING1:
|
|
case FIST3_SWING2:
|
|
case BLOODYFIST_SWING0:
|
|
case BLOODYFIST_SWING1:
|
|
case BLOODYFIST_SWING2:
|
|
case BLOODYFIST2_SWING0:
|
|
case BLOODYFIST2_SWING1:
|
|
case BLOODYFIST2_SWING2:
|
|
case BLOODYFIST3_SWING0:
|
|
case BLOODYFIST3_SWING1:
|
|
case BLOODYFIST3_SWING2:
|
|
if (TEST(flags, RS_XFLIPHUD) && x > 160)
|
|
x = 65;
|
|
else if (!TEST(flags, RS_XFLIPHUD) && x < 160)
|
|
x = 345;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
hud_drawsprite(x, y, psp->scale, ang, picnum, shade, pal, flags);
|
|
|
|
// do overlays (if any)
|
|
for (i = 0; i < SIZ(psp->over); i++)
|
|
{
|
|
// get pic from state
|
|
if (psp->over[i].State)
|
|
picnum = psp->over[i].State->picndx;
|
|
else
|
|
// get pic from over variable
|
|
if (psp->over[i].pic >= 0)
|
|
picnum = psp->over[i].pic;
|
|
else
|
|
continue;
|
|
|
|
if (TEST(psp->over[i].flags, psf_ShadeNone))
|
|
overlay_shade = 0;
|
|
|
|
if (picnum)
|
|
{
|
|
hud_drawsprite((x + psp->over[i].xoff), (y + psp->over[i].yoff), psp->scale, ang, picnum, overlay_shade, pal, flags);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
pSpriteControl(PLAYERp pp)
|
|
{
|
|
PANEL_SPRITEp next=nullptr;
|
|
|
|
auto list = pp->GetPanelSpriteList();
|
|
for (auto psp = list->Next; next = psp->Next, psp != list; psp = next)
|
|
{
|
|
// reminder - if these give an assertion look for pKillSprites
|
|
// somewhere else other than by themselves
|
|
// RULE: Sprites can only kill themselves
|
|
PRODUCTION_ASSERT(psp);
|
|
|
|
if (psp->State)
|
|
pStateControl(psp);
|
|
else
|
|
// for sprits that are not state controled but still need to call
|
|
// something
|
|
if (psp->PanelSpriteFunc)
|
|
{
|
|
(*psp->PanelSpriteFunc)(psp);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
pSetState(PANEL_SPRITEp psp, PANEL_STATEp panel_state)
|
|
{
|
|
PRODUCTION_ASSERT(psp);
|
|
psp->tics = 0;
|
|
psp->State = panel_state;
|
|
psp->picndx = panel_state ? panel_state->picndx : 0;
|
|
}
|
|
|
|
|
|
void
|
|
pNextState(PANEL_SPRITEp psp)
|
|
{
|
|
// Transition to the next state
|
|
psp->State = psp->State->NextState;
|
|
|
|
if (TEST(psp->State->flags, psf_QuickCall))
|
|
{
|
|
(*psp->State->Animator)(psp);
|
|
psp->State = psp->State->NextState;
|
|
}
|
|
}
|
|
|
|
void
|
|
pStatePlusOne(PANEL_SPRITEp psp)
|
|
{
|
|
psp->tics = 0;
|
|
psp->State++;
|
|
|
|
if (TEST(psp->State->flags, psf_QuickCall))
|
|
{
|
|
(*psp->State->Animator)(psp);
|
|
psp->State = psp->State->NextState;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
pStateControl(PANEL_SPRITEp psp)
|
|
{
|
|
unsigned i;
|
|
short tics = synctics;
|
|
|
|
psp->tics += tics;
|
|
|
|
// Skip states if too much time has passed
|
|
while (psp->tics >= psp->State->tics)
|
|
{
|
|
// Set Tics
|
|
psp->tics -= psp->State->tics;
|
|
|
|
pNextState(psp);
|
|
}
|
|
|
|
// Set picnum to the correct pic
|
|
psp->picndx = psp->State->picndx;
|
|
|
|
// do overlay states
|
|
for (i = 0; i < SIZ(psp->over); i++)
|
|
{
|
|
if (!psp->over[i].State)
|
|
continue;
|
|
|
|
psp->over[i].tics += tics;
|
|
|
|
// Skip states if too much time has passed
|
|
while (psp->over[i].tics >= psp->over[i].State->tics)
|
|
{
|
|
// Set Tics
|
|
psp->over[i].tics -= psp->over[i].State->tics;
|
|
psp->over[i].State = psp->over[i].State->NextState;
|
|
|
|
if (!psp->over[i].State)
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Call the correct animator
|
|
if (psp->State->Animator)
|
|
(*psp->State->Animator)(psp);
|
|
|
|
}
|
|
|
|
|
|
void
|
|
UpdatePanel(double smoothratio)
|
|
{
|
|
short pnum;
|
|
|
|
TRAVERSE_CONNECT(pnum)
|
|
{
|
|
if (pnum == screenpeek)
|
|
pDisplaySprites(Player + pnum, smoothratio);
|
|
}
|
|
}
|
|
|
|
void
|
|
PreUpdatePanel(double smoothratio)
|
|
{
|
|
short pnum;
|
|
DrawBeforeView = true;
|
|
|
|
//if (DrawBeforeView)
|
|
TRAVERSE_CONNECT(pnum)
|
|
{
|
|
if (pnum == screenpeek)
|
|
pDisplaySprites(Player + pnum, smoothratio);
|
|
}
|
|
|
|
DrawBeforeView = false;
|
|
}
|
|
|
|
#define EnvironSuit_RATE 10
|
|
#define Fly_RATE 10
|
|
#define Cloak_RATE 10
|
|
#define Night_RATE 10
|
|
#define Box_RATE 10
|
|
#define Medkit_RATE 10
|
|
#define RepairKit_RATE 10
|
|
#define ChemBomb_RATE 10
|
|
#define FlashBomb_RATE 10
|
|
#define SmokeBomb_RATE 10
|
|
#define Caltrops_RATE 10
|
|
|
|
#define ID_PanelEnvironSuit 2397
|
|
PANEL_STATE ps_PanelEnvironSuit[] =
|
|
{
|
|
{ID_PanelEnvironSuit, EnvironSuit_RATE, PanelInvTestSuicide, &ps_PanelEnvironSuit[0], 0,0,0}
|
|
};
|
|
|
|
|
|
#include "saveable.h"
|
|
|
|
static saveable_code saveable_panel_code[] =
|
|
{
|
|
SAVE_CODE(pSuicide),
|
|
SAVE_CODE(SwordBlur),
|
|
SAVE_CODE(SpecialUziRetractFunc),
|
|
SAVE_CODE(FistBlur),
|
|
};
|
|
|
|
static saveable_data saveable_panel_data[] =
|
|
{
|
|
SAVE_DATA(ps_PresentSword),
|
|
SAVE_DATA(ps_SwordRest),
|
|
SAVE_DATA(ps_SwordHide),
|
|
SAVE_DATA(ps_SwordSwing),
|
|
SAVE_DATA(ps_RetractSword),
|
|
|
|
SAVE_DATA(ps_PresentStar),
|
|
SAVE_DATA(ps_StarHide),
|
|
SAVE_DATA(ps_StarRest),
|
|
SAVE_DATA(ps_ThrowStar),
|
|
SAVE_DATA(ps_RetractStar),
|
|
|
|
SAVE_DATA(ps_FireUzi),
|
|
SAVE_DATA(ps_UziNull),
|
|
SAVE_DATA(ps_UziHide),
|
|
SAVE_DATA(ps_PresentUzi),
|
|
SAVE_DATA(ps_PresentUziReload),
|
|
SAVE_DATA(ps_RetractUzi),
|
|
SAVE_DATA(ps_FireUzi2),
|
|
SAVE_DATA(ps_PresentUzi2),
|
|
SAVE_DATA(ps_Uzi2Hide),
|
|
SAVE_DATA(ps_RetractUzi2),
|
|
SAVE_DATA(ps_Uzi2Suicide),
|
|
SAVE_DATA(ps_Uzi2Null),
|
|
SAVE_DATA(ps_UziEject),
|
|
SAVE_DATA(ps_UziClip),
|
|
SAVE_DATA(ps_UziReload),
|
|
SAVE_DATA(ps_UziDoneReload),
|
|
SAVE_DATA(ps_UziShell),
|
|
SAVE_DATA(ps_Uzi2Shell),
|
|
|
|
SAVE_DATA(ps_ShotgunShell),
|
|
SAVE_DATA(ps_PresentShotgun),
|
|
SAVE_DATA(ps_ShotgunRest),
|
|
SAVE_DATA(ps_ShotgunHide),
|
|
SAVE_DATA(ps_ShotgunRecoil),
|
|
SAVE_DATA(ps_ShotgunRecoilAuto),
|
|
SAVE_DATA(ps_ShotgunFire),
|
|
SAVE_DATA(ps_ShotgunAutoFire),
|
|
SAVE_DATA(ps_ShotgunReload),
|
|
SAVE_DATA(ps_RetractShotgun),
|
|
SAVE_DATA(ps_ShotgunFlash),
|
|
|
|
SAVE_DATA(ps_PresentRail),
|
|
SAVE_DATA(ps_RailRest),
|
|
SAVE_DATA(ps_RailHide),
|
|
SAVE_DATA(ps_RailRecoil),
|
|
SAVE_DATA(ps_RailFire),
|
|
SAVE_DATA(ps_RailFireEMP),
|
|
SAVE_DATA(ps_RetractRail),
|
|
|
|
SAVE_DATA(ps_PresentHothead),
|
|
SAVE_DATA(ps_HotheadHide),
|
|
SAVE_DATA(ps_RetractHothead),
|
|
SAVE_DATA(ps_HotheadRest),
|
|
SAVE_DATA(ps_HotheadRestRing),
|
|
SAVE_DATA(ps_HotheadRestNapalm),
|
|
SAVE_DATA(ps_HotheadAttack),
|
|
SAVE_DATA(ps_HotheadRing),
|
|
SAVE_DATA(ps_HotheadNapalm),
|
|
SAVE_DATA(ps_HotheadTurn),
|
|
SAVE_DATA(ps_HotheadTurnRing),
|
|
SAVE_DATA(ps_HotheadTurnNapalm),
|
|
SAVE_DATA(ps_OnFire),
|
|
|
|
SAVE_DATA(ps_PresentMicro),
|
|
SAVE_DATA(ps_MicroRest),
|
|
SAVE_DATA(ps_MicroHide),
|
|
SAVE_DATA(ps_InitNuke),
|
|
SAVE_DATA(ps_MicroRecoil),
|
|
SAVE_DATA(ps_MicroFire),
|
|
SAVE_DATA(ps_MicroSingleFire),
|
|
SAVE_DATA(ps_RetractMicro),
|
|
SAVE_DATA(ps_MicroHeatFlash),
|
|
SAVE_DATA(ps_MicroNukeFlash),
|
|
|
|
SAVE_DATA(ps_PresentHeart),
|
|
SAVE_DATA(ps_HeartRest),
|
|
SAVE_DATA(ps_HeartHide),
|
|
SAVE_DATA(ps_HeartAttack),
|
|
SAVE_DATA(ps_RetractHeart),
|
|
SAVE_DATA(ps_HeartBlood),
|
|
SAVE_DATA(ps_HeartBloodSmall),
|
|
SAVE_DATA(ps_HeartBlood),
|
|
|
|
SAVE_DATA(ps_PresentGrenade),
|
|
SAVE_DATA(ps_GrenadeRest),
|
|
SAVE_DATA(ps_GrenadeHide),
|
|
SAVE_DATA(ps_GrenadeFire),
|
|
SAVE_DATA(ps_GrenadeRecoil),
|
|
SAVE_DATA(ps_RetractGrenade),
|
|
|
|
SAVE_DATA(ps_PresentMine),
|
|
SAVE_DATA(ps_MineRest),
|
|
SAVE_DATA(ps_MineHide),
|
|
SAVE_DATA(ps_MineThrow),
|
|
SAVE_DATA(ps_RetractMine),
|
|
|
|
SAVE_DATA(ps_ChopsAttack1),
|
|
SAVE_DATA(ps_ChopsAttack2),
|
|
SAVE_DATA(ps_ChopsAttack3),
|
|
SAVE_DATA(ps_ChopsAttack4),
|
|
SAVE_DATA(ps_ChopsWait),
|
|
SAVE_DATA(ps_ChopsRetract),
|
|
|
|
SAVE_DATA(ps_PresentFist),
|
|
SAVE_DATA(ps_FistRest),
|
|
SAVE_DATA(ps_FistHide),
|
|
SAVE_DATA(ps_PresentFist2),
|
|
SAVE_DATA(ps_Fist2Rest),
|
|
SAVE_DATA(ps_Fist2Hide),
|
|
/*
|
|
SAVE_DATA(ps_PresentFist3),
|
|
SAVE_DATA(ps_Fist3Rest),
|
|
SAVE_DATA(ps_Fist3Hide),
|
|
*/
|
|
SAVE_DATA(ps_FistSwing),
|
|
SAVE_DATA(ps_Fist2Swing),
|
|
SAVE_DATA(ps_Fist3Swing),
|
|
SAVE_DATA(ps_Kick),
|
|
SAVE_DATA(ps_RetractFist),
|
|
|
|
SAVE_DATA(ps_PanelEnvironSuit),
|
|
};
|
|
|
|
saveable_module saveable_panel =
|
|
{
|
|
// code
|
|
saveable_panel_code,
|
|
SIZ(saveable_panel_code),
|
|
|
|
// data
|
|
saveable_panel_data,
|
|
SIZ(saveable_panel_data)
|
|
};
|
|
|
|
END_SW_NS
|