/**
* @ file player . h
*
* Interface of player functionality , leveling , actions , creation , loading , etc .
*/
# pragma once
# include <array>
# include <cstdint>
# include "diablo.h"
# include "engine.h"
# include "engine/actor_position.hpp"
# include "engine/animationinfo.h"
# include "engine/cel_sprite.hpp"
# include "engine/path.h"
# include "engine/point.hpp"
# include "interfac.h"
# include "items.h"
# include "levels/gendung.h"
# include "multi.h"
# include "spelldat.h"
# include "utils/attributes.h"
# include "utils/enum_traits.h"
# include "utils/stdcompat/algorithm.hpp"
namespace devilution {
// number of inventory grid cells
# define NUM_INV_GRID_ELEM 40
# define MAXBELTITEMS 8
# define MAXRESIST 75
# define MAXCHARLEVEL 50
# define MAX_SPELL_LEVEL 15
# define PLR_NAME_LEN 32
constexpr size_t NumHotkeys = 12 ;
constexpr int BaseHitChance = 50 ;
/** Walking directions */
enum {
// clang-format off
WALK_NE = 1 ,
WALK_NW = 2 ,
WALK_SE = 3 ,
WALK_SW = 4 ,
WALK_N = 5 ,
WALK_E = 6 ,
WALK_S = 7 ,
WALK_W = 8 ,
WALK_NONE = - 1 ,
// clang-format on
} ;
enum class HeroClass : uint8_t {
Warrior ,
Rogue ,
Sorcerer ,
Monk ,
Bard ,
Barbarian ,
LAST = Barbarian
} ;
enum class CharacterAttribute : uint8_t {
Strength ,
Magic ,
Dexterity ,
Vitality ,
FIRST = Strength ,
LAST = Vitality
} ;
// Logical equipment locations
enum inv_body_loc : uint8_t {
INVLOC_HEAD ,
INVLOC_RING_LEFT ,
INVLOC_RING_RIGHT ,
INVLOC_AMULET ,
INVLOC_HAND_LEFT ,
INVLOC_HAND_RIGHT ,
INVLOC_CHEST ,
NUM_INVLOC ,
} ;
enum class player_graphic : uint8_t {
Stand ,
Walk ,
Attack ,
Hit ,
Lightning ,
Fire ,
Magic ,
Death ,
Block ,
LAST = Block
} ;
enum class PlayerWeaponGraphic : uint8_t {
Unarmed ,
UnarmedShield ,
Sword ,
SwordShield ,
Bow ,
Axe ,
Mace ,
MaceShield ,
Staff ,
} ;
enum PLR_MODE : uint8_t {
PM_STAND ,
PM_WALK , // Movement towards N, NW, or NE
PM_WALK2 , // Movement towards S, SW, or SE
PM_WALK3 , // Movement towards W or E
PM_ATTACK ,
PM_RATTACK ,
PM_BLOCK ,
PM_GOTHIT ,
PM_DEATH ,
PM_SPELL ,
PM_NEWLVL ,
PM_QUIT ,
} ;
enum action_id : int8_t {
// clang-format off
ACTION_WALK = - 2 , // Automatic walk when using gamepad
ACTION_NONE = - 1 ,
ACTION_ATTACK = 9 ,
ACTION_RATTACK = 10 ,
ACTION_SPELL = 12 ,
ACTION_OPERATE = 13 ,
ACTION_DISARM = 14 ,
ACTION_PICKUPITEM = 15 , // put item in hand (inventory screen open)
ACTION_PICKUPAITEM = 16 , // put item in inventory
ACTION_TALK = 17 ,
ACTION_OPERATETK = 18 , // operate via telekinesis
ACTION_ATTACKMON = 20 ,
ACTION_ATTACKPLR = 21 ,
ACTION_RATTACKMON = 22 ,
ACTION_RATTACKPLR = 23 ,
ACTION_SPELLMON = 24 ,
ACTION_SPELLPLR = 25 ,
ACTION_SPELLWALL = 26 ,
// clang-format on
} ;
enum class SpellFlag : uint8_t {
// clang-format off
None = 0 ,
Etherealize = 1 < < 0 ,
RageActive = 1 < < 1 ,
RageCooldown = 1 < < 2 ,
// bits 3-7 are unused
// clang-format on
} ;
use_enum_as_flags ( SpellFlag ) ;
/** Maps from armor animation to letter used in graphic files. */
constexpr std : : array < char , 4 > ArmourChar = {
' L ' , // light
' M ' , // medium
' H ' , // heavy
} ;
/** Maps from weapon animation to letter used in graphic files. */
constexpr std : : array < char , 9 > WepChar = {
' N ' , // unarmed
' U ' , // no weapon + shield
' S ' , // sword + no shield
' D ' , // sword + shield
' B ' , // bow
' A ' , // axe
' M ' , // blunt + no shield
' H ' , // blunt + shield
' T ' , // staff
} ;
/** Maps from player class to letter used in graphic files. */
constexpr std : : array < char , 6 > CharChar = {
' W ' , // warrior
' R ' , // rogue
' S ' , // sorcerer
' M ' , // monk
' B ' ,
' C ' ,
} ;
/**
* @ brief Contains Data ( CelSprites ) for a player graphic ( player_graphic )
*/
struct PlayerAnimationData {
/**
* @ brief CelSprites for the different directions
*/
std : : array < std : : optional < CelSprite > , 8 > CelSpritesForDirections ;
/**
* @ brief Raw Data ( binary ) of the CL2 file .
* Is referenced from CelSprite in CelSpritesForDirections
*/
std : : unique_ptr < byte [ ] > RawData ;
[ [ nodiscard ] ] std : : optional < CelSprite > GetCelSpritesForDirection ( Direction direction ) const
{
return CelSpritesForDirections [ static_cast < size_t > ( direction ) ] ;
}
} ;
struct Player {
Player ( ) = default ;
Player ( Player & & ) noexcept = default ;
Player & operator = ( Player & & ) noexcept = default ;
PLR_MODE _pmode ;
int8_t walkpath [ MaxPathLength ] ;
bool plractive ;
action_id destAction ;
int destParam1 ;
int destParam2 ;
int destParam3 ;
int destParam4 ;
uint8_t plrlevel ;
bool plrIsOnSetLevel ;
ActorPosition position ;
Direction _pdir ; // Direction faced by player (direction enum)
int _pgfxnum ; // Bitmask indicating what variant of the sprite the player is using. Lower byte define weapon (PlayerWeaponGraphic) and higher values define armour (starting with PlayerArmorGraphic)
/**
* @ brief Contains Information for current Animation
*/
AnimationInfo AnimInfo ;
/**
* @ brief Contains a optional preview CelSprite that is displayed until the current command is handled by the game logic
*/
std : : optional < CelSprite > previewCelSprite ;
/**
* @ brief Contains the progress to next game tick when previewCelSprite was set
*/
float progressToNextGameTickWhenPreviewWasSet ;
int _plid ;
int _pvid ;
spell_id _pSpell ;
spell_type _pSplType ;
int8_t _pSplFrom ; // TODO Create enum
spell_id _pTSpell ;
spell_id _pRSpell ;
spell_type _pRSplType ;
spell_id _pSBkSpell ;
int8_t _pSplLvl [ 64 ] ;
uint64_t _pMemSpells ; // Bitmask of learned spells
uint64_t _pAblSpells ; // Bitmask of abilities
uint64_t _pScrlSpells ; // Bitmask of spells available via scrolls
SpellFlag _pSpellFlags ;
spell_id _pSplHotKey [ NumHotkeys ] ;
spell_type _pSplTHotKey [ NumHotkeys ] ;
bool _pBlockFlag ;
bool _pInvincible ;
int8_t _pLightRad ;
bool _pLvlChanging ; // True when the player is transitioning between levels
char _pName [ PLR_NAME_LEN ] ;
HeroClass _pClass ;
int _pStrength ;
int _pBaseStr ;
int _pMagic ;
int _pBaseMag ;
int _pDexterity ;
int _pBaseDex ;
int _pVitality ;
int _pBaseVit ;
int _pStatPts ;
int _pDamageMod ;
int _pBaseToBlk ;
int _pHPBase ;
int _pMaxHPBase ;
int _pHitPoints ;
int _pMaxHP ;
int _pHPPer ;
int _pManaBase ;
int _pMaxManaBase ;
int _pMana ;
int _pMaxMana ;
int _pManaPer ;
int8_t _pLevel ;
int8_t _pMaxLvl ;
uint32_t _pExperience ;
uint32_t _pNextExper ;
int8_t _pArmorClass ;
int8_t _pMagResist ;
int8_t _pFireResist ;
int8_t _pLghtResist ;
int _pGold ;
bool _pInfraFlag ;
/** Player's direction when ending movement. Also used for casting direction of SPL_FIREWALL. */
Direction tempDirection ;
/** Used for spell level */
int spellLevel ;
bool _pLvlVisited [ NUMLEVELS ] ;
bool _pSLvlVisited [ NUMLEVELS ] ; // only 10 used
/**
* @ brief Contains Data ( Sprites ) for the different Animations
*/
std : : array < PlayerAnimationData , enum_size < player_graphic > : : value > AnimationData ;
int _pNFrames ;
int _pWFrames ;
int _pAFrames ;
int _pAFNum ;
int _pSFrames ;
int _pSFNum ;
int _pHFrames ;
int _pDFrames ;
int _pBFrames ;
Item InvBody [ NUM_INVLOC ] ;
Item InvList [ NUM_INV_GRID_ELEM ] ;
int _pNumInv ;
int8_t InvGrid [ NUM_INV_GRID_ELEM ] ;
Item SpdList [ MAXBELTITEMS ] ;
Item HoldItem ;
int _pIMinDam ;
int _pIMaxDam ;
int _pIAC ;
int _pIBonusDam ;
int _pIBonusToHit ;
int _pIBonusAC ;
int _pIBonusDamMod ;
/** Bitmask of staff spell */
uint64_t _pISpells ;
/** Bitmask using item_special_effect */
ItemSpecialEffect _pIFlags ;
int _pIGetHit ;
int8_t _pISplLvlAdd ;
int _pISplDur ;
int _pIEnAc ;
int _pIFMinDam ;
int _pIFMaxDam ;
int _pILMinDam ;
int _pILMaxDam ;
item_misc_id _pOilType ;
uint8_t pTownWarps ;
uint8_t pDungMsgs ;
uint8_t pLvlLoad ;
bool pBattleNet ;
bool pManaShield ;
uint8_t pDungMsgs2 ;
bool pOriginalCathedral ;
uint16_t wReflections ;
uint8_t pDiabloKillLevel ;
_difficulty pDifficulty ;
ItemSpecialEffectHf pDamAcFlags ;
/** @brief Specifies whether players are in non-PvP mode. */
bool friendlyMode = true ;
void CalcScrolls ( ) ;
bool CanUseItem ( const Item & item ) const
{
return _pStrength > = item . _iMinStr
& & _pMagic > = item . _iMinMag
& & _pDexterity > = item . _iMinDex ;
}
/**
* @ brief Remove an item from player inventory
* @ param iv invList index of item to be removed
* @ param calcScrolls If true , CalcScrolls ( ) gets called after removing item
*/
void RemoveInvItem ( int iv , bool calcScrolls = true ) ;
void RemoveSpdBarItem ( int iv ) ;
/**
* @ brief Gets the most valuable item out of all the player ' s items that match the given predicate .
* @ param itemPredicate The predicate used to match the items .
* @ return The most valuable item out of all the player ' s items that match the given predicate , or ' nullptr ' in case no
* matching items were found .
*/
template < typename TPredicate >
const Item * GetMostValuableItem ( const TPredicate & itemPredicate ) const
{
const auto getMostValuableItem = [ & itemPredicate ] ( const Item * begin , const Item * end , const Item * mostValuableItem = nullptr ) {
for ( const auto * item = begin ; item < end ; item + + ) {
if ( item - > isEmpty ( ) | | ! itemPredicate ( * item ) ) {
continue ;
}
if ( mostValuableItem = = nullptr | | item - > _iIvalue > mostValuableItem - > _iIvalue ) {
mostValuableItem = item ;
}
}
return mostValuableItem ;
} ;
const Item * mostValuableItem = getMostValuableItem ( SpdList , SpdList + MAXBELTITEMS ) ;
mostValuableItem = getMostValuableItem ( InvBody , InvBody + inv_body_loc : : NUM_INVLOC , mostValuableItem ) ;
mostValuableItem = getMostValuableItem ( InvList , InvList + _pNumInv , mostValuableItem ) ;
return mostValuableItem ;
}
/**
* @ brief Gets the base value of the player ' s specified attribute .
* @ param attribute The attribute to retrieve the base value for
* @ return The base value for the requested attribute .
*/
int GetBaseAttributeValue ( CharacterAttribute attribute ) const ;
/**
* @ brief Gets the current value of the player ' s specified attribute .
* @ param attribute The attribute to retrieve the current value for
* @ return The current value for the requested attribute .
*/
int GetCurrentAttributeValue ( CharacterAttribute attribute ) const ;
/**
* @ brief Gets the maximum value of the player ' s specified attribute .
* @ param attribute The attribute to retrieve the maximum value for
* @ return The maximum value for the requested attribute .
*/
int GetMaximumAttributeValue ( CharacterAttribute attribute ) const ;
/**
* @ brief Get the tile coordinates a player is moving to ( if not moving , then it corresponds to current position ) .
*/
Point GetTargetPosition ( ) const ;
/**
* @ brief Says a speech line .
* @ todo BUGFIX Prevent more than one speech to be played at a time ( reject new requests ) .
*/
void Say ( HeroSpeech speechId ) const ;
/**
* @ brief Says a speech line after a given delay .
* @ param delay Multiple of 50 ms wait before starting the speech
*/
void Say ( HeroSpeech speechId , int delay ) const ;
/**
* @ brief Says a speech line , without random variants .
*/
void SaySpecific ( HeroSpeech speechId ) const ;
/**
* @ brief Attempts to stop the player from performing any queued up action . If the player is currently walking , his walking will
* stop as soon as he reaches the next tile . If any action was queued with the previous command ( like targeting a monster ,
* opening a chest , picking an item up , etc ) this action will also be cancelled .
*/
void Stop ( ) ;
/**
* @ brief Is the player currently walking ?
*/
bool IsWalking ( ) const ;
/**
* @ brief Resets all Data of the current Player
*/
void Reset ( ) ;
/**
* @ brief Returns item location taking into consideration barbarian ' s ability to hold two - handed maces and clubs in one hand .
*/
item_equip_type GetItemLocation ( const Item & item ) const
{
if ( _pClass = = HeroClass : : Barbarian & & item . _iLoc = = ILOC_TWOHAND & & IsAnyOf ( item . _itype , ItemType : : Sword , ItemType : : Mace ) )
return ILOC_ONEHAND ;
return item . _iLoc ;
}
/**
* @ brief Return player ' s armor value
*/
int GetArmor ( ) const
{
return _pIBonusAC + _pIAC + _pDexterity / 5 ;
}
/**
* @ brief Return player ' s melee to hit value
*/
int GetMeleeToHit ( ) const
{
int hper = _pLevel + _pDexterity / 2 + _pIBonusToHit + BaseHitChance ;
if ( _pClass = = HeroClass : : Warrior )
hper + = 20 ;
return hper ;
}
/**
* @ brief Return player ' s melee to hit value , including armor piercing
*/
int GetMeleePiercingToHit ( ) const
{
int hper = GetMeleeToHit ( ) ;
// in hellfire armor piercing ignores % of enemy armor instead, no way to include it here
if ( ! gbIsHellfire )
hper + = _pIEnAc ;
return hper ;
}
/**
* @ brief Return player ' s ranged to hit value
*/
int GetRangedToHit ( ) const
{
int hper = _pLevel + _pDexterity + _pIBonusToHit + BaseHitChance ;
if ( _pClass = = HeroClass : : Rogue )
hper + = 20 ;
else if ( _pClass = = HeroClass : : Warrior | | _pClass = = HeroClass : : Bard )
hper + = 10 ;
return hper ;
}
int GetRangedPiercingToHit ( ) const
{
int hper = GetRangedToHit ( ) ;
// in hellfire armor piercing ignores % of enemy armor instead, no way to include it here
if ( ! gbIsHellfire )
hper + = _pIEnAc ;
return hper ;
}
/**
* @ brief Return magic hit chance
*/
int GetMagicToHit ( ) const
{
int hper = _pMagic + BaseHitChance ;
if ( _pClass = = HeroClass : : Sorcerer )
hper + = 20 ;
else if ( _pClass = = HeroClass : : Bard )
hper + = 10 ;
return hper ;
}
/**
* @ brief Return block chance
* @ param useLevel - indicate if player ' s level should be added to block chance ( the only case where it isn ' t is blocking a trap )
*/
int GetBlockChance ( bool useLevel = true ) const
{
int blkper = _pDexterity + _pBaseToBlk ;
if ( useLevel )
blkper + = _pLevel * 2 ;
return blkper ;
}
/**
* @ brief Return reciprocal of the factor for calculating damage reduction due to Mana Shield .
*
* Valid only for players with Mana Shield spell level greater than zero .
*/
int GetManaShieldDamageReduction ( ) ;
/**
* @ brief Gets the effective spell level for the player , considering item bonuses
* @ param spell spell_id enum member identifying the spell
* @ return effective spell level
*/
int GetSpellLevel ( spell_id spell ) const
{
if ( spell = = SPL_INVALID | | static_cast < std : : size_t > ( spell ) > = sizeof ( _pSplLvl ) ) {
return 0 ;
}
return std : : max < int8_t > ( _pISplLvlAdd + _pSplLvl [ static_cast < std : : size_t > ( spell ) ] , 0 ) ;
}
/**
* @ brief Return monster armor value after including player ' s armor piercing % ( hellfire only )
* @ param monsterArmor - monster armor before applying % armor pierce
* @ param isMelee - indicates if it ' s melee or ranged combat
*/
int CalculateArmorPierce ( int monsterArmor , bool isMelee ) const
{
int tmac = monsterArmor ;
if ( _pIEnAc > 0 ) {
if ( gbIsHellfire ) {
int pIEnAc = _pIEnAc - 1 ;
if ( pIEnAc > 0 )
tmac > > = pIEnAc ;
else
tmac - = tmac / 4 ;
}
if ( isMelee & & _pClass = = HeroClass : : Barbarian ) {
tmac - = monsterArmor / 8 ;
}
}
if ( tmac < 0 )
tmac = 0 ;
return tmac ;
}
/**
* @ brief Calculates the players current Hit Points as a percentage of their max HP and stores it for later reference
*
* The stored value is unused . . .
* @ see _pHPPer
* @ return The players current hit points as a percentage of their maximum ( from 0 to 80 % )
*/
int UpdateHitPointPercentage ( )
{
if ( _pMaxHP < = 0 ) { // divide by zero guard
_pHPPer = 0 ;
} else {
// Maximum achievable HP is approximately 1200. Diablo uses fixed point integers where the last 6 bits are
// fractional values. This means that we will never overflow HP values normally by doing this multiplication
// as the max value is representable in 17 bits and the multiplication result will be at most 23 bits
_pHPPer = clamp ( _pHitPoints * 80 / _pMaxHP , 0 , 80 ) ; // hp should never be greater than maxHP but just in case
}
return _pHPPer ;
}
int UpdateManaPercentage ( )
{
if ( _pMaxMana < = 0 ) {
_pManaPer = 0 ;
} else {
_pManaPer = clamp ( _pMana * 80 / _pMaxMana , 0 , 80 ) ;
}
return _pManaPer ;
}
/**
* @ brief Restores between 1 / 8 ( inclusive ) and 1 / 4 ( exclusive ) of the players max HP ( further adjusted by class ) .
*
* This determines a random amount of non - fractional life points to restore then scales the value based on the
* player class . Warriors / barbarians get between 1 / 4 and 1 / 2 life restored per potion , rogue / monk / bard get 3 / 16
* to 3 / 8 , and sorcerers get the base amount .
*/
void RestorePartialLife ( ) ;
/**
* @ brief Resets hp to maxHp
*/
void RestoreFullLife ( )
{
_pHitPoints = _pMaxHP ;
_pHPBase = _pMaxHPBase ;
}
/**
* @ brief Restores between 1 / 8 ( inclusive ) and 1 / 4 ( exclusive ) of the players max Mana ( further adjusted by class ) .
*
* This determines a random amount of non - fractional mana points to restore then scales the value based on the
* player class . Sorcerers get between 1 / 4 and 1 / 2 mana restored per potion , rogue / monk / bard get 3 / 16 to 3 / 8 ,
* and warrior / barbarian get the base amount . However if the player can ' t use magic due to an equipped item then
* they get nothing .
*/
void RestorePartialMana ( ) ;
/**
* @ brief Resets mana to maxMana ( if the player can use magic )
*/
void RestoreFullMana ( )
{
if ( HasNoneOf ( _pIFlags , ItemSpecialEffect : : NoMana ) ) {
_pMana = _pMaxMana ;
_pManaBase = _pMaxManaBase ;
}
}
/**
* @ brief Sets the readied spell to the spell in the specified equipment slot . Does nothing if the item does not have a valid spell .
* @ param bodyLocation - the body location whose item will be checked for the spell .
*/
void ReadySpellFromEquipment ( inv_body_loc bodyLocation )
{
auto & item = InvBody [ bodyLocation ] ;
if ( item . _itype = = ItemType : : Staff & & item . _iSpell ! = SPL_NULL & & item . _iCharges > 0 ) {
_pRSpell = item . _iSpell ;
_pRSplType = RSPLTYPE_CHARGES ;
force_redraw = 255 ;
}
}
/**
* @ brief Does the player currently have a ranged weapon equipped ?
*/
bool UsesRangedWeapon ( ) const
{
return static_cast < PlayerWeaponGraphic > ( _pgfxnum & 0xF ) = = PlayerWeaponGraphic : : Bow ;
}
bool CanChangeAction ( )
{
if ( _pmode = = PM_STAND )
return true ;
if ( _pmode = = PM_ATTACK & & AnimInfo . CurrentFrame > = _pAFNum )
return true ;
if ( _pmode = = PM_RATTACK & & AnimInfo . CurrentFrame > = _pAFNum )
return true ;
if ( _pmode = = PM_SPELL & & AnimInfo . CurrentFrame > = _pSFNum )
return true ;
if ( IsWalking ( ) & & AnimInfo . CurrentFrame = = AnimInfo . NumberOfFrames - 1 )
return true ;
return false ;
}
/**
* @ brief Updates previewCelSprite according to new requested command
* @ param cmdId What command is requested
* @ param point Point for the command
* @ param wParam1 First Parameter
* @ param wParam2 Second Parameter
*/
void UpdatePreviewCelSprite ( _cmd_id cmdId , Point point , uint16_t wParam1 , uint16_t wParam2 ) ;
/** @brief Checks if the player is on the same level as the local player (MyPlayer). */
bool isOnActiveLevel ( ) const
{
if ( setlevel )
return isOnLevel ( setlvlnum ) ;
return isOnLevel ( currlevel ) ;
}
/** @brief Checks if the player is on the correspondig level. */
bool isOnLevel ( uint8_t level ) const
{
return ! this - > plrIsOnSetLevel & & this - > plrlevel = = level ;
}
/** @brief Checks if the player is on the correspondig level. */
bool isOnLevel ( _setlevels level ) const
{
return this - > plrIsOnSetLevel & & this - > plrlevel = = static_cast < uint8_t > ( level ) ;
}
void setLevel ( uint8_t level )
{
this - > plrlevel = level ;
this - > plrIsOnSetLevel = false ;
}
void setLevel ( _setlevels level )
{
this - > plrlevel = static_cast < uint8_t > ( level ) ;
this - > plrIsOnSetLevel = true ;
}
} ;
extern DVL_API_FOR_TEST int MyPlayerId ;
extern DVL_API_FOR_TEST Player * MyPlayer ;
extern DVL_API_FOR_TEST Player Players [ MAX_PLRS ] ;
extern bool MyPlayerIsDead ;
extern int BlockBonuses [ enum_size < HeroClass > : : value ] ;
void LoadPlrGFX ( Player & player , player_graphic graphic ) ;
void InitPlayerGFX ( Player & player ) ;
void ResetPlayerGFX ( Player & player ) ;
/**
* @ brief Sets the new Player Animation with all relevant information for rendering
* @ param graphic What player animation should be displayed
* @ param dir Direction of the animation
* @ param numberOfFrames Number of Frames in Animation
* @ param delayLen Delay after each Animation sequence
* @ param flags Specifies what special logics are applied to this Animation
* @ param numSkippedFrames Number of Frames that will be skipped ( for example with modifier " faster attack " )
* @ param distributeFramesBeforeFrame Distribute the numSkippedFrames only before this frame
*/
void NewPlrAnim ( Player & player , player_graphic graphic , Direction dir , int numberOfFrames , int delayLen , AnimationDistributionFlags flags = AnimationDistributionFlags : : None , int numSkippedFrames = 0 , int distributeFramesBeforeFrame = 0 ) ;
void SetPlrAnims ( Player & player ) ;
void CreatePlayer ( int playerId , HeroClass c ) ;
int CalcStatDiff ( Player & player ) ;
# ifdef _DEBUG
void NextPlrLevel ( Player & player ) ;
# endif
void AddPlrExperience ( Player & player , int lvl , int exp ) ;
void AddPlrMonstExper ( int lvl , int exp , char pmask ) ;
void ApplyPlrDamage ( int pnum , int dam , int minHP = 0 , int frac = 0 , int earflag = 0 ) ;
void InitPlayer ( Player & player , bool FirstTime ) ;
void InitMultiView ( ) ;
void PlrClrTrans ( Point position ) ;
void PlrDoTrans ( Point position ) ;
void SetPlayerOld ( Player & player ) ;
void FixPlayerLocation ( Player & player , Direction bDir ) ;
void StartStand ( int pnum , Direction dir ) ;
void StartPlrBlock ( int pnum , Direction dir ) ;
void FixPlrWalkTags ( int pnum ) ;
void RemovePlrFromMap ( int pnum ) ;
void StartPlrHit ( int pnum , int dam , bool forcehit ) ;
void StartPlayerKill ( int pnum , int earflag ) ;
/**
* @ brief Strip the top off gold piles that are larger than MaxGold
*/
void StripTopGold ( Player & player ) ;
void SyncPlrKill ( int pnum , int earflag ) ;
void RemovePlrMissiles ( int pnum ) ;
void StartNewLvl ( int pnum , interface_mode fom , int lvl ) ;
void RestartTownLvl ( int pnum ) ;
void StartWarpLvl ( int pnum , int pidx ) ;
void ProcessPlayers ( ) ;
void ClrPlrPath ( Player & player ) ;
bool PosOkPlayer ( const Player & player , Point position ) ;
void MakePlrPath ( Player & player , Point targetPosition , bool endspace ) ;
void CalcPlrStaff ( Player & player ) ;
void CheckPlrSpell ( bool isShiftHeld , spell_id spellID = MyPlayer - > _pRSpell , spell_type spellType = MyPlayer - > _pRSplType ) ;
void SyncPlrAnim ( Player & player ) ;
void SyncInitPlrPos ( int pnum ) ;
void SyncInitPlr ( int pnum ) ;
void CheckStats ( Player & player ) ;
void ModifyPlrStr ( Player & player , int l ) ;
void ModifyPlrMag ( Player & player , int l ) ;
void ModifyPlrDex ( Player & player , int l ) ;
void ModifyPlrVit ( Player & player , int l ) ;
void SetPlayerHitPoints ( Player & player , int val ) ;
void SetPlrStr ( Player & player , int v ) ;
void SetPlrMag ( Player & player , int v ) ;
void SetPlrDex ( Player & player , int v ) ;
void SetPlrVit ( Player & player , int v ) ;
void InitDungMsgs ( Player & player ) ;
void PlayDungMsgs ( ) ;
/* data */
extern int plrxoff [ 9 ] ;
extern int plryoff [ 9 ] ;
extern int plrxoff2 [ 9 ] ;
extern int plryoff2 [ 9 ] ;
extern int StrengthTbl [ enum_size < HeroClass > : : value ] ;
extern int MagicTbl [ enum_size < HeroClass > : : value ] ;
extern int DexterityTbl [ enum_size < HeroClass > : : value ] ;
extern int VitalityTbl [ enum_size < HeroClass > : : value ] ;
extern uint32_t ExpLvlsTbl [ MAXCHARLEVEL + 1 ] ;
} // namespace devilution