mirror of
https://github.com/ZDoom/Raze.git
synced 2024-11-16 09:21:36 +00:00
2779 lines
80 KiB
C++
2779 lines
80 KiB
C++
//-------------------------------------------------------------------------
|
|
/*
|
|
Copyright (C) 2010-2019 EDuke32 developers and contributors
|
|
Copyright (C) 2019 sirlemonhead, Nuke.YKT
|
|
This file is part of PCExhumed.
|
|
PCExhumed is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License version 2
|
|
as published by the Free Software Foundation.
|
|
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.
|
|
*/
|
|
//-------------------------------------------------------------------------
|
|
#include "ns.h"
|
|
#include "compat.h"
|
|
#include "player.h"
|
|
#include "aistuff.h"
|
|
#include "exhumed.h"
|
|
#include "names.h"
|
|
#include "engine.h"
|
|
#include "sequence.h"
|
|
#include "view.h"
|
|
#include "input.h"
|
|
#include "status.h"
|
|
#include "sound.h"
|
|
#include "sound.h"
|
|
#include "buildtiles.h"
|
|
#include "gstrings.h"
|
|
#include "gamestate.h"
|
|
#include "mapinfo.h"
|
|
#include "automap.h"
|
|
#include "interpolate.h"
|
|
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
BEGIN_PS_NS
|
|
|
|
extern short nStatusSeqOffset;
|
|
|
|
int lPlayerXVel = 0;
|
|
int lPlayerYVel = 0;
|
|
short obobangle = 0, bobangle = 0;
|
|
|
|
static actionSeq PlayerSeq[] = {
|
|
{18, 0}, {0, 0}, {9, 0}, {27, 0}, {63, 0},
|
|
{72, 0}, {54, 0}, {45, 0}, {54, 0}, {81, 0},
|
|
{90, 0}, {99, 0}, {108, 0}, {8, 0}, {0, 0},
|
|
{139, 0}, {117, 1}, {119, 1}, {120, 1}, {121, 1},
|
|
{122, 1}
|
|
};
|
|
|
|
static short nHeightTemplate[] = { 0, 0, 0, 0, 0, 0, 7, 7, 7, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
|
|
short nActionEyeLevel[] = {
|
|
-14080, -14080, -14080, -14080, -14080, -14080, -8320,
|
|
-8320, -8320, -8320, -8320, -8320, -8320, -14080,
|
|
-14080, -14080, -14080, -14080, -14080, -14080, -14080
|
|
};
|
|
|
|
uint16_t nGunLotag[] = { 52, 53, 54, 55, 56, 57 };
|
|
uint16_t nGunPicnum[] = { 57, 488, 490, 491, 878, 899, 3455 };
|
|
|
|
int16_t nItemText[] = {
|
|
-1, -1, -1, -1, -1, -1, 18, 20, 19, 13, -1, 10, 1, 0, 2, -1, 3,
|
|
-1, 4, 5, 9, 6, 7, 8, -1, 11, -1, 13, 12, 14, 15, -1, 16, 17,
|
|
-1, -1, -1, 21, 22, -1, -1, -1, -1, -1, -1, 23, 24, 25, 26, 27,
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
|
|
};
|
|
|
|
|
|
int nLocalPlayer = 0;
|
|
|
|
Player PlayerList[kMaxPlayers];
|
|
|
|
DExhumedActor* nNetStartSprite[kMaxPlayers] = { };
|
|
|
|
short nStandHeight;
|
|
|
|
|
|
|
|
short PlayerCount;
|
|
|
|
short nNetStartSprites;
|
|
short nCurStartSprite;
|
|
|
|
void RestoreSavePoint(int nPlayer, int *x, int *y, int *z, short *nSector, short *nAngle)
|
|
{
|
|
*x = PlayerList[nPlayer].sPlayerSave.x;
|
|
*y = PlayerList[nPlayer].sPlayerSave.y;
|
|
*z = PlayerList[nPlayer].sPlayerSave.z;
|
|
*nSector = PlayerList[nPlayer].sPlayerSave.nSector;
|
|
*nAngle = PlayerList[nPlayer].sPlayerSave.nAngle;
|
|
}
|
|
|
|
void SetSavePoint(int nPlayer, int x, int y, int z, short nSector, short nAngle)
|
|
{
|
|
PlayerList[nPlayer].sPlayerSave.x = x;
|
|
PlayerList[nPlayer].sPlayerSave.y = y;
|
|
PlayerList[nPlayer].sPlayerSave.z = z;
|
|
PlayerList[nPlayer].sPlayerSave.nSector = nSector;
|
|
PlayerList[nPlayer].sPlayerSave.nAngle = nAngle;
|
|
}
|
|
|
|
void feebtag(int x, int y, int z, int nSector, DExhumedActor **nSprite, int nVal2, int nVal3)
|
|
{
|
|
*nSprite = nullptr;
|
|
|
|
int startwall = sector[nSector].wallptr;
|
|
|
|
int nWalls = sector[nSector].wallnum;
|
|
|
|
int var_20 = nVal2 & 2;
|
|
int var_14 = nVal2 & 1;
|
|
|
|
while (1)
|
|
{
|
|
if (nSector != -1)
|
|
{
|
|
ExhumedSectIterator it(nSector);
|
|
while (auto pActor = it.Next())
|
|
{
|
|
auto pSprite = &pActor->s();
|
|
short nStat = pSprite->statnum;
|
|
|
|
if (nStat >= 900 && !(pSprite->cstat & 0x8000))
|
|
{
|
|
uint32_t xDiff = abs(pSprite->x - x);
|
|
uint32_t yDiff = abs(pSprite->y - y);
|
|
int zDiff = pSprite->z - z;
|
|
|
|
if (zDiff < 5120 && zDiff > -25600)
|
|
{
|
|
uint32_t diff = xDiff * xDiff + yDiff * yDiff;
|
|
|
|
if (diff > INT_MAX)
|
|
{
|
|
DPrintf(DMSG_WARNING, "%s %d: overflow\n", __func__, __LINE__);
|
|
diff = INT_MAX;
|
|
}
|
|
|
|
int theSqrt = ksqrt(diff);
|
|
|
|
if (theSqrt < nVal3 && ((nStat != 950 && nStat != 949) || !(var_14 & 1)) && ((nStat != 912 && nStat != 913) || !(var_20 & 2)))
|
|
{
|
|
nVal3 = theSqrt;
|
|
*nSprite = pActor;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
nWalls--;
|
|
if (nWalls < -1)
|
|
return;
|
|
|
|
nSector = wall[startwall].nextsector;
|
|
startwall++;
|
|
}
|
|
}
|
|
|
|
void InitPlayer()
|
|
{
|
|
for (int i = 0; i < kMaxPlayers; i++) {
|
|
PlayerList[i].pActor = nullptr;
|
|
}
|
|
}
|
|
|
|
void InitPlayerKeys(short nPlayer)
|
|
{
|
|
PlayerList[nPlayer].keys = 0;
|
|
}
|
|
|
|
void InitPlayerInventory(short nPlayer)
|
|
{
|
|
memset(&PlayerList[nPlayer], 0, sizeof(Player));
|
|
|
|
PlayerList[nPlayer].nItem = -1;
|
|
PlayerList[nPlayer].nPlayerSwear = 4;
|
|
|
|
ResetPlayerWeapons(nPlayer);
|
|
|
|
PlayerList[nPlayer].nLives = kDefaultLives;
|
|
|
|
PlayerList[nPlayer].pActor = nullptr;
|
|
PlayerList[nPlayer].nRun = -1;
|
|
|
|
PlayerList[nPlayer].nPistolClip = 6;
|
|
PlayerList[nPlayer].nPlayerClip = 0;
|
|
|
|
PlayerList[nPlayer].nCurrentWeapon = 0;
|
|
|
|
if (nPlayer == nLocalPlayer) {
|
|
automapMode = am_off;
|
|
}
|
|
|
|
PlayerList[nPlayer].nPlayerScore = 0;
|
|
|
|
auto pixels = tilePtr(kTile3571 + nPlayer);
|
|
|
|
PlayerList[nPlayer].nPlayerColor = pixels[tileWidth(nPlayer + kTile3571) * tileHeight(nPlayer + kTile3571) / 2];
|
|
}
|
|
|
|
short GetPlayerFromActor(DExhumedActor* pActor)
|
|
{
|
|
auto pSprite = &pActor->s();
|
|
return RunData[pSprite->owner].nObjIndex;
|
|
}
|
|
|
|
void RestartPlayer(short nPlayer)
|
|
{
|
|
auto plr = &PlayerList[nPlayer];
|
|
auto pActor = plr->Actor();
|
|
auto pDopSprite = plr->pDoppleSprite;
|
|
|
|
DExhumedActor* floorsprt;
|
|
|
|
if (pActor)
|
|
{
|
|
auto nSpr = &pActor->s();
|
|
runlist_DoSubRunRec(nSpr->owner);
|
|
runlist_FreeRun(nSpr->lotag - 1);
|
|
|
|
ChangeActorStat(pActor, 0);
|
|
|
|
plr->pActor = nullptr;
|
|
|
|
auto pFloorSprite = plr->pPlayerFloorSprite;
|
|
if (pFloorSprite != nullptr) {
|
|
DeleteActor(pFloorSprite);
|
|
}
|
|
|
|
if (pDopSprite)
|
|
{
|
|
auto sp = &pDopSprite->s();
|
|
runlist_DoSubRunRec(sp->owner);
|
|
runlist_FreeRun(sp->lotag - 1);
|
|
DeleteActor(pDopSprite);
|
|
}
|
|
}
|
|
|
|
pActor = GrabBody();
|
|
auto nSpr = &pActor->s();
|
|
|
|
ChangeActorSect(pActor, plr->sPlayerSave.nSector);
|
|
ChangeActorStat(pActor, 100);
|
|
|
|
auto pDActor = insertActor(nSpr->sectnum, 100);
|
|
plr->pDoppleSprite = pDActor;
|
|
|
|
if (nTotalPlayers > 1)
|
|
{
|
|
auto nNStartSprite = nNetStartSprite[nCurStartSprite];
|
|
auto nstspr = &nNStartSprite->s();
|
|
nCurStartSprite++;
|
|
|
|
if (nCurStartSprite >= nNetStartSprites) {
|
|
nCurStartSprite = 0;
|
|
}
|
|
|
|
nSpr->x = nstspr->x;
|
|
nSpr->y = nstspr->y;
|
|
nSpr->z = nstspr->z;
|
|
ChangeActorSect(pActor, nstspr->sectnum);
|
|
plr->angle.ang = buildang(nstspr->ang&kAngleMask);
|
|
nSpr->ang = plr->angle.ang.asbuild();
|
|
|
|
floorsprt = insertActor(nSpr->sectnum, 0);
|
|
auto fspr = &floorsprt->s();
|
|
|
|
fspr->x = nSpr->x;
|
|
fspr->y = nSpr->y;
|
|
fspr->z = nSpr->z;
|
|
fspr->yrepeat = 64;
|
|
fspr->xrepeat = 64;
|
|
fspr->cstat = 32;
|
|
fspr->picnum = nPlayer + kTile3571;
|
|
}
|
|
else
|
|
{
|
|
nSpr->x = plr->sPlayerSave.x;
|
|
nSpr->y = plr->sPlayerSave.y;
|
|
nSpr->z = sector[plr->sPlayerSave.nSector].floorz;
|
|
plr->angle.ang = buildang(plr->sPlayerSave.nAngle&kAngleMask);
|
|
nSpr->ang = plr->angle.ang.asbuild();
|
|
|
|
floorsprt = nullptr;
|
|
}
|
|
|
|
plr->angle.backup();
|
|
plr->horizon.backup();
|
|
|
|
plr->pPlayerFloorSprite = floorsprt;
|
|
|
|
nSpr->cstat = 0x101;
|
|
nSpr->shade = -12;
|
|
nSpr->clipdist = 58;
|
|
nSpr->pal = 0;
|
|
nSpr->xrepeat = 40;
|
|
nSpr->yrepeat = 40;
|
|
nSpr->xoffset = 0;
|
|
nSpr->yoffset = 0;
|
|
nSpr->picnum = seq_GetSeqPicnum(kSeqJoe, 18, 0);
|
|
|
|
int nHeight = GetActorHeight(pActor);
|
|
nSpr->xvel = 0;
|
|
nSpr->yvel = 0;
|
|
nSpr->zvel = 0;
|
|
|
|
nStandHeight = nHeight;
|
|
|
|
nSpr->hitag = 0;
|
|
nSpr->extra = -1;
|
|
nSpr->lotag = runlist_HeadRun() + 1;
|
|
|
|
auto nDSpr = &pDActor->s();
|
|
nDSpr->x = nSpr->x;
|
|
nDSpr->y = nSpr->y;
|
|
nDSpr->z = nSpr->z;
|
|
nDSpr->xrepeat = nSpr->xrepeat;
|
|
nDSpr->yrepeat = nSpr->yrepeat;
|
|
nDSpr->xoffset = 0;
|
|
nDSpr->yoffset = 0;
|
|
nDSpr->shade = nSpr->shade;
|
|
nDSpr->ang = nSpr->ang;
|
|
nDSpr->cstat = nSpr->cstat;
|
|
|
|
nDSpr->lotag = runlist_HeadRun() + 1;
|
|
|
|
plr->nAction = 0;
|
|
plr->nHealth = 800; // TODO - define
|
|
|
|
if (nNetPlayerCount) {
|
|
plr->nHealth = 1600; // TODO - define
|
|
}
|
|
|
|
plr->field_2 = 0;
|
|
plr->pActor = pActor;
|
|
plr->bIsMummified = false;
|
|
|
|
if (plr->invincibility >= 0) {
|
|
plr->invincibility = 0;
|
|
}
|
|
|
|
plr->nTorch = 0;
|
|
plr->nMaskAmount = 0;
|
|
|
|
SetTorch(nPlayer, 0);
|
|
|
|
plr->nInvisible = 0;
|
|
|
|
plr->bIsFiring = 0;
|
|
plr->field_3FOUR = 0;
|
|
plr->nPlayerViewSect = plr->sPlayerSave.nSector;
|
|
plr->field_3A = 0;
|
|
|
|
plr->nDouble = 0;
|
|
|
|
plr->nSeq = kSeqJoe;
|
|
|
|
plr->nPlayerPushSound = -1;
|
|
|
|
plr->field_38 = -1;
|
|
|
|
if (plr->nCurrentWeapon == 7) {
|
|
plr->nCurrentWeapon = plr->field_3C;
|
|
}
|
|
|
|
plr->field_3C = 0;
|
|
plr->nAir = 100;
|
|
|
|
if (!(currentLevel->gameflags & LEVEL_EX_MULTI))
|
|
{
|
|
RestoreMinAmmo(nPlayer);
|
|
}
|
|
else
|
|
{
|
|
ResetPlayerWeapons(nPlayer);
|
|
plr->nMagic = 0;
|
|
}
|
|
|
|
plr->pPlayerGrenade = nullptr;
|
|
plr->oeyelevel = plr->eyelevel = -14080;
|
|
dVertPan[nPlayer] = 0;
|
|
|
|
nTemperature[nPlayer] = 0;
|
|
|
|
plr->nYDamage = 0;
|
|
plr->nXDamage = 0;
|
|
|
|
plr->nDestVertPan = plr->horizon.ohoriz = plr->horizon.horiz = q16horiz(0);
|
|
plr->nBreathTimer = 90;
|
|
|
|
plr->nTauntTimer = RandomSize(3) + 3;
|
|
|
|
nDSpr->owner = runlist_AddRunRec(nDSpr->lotag - 1, nPlayer, 0xA0000);
|
|
nSpr->owner = runlist_AddRunRec(nSpr->lotag - 1, nPlayer, 0xA0000);
|
|
|
|
if (plr->nRun < 0) {
|
|
plr->nRun = runlist_AddRunRec(NewRun, nPlayer, 0xA0000);
|
|
}
|
|
|
|
BuildRa(nPlayer);
|
|
|
|
if (nPlayer == nLocalPlayer)
|
|
{
|
|
RestoreGreenPal();
|
|
plr->bPlayerPan = plr->bLockPan = false;
|
|
}
|
|
|
|
plr->ototalvel = plr->totalvel = 0;
|
|
|
|
memset(&sPlayerInput[nPlayer], 0, sizeof(PlayerInput));
|
|
sPlayerInput[nPlayer].nItem = -1;
|
|
|
|
plr->nDeathType = 0;
|
|
nQuake[nPlayer] = 0;
|
|
}
|
|
|
|
int GrabPlayer()
|
|
{
|
|
if (PlayerCount >= kMaxPlayers) {
|
|
return -1;
|
|
}
|
|
|
|
return PlayerCount++;
|
|
}
|
|
|
|
void StartDeathSeq(int nPlayer, int nVal)
|
|
{
|
|
FreeRa(nPlayer);
|
|
|
|
auto pActor = PlayerList[nPlayer].Actor();
|
|
auto pSprite = &pActor->s();
|
|
PlayerList[nPlayer].nHealth = 0;
|
|
|
|
short nLotag = sector[pSprite->sectnum].lotag;
|
|
|
|
if (nLotag > 0) {
|
|
runlist_SignalRun(nLotag - 1, nPlayer, &ExhumedAI::EnterSector);
|
|
}
|
|
|
|
if (PlayerList[nPlayer].pPlayerGrenade)
|
|
{
|
|
ThrowGrenade(nPlayer, 0, 0, 0, -10000);
|
|
}
|
|
else
|
|
{
|
|
if (nNetPlayerCount)
|
|
{
|
|
int nWeapon = PlayerList[nPlayer].nCurrentWeapon;
|
|
|
|
if (nWeapon > kWeaponSword && nWeapon <= kWeaponRing)
|
|
{
|
|
short nSector = pSprite->sectnum;
|
|
if (SectBelow[nSector] > -1) {
|
|
nSector = SectBelow[nSector];
|
|
}
|
|
|
|
auto pGunActor = GrabBodyGunSprite();
|
|
ChangeActorSect(pGunActor, nSector);
|
|
auto pGunSprite = &pGunActor->s();
|
|
|
|
pGunSprite->x = pSprite->x;
|
|
pGunSprite->y = pSprite->y;
|
|
pGunSprite->z = sector[nSector].floorz - 512;
|
|
|
|
ChangeActorStat(pGunActor, nGunLotag[nWeapon] + 900);
|
|
|
|
pGunSprite->picnum = nGunPicnum[nWeapon];
|
|
|
|
BuildItemAnim(pGunActor);
|
|
}
|
|
}
|
|
}
|
|
|
|
StopFiringWeapon(nPlayer);
|
|
|
|
PlayerList[nPlayer].horizon.ohoriz = PlayerList[nPlayer].horizon.horiz = q16horiz(0);
|
|
PlayerList[nPlayer].oeyelevel = PlayerList[nPlayer].eyelevel = -14080;
|
|
PlayerList[nPlayer].nInvisible = 0;
|
|
dVertPan[nPlayer] = 15;
|
|
|
|
pSprite->cstat &= 0x7FFF;
|
|
|
|
SetNewWeaponImmediate(nPlayer, -2);
|
|
|
|
if (SectDamage[pSprite->sectnum] <= 0)
|
|
{
|
|
PlayerList[nPlayer].nDeathType = nVal;
|
|
}
|
|
else
|
|
{
|
|
PlayerList[nPlayer].nDeathType = 2;
|
|
}
|
|
|
|
nVal *= 2;
|
|
|
|
if (nVal || !(SectFlag[pSprite->sectnum] & kSectUnderwater))
|
|
{
|
|
PlayerList[nPlayer].nAction = nVal + 17;
|
|
}
|
|
else {
|
|
PlayerList[nPlayer].nAction = 16;
|
|
}
|
|
|
|
PlayerList[nPlayer].field_2 = 0;
|
|
|
|
pSprite->cstat &= 0xFEFE;
|
|
|
|
if (nTotalPlayers == 1)
|
|
{
|
|
if (!(currentLevel->gameflags & LEVEL_EX_TRAINING)) { // if not on the training level
|
|
PlayerList[nPlayer].nLives--;
|
|
}
|
|
|
|
if (PlayerList[nPlayer].nLives < 0) {
|
|
PlayerList[nPlayer].nLives = 0;
|
|
}
|
|
}
|
|
|
|
PlayerList[nPlayer].ototalvel = PlayerList[nPlayer].totalvel = 0;
|
|
}
|
|
|
|
int AddAmmo(int nPlayer, int nWeapon, int nAmmoAmount)
|
|
{
|
|
if (!nAmmoAmount) {
|
|
nAmmoAmount = 1;
|
|
}
|
|
|
|
short nCurAmmo = PlayerList[nPlayer].nAmmo[nWeapon];
|
|
|
|
if (nCurAmmo >= 300 && nAmmoAmount > 0) {
|
|
return 0;
|
|
}
|
|
|
|
nAmmoAmount = nCurAmmo + nAmmoAmount;
|
|
if (nAmmoAmount > 300) {
|
|
nAmmoAmount = 300;
|
|
}
|
|
|
|
PlayerList[nPlayer].nAmmo[nWeapon] = nAmmoAmount;
|
|
|
|
if (nWeapon == 1)
|
|
{
|
|
if (!PlayerList[nPlayer].nPistolClip) {
|
|
PlayerList[nPlayer].nPistolClip = 6;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void SetPlayerMummified(int nPlayer, int bIsMummified)
|
|
{
|
|
auto pActor = PlayerList[nPlayer].pActor;
|
|
auto pSprite = &pActor->s();
|
|
|
|
pSprite->yvel = 0;
|
|
pSprite->xvel = 0;
|
|
|
|
PlayerList[nPlayer].bIsMummified = bIsMummified;
|
|
|
|
if (bIsMummified)
|
|
{
|
|
PlayerList[nPlayer].nAction = 13;
|
|
PlayerList[nPlayer].nSeq = kSeqMummy;
|
|
}
|
|
else
|
|
{
|
|
PlayerList[nPlayer].nAction = 0;
|
|
PlayerList[nPlayer].nSeq = kSeqJoe;
|
|
}
|
|
|
|
PlayerList[nPlayer].field_2 = 0;
|
|
}
|
|
|
|
void ShootStaff(int nPlayer)
|
|
{
|
|
PlayerList[nPlayer].nAction = 15;
|
|
PlayerList[nPlayer].field_2 = 0;
|
|
PlayerList[nPlayer].nSeq = kSeqJoe;
|
|
}
|
|
|
|
void PlayAlert(const char *str)
|
|
{
|
|
StatusMessage(300, str);
|
|
PlayLocalSound(StaticSound[kSound63], 0);
|
|
}
|
|
|
|
|
|
static void pickupMessage(int no)
|
|
{
|
|
no = nItemText[no];
|
|
if (no != -1)
|
|
{
|
|
FStringf label("TXT_EX_PICKUP%d", no + 1);
|
|
auto str = GStrings[label];
|
|
if (str) Printf(PRINT_NOTIFY, "%s\n", str);
|
|
}
|
|
}
|
|
|
|
void UpdatePlayerSpriteAngle(Player* pPlayer)
|
|
{
|
|
inita = pPlayer->angle.ang.asbuild();
|
|
if (pPlayer->Actor()) pPlayer->Actor()->s().ang = inita;
|
|
}
|
|
|
|
void AIPlayer::Draw(RunListEvent* ev)
|
|
{
|
|
short nPlayer = RunData[ev->nRun].nObjIndex;
|
|
assert(nPlayer >= 0 && nPlayer < kMaxPlayers);
|
|
short nAction = PlayerList[nPlayer].nAction;
|
|
|
|
seq_PlotSequence(ev->nParam, SeqOffsets[PlayerList[nPlayer].nSeq] + PlayerSeq[nAction].a, PlayerList[nPlayer].field_2, PlayerSeq[nAction].b);
|
|
}
|
|
|
|
void AIPlayer::RadialDamage(RunListEvent* ev)
|
|
{
|
|
short nPlayer = RunData[ev->nRun].nObjIndex;
|
|
assert(nPlayer >= 0 && nPlayer < kMaxPlayers);
|
|
|
|
auto pPlayerActor = PlayerList[nPlayer].Actor();
|
|
|
|
if (PlayerList[nPlayer].nHealth <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ev->nDamage = runlist_CheckRadialDamage(pPlayerActor);
|
|
Damage(ev);
|
|
}
|
|
|
|
void AIPlayer::Damage(RunListEvent* ev)
|
|
{
|
|
int nDamage = ev->nDamage;
|
|
short nPlayer = RunData[ev->nRun].nObjIndex;
|
|
auto pPlayerActor = PlayerList[nPlayer].Actor();
|
|
short nAction = PlayerList[nPlayer].nAction;
|
|
auto pPlayerSprite = &pPlayerActor->s();
|
|
auto pDopple = PlayerList[nPlayer].pDoppleSprite;
|
|
|
|
if (!nDamage) {
|
|
return;
|
|
}
|
|
|
|
DExhumedActor* pActor2 = (!ev->isRadialEvent()) ? ev->pOtherActor : ev->pRadialActor->pTarget;
|
|
|
|
// ok continue case 0x80000 as normal, loc_1C57C
|
|
if (!PlayerList[nPlayer].nHealth) {
|
|
return;
|
|
}
|
|
|
|
if (!PlayerList[nPlayer].invincibility)
|
|
{
|
|
PlayerList[nPlayer].nHealth -= nDamage;
|
|
if (nPlayer == nLocalPlayer)
|
|
{
|
|
TintPalette(nDamage, 0, 0);
|
|
}
|
|
}
|
|
|
|
if (PlayerList[nPlayer].nHealth > 0)
|
|
{
|
|
if (nDamage > 40 || (totalmoves & 0xF) < 2)
|
|
{
|
|
if (PlayerList[nPlayer].invincibility) {
|
|
return;
|
|
}
|
|
|
|
if (SectFlag[pPlayerSprite->sectnum] & kSectUnderwater)
|
|
{
|
|
if (nAction != 12)
|
|
{
|
|
PlayerList[nPlayer].field_2 = 0;
|
|
PlayerList[nPlayer].nAction = 12;
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (nAction != 4)
|
|
{
|
|
PlayerList[nPlayer].field_2 = 0;
|
|
PlayerList[nPlayer].nAction = 4;
|
|
|
|
if (pActor2)
|
|
{
|
|
PlayerList[nPlayer].nPlayerSwear--;
|
|
if (PlayerList[nPlayer].nPlayerSwear <= 0)
|
|
{
|
|
D3PlayFX(StaticSound[kSound52], pDopple);
|
|
PlayerList[nPlayer].nPlayerSwear = RandomSize(3) + 4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// player has died
|
|
if (pActor2 && pActor2->s().statnum == 100)
|
|
{
|
|
short nPlayer2 = GetPlayerFromActor(pActor2);
|
|
|
|
if (nPlayer2 == nPlayer) // player caused their own death
|
|
{
|
|
PlayerList[nPlayer].nPlayerScore--;
|
|
}
|
|
else
|
|
{
|
|
PlayerList[nPlayer].nPlayerScore++;
|
|
}
|
|
}
|
|
else if (pActor2 == nullptr)
|
|
{
|
|
PlayerList[nPlayer].nPlayerScore--;
|
|
}
|
|
|
|
if (ev->isRadialEvent())
|
|
{
|
|
for (int i = 122; i <= 131; i++)
|
|
{
|
|
BuildCreatureChunk(pPlayerActor, seq_GetSeqPicnum(kSeqJoe, i, 0));
|
|
}
|
|
|
|
StartDeathSeq(nPlayer, 1);
|
|
}
|
|
else
|
|
{
|
|
StartDeathSeq(nPlayer, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void AIPlayer::Tick(RunListEvent* ev)
|
|
{
|
|
int var_48 = 0;
|
|
int var_40;
|
|
bool mplevel = (currentLevel->gameflags & LEVEL_EX_MULTI);
|
|
|
|
short nPlayer = RunData[ev->nRun].nObjIndex;
|
|
assert(nPlayer >= 0 && nPlayer < kMaxPlayers);
|
|
|
|
auto pPlayerActor = PlayerList[nPlayer].Actor();
|
|
auto pPlayerSprite = &pPlayerActor->s();
|
|
|
|
auto pDopple = PlayerList[nPlayer].pDoppleSprite;
|
|
|
|
short nAction = PlayerList[nPlayer].nAction;
|
|
short nActionB = PlayerList[nPlayer].nAction;
|
|
|
|
PlayerList[nPlayer].angle.backup();
|
|
PlayerList[nPlayer].horizon.backup();
|
|
PlayerList[nPlayer].angle.resetadjustment();
|
|
PlayerList[nPlayer].horizon.resetadjustment();
|
|
PlayerList[nPlayer].oeyelevel = PlayerList[nPlayer].eyelevel;
|
|
|
|
pPlayerSprite->xvel = sPlayerInput[nPlayer].xVel >> 14;
|
|
pPlayerSprite->yvel = sPlayerInput[nPlayer].yVel >> 14;
|
|
|
|
if (sPlayerInput[nPlayer].nItem > -1)
|
|
{
|
|
UseItem(nPlayer, sPlayerInput[nPlayer].nItem);
|
|
sPlayerInput[nPlayer].nItem = -1;
|
|
}
|
|
|
|
int var_EC = PlayerList[nPlayer].field_2;
|
|
|
|
pPlayerSprite->picnum = seq_GetSeqPicnum(PlayerList[nPlayer].nSeq, PlayerSeq[nHeightTemplate[nAction]].a, var_EC);
|
|
pDopple->s().picnum = pPlayerSprite->picnum;
|
|
|
|
if (PlayerList[nPlayer].nTorch > 0)
|
|
{
|
|
PlayerList[nPlayer].nTorch--;
|
|
if (PlayerList[nPlayer].nTorch == 0)
|
|
{
|
|
SetTorch(nPlayer, 0);
|
|
}
|
|
else
|
|
{
|
|
if (nPlayer != nLocalPlayer)
|
|
{
|
|
nFlashDepth = 5;
|
|
AddFlash(pPlayerSprite->sectnum,
|
|
pPlayerSprite->x,
|
|
pPlayerSprite->y,
|
|
pPlayerSprite->z, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (PlayerList[nPlayer].nDouble > 0)
|
|
{
|
|
PlayerList[nPlayer].nDouble--;
|
|
if (PlayerList[nPlayer].nDouble == 150 && nPlayer == nLocalPlayer) {
|
|
PlayAlert("WEAPON POWER IS ABOUT TO EXPIRE");
|
|
}
|
|
}
|
|
|
|
if (PlayerList[nPlayer].nInvisible > 0)
|
|
{
|
|
PlayerList[nPlayer].nInvisible--;
|
|
if (PlayerList[nPlayer].nInvisible == 0)
|
|
{
|
|
pPlayerSprite->cstat &= 0x7FFF; // set visible
|
|
auto pFloorSprite = PlayerList[nPlayer].pPlayerFloorSprite;
|
|
|
|
if (pFloorSprite != nullptr) {
|
|
pFloorSprite->s().cstat &= 0x7FFF; // set visible
|
|
}
|
|
}
|
|
else if (PlayerList[nPlayer].nInvisible == 150 && nPlayer == nLocalPlayer)
|
|
{
|
|
PlayAlert("INVISIBILITY IS ABOUT TO EXPIRE");
|
|
}
|
|
}
|
|
|
|
if (PlayerList[nPlayer].invincibility > 0)
|
|
{
|
|
PlayerList[nPlayer].invincibility--;
|
|
if (PlayerList[nPlayer].invincibility == 150 && nPlayer == nLocalPlayer) {
|
|
PlayAlert("INVINCIBILITY IS ABOUT TO EXPIRE");
|
|
}
|
|
}
|
|
|
|
if (nQuake[nPlayer] != 0)
|
|
{
|
|
nQuake[nPlayer] = -nQuake[nPlayer];
|
|
if (nQuake[nPlayer] > 0)
|
|
{
|
|
nQuake[nPlayer] -= 512;
|
|
if (nQuake[nPlayer] < 0)
|
|
nQuake[nPlayer] = 0;
|
|
}
|
|
}
|
|
|
|
// loc_1A494:
|
|
if (SyncInput())
|
|
{
|
|
Player* pPlayer = &PlayerList[nPlayer];
|
|
pPlayer->angle.applyinput(sPlayerInput[nPlayer].nAngle, &sPlayerInput[nLocalPlayer].actions);
|
|
UpdatePlayerSpriteAngle(pPlayer);
|
|
}
|
|
|
|
// pPlayerSprite->zvel is modified within Gravity()
|
|
short zVel = pPlayerSprite->zvel;
|
|
|
|
Gravity(pPlayerActor);
|
|
|
|
if (pPlayerSprite->zvel >= 6500 && zVel < 6500)
|
|
{
|
|
D3PlayFX(StaticSound[kSound17], pPlayerActor);
|
|
}
|
|
|
|
// loc_1A4E6
|
|
short nSector = pPlayerSprite->sectnum;
|
|
short nSectFlag = SectFlag[PlayerList[nPlayer].nPlayerViewSect];
|
|
|
|
int playerX = pPlayerSprite->x;
|
|
int playerY = pPlayerSprite->y;
|
|
|
|
int x = (sPlayerInput[nPlayer].xVel * 4) >> 2;
|
|
int y = (sPlayerInput[nPlayer].yVel * 4) >> 2;
|
|
int z = (pPlayerSprite->zvel * 4) >> 2;
|
|
|
|
if (pPlayerSprite->zvel > 8192)
|
|
pPlayerSprite->zvel = 8192;
|
|
|
|
if (PlayerList[nPlayer].bIsMummified)
|
|
{
|
|
x /= 2;
|
|
y /= 2;
|
|
}
|
|
|
|
int spr_x = pPlayerSprite->x;
|
|
int spr_y = pPlayerSprite->y;
|
|
int spr_z = pPlayerSprite->z;
|
|
int spr_sectnum = pPlayerSprite->sectnum;
|
|
|
|
// TODO
|
|
// nSectFlag & kSectUnderwater;
|
|
|
|
zVel = pPlayerSprite->zvel;
|
|
|
|
Collision nMove(0);
|
|
if (bSlipMode)
|
|
{
|
|
pPlayerSprite->x += (x >> 14);
|
|
pPlayerSprite->y += (y >> 14);
|
|
|
|
vec3_t pos = { pPlayerSprite->x, pPlayerSprite->y, pPlayerSprite->z };
|
|
setActorPos(pPlayerActor, &pos);
|
|
|
|
pPlayerSprite->z = sector[pPlayerSprite->sectnum].floorz;
|
|
}
|
|
else
|
|
{
|
|
nMove = movesprite(pPlayerActor, x, y, z, 5120, -5120, CLIPMASK0);
|
|
|
|
int var_54 = pPlayerSprite->sectnum;
|
|
|
|
pushmove(&pPlayerSprite->pos, &var_54, pPlayerSprite->clipdist << 2, 5120, -5120, CLIPMASK0);
|
|
if (var_54 != pPlayerSprite->sectnum) {
|
|
ChangeActorSect(pPlayerActor, var_54);
|
|
}
|
|
}
|
|
|
|
// loc_1A6E4
|
|
if (inside(pPlayerSprite->x, pPlayerSprite->y, pPlayerSprite->sectnum) != 1)
|
|
{
|
|
ChangeActorSect(pPlayerActor, spr_sectnum);
|
|
|
|
pPlayerSprite->x = spr_x;
|
|
pPlayerSprite->y = spr_y;
|
|
|
|
if (zVel < pPlayerSprite->zvel) {
|
|
pPlayerSprite->zvel = zVel;
|
|
}
|
|
}
|
|
|
|
// int _bTouchFloor = bTouchFloor;
|
|
short bUnderwater = SectFlag[pPlayerSprite->sectnum] & kSectUnderwater;
|
|
|
|
if (bUnderwater)
|
|
{
|
|
PlayerList[nPlayer].nXDamage /= 2;
|
|
PlayerList[nPlayer].nYDamage /= 2;
|
|
}
|
|
|
|
// Trigger Ramses?
|
|
if ((SectFlag[pPlayerSprite->sectnum] & 0x8000) && bTouchFloor)
|
|
{
|
|
if (nTotalPlayers <= 1)
|
|
{
|
|
auto ang = GetAngleToSprite(pPlayerActor, pSpiritSprite) & kAngleMask;
|
|
PlayerList[nPlayer].angle.settarget(ang, true);
|
|
pPlayerSprite->ang = ang;
|
|
|
|
PlayerList[nPlayer].horizon.settarget(0, true);
|
|
|
|
lPlayerXVel = 0;
|
|
lPlayerYVel = 0;
|
|
|
|
pPlayerSprite->xvel = 0;
|
|
pPlayerSprite->yvel = 0;
|
|
pPlayerSprite->zvel = 0;
|
|
|
|
if (nFreeze < 1)
|
|
{
|
|
nFreeze = 1;
|
|
StopAllSounds();
|
|
StopLocalSound();
|
|
InitSpiritHead();
|
|
|
|
PlayerList[nPlayer].nDestVertPan = q16horiz(0);
|
|
PlayerList[nPlayer].horizon.settarget(currentLevel->ex_ramses_horiz);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LevelFinished();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (nMove.type || nMove.exbits)
|
|
{
|
|
if (bTouchFloor)
|
|
{
|
|
// Damage stuff..
|
|
PlayerList[nPlayer].nXDamage /= 2;
|
|
PlayerList[nPlayer].nYDamage /= 2;
|
|
|
|
if (nPlayer == nLocalPlayer)
|
|
{
|
|
short zVelB = zVel;
|
|
|
|
if (zVelB < 0) {
|
|
zVelB = -zVelB;
|
|
}
|
|
|
|
if (zVelB > 512 && !PlayerList[nPlayer].horizon.horiz.asq16() && cl_slopetilting) {
|
|
PlayerList[nPlayer].nDestVertPan = q16horiz(0);
|
|
}
|
|
}
|
|
|
|
if (zVel >= 6500)
|
|
{
|
|
pPlayerSprite->xvel >>= 2;
|
|
pPlayerSprite->yvel >>= 2;
|
|
|
|
runlist_DamageEnemy(pPlayerActor, nullptr, ((zVel - 6500) >> 7) + 10);
|
|
|
|
if (PlayerList[nPlayer].nHealth <= 0)
|
|
{
|
|
pPlayerSprite->xvel = 0;
|
|
pPlayerSprite->yvel = 0;
|
|
|
|
StopActorSound(pPlayerActor);
|
|
PlayFXAtXYZ(StaticSound[kSoundJonFDie], pPlayerSprite->x, pPlayerSprite->y, pPlayerSprite->z, pPlayerSprite->sectnum, CHANF_NONE, 1); // CHECKME
|
|
}
|
|
else
|
|
{
|
|
D3PlayFX(StaticSound[kSound27] | 0x2000, pPlayerActor);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nMove.type == kHitSector || nMove.type == kHitWall)
|
|
{
|
|
int sectnum = 0;
|
|
int nNormal = 0;
|
|
|
|
if (nMove.type == kHitSector)
|
|
{
|
|
sectnum = nMove.index;
|
|
// Hm... Normal calculation here was broken.
|
|
}
|
|
else if (nMove.type == kHitWall)
|
|
{
|
|
sectnum = wall[nMove.index].nextsector;
|
|
nNormal = GetWallNormal(nMove.index);
|
|
}
|
|
|
|
if (sectnum >= 0)
|
|
{
|
|
if ((sector[sectnum].hitag == 45) && bTouchFloor)
|
|
{
|
|
int nDiff = AngleDiff(nNormal, (pPlayerSprite->ang + 1024) & kAngleMask);
|
|
|
|
if (nDiff < 0) {
|
|
nDiff = -nDiff;
|
|
}
|
|
|
|
if (nDiff <= 256)
|
|
{
|
|
PlayerList[nPlayer].nPlayerPushSect = sectnum;
|
|
|
|
int xvel = sPlayerInput[nPlayer].xVel;
|
|
int yvel = sPlayerInput[nPlayer].yVel;
|
|
int nMyAngle = GetMyAngle(xvel, yvel);
|
|
|
|
setsectinterpolate(sectnum);
|
|
MoveSector(sectnum, nMyAngle, &xvel, &yvel);
|
|
|
|
if (PlayerList[nPlayer].nPlayerPushSound <= -1)
|
|
{
|
|
PlayerList[nPlayer].nPlayerPushSound = 1;
|
|
short nBlock = sector[PlayerList[nPlayer].nPlayerPushSect].extra;
|
|
auto pBlockActor = sBlockInfo[nBlock].pActor;
|
|
|
|
D3PlayFX(StaticSound[kSound23], pBlockActor, 0x4000);
|
|
}
|
|
else
|
|
{
|
|
pPlayerSprite->x = spr_x;
|
|
pPlayerSprite->y = spr_y;
|
|
pPlayerSprite->z = spr_z;
|
|
|
|
ChangeActorSect(pPlayerActor, spr_sectnum);
|
|
}
|
|
|
|
movesprite(pPlayerActor, xvel, yvel, z, 5120, -5120, CLIPMASK0);
|
|
goto sectdone;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// loc_1AB46:
|
|
if (PlayerList[nPlayer].nPlayerPushSound > -1)
|
|
{
|
|
if (PlayerList[nPlayer].nPlayerPushSect > -1)
|
|
{
|
|
StopActorSound(sBlockInfo[sector[PlayerList[nPlayer].nPlayerPushSect].extra].pActor);
|
|
}
|
|
|
|
PlayerList[nPlayer].nPlayerPushSound = -1;
|
|
}
|
|
|
|
sectdone:
|
|
if (!PlayerList[nPlayer].bPlayerPan && !PlayerList[nPlayer].bLockPan)
|
|
{
|
|
PlayerList[nPlayer].nDestVertPan = q16horiz(clamp((spr_z - pPlayerSprite->z) << 9, gi->playerHorizMin(), gi->playerHorizMax()));
|
|
}
|
|
|
|
playerX -= pPlayerSprite->x;
|
|
playerY -= pPlayerSprite->y;
|
|
|
|
uint32_t sqrtNum = playerX * playerX + playerY * playerY;
|
|
|
|
if (sqrtNum > INT_MAX)
|
|
{
|
|
DPrintf(DMSG_WARNING, "%s %d: overflow\n", __func__, __LINE__);
|
|
sqrtNum = INT_MAX;
|
|
}
|
|
|
|
PlayerList[nPlayer].ototalvel = PlayerList[nPlayer].totalvel;
|
|
PlayerList[nPlayer].totalvel = ksqrt(sqrtNum);
|
|
|
|
int nViewSect = pPlayerSprite->sectnum;
|
|
|
|
int EyeZ = PlayerList[nPlayer].eyelevel + pPlayerSprite->z + nQuake[nPlayer];
|
|
|
|
while (1)
|
|
{
|
|
int nCeilZ = sector[nViewSect].ceilingz;
|
|
|
|
if (EyeZ >= nCeilZ)
|
|
break;
|
|
|
|
if (SectAbove[nViewSect] <= -1)
|
|
break;
|
|
|
|
nViewSect = SectAbove[nViewSect];
|
|
}
|
|
|
|
// Do underwater sector check
|
|
if (bUnderwater)
|
|
{
|
|
if (nViewSect != pPlayerSprite->sectnum)
|
|
{
|
|
if (nMove.type == kHitWall)
|
|
{
|
|
int var_C4 = pPlayerSprite->x;
|
|
int var_D4 = pPlayerSprite->y;
|
|
int var_C8 = pPlayerSprite->z;
|
|
|
|
ChangeActorSect(pPlayerActor, nViewSect);
|
|
|
|
pPlayerSprite->x = spr_x;
|
|
pPlayerSprite->y = spr_y;
|
|
|
|
int var_FC = sector[nViewSect].floorz + (-5120);
|
|
|
|
pPlayerSprite->z = var_FC;
|
|
|
|
auto coll = movesprite(pPlayerActor, x, y, 0, 5120, 0, CLIPMASK0);
|
|
if (coll.type == kHitWall)
|
|
{
|
|
ChangeActorSect(pPlayerActor, pPlayerSprite->sectnum);
|
|
|
|
pPlayerSprite->x = var_C4;
|
|
pPlayerSprite->y = var_D4;
|
|
pPlayerSprite->z = var_C8;
|
|
}
|
|
else
|
|
{
|
|
pPlayerSprite->z = var_FC - 256;
|
|
D3PlayFX(StaticSound[kSound42], pPlayerActor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// loc_1ADAF
|
|
PlayerList[nPlayer].nPlayerViewSect = nViewSect;
|
|
|
|
PlayerList[nPlayer].nPlayerDX = pPlayerSprite->x - spr_x;
|
|
PlayerList[nPlayer].nPlayerDY = pPlayerSprite->y - spr_y;
|
|
|
|
int var_5C = SectFlag[nViewSect] & kSectUnderwater;
|
|
|
|
uint16_t buttons = sPlayerInput[nPlayer].buttons;
|
|
auto actions = sPlayerInput[nPlayer].actions;
|
|
|
|
// loc_1AEF5:
|
|
if (PlayerList[nPlayer].nHealth > 0)
|
|
{
|
|
if (PlayerList[nPlayer].nMaskAmount > 0)
|
|
{
|
|
PlayerList[nPlayer].nMaskAmount--;
|
|
if (PlayerList[nPlayer].nMaskAmount == 150 && nPlayer == nLocalPlayer) {
|
|
PlayAlert("MASK IS ABOUT TO EXPIRE");
|
|
}
|
|
}
|
|
|
|
if (!PlayerList[nPlayer].invincibility)
|
|
{
|
|
// Handle air
|
|
PlayerList[nPlayer].nBreathTimer--;
|
|
|
|
if (PlayerList[nPlayer].nBreathTimer <= 0)
|
|
{
|
|
PlayerList[nPlayer].nBreathTimer = 90;
|
|
|
|
// if underwater
|
|
if (var_5C)
|
|
{
|
|
if (PlayerList[nPlayer].nMaskAmount > 0)
|
|
{
|
|
D3PlayFX(StaticSound[kSound30], pPlayerActor);
|
|
|
|
PlayerList[nPlayer].nAir = 100;
|
|
}
|
|
else
|
|
{
|
|
PlayerList[nPlayer].nAir -= 25;
|
|
if (PlayerList[nPlayer].nAir > 0)
|
|
{
|
|
D3PlayFX(StaticSound[kSound25], pPlayerActor);
|
|
}
|
|
else
|
|
{
|
|
PlayerList[nPlayer].nHealth += (PlayerList[nPlayer].nAir << 2);
|
|
if (PlayerList[nPlayer].nHealth <= 0)
|
|
{
|
|
PlayerList[nPlayer].nHealth = 0;
|
|
StartDeathSeq(nPlayer, 0);
|
|
}
|
|
|
|
PlayerList[nPlayer].nAir = 0;
|
|
|
|
if (PlayerList[nPlayer].nHealth < 300)
|
|
{
|
|
D3PlayFX(StaticSound[kSound79], pPlayerActor);
|
|
}
|
|
else
|
|
{
|
|
D3PlayFX(StaticSound[kSound19], pPlayerActor);
|
|
}
|
|
}
|
|
}
|
|
|
|
DoBubbles(nPlayer);
|
|
}
|
|
}
|
|
}
|
|
|
|
// loc_1B0B9
|
|
if (var_5C) // if underwater
|
|
{
|
|
if (PlayerList[nPlayer].nTorch > 0)
|
|
{
|
|
PlayerList[nPlayer].nTorch = 0;
|
|
SetTorch(nPlayer, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int nTmpSectNum = pPlayerSprite->sectnum;
|
|
|
|
if (PlayerList[nPlayer].totalvel > 25 && pPlayerSprite->z > sector[nTmpSectNum].floorz)
|
|
{
|
|
if (SectDepth[nTmpSectNum] && !SectSpeed[nTmpSectNum] && !SectDamage[nTmpSectNum])
|
|
{
|
|
D3PlayFX(StaticSound[kSound42], pPlayerActor);
|
|
}
|
|
}
|
|
|
|
// CHECKME - wrong place?
|
|
if (nSectFlag & kSectUnderwater)
|
|
{
|
|
if (PlayerList[nPlayer].nAir < 50)
|
|
{
|
|
D3PlayFX(StaticSound[kSound14], pPlayerActor);
|
|
}
|
|
|
|
PlayerList[nPlayer].nBreathTimer = 1;
|
|
}
|
|
|
|
PlayerList[nPlayer].nBreathTimer--;
|
|
if (PlayerList[nPlayer].nBreathTimer <= 0)
|
|
{
|
|
PlayerList[nPlayer].nBreathTimer = 90;
|
|
}
|
|
|
|
if (PlayerList[nPlayer].nAir < 100)
|
|
{
|
|
PlayerList[nPlayer].nAir = 100;
|
|
}
|
|
}
|
|
|
|
// loc_1B1EB
|
|
auto pFloorActor = PlayerList[nPlayer].pPlayerFloorSprite;
|
|
if (nTotalPlayers > 1 && pFloorActor)
|
|
{
|
|
auto pFloorSprite = &pFloorActor->s();
|
|
|
|
pFloorSprite->x = pPlayerSprite->x;
|
|
pFloorSprite->y = pPlayerSprite->y;
|
|
|
|
if (pFloorSprite->sectnum != pPlayerSprite->sectnum)
|
|
{
|
|
ChangeActorSect(pFloorActor, pPlayerSprite->sectnum);
|
|
}
|
|
|
|
pFloorSprite->z = sector[pPlayerSprite->sectnum].floorz;
|
|
}
|
|
|
|
int var_30 = 0;
|
|
|
|
if (PlayerList[nPlayer].nHealth >= 800)
|
|
{
|
|
var_30 = 2;
|
|
}
|
|
|
|
if (PlayerList[nPlayer].nMagic >= 1000)
|
|
{
|
|
var_30 |= 1;
|
|
}
|
|
|
|
// code to handle item pickup?
|
|
short nearTagSector, nearTagWall, nearTagSprite;
|
|
int nearHitDist;
|
|
|
|
// neartag finds the nearest sector, wall, and sprite which has its hitag and/or lotag set to a value.
|
|
neartag(pPlayerSprite->x, pPlayerSprite->y, pPlayerSprite->z, pPlayerSprite->sectnum, pPlayerSprite->ang,
|
|
&nearTagSector, &nearTagWall, &nearTagSprite, (int32_t*)&nearHitDist, 1024, 2, nullptr);
|
|
|
|
DExhumedActor* pActorB;
|
|
feebtag(pPlayerSprite->x, pPlayerSprite->y, pPlayerSprite->z, pPlayerSprite->sectnum, &pActorB, var_30, 768);
|
|
|
|
// Item pickup code
|
|
if (pActorB != nullptr && pActorB->s().statnum >= 900)
|
|
{
|
|
auto pSpriteB = &pActorB->s();
|
|
int var_8C = 16;
|
|
int var_88 = 9;
|
|
|
|
int var_70 = pSpriteB->statnum - 900;
|
|
int var_44 = 0;
|
|
|
|
// item lotags start at 6 (1-5 reserved?) so 0-offset them
|
|
int itemtype = var_70 - 6;
|
|
|
|
if (itemtype <= 54)
|
|
{
|
|
switch (itemtype)
|
|
{
|
|
do_default:
|
|
default:
|
|
{
|
|
// loc_1B3C7
|
|
|
|
// CHECKME - is order of evaluation correct?
|
|
if (!mplevel || (var_70 >= 25 && (var_70 <= 25 || var_70 == 50)))
|
|
{
|
|
// If this is an anim we need to properly destroy it so we need to do some proper detection and not wild guesses.
|
|
if (pActorB->nRun == pActorB->nDamage && pActorB->nRun != 0 && pActorB->nPhase == ITEM_MAGIC)
|
|
DestroyAnim(pActorB);
|
|
else
|
|
DeleteActor(pActorB);
|
|
}
|
|
else
|
|
{
|
|
StartRegenerate(pActorB);
|
|
}
|
|
do_default_b:
|
|
// loc_1BA74
|
|
if (nPlayer == nLocalPlayer)
|
|
{
|
|
if (nItemText[var_70] > -1 && nTotalPlayers == 1)
|
|
{
|
|
pickupMessage(var_70);
|
|
}
|
|
|
|
TintPalette(var_44 * 4, var_8C * 4, 0);
|
|
|
|
if (var_88 > -1)
|
|
{
|
|
PlayLocalSound(var_88, 0);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case 0: // Speed Loader
|
|
{
|
|
if (AddAmmo(nPlayer, 1, pSpriteB->hitag))
|
|
{
|
|
var_88 = StaticSound[kSoundAmmoPickup];
|
|
goto do_default;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case 1: // Fuel Canister
|
|
{
|
|
if (AddAmmo(nPlayer, 3, pSpriteB->hitag))
|
|
{
|
|
var_88 = StaticSound[kSoundAmmoPickup];
|
|
goto do_default;
|
|
}
|
|
break;
|
|
}
|
|
case 2: // M - 60 Ammo Belt
|
|
{
|
|
if (AddAmmo(nPlayer, 2, pSpriteB->hitag))
|
|
{
|
|
var_88 = StaticSound[kSoundAmmoPickup];
|
|
CheckClip(nPlayer);
|
|
goto do_default;
|
|
}
|
|
break;
|
|
}
|
|
case 3: // Grenade
|
|
case 21:
|
|
case 49:
|
|
{
|
|
if (AddAmmo(nPlayer, 4, 1))
|
|
{
|
|
var_88 = StaticSound[kSoundAmmoPickup];
|
|
if (!(PlayerList[nPlayer].nPlayerWeapons & 0x10))
|
|
{
|
|
PlayerList[nPlayer].nPlayerWeapons |= 0x10;
|
|
SetNewWeaponIfBetter(nPlayer, 4);
|
|
}
|
|
|
|
if (var_70 == 55)
|
|
{
|
|
pSpriteB->cstat = 0x8000;
|
|
DestroyItemAnim(pActorB);
|
|
|
|
// loc_1BA74: - repeated block, see in default case
|
|
if (nPlayer == nLocalPlayer)
|
|
{
|
|
if (nItemText[var_70] > -1 && nTotalPlayers == 1)
|
|
{
|
|
pickupMessage(var_70);
|
|
}
|
|
|
|
TintPalette(var_44 * 4, var_8C * 4, 0);
|
|
|
|
if (var_88 > -1)
|
|
{
|
|
PlayLocalSound(var_88, 0);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
goto do_default;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 4: // Pickable item
|
|
case 9: // Pickable item
|
|
case 10: // Reserved
|
|
case 18:
|
|
case 25:
|
|
case 28:
|
|
case 29:
|
|
case 30:
|
|
case 33:
|
|
case 34:
|
|
case 35:
|
|
case 36:
|
|
case 37:
|
|
case 38:
|
|
case 45:
|
|
case 52:
|
|
{
|
|
goto do_default;
|
|
}
|
|
|
|
case 5: // Map
|
|
{
|
|
GrabMap();
|
|
goto do_default;
|
|
}
|
|
|
|
case 6: // Berry Twig
|
|
{
|
|
if (pSpriteB->hitag == 0) {
|
|
break;
|
|
}
|
|
|
|
var_88 = 20;
|
|
int edx = 40;
|
|
|
|
if (edx <= 0 || (!(var_30 & 2)))
|
|
{
|
|
if (!PlayerList[nPlayer].invincibility || edx > 0)
|
|
{
|
|
PlayerList[nPlayer].nHealth += edx;
|
|
if (PlayerList[nPlayer].nHealth > 800)
|
|
{
|
|
PlayerList[nPlayer].nHealth = 800;
|
|
}
|
|
else
|
|
{
|
|
if (PlayerList[nPlayer].nHealth < 0)
|
|
{
|
|
var_88 = -1;
|
|
StartDeathSeq(nPlayer, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (var_70 == 12)
|
|
{
|
|
pSpriteB->hitag = 0;
|
|
pSpriteB->picnum++;
|
|
|
|
ChangeActorStat(pActorB, 0);
|
|
|
|
// loc_1BA74: - repeated block, see in default case
|
|
if (nPlayer == nLocalPlayer)
|
|
{
|
|
if (nItemText[var_70] > -1 && nTotalPlayers == 1)
|
|
{
|
|
pickupMessage(var_70);
|
|
}
|
|
|
|
TintPalette(var_44 * 4, var_8C * 4, 0);
|
|
|
|
if (var_88 > -1)
|
|
{
|
|
PlayLocalSound(var_88, 0);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (var_70 != 14)
|
|
{
|
|
var_88 = 21;
|
|
}
|
|
else
|
|
{
|
|
var_44 = var_8C;
|
|
var_88 = 22;
|
|
var_8C = 0;
|
|
}
|
|
|
|
goto do_default;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 7: // Blood Bowl
|
|
{
|
|
int edx = 160;
|
|
|
|
// Same code as case 6 now till break
|
|
if (edx <= 0 || (!(var_30 & 2)))
|
|
{
|
|
if (!PlayerList[nPlayer].invincibility || edx > 0)
|
|
{
|
|
PlayerList[nPlayer].nHealth += edx;
|
|
if (PlayerList[nPlayer].nHealth > 800)
|
|
{
|
|
PlayerList[nPlayer].nHealth = 800;
|
|
}
|
|
else
|
|
{
|
|
if (PlayerList[nPlayer].nHealth < 0)
|
|
{
|
|
var_88 = -1;
|
|
StartDeathSeq(nPlayer, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (var_70 == 12)
|
|
{
|
|
pSpriteB->hitag = 0;
|
|
pSpriteB->picnum++;
|
|
|
|
ChangeActorStat(pActorB, 0);
|
|
|
|
// loc_1BA74: - repeated block, see in default case
|
|
if (nPlayer == nLocalPlayer)
|
|
{
|
|
if (nItemText[var_70] > -1 && nTotalPlayers == 1)
|
|
{
|
|
pickupMessage(var_70);
|
|
}
|
|
|
|
TintPalette(var_44 * 4, var_8C * 4, 0);
|
|
|
|
if (var_88 > -1)
|
|
{
|
|
PlayLocalSound(var_88, 0);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (var_70 != 14)
|
|
{
|
|
var_88 = 21;
|
|
}
|
|
else
|
|
{
|
|
var_44 = var_8C;
|
|
var_88 = 22;
|
|
var_8C = 0;
|
|
}
|
|
|
|
goto do_default;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 8: // Cobra Venom Bowl
|
|
{
|
|
int edx = -200;
|
|
|
|
// Same code as case 6 and 7 from now till break
|
|
if (edx <= 0 || (!(var_30 & 2)))
|
|
{
|
|
if (!PlayerList[nPlayer].invincibility || edx > 0)
|
|
{
|
|
PlayerList[nPlayer].nHealth += edx;
|
|
if (PlayerList[nPlayer].nHealth > 800)
|
|
{
|
|
PlayerList[nPlayer].nHealth = 800;
|
|
}
|
|
else
|
|
{
|
|
if (PlayerList[nPlayer].nHealth < 0)
|
|
{
|
|
var_88 = -1;
|
|
StartDeathSeq(nPlayer, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (var_70 == 12)
|
|
{
|
|
pSpriteB->hitag = 0;
|
|
pSpriteB->picnum++;
|
|
|
|
ChangeActorStat(pActorB, 0);
|
|
|
|
// loc_1BA74: - repeated block, see in default case
|
|
if (nPlayer == nLocalPlayer)
|
|
{
|
|
if (nItemText[var_70] > -1 && nTotalPlayers == 1)
|
|
{
|
|
pickupMessage(var_70);
|
|
}
|
|
|
|
TintPalette(var_44 * 4, var_8C * 4, 0);
|
|
|
|
if (var_88 > -1)
|
|
{
|
|
PlayLocalSound(var_88, 0);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if (var_70 != 14)
|
|
{
|
|
var_88 = 21;
|
|
}
|
|
else
|
|
{
|
|
var_44 = var_8C;
|
|
var_88 = 22;
|
|
var_8C = 0;
|
|
}
|
|
|
|
goto do_default;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 11: // Bubble Nest
|
|
{
|
|
PlayerList[nPlayer].nAir += 10;
|
|
if (PlayerList[nPlayer].nAir > 100) {
|
|
PlayerList[nPlayer].nAir = 100; // TODO - constant
|
|
}
|
|
|
|
if (PlayerList[nPlayer].nBreathTimer < 89)
|
|
{
|
|
D3PlayFX(StaticSound[kSound13], pPlayerActor);
|
|
}
|
|
|
|
PlayerList[nPlayer].nBreathTimer = 90;
|
|
break;
|
|
}
|
|
|
|
case 12: // Still Beating Heart
|
|
{
|
|
if (GrabItem(nPlayer, kItemHeart)) {
|
|
goto do_default;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 13: // Scarab amulet(Invicibility)
|
|
{
|
|
if (GrabItem(nPlayer, kItemInvincibility)) {
|
|
goto do_default;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 14: // Severed Slave Hand(double damage)
|
|
{
|
|
if (GrabItem(nPlayer, kItemDoubleDamage)) {
|
|
goto do_default;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 15: // Unseen eye(Invisibility)
|
|
{
|
|
if (GrabItem(nPlayer, kItemInvisibility)) {
|
|
goto do_default;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 16: // Torch
|
|
{
|
|
if (GrabItem(nPlayer, kItemTorch)) {
|
|
goto do_default;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 17: // Sobek Mask
|
|
{
|
|
if (GrabItem(nPlayer, kItemMask)) {
|
|
goto do_default;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 19: // Extra Life
|
|
{
|
|
var_88 = -1;
|
|
|
|
if (PlayerList[nPlayer].nLives >= kMaxPlayerLives) {
|
|
break;
|
|
}
|
|
|
|
PlayerList[nPlayer].nLives++;
|
|
|
|
var_8C = 32;
|
|
var_44 = 32;
|
|
goto do_default;
|
|
}
|
|
|
|
// FIXME - lots of repeated code from here down!!
|
|
case 20: // sword pickup??
|
|
{
|
|
var_40 = 0;
|
|
int ebx = 0;
|
|
|
|
// loc_1B75D
|
|
int var_18 = 1 << var_40;
|
|
|
|
short weapons = PlayerList[nPlayer].nPlayerWeapons;
|
|
|
|
if (weapons & var_18)
|
|
{
|
|
if (mplevel)
|
|
{
|
|
AddAmmo(nPlayer, WeaponInfo[var_40].nAmmoType, ebx);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
weapons = var_40;
|
|
|
|
SetNewWeaponIfBetter(nPlayer, weapons);
|
|
|
|
PlayerList[nPlayer].nPlayerWeapons |= var_18;
|
|
|
|
AddAmmo(nPlayer, WeaponInfo[weapons].nAmmoType, ebx);
|
|
|
|
var_88 = StaticSound[kSound72];
|
|
}
|
|
|
|
if (var_40 == 2) {
|
|
CheckClip(nPlayer);
|
|
}
|
|
|
|
if (var_70 <= 50) {
|
|
goto do_default;
|
|
}
|
|
|
|
pSpriteB->cstat = 0x8000;
|
|
DestroyItemAnim(pActorB);
|
|
////
|
|
// loc_1BA74: - repeated block, see in default case
|
|
if (nPlayer == nLocalPlayer)
|
|
{
|
|
if (nItemText[var_70] > -1 && nTotalPlayers == 1)
|
|
{
|
|
pickupMessage(var_70);
|
|
}
|
|
|
|
TintPalette(var_44 * 4, var_8C * 4, 0);
|
|
|
|
if (var_88 > -1)
|
|
{
|
|
PlayLocalSound(var_88, 0);
|
|
}
|
|
}
|
|
|
|
break;
|
|
/////
|
|
}
|
|
|
|
case 22: // .357 Magnum Revolver
|
|
case 46:
|
|
{
|
|
var_40 = 1;
|
|
int ebx = 6;
|
|
|
|
// loc_1B75D
|
|
int var_18 = 1 << var_40;
|
|
|
|
short weapons = PlayerList[nPlayer].nPlayerWeapons;
|
|
|
|
if (weapons & var_18)
|
|
{
|
|
if (mplevel)
|
|
{
|
|
AddAmmo(nPlayer, WeaponInfo[var_40].nAmmoType, ebx);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
weapons = var_40;
|
|
|
|
SetNewWeaponIfBetter(nPlayer, weapons);
|
|
|
|
PlayerList[nPlayer].nPlayerWeapons |= var_18;
|
|
|
|
AddAmmo(nPlayer, WeaponInfo[weapons].nAmmoType, ebx);
|
|
|
|
var_88 = StaticSound[kSound72];
|
|
}
|
|
|
|
if (var_40 == 2) {
|
|
CheckClip(nPlayer);
|
|
}
|
|
|
|
if (var_70 <= 50) {
|
|
goto do_default;
|
|
}
|
|
|
|
pSpriteB->cstat = 0x8000;
|
|
DestroyItemAnim(pActorB);
|
|
////
|
|
// loc_1BA74: - repeated block, see in default case
|
|
if (nPlayer == nLocalPlayer)
|
|
{
|
|
if (nItemText[var_70] > -1 && nTotalPlayers == 1)
|
|
{
|
|
pickupMessage(var_70);
|
|
}
|
|
|
|
TintPalette(var_44 * 4, var_8C * 4, 0);
|
|
|
|
if (var_88 > -1)
|
|
{
|
|
PlayLocalSound(var_88, 0);
|
|
}
|
|
}
|
|
|
|
break;
|
|
/////
|
|
}
|
|
|
|
case 23: // M - 60 Machine Gun
|
|
case 47:
|
|
{
|
|
var_40 = 2;
|
|
int ebx = 24;
|
|
|
|
// loc_1B75D
|
|
int var_18 = 1 << var_40;
|
|
|
|
short weapons = PlayerList[nPlayer].nPlayerWeapons;
|
|
|
|
if (weapons & var_18)
|
|
{
|
|
if (mplevel)
|
|
{
|
|
AddAmmo(nPlayer, WeaponInfo[var_40].nAmmoType, ebx);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
weapons = var_40;
|
|
|
|
SetNewWeaponIfBetter(nPlayer, weapons);
|
|
|
|
PlayerList[nPlayer].nPlayerWeapons |= var_18;
|
|
|
|
AddAmmo(nPlayer, WeaponInfo[weapons].nAmmoType, ebx);
|
|
|
|
var_88 = StaticSound[kSound72];
|
|
}
|
|
|
|
if (var_40 == 2) {
|
|
CheckClip(nPlayer);
|
|
}
|
|
|
|
if (var_70 <= 50) {
|
|
goto do_default;
|
|
}
|
|
|
|
pSpriteB->cstat = 0x8000;
|
|
DestroyItemAnim(pActorB);
|
|
////
|
|
// loc_1BA74: - repeated block, see in default case
|
|
if (nPlayer == nLocalPlayer)
|
|
{
|
|
if (nItemText[var_70] > -1 && nTotalPlayers == 1)
|
|
{
|
|
pickupMessage(var_70);
|
|
}
|
|
|
|
TintPalette(var_44 * 4, var_8C * 4, 0);
|
|
|
|
if (var_88 > -1)
|
|
{
|
|
PlayLocalSound(var_88, 0);
|
|
}
|
|
}
|
|
|
|
break;
|
|
/////
|
|
}
|
|
|
|
case 24: // Flame Thrower
|
|
case 48:
|
|
{
|
|
var_40 = 3;
|
|
int ebx = 100;
|
|
|
|
// loc_1B75D
|
|
int var_18 = 1 << var_40;
|
|
|
|
short weapons = PlayerList[nPlayer].nPlayerWeapons;
|
|
|
|
if (weapons & var_18)
|
|
{
|
|
if (mplevel)
|
|
{
|
|
AddAmmo(nPlayer, WeaponInfo[var_40].nAmmoType, ebx);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
weapons = var_40;
|
|
|
|
SetNewWeaponIfBetter(nPlayer, weapons);
|
|
|
|
PlayerList[nPlayer].nPlayerWeapons |= var_18;
|
|
|
|
AddAmmo(nPlayer, WeaponInfo[weapons].nAmmoType, ebx);
|
|
|
|
var_88 = StaticSound[kSound72];
|
|
}
|
|
|
|
if (var_40 == 2) {
|
|
CheckClip(nPlayer);
|
|
}
|
|
|
|
if (var_70 <= 50) {
|
|
goto do_default;
|
|
}
|
|
|
|
pSpriteB->cstat = 0x8000;
|
|
DestroyItemAnim(pActorB);
|
|
////
|
|
// loc_1BA74: - repeated block, see in default case
|
|
if (nPlayer == nLocalPlayer)
|
|
{
|
|
if (nItemText[var_70] > -1 && nTotalPlayers == 1)
|
|
{
|
|
pickupMessage(var_70);
|
|
}
|
|
|
|
TintPalette(var_44 * 4, var_8C * 4, 0);
|
|
|
|
if (var_88 > -1)
|
|
{
|
|
PlayLocalSound(var_88, 0);
|
|
}
|
|
}
|
|
|
|
break;
|
|
/////
|
|
}
|
|
|
|
case 26: // Cobra Staff
|
|
case 50:
|
|
{
|
|
var_40 = 5;
|
|
int ebx = 20;
|
|
|
|
// loc_1B75D
|
|
int var_18 = 1 << var_40;
|
|
|
|
short weapons = PlayerList[nPlayer].nPlayerWeapons;
|
|
|
|
if (weapons & var_18)
|
|
{
|
|
if (mplevel)
|
|
{
|
|
AddAmmo(nPlayer, WeaponInfo[var_40].nAmmoType, ebx);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
weapons = var_40;
|
|
|
|
SetNewWeaponIfBetter(nPlayer, weapons);
|
|
|
|
PlayerList[nPlayer].nPlayerWeapons |= var_18;
|
|
|
|
AddAmmo(nPlayer, WeaponInfo[weapons].nAmmoType, ebx);
|
|
|
|
var_88 = StaticSound[kSound72];
|
|
}
|
|
|
|
if (var_40 == 2) {
|
|
CheckClip(nPlayer);
|
|
}
|
|
|
|
if (var_70 <= 50) {
|
|
goto do_default;
|
|
}
|
|
|
|
pSpriteB->cstat = 0x8000;
|
|
DestroyItemAnim(pActorB);
|
|
////
|
|
// loc_1BA74: - repeated block, see in default case
|
|
if (nPlayer == nLocalPlayer)
|
|
{
|
|
if (nItemText[var_70] > -1 && nTotalPlayers == 1)
|
|
{
|
|
pickupMessage(var_70);
|
|
}
|
|
|
|
TintPalette(var_44 * 4, var_8C * 4, 0);
|
|
|
|
if (var_88 > -1)
|
|
{
|
|
PlayLocalSound(var_88, 0);
|
|
}
|
|
}
|
|
|
|
break;
|
|
/////
|
|
}
|
|
|
|
case 27: // Eye of Ra Gauntlet
|
|
case 51:
|
|
{
|
|
var_40 = 6;
|
|
int ebx = 2;
|
|
|
|
// loc_1B75D
|
|
int var_18 = 1 << var_40;
|
|
|
|
short weapons = PlayerList[nPlayer].nPlayerWeapons;
|
|
|
|
if (weapons & var_18)
|
|
{
|
|
if (mplevel)
|
|
{
|
|
AddAmmo(nPlayer, WeaponInfo[var_40].nAmmoType, ebx);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
weapons = var_40;
|
|
|
|
SetNewWeaponIfBetter(nPlayer, weapons);
|
|
|
|
PlayerList[nPlayer].nPlayerWeapons |= var_18;
|
|
|
|
AddAmmo(nPlayer, WeaponInfo[weapons].nAmmoType, ebx);
|
|
|
|
var_88 = StaticSound[kSound72];
|
|
}
|
|
|
|
if (var_40 == 2) {
|
|
CheckClip(nPlayer);
|
|
}
|
|
|
|
if (var_70 <= 50) {
|
|
goto do_default;
|
|
}
|
|
|
|
pSpriteB->cstat = 0x8000;
|
|
DestroyItemAnim(pActorB);
|
|
////
|
|
// loc_1BA74: - repeated block, see in default case
|
|
if (nPlayer == nLocalPlayer)
|
|
{
|
|
if (nItemText[var_70] > -1 && nTotalPlayers == 1)
|
|
{
|
|
pickupMessage(var_70);
|
|
}
|
|
|
|
TintPalette(var_44 * 4, var_8C * 4, 0);
|
|
|
|
if (var_88 > -1)
|
|
{
|
|
PlayLocalSound(var_88, 0);
|
|
}
|
|
}
|
|
|
|
break;
|
|
/////
|
|
}
|
|
|
|
case 31: // Cobra staff ammo
|
|
{
|
|
if (AddAmmo(nPlayer, 5, 1)) {
|
|
var_88 = StaticSound[kSoundAmmoPickup];
|
|
goto do_default;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 32: // Raw Energy
|
|
{
|
|
if (AddAmmo(nPlayer, 6, pSpriteB->hitag)) {
|
|
var_88 = StaticSound[kSoundAmmoPickup];
|
|
goto do_default;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 39: // Power key
|
|
case 40: // Time key
|
|
case 41: // War key
|
|
case 42: // Earth key
|
|
{
|
|
int keybit = 4096 << (itemtype - 39);
|
|
|
|
var_88 = -1;
|
|
|
|
if (!(PlayerList[nPlayer].keys & keybit))
|
|
{
|
|
PlayerList[nPlayer].keys |= keybit;
|
|
|
|
if (nTotalPlayers > 1)
|
|
{
|
|
goto do_default_b;
|
|
}
|
|
else
|
|
{
|
|
goto do_default;
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 43: // Magical Essence
|
|
case 44: // ?
|
|
{
|
|
if (PlayerList[nPlayer].nMagic >= 1000) {
|
|
break;
|
|
}
|
|
|
|
var_88 = StaticSound[kSoundMana1];
|
|
|
|
PlayerList[nPlayer].nMagic += 100;
|
|
if (PlayerList[nPlayer].nMagic >= 1000) {
|
|
PlayerList[nPlayer].nMagic = 1000;
|
|
}
|
|
|
|
goto do_default;
|
|
}
|
|
|
|
case 53: // Scarab (Checkpoint)
|
|
{
|
|
if (nLocalPlayer == nPlayer)
|
|
{
|
|
pActorB->nIndex2++;
|
|
pActorB->nAction &= 0xEF;
|
|
pActorB->nIndex = 0;
|
|
|
|
ChangeActorStat(pActorB, 899);
|
|
}
|
|
|
|
SetSavePoint(nPlayer, pPlayerSprite->x, pPlayerSprite->y, pPlayerSprite->z, pPlayerSprite->sectnum, pPlayerSprite->ang);
|
|
break;
|
|
}
|
|
|
|
case 54: // Golden Sarcophagus (End Level)
|
|
{
|
|
if (!bInDemo)
|
|
{
|
|
LevelFinished();
|
|
}
|
|
|
|
DestroyItemAnim(pActorB);
|
|
DeleteActor(pActorB);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// CORRECT ? // loc_1BAF9:
|
|
if (bTouchFloor)
|
|
{
|
|
if (sector[pPlayerSprite->sectnum].lotag > 0)
|
|
{
|
|
runlist_SignalRun(sector[pPlayerSprite->sectnum].lotag - 1, nPlayer, &ExhumedAI::TouchFloor);
|
|
}
|
|
}
|
|
|
|
if (nSector != pPlayerSprite->sectnum)
|
|
{
|
|
if (sector[nSector].lotag > 0)
|
|
{
|
|
runlist_SignalRun(sector[nSector].lotag - 1, nPlayer, &ExhumedAI::EnterSector);
|
|
}
|
|
|
|
if (sector[pPlayerSprite->sectnum].lotag > 0)
|
|
{
|
|
runlist_SignalRun(sector[pPlayerSprite->sectnum].lotag - 1, nPlayer, &ExhumedAI::LeaveSector);
|
|
}
|
|
}
|
|
|
|
if (!PlayerList[nPlayer].bIsMummified)
|
|
{
|
|
if (actions & SB_OPEN)
|
|
{
|
|
ClearSpaceBar(nPlayer);
|
|
|
|
if (nearTagWall >= 0 && wall[nearTagWall].lotag > 0)
|
|
{
|
|
runlist_SignalRun(wall[nearTagWall].lotag - 1, nPlayer, &ExhumedAI::Use);
|
|
}
|
|
|
|
if (nearTagSector >= 0 && sector[nearTagSector].lotag > 0)
|
|
{
|
|
runlist_SignalRun(sector[nearTagSector].lotag - 1, nPlayer, &ExhumedAI::Use);
|
|
}
|
|
}
|
|
|
|
// was int var_38 = buttons & 0x8
|
|
if (actions & SB_FIRE)
|
|
{
|
|
FireWeapon(nPlayer);
|
|
}
|
|
else
|
|
{
|
|
StopFiringWeapon(nPlayer);
|
|
}
|
|
|
|
// loc_1BC57:
|
|
|
|
// CHECKME - are we finished with 'nSector' variable at this point? if so, maybe set it to pPlayerSprite->sectnum so we can make this code a bit neater. Don't assume pPlayerSprite->sectnum == nSector here!!
|
|
if (nStandHeight > (sector[pPlayerSprite->sectnum].floorz - sector[pPlayerSprite->sectnum].ceilingz)) {
|
|
var_48 = 1;
|
|
}
|
|
|
|
// Jumping
|
|
if (actions & SB_JUMP)
|
|
{
|
|
if (bUnderwater)
|
|
{
|
|
pPlayerSprite->zvel = -2048;
|
|
nActionB = 10;
|
|
}
|
|
else if (bTouchFloor)
|
|
{
|
|
if (nAction < 6 || nAction > 8)
|
|
{
|
|
pPlayerSprite->zvel = -3584;
|
|
nActionB = 3;
|
|
}
|
|
}
|
|
|
|
// goto loc_1BE70:
|
|
}
|
|
else if (actions & SB_CROUCH)
|
|
{
|
|
if (bUnderwater)
|
|
{
|
|
pPlayerSprite->zvel = 2048;
|
|
nActionB = 10;
|
|
}
|
|
else
|
|
{
|
|
if (PlayerList[nPlayer].eyelevel < -8320) {
|
|
PlayerList[nPlayer].eyelevel += ((-8320 - PlayerList[nPlayer].eyelevel) >> 1);
|
|
}
|
|
|
|
loc_1BD2E:
|
|
if (PlayerList[nPlayer].totalvel < 1) {
|
|
nActionB = 6;
|
|
}
|
|
else {
|
|
nActionB = 7;
|
|
}
|
|
}
|
|
|
|
// goto loc_1BE70:
|
|
}
|
|
else
|
|
{
|
|
if (PlayerList[nPlayer].nHealth > 0)
|
|
{
|
|
int var_EC = nActionEyeLevel[nAction];
|
|
PlayerList[nPlayer].eyelevel += (var_EC - PlayerList[nPlayer].eyelevel) >> 1;
|
|
|
|
if (bUnderwater)
|
|
{
|
|
if (PlayerList[nPlayer].totalvel <= 1)
|
|
nActionB = 9;
|
|
else
|
|
nActionB = 10;
|
|
}
|
|
else
|
|
{
|
|
// CHECKME - confirm branching in this area is OK
|
|
if (var_48)
|
|
{
|
|
goto loc_1BD2E;
|
|
}
|
|
else
|
|
{
|
|
if (PlayerList[nPlayer].totalvel <= 1) {
|
|
nActionB = 0;//bUnderwater; // this is just setting to 0
|
|
}
|
|
else if (PlayerList[nPlayer].totalvel <= 30) {
|
|
nActionB = 2;
|
|
}
|
|
else
|
|
{
|
|
nActionB = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// loc_1BE30
|
|
if (actions & SB_FIRE) // was var_38
|
|
{
|
|
if (bUnderwater)
|
|
{
|
|
nActionB = 11;
|
|
}
|
|
else
|
|
{
|
|
if (nActionB != 2 && nActionB != 1)
|
|
{
|
|
nActionB = 5;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// loc_1BE70:
|
|
// Handle player pressing number keys to change weapon
|
|
uint8_t var_90 = sPlayerInput[nPlayer].getNewWeapon();
|
|
|
|
if (var_90)
|
|
{
|
|
var_90--;
|
|
|
|
if (PlayerList[nPlayer].nPlayerWeapons & (1 << var_90))
|
|
{
|
|
SetNewWeapon(nPlayer, var_90);
|
|
}
|
|
}
|
|
}
|
|
else // player is mummified
|
|
{
|
|
if (actions & SB_FIRE)
|
|
{
|
|
FireWeapon(nPlayer);
|
|
}
|
|
|
|
if (nAction != 15)
|
|
{
|
|
if (PlayerList[nPlayer].totalvel <= 1)
|
|
{
|
|
nActionB = 13;
|
|
}
|
|
else
|
|
{
|
|
nActionB = 14;
|
|
}
|
|
}
|
|
}
|
|
|
|
// loc_1BF09
|
|
if (nActionB != nAction && nAction != 4)
|
|
{
|
|
nAction = nActionB;
|
|
PlayerList[nPlayer].nAction = nActionB;
|
|
PlayerList[nPlayer].field_2 = 0;
|
|
}
|
|
|
|
Player* pPlayer = &PlayerList[nPlayer];
|
|
|
|
if (SyncInput())
|
|
{
|
|
pPlayer->horizon.applyinput(sPlayerInput[nPlayer].pan, &sPlayerInput[nLocalPlayer].actions);
|
|
}
|
|
|
|
if (actions & (SB_AIM_UP | SB_AIM_DOWN) || sPlayerInput[nPlayer].pan)
|
|
{
|
|
pPlayer->nDestVertPan = pPlayer->horizon.horiz;
|
|
pPlayer->bPlayerPan = pPlayer->bLockPan = true;
|
|
}
|
|
else if (actions & (SB_LOOK_UP | SB_LOOK_DOWN | SB_CENTERVIEW))
|
|
{
|
|
pPlayer->nDestVertPan = pPlayer->horizon.horiz;
|
|
pPlayer->bPlayerPan = pPlayer->bLockPan = false;
|
|
}
|
|
|
|
if (PlayerList[nPlayer].totalvel > 20)
|
|
{
|
|
pPlayer->bPlayerPan = false;
|
|
}
|
|
|
|
if (cl_slopetilting && !pPlayer->bPlayerPan && !pPlayer->bLockPan)
|
|
{
|
|
double nVertPan = (pPlayer->nDestVertPan - pPlayer->horizon.horiz).asbuildf() * 0.25;
|
|
if (nVertPan != 0)
|
|
{
|
|
pPlayer->horizon.addadjustment(abs(nVertPan) >= 4 ? clamp(nVertPan, -4., 4.) : nVertPan * 2.);
|
|
}
|
|
}
|
|
}
|
|
else // else, player's health is less than 0
|
|
{
|
|
// loc_1C0E9
|
|
if (actions & SB_OPEN)
|
|
{
|
|
ClearSpaceBar(nPlayer);
|
|
|
|
if (nAction >= 16)
|
|
{
|
|
if (nPlayer == nLocalPlayer)
|
|
{
|
|
StopAllSounds();
|
|
StopLocalSound();
|
|
GrabPalette();
|
|
}
|
|
|
|
PlayerList[nPlayer].nCurrentWeapon = PlayerList[nPlayer].nPlayerOldWeapon;
|
|
|
|
if (PlayerList[nPlayer].nLives && nNetTime)
|
|
{
|
|
if (nAction != 20)
|
|
{
|
|
pPlayerSprite->picnum = seq_GetSeqPicnum(kSeqJoe, 120, 0);
|
|
pPlayerSprite->cstat = 0;
|
|
pPlayerSprite->z = sector[pPlayerSprite->sectnum].floorz;
|
|
}
|
|
|
|
// will invalidate nPlayerSprite
|
|
RestartPlayer(nPlayer);
|
|
|
|
pPlayerActor = PlayerList[nPlayer].Actor();
|
|
pDopple = PlayerList[nPlayer].pDoppleSprite;
|
|
}
|
|
else
|
|
{
|
|
DoGameOverScene(mplevel);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// loc_1C201:
|
|
if (nLocalPlayer == nPlayer)
|
|
{
|
|
nLocalEyeSect = PlayerList[nLocalPlayer].nPlayerViewSect;
|
|
CheckAmbience(nLocalEyeSect);
|
|
}
|
|
|
|
int var_AC = SeqOffsets[PlayerList[nPlayer].nSeq] + PlayerSeq[nAction].a;
|
|
|
|
seq_MoveSequence(pPlayerActor, var_AC, PlayerList[nPlayer].field_2);
|
|
PlayerList[nPlayer].field_2++;
|
|
|
|
if (PlayerList[nPlayer].field_2 >= SeqSize[var_AC])
|
|
{
|
|
PlayerList[nPlayer].field_2 = 0;
|
|
|
|
switch (PlayerList[nPlayer].nAction)
|
|
{
|
|
default:
|
|
break;
|
|
|
|
case 3:
|
|
PlayerList[nPlayer].field_2 = SeqSize[var_AC] - 1;
|
|
break;
|
|
case 4:
|
|
PlayerList[nPlayer].nAction = 0;
|
|
break;
|
|
case 16:
|
|
PlayerList[nPlayer].field_2 = SeqSize[var_AC] - 1;
|
|
|
|
if (pPlayerSprite->z < sector[pPlayerSprite->sectnum].floorz) {
|
|
pPlayerSprite->z += 256;
|
|
}
|
|
|
|
if (!RandomSize(5))
|
|
{
|
|
vec3_t pos;
|
|
int mouthSect;
|
|
WheresMyMouth(nPlayer, &pos, &mouthSect);
|
|
|
|
BuildAnim(nullptr, 71, 0, pos.x, pos.y, pPlayerSprite->z + 3840, mouthSect, 75, 128);
|
|
}
|
|
break;
|
|
case 17:
|
|
PlayerList[nPlayer].nAction = 18;
|
|
break;
|
|
case 19:
|
|
pPlayerSprite->cstat |= 0x8000;
|
|
PlayerList[nPlayer].nAction = 20;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// loc_1C3B4:
|
|
if (nPlayer == nLocalPlayer)
|
|
{
|
|
initx = pPlayerSprite->x;
|
|
inity = pPlayerSprite->y;
|
|
initz = pPlayerSprite->z;
|
|
initsect = pPlayerSprite->sectnum;
|
|
inita = pPlayerSprite->ang;
|
|
}
|
|
|
|
if (!PlayerList[nPlayer].nHealth)
|
|
{
|
|
PlayerList[nPlayer].nYDamage = 0;
|
|
PlayerList[nPlayer].nXDamage = 0;
|
|
|
|
if (PlayerList[nPlayer].eyelevel >= -2816)
|
|
{
|
|
PlayerList[nPlayer].eyelevel = -2816;
|
|
dVertPan[nPlayer] = 0;
|
|
}
|
|
else
|
|
{
|
|
if (PlayerList[nPlayer].horizon.horiz.asq16() < 0)
|
|
{
|
|
PlayerList[nPlayer].horizon.settarget(0);
|
|
PlayerList[nPlayer].eyelevel -= (dVertPan[nPlayer] << 8);
|
|
}
|
|
else
|
|
{
|
|
PlayerList[nPlayer].horizon.addadjustment(dVertPan[nPlayer]);
|
|
|
|
if (PlayerList[nPlayer].horizon.horiz.asq16() > gi->playerHorizMax())
|
|
{
|
|
PlayerList[nPlayer].horizon.settarget(gi->playerHorizMax());
|
|
}
|
|
else if (PlayerList[nPlayer].horizon.horiz.asq16() <= 0)
|
|
{
|
|
if (!(SectFlag[pPlayerSprite->sectnum] & kSectUnderwater))
|
|
{
|
|
SetNewWeapon(nPlayer, PlayerList[nPlayer].nDeathType + 8);
|
|
}
|
|
}
|
|
|
|
dVertPan[nPlayer]--;
|
|
}
|
|
}
|
|
}
|
|
|
|
// loc_1C4E1
|
|
pDopple->s().pos = pPlayerSprite->pos;
|
|
|
|
if (SectAbove[pPlayerSprite->sectnum] > -1)
|
|
{
|
|
pDopple->s().ang = pPlayerSprite->ang;
|
|
ChangeActorSect(pDopple, SectAbove[pPlayerSprite->sectnum]);
|
|
pDopple->s().cstat = 0x101;
|
|
}
|
|
else
|
|
{
|
|
pDopple->s().cstat = 0x8000;
|
|
}
|
|
|
|
MoveWeapons(nPlayer);
|
|
}
|
|
|
|
|
|
FSerializer& Serialize(FSerializer& arc, const char* keyname, Player& w, Player* def)
|
|
{
|
|
if (arc.BeginObject(keyname))
|
|
{
|
|
arc("health", w.nHealth)
|
|
("at2", w.field_2)
|
|
("action", w.nAction)
|
|
("sprite", w.pActor)
|
|
("mummy", w.bIsMummified)
|
|
("invincible", w.invincibility)
|
|
("air", w.nAir)
|
|
("seq", w.nSeq)
|
|
("item", w.nItem)
|
|
("maskamount", w.nMaskAmount)
|
|
("keys", w.keys)
|
|
("magic", w.nMagic)
|
|
.Array("items", w.items, countof(w.items))
|
|
.Array("ammo", w.nAmmo, countof(w.nAmmo))
|
|
("weapon", w.nCurrentWeapon)
|
|
("isfiring", w.bIsFiring)
|
|
("field3f", w.field_3FOUR)
|
|
("field38", w.field_38)
|
|
("field3a", w.field_3A)
|
|
("field3c", w.field_3C)
|
|
("seq", w.nSeq)
|
|
("horizon", w.horizon)
|
|
("angle", w.angle)
|
|
("lives", w.nLives)
|
|
("double", w.nDouble)
|
|
("invisible", w.nInvisible)
|
|
("torch", w.nTorch)
|
|
("breathtimer", w.nBreathTimer)
|
|
("playerswear", w.nPlayerSwear)
|
|
("pushsect", w.nPlayerPushSect)
|
|
("deathtype", w.nDeathType)
|
|
("score", w.nPlayerScore)
|
|
("color", w.nPlayerColor)
|
|
("dx", w.nPlayerDX)
|
|
("dy", w.nPlayerDY)
|
|
("pistolclip", w.nPistolClip)
|
|
("xdamage", w.nXDamage)
|
|
("ydamage", w.nYDamage)
|
|
("dopplesprite", w.pDoppleSprite)
|
|
("oldweapon", w.nPlayerOldWeapon)
|
|
("clip", w.nPlayerClip)
|
|
("pushsound", w.nPlayerPushSound)
|
|
("taunttimer", w.nTauntTimer)
|
|
("weapons", w.nPlayerWeapons)
|
|
("viewsect", w.nPlayerViewSect)
|
|
("floorspr", w.pPlayerFloorSprite)
|
|
("save", w.sPlayerSave)
|
|
("totalvel", w.totalvel)
|
|
("eyelevel", w.eyelevel)
|
|
("grenade", w.pPlayerGrenade)
|
|
|
|
.EndObject();
|
|
}
|
|
return arc;
|
|
}
|
|
|
|
FSerializer& Serialize(FSerializer& arc, const char* keyname, PlayerSave& w, PlayerSave* def)
|
|
{
|
|
if (arc.BeginObject(keyname))
|
|
{
|
|
arc("x", w.x)
|
|
("y", w.y)
|
|
("z", w.z)
|
|
("sector", w.nSector)
|
|
("angle", w.nAngle)
|
|
.EndObject();
|
|
}
|
|
return arc;
|
|
}
|
|
|
|
void SerializePlayer(FSerializer& arc)
|
|
{
|
|
if (arc.BeginObject("player"))
|
|
{
|
|
arc("lxvel", lPlayerXVel)
|
|
("lyvel", lPlayerYVel)
|
|
("bobangle", bobangle)
|
|
("standheight", nStandHeight)
|
|
("playercount", PlayerCount)
|
|
("netstartsprites", nNetStartSprites)
|
|
("localplayer", nLocalPlayer)
|
|
("curstartsprite", nCurStartSprite)
|
|
.Array("netstartsprite", nNetStartSprite, kMaxPlayers)
|
|
.Array("list", PlayerList, PlayerCount);
|
|
|
|
arc.EndObject();
|
|
}
|
|
}
|
|
|
|
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, nHealth);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, nLives);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, nDouble);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, nInvisible);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, nTorch);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, field_2);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, nAction);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, pActor);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, bIsMummified);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, invincibility);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, nAir);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, nSeq);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, nMaskAmount);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, keys);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, nMagic);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, nItem);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, items);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, nAmmo); // TODO - kMaxWeapons?
|
|
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, nCurrentWeapon);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, field_3FOUR);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, bIsFiring);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, field_38);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, field_3A);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, field_3C);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, nRun);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, bPlayerPan);
|
|
DEFINE_FIELD_X(ExhumedPlayer, Player, bLockPan);
|
|
|
|
DEFINE_ACTION_FUNCTION(_Exhumed, GetViewPlayer)
|
|
{
|
|
ACTION_RETURN_POINTER(&PlayerList[nLocalPlayer]);
|
|
}
|
|
|
|
DEFINE_ACTION_FUNCTION(_Exhumed, GetPistolClip)
|
|
{
|
|
ACTION_RETURN_POINTER(&PlayerList[nLocalPlayer].nPistolClip);
|
|
}
|
|
|
|
DEFINE_ACTION_FUNCTION(_Exhumed, GetPlayerClip)
|
|
{
|
|
ACTION_RETURN_POINTER(&PlayerList[nLocalPlayer].nPlayerClip);
|
|
}
|
|
|
|
DEFINE_ACTION_FUNCTION(_ExhumedPlayer, IsUnderwater)
|
|
{
|
|
PARAM_SELF_STRUCT_PROLOGUE(Player);
|
|
auto nLocalPlayer = self - PlayerList;
|
|
ACTION_RETURN_BOOL(SectFlag[PlayerList[nLocalPlayer].nPlayerViewSect] & kSectUnderwater);
|
|
}
|
|
|
|
DEFINE_ACTION_FUNCTION(_ExhumedPlayer, GetAngle)
|
|
{
|
|
PARAM_SELF_STRUCT_PROLOGUE(Player);
|
|
ACTION_RETURN_INT(self->Actor()->s().ang);
|
|
}
|
|
|
|
|
|
END_PS_NS
|