gzdoom/src/playsim/d_player.h

482 lines
14 KiB
C++

//-----------------------------------------------------------------------------
//
// Copyright 1993-1996 id Software
// Copyright 1994-1996 Raven Software
// Copyright 1998-1998 Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
// Copyright 1999-2016 Randy Heit
// Copyright 2002-2016 Christoph Oelckers
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 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, see http://www.gnu.org/licenses/
//
//-----------------------------------------------------------------------------
//
#ifndef __D_PLAYER_H__
#define __D_PLAYER_H__
// Finally, for odd reasons, the player input
// is buffered within the player data struct,
// as commands per game tick.
#include "d_protocol.h"
#include "doomstat.h"
#include "a_weapons.h"
#include "d_netinf.h"
// The player data structure depends on a number
// of other structs: items (internal inventory),
// animation states (closely tied to the sprites
// used to represent them, unfortunately).
#include "p_pspr.h"
// In addition, the player is just a special
// case of the generic moving object/actor.
#include "actor.h"
//Added by MC:
#include "b_bot.h"
class player_t;
// Standard pre-defined skin colors
struct FPlayerColorSet
{
struct ExtraRange
{
uint8_t RangeStart, RangeEnd; // colors to remap
uint8_t FirstColor, LastColor; // colors to map to
};
FName Name; // Name of this color
int Lump; // Lump to read the translation from, otherwise use next 2 fields
uint8_t FirstColor, LastColor; // Describes the range of colors to use for the translation
uint8_t RepresentativeColor; // A palette entry representative of this translation,
// for map arrows and status bar backgrounds and such
uint8_t NumExtraRanges;
ExtraRange Extra[6];
};
typedef TArray<std::tuple<PClass*, FName, PalEntry>> PainFlashList;
typedef TArray<std::tuple<PClass*, int, FPlayerColorSet>> ColorSetList;
extern PainFlashList PainFlashes;
extern ColorSetList ColorSets;
FString GetPrintableDisplayName(PClassActor *cls);
void PlayIdle(AActor *player);
//
// PlayerPawn flags
//
enum
{
PPF_NOTHRUSTWHENINVUL = 1, // Attacks do not thrust the player if they are invulnerable.
};
//
// Player states.
//
typedef enum
{
PST_LIVE, // Playing or camping.
PST_DEAD, // Dead on the ground, view follows killer.
PST_REBORN, // Ready to restart/respawn???
PST_ENTER, // [BC] Entered the game
PST_GONE // Player has left the game
} playerstate_t;
//
// Player internal flags, for cheats and debug.
//
typedef enum
{
CF_NOCLIP = 1 << 0, // No clipping, walk through barriers.
CF_GODMODE = 1 << 1, // No damage, no health loss.
CF_NOVELOCITY = 1 << 2, // Not really a cheat, just a debug aid.
CF_NOTARGET = 1 << 3, // [RH] Monsters don't target
CF_FLY = 1 << 4, // [RH] Flying player
CF_CHASECAM = 1 << 5, // [RH] Put camera behind player
CF_FROZEN = 1 << 6, // [RH] Don't let the player move
CF_REVERTPLEASE = 1 << 7, // [RH] Stick camera in player's head if (s)he moves
CF_STEPLEFT = 1 << 9, // [RH] Play left footstep sound next time
CF_FRIGHTENING = 1 << 10, // [RH] Scare monsters away
CF_INSTANTWEAPSWITCH= 1 << 11, // [RH] Switch weapons instantly
CF_TOTALLYFROZEN = 1 << 12, // [RH] All players can do is press +use
CF_PREDICTING = 1 << 13, // [RH] Player movement is being predicted
CF_INTERPVIEW = 1 << 14, // [RH] view was changed outside of input, so interpolate one frame
CF_EXTREMELYDEAD = 1 << 22, // [RH] Reliably let the status bar know about extreme deaths.
CF_BUDDHA2 = 1 << 24, // [MC] Absolute buddha. No voodoo can kill it either.
CF_GODMODE2 = 1 << 25, // [MC] Absolute godmode. No voodoo can kill it either.
CF_BUDDHA = 1 << 27, // [SP] Buddha mode - take damage, but don't die
CF_NOCLIP2 = 1 << 30, // [RH] More Quake-like noclip
} cheat_t;
enum
{
WF_WEAPONREADY = 1 << 0, // [RH] Weapon is in the ready state and can fire its primary attack
WF_WEAPONBOBBING = 1 << 1, // [HW] Bob weapon while the player is moving
WF_WEAPONREADYALT = 1 << 2, // Weapon can fire its secondary attack
WF_WEAPONSWITCHOK = 1 << 3, // It is okay to switch away from this weapon
WF_DISABLESWITCH = 1 << 4, // Disable weapon switching completely
WF_WEAPONRELOADOK = 1 << 5, // [XA] Okay to reload this weapon.
WF_WEAPONZOOMOK = 1 << 6, // [XA] Okay to use weapon zoom function.
WF_REFIRESWITCHOK = 1 << 7, // Mirror WF_WEAPONSWITCHOK for A_ReFire
WF_USER1OK = 1 << 8, // [MC] Allow pushing of custom state buttons 1-4
WF_USER2OK = 1 << 9,
WF_USER3OK = 1 << 10,
WF_USER4OK = 1 << 11,
};
// The VM cannot deal with this as an invalid pointer because it performs a read barrier on every object pointer read.
// This doesn't have to point to a valid weapon, though, because WP_NOCHANGE is never dereferenced, but it must point to a valid object
// and the class descriptor just works fine for that.
extern DObject *WP_NOCHANGE;
// [GRB] Custom player classes
enum
{
PCF_NOMENU = 1, // Hide in new game menu
};
class FPlayerClass
{
public:
FPlayerClass ();
FPlayerClass (const FPlayerClass &other);
~FPlayerClass ();
bool CheckSkin (int skin);
PClassActor *Type;
uint32_t Flags;
TArray<int> Skins;
};
extern TArray<FPlayerClass> PlayerClasses;
// User info (per-player copies of each CVAR_USERINFO cvar)
struct userinfo_t : TMap<FName,FBaseCVar *>
{
~userinfo_t();
double GetAimDist() const
{
if (dmflags2 & DF2_NOAUTOAIM)
{
return 0;
}
float aim = *static_cast<FFloatCVar *>(*CheckKey(NAME_Autoaim));
if (aim > 35 || aim < 0)
{
return 35.;
}
else
{
return aim;
}
}
// Same but unfiltered.
double GetAutoaim() const
{
return *static_cast<FFloatCVar *>(*CheckKey(NAME_Autoaim));
}
const char *GetName() const
{
return *static_cast<FStringCVar *>(*CheckKey(NAME_Name));
}
int GetTeam() const
{
return *static_cast<FIntCVar *>(*CheckKey(NAME_Team));
}
int GetColorSet() const
{
return *static_cast<FIntCVar *>(*CheckKey(NAME_ColorSet));
}
uint32_t GetColor() const
{
return *static_cast<FColorCVar *>(*CheckKey(NAME_Color));
}
bool GetNeverSwitch() const
{
return *static_cast<FBoolCVar *>(*CheckKey(NAME_NeverSwitchOnPickup));
}
double GetMoveBob() const
{
return *static_cast<FFloatCVar *>(*CheckKey(NAME_MoveBob));
}
double GetStillBob() const
{
return *static_cast<FFloatCVar *>(*CheckKey(NAME_StillBob));
}
float GetWBobSpeed() const
{
return *static_cast<FFloatCVar *>(*CheckKey(NAME_WBobSpeed));
}
double GetWBobFire() const
{
return *static_cast<FFloatCVar *>(*CheckKey(NAME_WBobFire));
}
int GetPlayerClassNum() const
{
return *static_cast<FIntCVar *>(*CheckKey(NAME_PlayerClass));
}
bool GetClassicFlight() const
{
return *static_cast<FBoolCVar *>(*CheckKey(NAME_ClassicFlight));
}
PClassActor *GetPlayerClassType() const
{
return PlayerClasses[GetPlayerClassNum()].Type;
}
int GetSkin() const
{
return *static_cast<FIntCVar *>(*CheckKey(NAME_Skin));
}
int GetGender() const
{
auto cvar = CheckKey(NAME_Gender);
return cvar ? *static_cast<FIntCVar *>(*cvar) : 0;
}
bool GetNoAutostartMap() const
{
return *static_cast<FBoolCVar *>(*CheckKey(NAME_Wi_NoAutostartMap));
}
void Reset();
int TeamChanged(int team);
int SkinChanged(const char *skinname, int playerclass);
int SkinNumChanged(int skinnum);
int GenderChanged(const char *gendername);
int PlayerClassChanged(const char *classname);
uint32_t ColorChanged(const char *colorname);
uint32_t ColorChanged(uint32_t colorval);
int ColorSetChanged(int setnum);
};
void ReadUserInfo(FSerializer &arc, userinfo_t &info, FString &skin);
void WriteUserInfo(FSerializer &arc, userinfo_t &info);
//
// Extended player object info: player_t
//
class player_t
{
public:
player_t() = default;
~player_t();
player_t &operator= (const player_t &p) = delete;
void CopyFrom(player_t &src, bool copyPSP);
void Serialize(FSerializer &arc);
size_t PropagateMark();
void SetLogNumber (int num);
void SetLogText (const char *text);
void SendPitchLimits() const;
void SetSubtitle(int num, FSoundID soundid);
AActor *mo = nullptr;
uint8_t playerstate = 0;
ticcmd_t cmd = {};
usercmd_t original_cmd;
uint32_t original_oldbuttons;
userinfo_t userinfo; // [RH] who is this?
PClassActor *cls = nullptr; // class of associated PlayerPawn
float DesiredFOV = 0; // desired field of vision
float FOV = 0; // current field of vision
double viewz = 0; // focal origin above r.z
double viewheight = 0; // base height above floor for viewz
double deltaviewheight = 0; // squat speed.
double bob = 0; // bounded/scaled total velocity
// killough 10/98: used for realistic bobbing (i.e. not simply overall speed)
// mo->velx and mo->vely represent true velocity experienced by player.
// This only represents the thrust that the player applies himself.
// This avoids anomalies with such things as Boom ice and conveyors.
DVector2 Vel = { 0,0 };
bool centering = false;
uint8_t turnticks = 0;
bool attackdown = false;
bool usedown = false;
uint32_t oldbuttons = false;
int health = 0; // only used between levels, mo->health
// is used during levels
int inventorytics = 0;
uint8_t CurrentPlayerClass = 0; // class # for this player instance
int frags[MAXPLAYERS] = {}; // kills of other players
int fragcount = 0; // [RH] Cumulative frags for this player
int lastkilltime = 0; // [RH] For multikills
uint8_t multicount = 0;
uint8_t spreecount = 0; // [RH] Keep track of killing sprees
uint16_t WeaponState = 0;
AActor *ReadyWeapon = nullptr;
AActor *PendingWeapon = nullptr; // WP_NOCHANGE if not changing
TObjPtr<DPSprite*> psprites = nullptr; // view sprites (gun, etc)
int cheats = 0; // bit flags
int timefreezer = 0; // Player has an active time freezer
short refire = 0; // refired shots are less accurate
short inconsistant = 0;
bool waiting = 0;
int killcount = 0, itemcount = 0, secretcount = 0; // for intermission
int damagecount = 0, bonuscount = 0;// for screen flashing
int hazardcount = 0; // for delayed Strife damage
int hazardinterval = 0; // Frequency of damage infliction
FName hazardtype = NAME_None; // Damage type of last hazardous damage encounter.
int poisoncount = 0; // screen flash for poison damage
FName poisontype = NAME_None; // type of poison damage to apply
FName poisonpaintype = NAME_None; // type of Pain state to enter for poison damage
TObjPtr<AActor*> poisoner = nullptr; // NULL for non-player actors
TObjPtr<AActor*> attacker = nullptr; // who did damage (NULL for floors)
int extralight = 0; // so gun flashes light up areas
short fixedcolormap = 0; // can be set to REDCOLORMAP, etc.
short fixedlightlevel = 0;
int morphTics = 0; // player is a chicken/pig if > 0
PClassActor *MorphedPlayerClass = nullptr; // [MH] (for SBARINFO) class # for this player instance when morphed
int MorphStyle = 0; // which effects to apply for this player instance when morphed
PClassActor *MorphExitFlash = nullptr; // flash to apply when demorphing (cache of value given to MorphPlayer)
TObjPtr<AActor*> PremorphWeapon = nullptr; // ready weapon before morphing
int chickenPeck = 0; // chicken peck countdown
int jumpTics = 0; // delay the next jump for a moment
bool onground = 0; // Identifies if this player is on the ground or other object
int respawn_time = 0; // [RH] delay respawning until this tic
TObjPtr<AActor*> camera = nullptr; // [RH] Whose eyes this player sees through
int air_finished = 0; // [RH] Time when you start drowning
FName LastDamageType = NAME_None; // [RH] For damage-specific pain and death sounds
TObjPtr<AActor*> MUSINFOactor = nullptr; // For MUSINFO purposes
int8_t MUSINFOtics = 0;
bool settings_controller = false; // Player can control game settings.
int8_t crouching = 0;
int8_t crouchdir = 0;
//Added by MC:
TObjPtr<DBot*> Bot = nullptr;
float BlendR = 0; // [RH] Final blending values
float BlendG = 0;
float BlendB = 0;
float BlendA = 0;
FString LogText; // [RH] Log for Strife
FString SubtitleText;
int SubtitleCounter;
DAngle MinPitch = 0.; // Viewpitch limits (negative is up, positive is down)
DAngle MaxPitch = 0.;
double crouchfactor = 0;
double crouchoffset = 0;
double crouchviewdelta = 0;
FWeaponSlots weapons;
// [CW] I moved these here for multiplayer conversation support.
TObjPtr<AActor*> ConversationNPC = nullptr, ConversationPC = nullptr;
DAngle ConversationNPCAngle = 0.;
bool ConversationFaceTalker = false;
double GetDeltaViewHeight() const
{
return (mo->FloatVar(NAME_ViewHeight) + crouchviewdelta - viewheight) / 8;
}
double DefaultViewHeight() const
{
return mo->FloatVar(NAME_ViewHeight);
}
void Uncrouch()
{
if (crouchfactor != 1)
{
crouchfactor = 1;
crouchoffset = 0;
crouchdir = 0;
crouching = 0;
crouchviewdelta = 0;
viewheight = mo ? mo->FloatVar(NAME_ViewHeight) : 0;
}
}
int GetSpawnClass();
// PSprite layers
void TickPSprites();
void DestroyPSprites();
DPSprite *FindPSprite(int layer);
// Used ONLY for compatibility with the old hardcoded layers.
// Make sure that a state is properly set after calling this unless
// you are 100% sure the context already implies the layer exists.
DPSprite *GetPSprite(PSPLayers layer);
// [Nash] set player FOV
void SetFOV(float fov);
bool HasWeaponsInSlot(int slot) const;
bool Resurrect();
};
// Bookkeeping on players - state.
extern player_t players[MAXPLAYERS];
void P_CheckPlayerSprite(AActor *mo, int &spritenum, DVector2 &scale);
void EnumColorSets(PClassActor *pc, TArray<int> *out);
FPlayerColorSet *GetColorSet(PClassActor *pc, int setnum);
inline void AActor::SetFriendPlayer(player_t *player)
{
if (player == NULL)
{
FriendPlayer = 0;
}
else
{
FriendPlayer = int(player - players) + 1;
}
}
inline bool AActor::IsNoClip2() const
{
if (player != NULL && player->mo == this)
{
return (player->cheats & CF_NOCLIP2) != 0;
}
return false;
}
bool P_IsPlayerTotallyFrozen(const player_t *player);
#endif // __D_PLAYER_H__