2018-03-06 22:22:19 +01:00
# include <Common.h>
# include <Util/Util.h>
# include <Util/UtilMath.h>
# include <Logging/Logger.h>
# include <Exd/ExdDataGenerated.h>
# include <Network/PacketContainer.h>
2018-06-23 21:38:04 +02:00
# include <Network/CommonActorControl.h>
2018-07-21 23:32:10 +10:00
# include <Network/PacketWrappers/EffectPacket.h>
2018-10-26 14:11:02 +02:00
# include <cmath>
2017-12-08 15:38:25 +01:00
# include "Session.h"
2017-08-08 13:53:47 +02:00
# include "Player.h"
2019-01-19 22:56:07 +01:00
# include "BNpc.h"
2017-08-08 13:53:47 +02:00
2019-01-13 17:32:43 +01:00
# include "Manager/HousingMgr.h"
2018-12-01 00:27:16 +11:00
# include "Manager/TerritoryMgr.h"
2019-01-13 17:32:43 +01:00
2018-12-01 00:27:16 +11:00
# include "Territory/Zone.h"
# include "Territory/ZonePosition.h"
2019-01-13 17:32:43 +01:00
# include "Territory/InstanceContent.h"
2018-12-01 00:27:16 +11:00
# include "Territory/Land.h"
2018-11-10 19:00:13 +01:00
2017-12-08 15:38:25 +01:00
# include "Network/GameConnection.h"
# include "Network/PacketWrappers/ActorControlPacket142.h"
# include "Network/PacketWrappers/ActorControlPacket143.h"
2018-02-18 01:50:20 +01:00
# include "Network/PacketWrappers/ActorControlPacket144.h"
2017-12-08 15:38:25 +01:00
# include "Network/PacketWrappers/InitUIPacket.h"
# include "Network/PacketWrappers/ServerNoticePacket.h"
# include "Network/PacketWrappers/ChatPacket.h"
# include "Network/PacketWrappers/ModelEquipPacket.h"
# include "Network/PacketWrappers/UpdateHpMpTpPacket.h"
# include "Network/PacketWrappers/PlayerStateFlagsPacket.h"
# include "Network/PacketWrappers/PlayerSpawnPacket.h"
2018-03-02 07:22:25 -03:00
# include "Script/ScriptMgr.h"
2017-12-08 15:38:25 +01:00
# include "Math/CalcStats.h"
# include "Math/CalcBattle.h"
2017-08-08 13:53:47 +02:00
2018-11-20 21:32:13 +01:00
# include "ServerMgr.h"
2018-03-02 07:22:25 -03:00
# include "Framework.h"
2018-11-29 16:55:48 +01:00
using namespace Sapphire : : Common ;
using namespace Sapphire : : Network : : Packets ;
using namespace Sapphire : : Network : : Packets : : Server ;
using namespace Sapphire : : Network : : ActorControl ;
2018-12-01 00:27:16 +11:00
using namespace Sapphire : : World : : Manager ;
2017-08-08 13:53:47 +02:00
2018-11-29 16:55:48 +01:00
using InventoryMap = std : : map < uint16_t , Sapphire : : ItemContainerPtr > ;
2018-07-24 23:58:08 +02:00
using InvSlotPair = std : : pair < uint16_t , int8_t > ;
using InvSlotPairVec = std : : vector < InvSlotPair > ;
2017-08-08 13:53:47 +02:00
// player constructor
2018-12-25 01:57:50 +01:00
Sapphire : : Entity : : Player : : Player ( FrameworkPtr pFw ) :
2018-12-29 00:53:52 +01:00
Chara ( ObjKind : : Player , pFw ) ,
2018-08-29 21:40:59 +02:00
m_lastWrite ( 0 ) ,
m_lastPing ( 0 ) ,
m_bIsLogin ( false ) ,
m_contentId ( 0 ) ,
m_modelMainWeapon ( 0 ) ,
m_modelSubWeapon ( 0 ) ,
m_homePoint ( 0 ) ,
m_startTown ( 0 ) ,
m_townWarpFstFlags ( 0 ) ,
m_playTime ( 0 ) ,
m_bInCombat ( false ) ,
m_bLoadingComplete ( false ) ,
m_bMarkedForZoning ( false ) ,
m_zoningType ( Common : : ZoneingType : : None ) ,
m_bAutoattack ( false ) ,
m_markedForRemoval ( false ) ,
m_mount ( 0 ) ,
m_emoteMode ( 0 ) ,
m_directorInitialized ( false ) ,
2019-02-06 08:49:57 +01:00
m_onEnterEventDone ( false ) ,
m_falling ( false )
2018-08-29 21:40:59 +02:00
{
m_id = 0 ;
m_currentStance = Stance : : Passive ;
m_onlineStatus = 0 ;
m_queuedZoneing = nullptr ;
m_status = ActorStatus : : Idle ;
m_invincibilityType = InvincibilityType : : InvincibilityNone ;
memset ( m_questTracking , 0 , sizeof ( m_questTracking ) ) ;
memset ( m_name , 0 , sizeof ( m_name ) ) ;
memset ( m_stateFlags , 0 , sizeof ( m_stateFlags ) ) ;
memset ( m_searchMessage , 0 , sizeof ( m_searchMessage ) ) ;
memset ( m_classArray , 0 , sizeof ( m_classArray ) ) ;
memset ( m_expArray , 0 , sizeof ( m_expArray ) ) ;
2018-11-07 11:59:59 +01:00
for ( uint8_t i = 0 ; i < 5 ; i + + )
{
2018-11-28 23:29:55 +11:00
memset ( & m_landFlags [ i ] , 0xFF , 8 ) ;
memset ( & m_landFlags [ i ] . landFlags , 0 , 8 ) ;
2018-11-07 11:59:59 +01:00
}
2018-08-29 21:40:59 +02:00
m_objSpawnIndexAllocator . init ( MAX_DISPLAYED_EOBJS ) ;
m_actorSpawnIndexAllocator . init ( MAX_DISPLAYED_ACTORS , true ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
Sapphire : : Entity : : Player : : ~ Player ( )
2017-08-08 13:53:47 +02:00
{
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : injectPacket ( const std : : string & path )
2018-03-05 22:10:14 +11:00
{
2018-12-25 01:57:50 +01:00
auto pServerZone = m_pFw - > get < World : : ServerMgr > ( ) ;
2018-08-29 21:40:59 +02:00
auto session = pServerZone - > getSession ( getId ( ) ) ;
if ( session )
session - > getZoneConnection ( ) - > injectPacket ( path , * this ) ;
2018-03-05 22:10:14 +11:00
}
2017-08-08 13:53:47 +02:00
// TODO: add a proper calculation based on race / job / level / gear
2018-11-29 16:55:48 +01:00
uint32_t Sapphire : : Entity : : Player : : getMaxHp ( )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_baseStats . max_hp ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint32_t Sapphire : : Entity : : Player : : getMaxMp ( )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_baseStats . max_mp ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint16_t Sapphire : : Entity : : Player : : getZoneId ( ) const
2017-08-08 13:53:47 +02:00
{
2018-12-02 15:32:22 +11:00
return m_territoryTypeId ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint32_t Sapphire : : Entity : : Player : : getTerritoryId ( ) const
2018-11-06 10:48:46 +01:00
{
return m_territoryId ;
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setTerritoryId ( uint32_t territoryId )
2018-11-06 10:48:46 +01:00
{
m_territoryId = territoryId ;
}
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getGmRank ( ) const
2017-09-11 18:59:50 +02:00
{
2018-08-29 21:40:59 +02:00
return m_gmRank ;
2017-09-11 18:59:50 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setGmRank ( uint8_t rank )
2017-09-11 18:59:50 +02:00
{
2018-08-29 21:40:59 +02:00
m_gmRank = rank ;
2017-09-11 18:59:50 +02:00
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : getGmInvis ( ) const
2018-04-18 21:00:20 +10:00
{
2018-08-29 21:40:59 +02:00
return m_gmInvis ;
2018-04-18 21:00:20 +10:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setGmInvis ( bool invis )
2018-04-18 21:00:20 +10:00
{
2018-08-29 21:40:59 +02:00
m_gmInvis = invis ;
2018-04-18 21:00:20 +10:00
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : isActingAsGm ( ) const
2018-07-01 21:31:49 +10:00
{
2018-08-29 21:40:59 +02:00
auto status = getOnlineStatus ( ) ;
return status = = OnlineStatus : : GameMaster | | status = = OnlineStatus : : GameMaster1 | |
status = = OnlineStatus : : GameMaster2 ;
2018-07-01 21:31:49 +10:00
}
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getMode ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_mode ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setMode ( uint8_t mode )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
m_mode = mode ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getStartTown ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_startTown ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setMarkedForRemoval ( )
2017-11-14 23:55:38 +01:00
{
2018-08-29 21:40:59 +02:00
m_markedForRemoval = true ;
2017-11-14 23:55:38 +01:00
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : isMarkedForRemoval ( ) const
2017-11-14 23:55:38 +01:00
{
2018-08-29 21:40:59 +02:00
return m_markedForRemoval ;
2017-11-14 23:55:38 +01:00
}
2018-11-29 16:55:48 +01:00
Sapphire : : Common : : OnlineStatus Sapphire : : Entity : : Player : : getOnlineStatus ( ) const
2017-08-08 13:53:47 +02:00
{
2018-12-25 01:57:50 +01:00
auto pExdData = m_pFw - > get < Data : : ExdDataGenerated > ( ) ;
2018-08-29 21:40:59 +02:00
if ( ! pExdData )
return OnlineStatus : : Online ;
2018-04-18 21:00:20 +10:00
2018-08-29 21:40:59 +02:00
uint32_t statusDisplayOrder = 0xFF14 ;
uint32_t applicableStatus = static_cast < uint32_t > ( OnlineStatus : : Online ) ;
2018-04-19 23:04:31 +10:00
2018-08-29 21:40:59 +02:00
for ( uint32_t i = 0 ; i < std : : numeric_limits < decltype ( m_onlineStatus ) > : : digits ; i + + )
{
bool bit = ( m_onlineStatus > > i ) & 1 ;
2018-04-18 21:00:20 +10:00
2018-08-29 21:40:59 +02:00
if ( ! bit )
continue ;
2018-04-18 21:00:20 +10:00
2018-08-29 21:40:59 +02:00
auto pOnlineStatus = pExdData - > get < Data : : OnlineStatus > ( i ) ;
if ( ! pOnlineStatus )
continue ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
if ( pOnlineStatus - > priority < statusDisplayOrder )
{
// todo: also check that the status can actually be set here, otherwise we need to ignore it (and ban the player obv)
statusDisplayOrder = pOnlineStatus - > priority ;
applicableStatus = i ;
}
}
2018-04-24 20:34:36 +10:00
2018-08-29 21:40:59 +02:00
return static_cast < OnlineStatus > ( applicableStatus ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setOnlineStatusMask ( uint64_t status )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
m_onlineStatus = status ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint64_t Sapphire : : Entity : : Player : : getOnlineStatusMask ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_onlineStatus ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : prepareZoning ( uint16_t targetZone , bool fadeOut , uint8_t fadeOutTime , uint16_t animation )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
auto preparePacket = makeZonePacket < FFXIVIpcPrepareZoning > ( getId ( ) ) ;
preparePacket - > data ( ) . targetZone = targetZone ;
preparePacket - > data ( ) . fadeOutTime = fadeOutTime ;
preparePacket - > data ( ) . animation = animation ;
preparePacket - > data ( ) . fadeOut = static_cast < uint8_t > ( fadeOut ? 1 : 0 ) ;
queuePacket ( preparePacket ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : calculateStats ( )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
uint8_t tribe = getLookAt ( Common : : CharaLook : : Tribe ) ;
uint8_t level = getLevel ( ) ;
uint8_t job = static_cast < uint8_t > ( getClass ( ) ) ;
2017-08-08 13:53:47 +02:00
2018-12-25 01:57:50 +01:00
auto pExdData = m_pFw - > get < Data : : ExdDataGenerated > ( ) ;
2018-03-09 00:06:44 +01:00
2018-11-29 16:55:48 +01:00
auto classInfo = pExdData - > get < Sapphire : : Data : : ClassJob > ( job ) ;
auto tribeInfo = pExdData - > get < Sapphire : : Data : : Tribe > ( tribe ) ;
auto paramGrowthInfo = pExdData - > get < Sapphire : : Data : : ParamGrow > ( level ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
// TODO: put formula somewhere else...
float base = Math : : CalcStats : : calculateBaseStat ( getAsPlayer ( ) ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
m_baseStats . str = static_cast < uint32_t > ( base * ( static_cast < float > ( classInfo - > modifierStrength ) / 100 ) +
tribeInfo - > sTR ) ;
m_baseStats . dex = static_cast < uint32_t > ( base * ( static_cast < float > ( classInfo - > modifierDexterity ) / 100 ) +
tribeInfo - > dEX ) ;
m_baseStats . vit = static_cast < uint32_t > ( base * ( static_cast < float > ( classInfo - > modifierVitality ) / 100 ) +
tribeInfo - > vIT ) ;
m_baseStats . inte = static_cast < uint32_t > ( base * ( static_cast < float > ( classInfo - > modifierIntelligence ) / 100 ) +
tribeInfo - > iNT ) ;
m_baseStats . mnd = static_cast < uint32_t > ( base * ( static_cast < float > ( classInfo - > modifierMind ) / 100 ) +
tribeInfo - > mND ) ;
m_baseStats . pie = static_cast < uint32_t > ( base * ( static_cast < float > ( classInfo - > modifierPiety ) / 100 ) +
tribeInfo - > pIE ) ;
2018-01-31 11:43:22 +01:00
2018-08-29 21:40:59 +02:00
m_baseStats . skillSpeed = paramGrowthInfo - > baseSpeed ;
m_baseStats . spellSpeed = paramGrowthInfo - > baseSpeed ;
m_baseStats . accuracy = paramGrowthInfo - > baseSpeed ;
m_baseStats . critHitRate = paramGrowthInfo - > baseSpeed ;
m_baseStats . attackPotMagic = paramGrowthInfo - > baseSpeed ;
m_baseStats . healingPotMagic = paramGrowthInfo - > baseSpeed ;
m_baseStats . tenacity = paramGrowthInfo - > baseSpeed ;
2017-08-08 13:53:47 +02:00
2018-12-29 00:53:52 +01:00
m_baseStats . max_mp = Math : : CalcStats : : calculateMaxMp ( getAsPlayer ( ) , m_pFw ) ;
2017-08-19 11:28:04 +09:00
2018-12-29 00:53:52 +01:00
m_baseStats . max_hp = Math : : CalcStats : : calculateMaxHp ( getAsPlayer ( ) , m_pFw ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
if ( m_mp > m_baseStats . max_mp )
m_mp = m_baseStats . max_mp ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
if ( m_hp > m_baseStats . max_hp )
m_hp = m_baseStats . max_hp ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
m_baseStats . determination = static_cast < uint32_t > ( base ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setAutoattack ( bool mode )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
m_bAutoattack = mode ;
m_lastAttack = Util : : getTimeMs ( ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : isAutoattackOn ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_bAutoattack ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : sendStats ( )
2017-08-08 13:53:47 +02:00
{
2018-06-28 00:07:07 +02:00
2018-08-29 21:40:59 +02:00
auto statPacket = makeZonePacket < FFXIVIpcPlayerStats > ( getId ( ) ) ;
statPacket - > data ( ) . strength = m_baseStats . str ;
statPacket - > data ( ) . dexterity = m_baseStats . dex ;
statPacket - > data ( ) . vitality = m_baseStats . vit ;
statPacket - > data ( ) . intelligence = m_baseStats . inte ;
statPacket - > data ( ) . mind = m_baseStats . mnd ;
statPacket - > data ( ) . piety = m_baseStats . pie ;
statPacket - > data ( ) . determination = m_baseStats . determination ;
statPacket - > data ( ) . hp = m_baseStats . max_hp ;
statPacket - > data ( ) . mp = m_baseStats . max_mp ;
statPacket - > data ( ) . accuracy = m_baseStats . accuracy ;
statPacket - > data ( ) . attack = m_baseStats . attack ;
statPacket - > data ( ) . attackMagicPotency = m_baseStats . attackPotMagic ;
statPacket - > data ( ) . healingMagicPotency = m_baseStats . healingPotMagic ;
statPacket - > data ( ) . skillSpeed = m_baseStats . skillSpeed ;
statPacket - > data ( ) . spellSpeed = m_baseStats . spellSpeed ;
statPacket - > data ( ) . spellSpeed1 = m_baseStats . spellSpeed ;
statPacket - > data ( ) . spellSpeedMod = 100 ;
statPacket - > data ( ) . criticalHitRate = m_baseStats . spellSpeed ;
statPacket - > data ( ) . defense = m_baseStats . spellSpeed ;
statPacket - > data ( ) . magicDefense = m_baseStats . spellSpeed ;
statPacket - > data ( ) . attack = m_baseStats . spellSpeed ;
queuePacket ( statPacket ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : teleport ( uint16_t aetheryteId , uint8_t type )
2017-08-08 13:53:47 +02:00
{
2018-12-25 01:57:50 +01:00
auto pExdData = m_pFw - > get < Data : : ExdDataGenerated > ( ) ;
auto pTeriMgr = m_pFw - > get < TerritoryMgr > ( ) ;
2018-03-09 00:06:44 +01:00
2018-11-29 16:55:48 +01:00
auto data = pExdData - > get < Sapphire : : Data : : Aetheryte > ( aetheryteId ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
if ( data = = nullptr )
{
return ;
}
setStateFlag ( PlayerStateFlag : : BetweenAreas ) ;
auto targetPos = pTeriMgr - > getTerritoryPosition ( data - > level . at ( 0 ) ) ;
Common : : FFXIVARR_POSITION3 pos ;
pos . x = 0 ;
pos . y = 0 ;
pos . z = 0 ;
float rot = 0 ;
if ( targetPos ! = nullptr )
{
pos = targetPos - > getTargetPosition ( ) ;
rot = targetPos - > getTargetRotation ( ) ;
}
2019-01-05 12:32:10 +01:00
sendDebug ( " Teleport: {0} {1} ({2}) " ,
pExdData - > get < Sapphire : : Data : : PlaceName > ( data - > placeName ) - > name ,
pExdData - > get < Sapphire : : Data : : PlaceName > ( data - > aethernetName ) - > name ,
data - > territory ) ;
2018-08-29 21:40:59 +02:00
// TODO: this should be simplified and a type created in server_common/common.h.
if ( type = = 1 ) // teleport
{
prepareZoning ( data - > territory , true , 1 , 112 ) ; // TODO: Really?
sendToInRangeSet ( makeActorControl142 ( getId ( ) , ActorDespawnEffect , 0x04 ) ) ;
setZoningType ( Common : : ZoneingType : : Teleport ) ;
}
else if ( type = = 2 ) // aethernet
{
prepareZoning ( data - > territory , true , 1 , 112 ) ;
sendToInRangeSet ( makeActorControl142 ( getId ( ) , ActorDespawnEffect , 0x04 ) ) ;
setZoningType ( Common : : ZoneingType : : Teleport ) ;
}
else if ( type = = 3 ) // return
{
prepareZoning ( data - > territory , true , 1 , 111 ) ;
sendToInRangeSet ( makeActorControl142 ( getId ( ) , ActorDespawnEffect , 0x03 ) ) ;
setZoningType ( Common : : ZoneingType : : Return ) ;
}
2018-10-25 12:44:51 +11:00
m_queuedZoneing = std : : make_shared < QueuedZoning > ( data - > territory , pos , Util : : getTimeMs ( ) , rot ) ;
2017-09-13 11:46:17 +02:00
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : forceZoneing ( uint32_t zoneId )
2017-08-08 13:53:47 +02:00
{
2018-10-25 12:44:51 +11:00
m_queuedZoneing = std : : make_shared < QueuedZoning > ( zoneId , getPos ( ) , Util : : getTimeMs ( ) , 0.f ) ;
2018-08-29 21:40:59 +02:00
//performZoning( zoneId, Common::ZoneingType::None, getPos() );
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : returnToHomepoint ( )
2017-08-10 16:31:48 +02:00
{
2018-08-29 21:40:59 +02:00
setZoningType ( Common : : ZoneingType : : Return ) ;
teleport ( getHomepoint ( ) , 3 ) ;
2017-08-10 16:31:48 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setZone ( uint32_t zoneId )
2017-08-08 13:53:47 +02:00
{
2018-12-25 01:57:50 +01:00
auto pTeriMgr = m_pFw - > get < TerritoryMgr > ( ) ;
2018-08-29 21:40:59 +02:00
m_onEnterEventDone = false ;
if ( ! pTeriMgr - > movePlayer ( zoneId , getAsPlayer ( ) ) )
{
// todo: this will require proper handling, for now just return the player to their previous area
m_pos = m_prevPos ;
m_rot = m_prevRot ;
2018-12-02 15:32:22 +11:00
m_territoryTypeId = m_prevTerritoryTypeId ;
2018-02-04 18:53:19 +01:00
2018-12-02 15:32:22 +11:00
if ( ! pTeriMgr - > movePlayer ( m_territoryTypeId , getAsPlayer ( ) ) )
2018-08-29 21:40:59 +02:00
return ;
}
2018-02-04 18:53:19 +01:00
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : setInstance ( uint32_t instanceContentId )
2018-01-29 13:05:33 +11:00
{
2018-08-29 21:40:59 +02:00
m_onEnterEventDone = false ;
2019-01-14 22:29:52 +01:00
auto pTeriMgr = m_pFw - > get < TerritoryMgr > ( ) ;
2018-08-29 21:40:59 +02:00
auto instance = pTeriMgr - > getInstanceZonePtr ( instanceContentId ) ;
if ( ! instance )
return false ;
2018-01-29 13:05:33 +11:00
2018-08-29 21:40:59 +02:00
return setInstance ( instance ) ;
2018-01-29 13:05:33 +11:00
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : setInstance ( ZonePtr instance )
2018-01-29 13:05:33 +11:00
{
2018-08-29 21:40:59 +02:00
m_onEnterEventDone = false ;
if ( ! instance )
return false ;
2018-01-29 13:05:33 +11:00
2018-12-25 01:57:50 +01:00
auto pTeriMgr = m_pFw - > get < TerritoryMgr > ( ) ;
2018-12-02 15:32:22 +11:00
auto currentZone = getCurrentZone ( ) ;
2018-08-29 21:40:59 +02:00
// zoning within the same zone won't cause the prev data to be overwritten
2018-12-02 15:32:22 +11:00
if ( instance - > getTerritoryTypeId ( ) ! = m_territoryTypeId )
2018-08-29 21:40:59 +02:00
{
m_prevPos = m_pos ;
m_prevRot = m_rot ;
2018-12-02 15:32:22 +11:00
m_prevTerritoryTypeId = currentZone - > getTerritoryTypeId ( ) ;
m_prevTerritoryId = getTerritoryId ( ) ;
2018-08-29 21:40:59 +02:00
}
2018-01-29 13:05:33 +11:00
2019-01-14 22:29:52 +01:00
return pTeriMgr - > movePlayer ( instance , getAsPlayer ( ) ) ;
2018-01-29 13:05:33 +11:00
}
2018-12-30 18:48:45 +11:00
bool Sapphire : : Entity : : Player : : setInstance ( ZonePtr instance , Common : : FFXIVARR_POSITION3 pos )
{
2019-01-14 22:29:52 +01:00
m_onEnterEventDone = false ;
2018-12-30 18:48:45 +11:00
if ( ! instance )
return false ;
auto pTeriMgr = m_pFw - > get < TerritoryMgr > ( ) ;
auto currentZone = getCurrentZone ( ) ;
2019-01-14 22:29:52 +01:00
// zoning within the same zone won't cause the prev data to be overwritten
if ( instance - > getTerritoryTypeId ( ) ! = m_territoryTypeId )
{
m_prevPos = m_pos ;
m_prevRot = m_rot ;
m_prevTerritoryTypeId = currentZone - > getTerritoryTypeId ( ) ;
m_prevTerritoryId = getTerritoryId ( ) ;
}
2018-12-30 18:48:45 +11:00
if ( pTeriMgr - > movePlayer ( instance , getAsPlayer ( ) ) )
{
m_pos = pos ;
return true ;
}
return false ;
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : exitInstance ( )
2018-01-29 13:05:33 +11:00
{
2018-12-25 01:57:50 +01:00
auto pTeriMgr = m_pFw - > get < TerritoryMgr > ( ) ;
2018-12-02 15:32:22 +11:00
2019-01-13 17:32:43 +01:00
auto pZone = getCurrentZone ( ) ;
auto pInstance = pZone - > getAsInstanceContent ( ) ;
2018-12-02 15:32:22 +11:00
// check if housing zone
if ( pTeriMgr - > isHousingTerritory ( m_prevTerritoryTypeId ) )
{
if ( ! pTeriMgr - > movePlayer ( pTeriMgr - > getZoneByLandSetId ( m_prevTerritoryId ) , getAsPlayer ( ) ) )
return false ;
}
else
{
if ( ! pTeriMgr - > movePlayer ( m_prevTerritoryTypeId , getAsPlayer ( ) ) )
return false ;
}
2018-01-29 13:05:33 +11:00
2018-08-29 21:40:59 +02:00
m_pos = m_prevPos ;
m_rot = m_prevRot ;
2018-12-02 15:32:22 +11:00
m_territoryTypeId = m_prevTerritoryTypeId ;
m_territoryId = m_prevTerritoryId ;
2018-01-29 13:05:33 +11:00
2019-01-13 17:32:43 +01:00
//m_queuedZoneing = std::make_shared< QueuedZoning >( m_territoryTypeId, m_pos, Util::getTimeMs(), m_rot );
2018-08-29 21:40:59 +02:00
return true ;
2018-01-29 13:05:33 +11:00
}
2018-11-29 16:55:48 +01:00
uint32_t Sapphire : : Entity : : Player : : getPlayTime ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_playTime ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getRace ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return getLookAt ( CharaLook : : Race ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getGender ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return getLookAt ( CharaLook : : Gender ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : initSpawnIdQueue ( )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
m_actorSpawnIndexAllocator . freeAllSpawnIndexes ( ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getSpawnIdForActorId ( uint32_t actorId )
2017-08-08 13:53:47 +02:00
{
2019-01-28 21:02:51 +11:00
auto index = m_actorSpawnIndexAllocator . getNextFreeSpawnIndex ( actorId ) ;
if ( index = = m_actorSpawnIndexAllocator . getAllocFailId ( ) )
{
Logger : : warn ( " Failed to spawn Chara#{0} for Player#{1} - no remaining spawn indexes available. "
" Consider lowering InRangeDistance in world config. " ,
actorId , getId ( ) ) ;
sendUrgent ( " Failed to spawn Chara#{0} for you - no remaining spawn slots. See world log. " , actorId ) ;
return index ;
}
return index ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : isActorSpawnIdValid ( uint8_t spawnIndex )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_actorSpawnIndexAllocator . isSpawnIndexValid ( spawnIndex ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : registerAetheryte ( uint8_t aetheryteId )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
uint16_t index ;
uint8_t value ;
Util : : valueToFlagByteIndexValue ( aetheryteId , value , index ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
m_aetheryte [ index ] | = value ;
queuePacket ( makeActorControl143 ( getId ( ) , LearnTeleport , aetheryteId , 1 ) ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : isAetheryteRegistered ( uint8_t aetheryteId ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
uint16_t index ;
uint8_t value ;
Util : : valueToFlagByteIndexValue ( aetheryteId , value , index ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
return ( m_aetheryte [ index ] & value ) ! = 0 ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint8_t * Sapphire : : Entity : : Player : : getDiscoveryBitmask ( )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_discovery ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : discover ( int16_t map_id , int16_t sub_id )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
// map.exd field 12 -> index in one of the two discovery sections, if field 15 is false, need to use 2nd section
// section 1 starts at 4 - 2 bytes each
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
// section to starts at 320 - 4 bytes long
2017-08-08 13:53:47 +02:00
2018-12-25 01:57:50 +01:00
auto pExdData = m_pFw - > get < Data : : ExdDataGenerated > ( ) ;
2018-03-09 00:06:44 +01:00
2018-08-29 21:40:59 +02:00
int32_t offset = 4 ;
2017-08-08 13:53:47 +02:00
2018-11-29 16:55:48 +01:00
auto info = pExdData - > get < Sapphire : : Data : : Map > (
pExdData - > get < Sapphire : : Data : : TerritoryType > ( getCurrentZone ( ) - > getTerritoryTypeId ( ) ) - > map ) ;
2018-08-29 21:40:59 +02:00
if ( info - > discoveryArrayByte )
2018-09-17 22:52:57 +02:00
offset = 5 + 2 * info - > discoveryIndex ;
2018-08-29 21:40:59 +02:00
else
2018-09-17 22:52:57 +02:00
offset = 325 + 4 * info - > discoveryIndex ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
int32_t index = offset + sub_id / 8 ;
uint8_t bitIndex = sub_id % 8 ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
uint8_t value = 1 < < bitIndex ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
m_discovery [ index ] | = value ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
uint16_t level = getLevel ( ) ;
2017-08-08 13:53:47 +02:00
2018-11-29 16:55:48 +01:00
uint32_t exp = ( pExdData - > get < Sapphire : : Data : : ParamGrow > ( level ) - > expToNext * 5 / 100 ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
gainExp ( exp ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : isNewAdventurer ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_bNewAdventurer ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setNewAdventurer ( bool state )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
//if( !state )
//{
// unsetStateFlag( PlayerStateFlag::NewAdventurer );
//}
//else
//{
// setStateFlag( PlayerStateFlag::NewAdventurer );
//}
m_bNewAdventurer = state ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : resetDiscovery ( )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
memset ( m_discovery , 0 , sizeof ( m_discovery ) ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : changePosition ( float x , float y , float z , float o )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
Common : : FFXIVARR_POSITION3 pos ;
pos . x = x ;
pos . y = y ;
pos . z = z ;
2018-10-25 12:44:51 +11:00
m_queuedZoneing = std : : make_shared < QueuedZoning > ( getZoneId ( ) , pos , Util : : getTimeMs ( ) , o ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : learnAction ( uint16_t actionId )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
uint16_t index ;
uint8_t value ;
Util : : valueToFlagByteIndexValue ( actionId , value , index ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
m_unlocks [ index ] | = value ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
queuePacket ( makeActorControl143 ( getId ( ) , ToggleActionUnlock , actionId , 1 ) ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : learnSong ( uint8_t songId , uint32_t itemId )
2017-10-09 20:09:49 +02:00
{
2018-08-29 21:40:59 +02:00
uint16_t index ;
uint8_t value ;
Util : : valueToFlagByteIndexValue ( songId , value , index ) ;
2017-10-09 20:09:49 +02:00
2018-08-29 21:40:59 +02:00
m_orchestrion [ index ] | = value ;
2017-10-09 20:09:49 +02:00
2018-08-29 21:40:59 +02:00
queuePacket ( makeActorControl143 ( getId ( ) , ToggleOrchestrionUnlock , songId , 1 , itemId ) ) ;
2017-10-09 20:09:49 +02:00
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : isActionLearned ( uint8_t actionId ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
uint16_t index ;
uint8_t value ;
Util : : valueToFlagByteIndexValue ( actionId , value , index ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
return ( m_unlocks [ index ] & value ) ! = 0 ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : gainExp ( uint32_t amount )
2017-08-08 13:53:47 +02:00
{
2018-12-25 01:57:50 +01:00
auto pExdData = m_pFw - > get < Data : : ExdDataGenerated > ( ) ;
2018-03-09 00:06:44 +01:00
2018-08-29 21:40:59 +02:00
uint32_t currentExp = getExp ( ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
uint16_t level = getLevel ( ) ;
2017-08-08 13:53:47 +02:00
2018-11-29 16:55:48 +01:00
uint32_t neededExpToLevel = pExdData - > get < Sapphire : : Data : : ParamGrow > ( level ) - > expToNext ;
2017-08-08 13:53:47 +02:00
2018-11-29 16:55:48 +01:00
uint32_t neededExpToLevelplus1 = pExdData - > get < Sapphire : : Data : : ParamGrow > ( level + 1 ) - > expToNext ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
queuePacket ( makeActorControl143 ( getId ( ) , GainExpMsg , static_cast < uint8_t > ( getClass ( ) ) , amount ) ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
if ( level > = 70 ) // temporary fix for leveling over levelcap
{
queuePacket ( makeActorControl143 ( getId ( ) , UpdateUiExp , static_cast < uint8_t > ( getClass ( ) ) , amount ) ) ;
return ;
}
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
if ( ( currentExp + amount ) > = neededExpToLevel )
{
// levelup
amount = ( currentExp + amount - neededExpToLevel ) > neededExpToLevelplus1 ?
neededExpToLevelplus1 - 1 :
( currentExp + amount - neededExpToLevel ) ;
setExp ( amount ) ;
gainLevel ( ) ;
queuePacket ( makeActorControl143 ( getId ( ) , UpdateUiExp , static_cast < uint8_t > ( getClass ( ) ) , amount ) ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
}
else
{
queuePacket (
makeActorControl143 ( getId ( ) , UpdateUiExp , static_cast < uint8_t > ( getClass ( ) ) , currentExp + amount ) ) ;
setExp ( currentExp + amount ) ;
}
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
sendStatusUpdate ( ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : gainLevel ( )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
setLevel ( getLevel ( ) + 1 ) ;
calculateStats ( ) ;
sendStats ( ) ;
sendStatusUpdate ( ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
m_hp = getMaxHp ( ) ;
m_mp = getMaxMp ( ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
auto effectListPacket = makeZonePacket < FFXIVIpcStatusEffectList > ( getId ( ) ) ;
effectListPacket - > data ( ) . classId = static_cast < uint8_t > ( getClass ( ) ) ;
effectListPacket - > data ( ) . level1 = getLevel ( ) ;
effectListPacket - > data ( ) . level = getLevel ( ) ;
effectListPacket - > data ( ) . current_hp = getMaxHp ( ) ;
effectListPacket - > data ( ) . current_mp = getMaxMp ( ) ;
effectListPacket - > data ( ) . currentTp = 1000 ;
effectListPacket - > data ( ) . max_hp = getMaxHp ( ) ;
effectListPacket - > data ( ) . max_mp = getMaxMp ( ) ;
sendToInRangeSet ( effectListPacket , true ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
sendToInRangeSet ( makeActorControl142 ( getId ( ) , LevelUpEffect , static_cast < uint8_t > ( getClass ( ) ) ,
getLevel ( ) , getLevel ( ) - 1 ) , true ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
auto classInfoPacket = makeZonePacket < FFXIVIpcUpdateClassInfo > ( getId ( ) ) ;
classInfoPacket - > data ( ) . classId = static_cast < uint8_t > ( getClass ( ) ) ;
classInfoPacket - > data ( ) . level1 = getLevel ( ) ;
classInfoPacket - > data ( ) . level = getLevel ( ) ;
classInfoPacket - > data ( ) . nextLevelIndex = getLevel ( ) ;
classInfoPacket - > data ( ) . currentExp = getExp ( ) ;
queuePacket ( classInfoPacket ) ;
2017-08-08 13:53:47 +02:00
}
2019-01-26 13:40:02 +11:00
void Sapphire : : Entity : : Player : : sendStatusUpdate ( )
2017-08-08 13:53:47 +02:00
{
2018-10-25 12:44:51 +11:00
sendToInRangeSet ( std : : make_shared < UpdateHpMpTpPacket > ( * this ) , true ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getLevel ( ) const
2017-08-08 13:53:47 +02:00
{
2018-12-25 01:57:50 +01:00
auto pExdData = m_pFw - > get < Data : : ExdDataGenerated > ( ) ;
2018-11-29 16:55:48 +01:00
uint8_t classJobIndex = pExdData - > get < Sapphire : : Data : : ClassJob > ( static_cast < uint8_t > ( getClass ( ) ) ) - > expArrayIndex ;
2018-08-29 21:40:59 +02:00
return static_cast < uint8_t > ( m_classArray [ classJobIndex ] ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getLevelForClass ( Common : : ClassJob pClass ) const
2017-08-09 14:38:46 +02:00
{
2018-12-25 01:57:50 +01:00
auto pExdData = m_pFw - > get < Data : : ExdDataGenerated > ( ) ;
2018-11-29 16:55:48 +01:00
uint8_t classJobIndex = pExdData - > get < Sapphire : : Data : : ClassJob > ( static_cast < uint8_t > ( pClass ) ) - > expArrayIndex ;
2018-08-29 21:40:59 +02:00
return static_cast < uint8_t > ( m_classArray [ classJobIndex ] ) ;
2017-08-09 14:38:46 +02:00
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : isClassJobUnlocked ( Common : : ClassJob classJob ) const
2018-08-26 16:19:05 +10:00
{
2018-08-29 21:40:59 +02:00
// todo: need to properly check if a job is unlocked, at the moment we just check the class array which will return true for every job if the base class is unlocked
return getLevelForClass ( classJob ) ! = 0 ;
2018-08-26 16:19:05 +10:00
}
2018-11-29 16:55:48 +01:00
uint32_t Sapphire : : Entity : : Player : : getExp ( ) const
2017-08-08 13:53:47 +02:00
{
2018-12-25 01:57:50 +01:00
auto pExdData = m_pFw - > get < Data : : ExdDataGenerated > ( ) ;
2018-11-29 16:55:48 +01:00
uint8_t classJobIndex = pExdData - > get < Sapphire : : Data : : ClassJob > ( static_cast < uint8_t > ( getClass ( ) ) ) - > expArrayIndex ;
2018-08-29 21:40:59 +02:00
return m_expArray [ classJobIndex ] ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setExp ( uint32_t amount )
2018-08-29 21:40:59 +02:00
{
2018-12-25 01:57:50 +01:00
auto pExdData = m_pFw - > get < Data : : ExdDataGenerated > ( ) ;
2018-11-29 16:55:48 +01:00
uint8_t classJobIndex = pExdData - > get < Sapphire : : Data : : ClassJob > ( static_cast < uint8_t > ( getClass ( ) ) ) - > expArrayIndex ;
2018-08-29 21:40:59 +02:00
m_expArray [ classJobIndex ] = amount ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : isInCombat ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_bInCombat ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setInCombat ( bool mode )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
//m_lastAttack = GetTickCount();
m_bInCombat = mode ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setClassJob ( Common : : ClassJob classJob )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
m_class = classJob ;
uint8_t level = getLevel ( ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
if ( getHp ( ) > getMaxHp ( ) )
m_hp = getMaxHp ( ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
if ( getMp ( ) > getMaxMp ( ) )
m_mp = getMaxMp ( ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
m_tp = 0 ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
auto classInfoPacket = makeZonePacket < FFXIVIpcPlayerClassInfo > ( getId ( ) ) ;
classInfoPacket - > data ( ) . classId = static_cast < uint8_t > ( getClass ( ) ) ;
2018-10-20 15:39:20 +03:00
classInfoPacket - > data ( ) . classLevel = getLevel ( ) ;
classInfoPacket - > data ( ) . syncedLevel = getLevel ( ) ;
2018-08-29 21:40:59 +02:00
queuePacket ( classInfoPacket ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
sendToInRangeSet ( makeActorControl142 ( getId ( ) , ClassJobChange , 0x04 ) , true ) ;
2017-08-08 13:53:47 +02:00
2019-01-26 13:40:02 +11:00
sendStatusUpdate ( ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setLevel ( uint8_t level )
2017-08-08 13:53:47 +02:00
{
2018-12-25 01:57:50 +01:00
auto pExdData = m_pFw - > get < Data : : ExdDataGenerated > ( ) ;
2018-11-29 16:55:48 +01:00
uint8_t classJobIndex = pExdData - > get < Sapphire : : Data : : ClassJob > ( static_cast < uint8_t > ( getClass ( ) ) ) - > expArrayIndex ;
2018-08-29 21:40:59 +02:00
m_classArray [ classJobIndex ] = level ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setLevelForClass ( uint8_t level , Common : : ClassJob classjob )
2017-08-09 14:38:46 +02:00
{
2018-12-25 01:57:50 +01:00
auto pExdData = m_pFw - > get < Data : : ExdDataGenerated > ( ) ;
2018-11-29 16:55:48 +01:00
uint8_t classJobIndex = pExdData - > get < Sapphire : : Data : : ClassJob > ( static_cast < uint8_t > ( classjob ) ) - > expArrayIndex ;
2017-12-16 23:00:04 +11:00
2018-08-29 21:40:59 +02:00
if ( m_classArray [ classJobIndex ] = = 0 )
insertDbClass ( classJobIndex ) ;
2017-12-16 23:00:04 +11:00
2018-08-29 21:40:59 +02:00
m_classArray [ classJobIndex ] = level ;
2017-08-09 14:38:46 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : sendModel ( )
2017-08-08 13:53:47 +02:00
{
2018-10-25 12:44:51 +11:00
sendToInRangeSet ( std : : make_shared < ModelEquipPacket > ( * getAsPlayer ( ) ) , true ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint32_t Sapphire : : Entity : : Player : : getModelForSlot ( Common : : GearModelSlot slot )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_modelEquip [ slot ] ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint64_t Sapphire : : Entity : : Player : : getModelMainWeapon ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_modelMainWeapon ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint64_t Sapphire : : Entity : : Player : : getModelSubWeapon ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_modelSubWeapon ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint64_t Sapphire : : Entity : : Player : : getModelSystemWeapon ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_modelSystemWeapon ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
int8_t Sapphire : : Entity : : Player : : getAetheryteMaskAt ( uint8_t index ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
if ( index > sizeof ( m_aetheryte ) )
return 0 ;
return m_aetheryte [ index ] ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getBirthDay ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_birthDay ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getBirthMonth ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_birthMonth ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getGuardianDeity ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_guardianDeity ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getLookAt ( uint8_t index ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_customize [ index ] ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setLookAt ( uint8_t index , uint8_t value )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
m_customize [ index ] = value ;
2017-08-08 13:53:47 +02:00
}
// spawn this player for pTarget
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : spawn ( Entity : : PlayerPtr pTarget )
2017-08-08 13:53:47 +02:00
{
2019-01-04 12:34:19 +01:00
Logger : : debug ( " [{0}] Spawning {1} for {2} " , pTarget - > getId ( ) , getName ( ) , pTarget - > getName ( ) ) ;
2017-08-08 13:53:47 +02:00
2018-10-25 12:44:51 +11:00
pTarget - > queuePacket ( std : : make_shared < PlayerSpawnPacket > ( * getAsPlayer ( ) , * pTarget ) ) ;
2017-08-08 13:53:47 +02:00
}
// despawn
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : despawn ( Entity : : PlayerPtr pTarget )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
auto pPlayer = pTarget ;
2019-01-04 12:34:19 +01:00
Logger : : debug ( " Despawning {0} for {1} " , getName ( ) , pTarget - > getName ( ) ) ;
2018-02-21 18:06:52 +01:00
2018-08-29 21:40:59 +02:00
pPlayer - > freePlayerSpawnId ( getId ( ) ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
pPlayer - > queuePacket ( makeActorControl143 ( getId ( ) , DespawnZoneScreenMsg , 0x04 , getId ( ) , 0x01 ) ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
Sapphire : : Entity : : ActorPtr Sapphire : : Entity : : Player : : lookupTargetById ( uint64_t targetId )
2017-08-10 22:06:05 +02:00
{
2018-08-29 21:40:59 +02:00
ActorPtr targetActor ;
auto inRange = getInRangeActors ( true ) ;
for ( auto actor : inRange )
{
if ( actor - > getId ( ) = = targetId )
targetActor = actor ;
}
return targetActor ;
2017-08-10 22:06:05 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setLastPing ( uint32_t ping )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
m_lastPing = ping ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint32_t Sapphire : : Entity : : Player : : getLastPing ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_lastPing ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setVoiceId ( uint8_t voiceId )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
m_voice = voiceId ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setGc ( uint8_t gc )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
m_gc = gc ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
auto gcAffPacket = makeZonePacket < FFXIVGCAffiliation > ( getId ( ) ) ;
gcAffPacket - > data ( ) . gcId = m_gc ;
gcAffPacket - > data ( ) . gcRank [ 0 ] = m_gcRank [ 0 ] ;
gcAffPacket - > data ( ) . gcRank [ 1 ] = m_gcRank [ 1 ] ;
gcAffPacket - > data ( ) . gcRank [ 2 ] = m_gcRank [ 2 ] ;
queuePacket ( gcAffPacket ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setGcRankAt ( uint8_t index , uint8_t rank )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
m_gcRank [ index ] = rank ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
auto gcAffPacket = makeZonePacket < FFXIVGCAffiliation > ( getId ( ) ) ;
gcAffPacket - > data ( ) . gcId = m_gc ;
gcAffPacket - > data ( ) . gcRank [ 0 ] = m_gcRank [ 0 ] ;
gcAffPacket - > data ( ) . gcRank [ 1 ] = m_gcRank [ 1 ] ;
gcAffPacket - > data ( ) . gcRank [ 2 ] = m_gcRank [ 2 ] ;
queuePacket ( gcAffPacket ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
const uint8_t * Sapphire : : Entity : : Player : : getStateFlags ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_stateFlags ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : actionHasCastTime ( uint32_t actionId ) //TODO: Add logic for special cases
2017-08-10 22:06:05 +02:00
{
2018-12-25 01:57:50 +01:00
auto pExdData = m_pFw - > get < Data : : ExdDataGenerated > ( ) ;
2018-11-29 16:55:48 +01:00
auto actionInfoPtr = pExdData - > get < Sapphire : : Data : : Action > ( actionId ) ;
2018-08-29 21:40:59 +02:00
if ( actionInfoPtr - > preservesCombo )
return false ;
2017-08-15 16:19:55 +02:00
2018-08-29 21:40:59 +02:00
return actionInfoPtr - > cast100ms ! = 0 ;
2017-08-15 16:19:55 +02:00
2017-08-10 22:06:05 +02:00
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : hasStateFlag ( Common : : PlayerStateFlag flag ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
int32_t iFlag = static_cast < uint32_t > ( flag ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
uint16_t index ;
uint8_t value ;
Util : : valueToFlagByteIndexValue ( iFlag , value , index ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
return ( m_stateFlags [ index ] & value ) ! = 0 ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setStateFlag ( Common : : PlayerStateFlag flag )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
auto prevOnlineStatus = getOnlineStatus ( ) ;
int32_t iFlag = static_cast < uint32_t > ( flag ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
uint16_t index ;
uint8_t value ;
Util : : valueToFlagByteIndexValue ( iFlag , value , index ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
m_stateFlags [ index ] | = value ;
sendStateFlags ( ) ;
2018-01-11 14:59:39 +01:00
2018-08-29 21:40:59 +02:00
auto newOnlineStatus = getOnlineStatus ( ) ;
2018-01-11 14:59:39 +01:00
2018-08-29 21:40:59 +02:00
if ( prevOnlineStatus ! = newOnlineStatus )
sendToInRangeSet ( makeActorControl142 ( getId ( ) , SetStatusIcon ,
static_cast < uint8_t > ( getOnlineStatus ( ) ) ) , true ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setStateFlags ( std : : vector < Common : : PlayerStateFlag > flags )
2017-08-13 18:28:05 +02:00
{
2018-08-29 21:40:59 +02:00
for ( const auto & flag : flags )
{
setStateFlag ( flag ) ;
}
2017-08-13 18:28:05 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : sendStateFlags ( )
2017-08-08 13:53:47 +02:00
{
2018-10-25 12:44:51 +11:00
queuePacket ( std : : make_shared < PlayerStateFlagsPacket > ( * getAsPlayer ( ) ) ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : unsetStateFlag ( Common : : PlayerStateFlag flag )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
if ( ! hasStateFlag ( flag ) )
return ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
auto prevOnlineStatus = getOnlineStatus ( ) ;
2018-01-11 14:59:39 +01:00
2018-08-29 21:40:59 +02:00
int32_t iFlag = static_cast < uint32_t > ( flag ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
uint16_t index ;
uint8_t value ;
Util : : valueToFlagByteIndexValue ( iFlag , value , index ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
m_stateFlags [ index ] ^ = value ;
sendStateFlags ( ) ;
2018-01-11 14:59:39 +01:00
2018-08-29 21:40:59 +02:00
auto newOnlineStatus = getOnlineStatus ( ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
if ( prevOnlineStatus ! = newOnlineStatus )
sendToInRangeSet ( makeActorControl142 ( getId ( ) , SetStatusIcon , static_cast < uint8_t > ( getOnlineStatus ( ) ) ) ,
true ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : update ( int64_t currTime )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
// a zoning is pending, lets do it
if ( m_queuedZoneing & & ( currTime - m_queuedZoneing - > m_queueTime ) > 800 )
{
Common : : FFXIVARR_POSITION3 targetPos = m_queuedZoneing - > m_targetPosition ;
2018-11-05 23:07:39 +01:00
if ( getCurrentZone ( ) - > getTerritoryTypeId ( ) ! = m_queuedZoneing - > m_targetZone )
2018-08-29 21:40:59 +02:00
{
performZoning ( m_queuedZoneing - > m_targetZone , targetPos , m_queuedZoneing - > m_targetRotation ) ;
}
else
{
auto setActorPosPacket = makeZonePacket < FFXIVIpcActorSetPos > ( getId ( ) ) ;
2018-12-02 02:01:41 +01:00
setActorPosPacket - > data ( ) . r16 = Util : : floatToUInt16Rot ( m_queuedZoneing - > m_targetRotation ) ;
2018-08-29 21:40:59 +02:00
setActorPosPacket - > data ( ) . waitForLoad = 0x04 ;
setActorPosPacket - > data ( ) . x = targetPos . x ;
setActorPosPacket - > data ( ) . y = targetPos . y ;
setActorPosPacket - > data ( ) . z = targetPos . z ;
sendToInRangeSet ( setActorPosPacket , true ) ;
setPos ( targetPos ) ;
}
m_queuedZoneing . reset ( ) ;
return ;
}
if ( m_hp < = 0 & & m_status ! = ActorStatus : : Dead )
die ( ) ;
if ( ! isAlive ( ) )
return ;
updateStatusEffects ( ) ;
m_lastUpdate = currTime ;
if ( ! checkAction ( ) )
{
if ( m_targetId & & m_currentStance = = Common : : Stance : : Active & & isAutoattackOn ( ) )
{
auto mainWeap = getItemAt ( Common : : GearSet0 , Common : : GearSetSlot : : MainHand ) ;
// @TODO i dislike this, iterating over all in range actors when you already know the id of the actor you need...
for ( auto actor : m_inRangeActor )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
if ( actor - > getId ( ) = = m_targetId & & actor - > getAsChara ( ) - > isAlive ( ) & & mainWeap )
{
// default autoattack range
// TODO make this dependant on bnpc size
uint32_t range = 7 ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
// default autoattack range for ranged classes
if ( getClass ( ) = = ClassJob : : Machinist | |
getClass ( ) = = ClassJob : : Bard | |
getClass ( ) = = ClassJob : : Archer )
range = 25 ;
2017-08-08 13:53:47 +02:00
2018-12-02 02:01:41 +01:00
if ( Util : : distance ( getPos ( ) . x , getPos ( ) . y , getPos ( ) . z ,
actor - > getPos ( ) . x , actor - > getPos ( ) . y , actor - > getPos ( ) . z ) < = range )
2018-08-29 21:40:59 +02:00
{
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
if ( ( currTime - m_lastAttack ) > mainWeap - > getDelay ( ) )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
m_lastAttack = currTime ;
autoAttack ( actor - > getAsChara ( ) ) ;
2017-08-08 13:53:47 +02:00
}
2018-08-29 21:40:59 +02:00
}
}
2017-08-08 13:53:47 +02:00
}
2018-08-29 21:40:59 +02:00
}
}
2017-08-08 13:53:47 +02:00
2019-01-28 19:16:44 +11:00
Chara : : update ( currTime ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : onMobKill ( uint16_t nameId )
2017-08-08 13:53:47 +02:00
{
2018-12-25 01:57:50 +01:00
auto pScriptMgr = m_pFw - > get < Scripting : : ScriptMgr > ( ) ;
2019-02-02 23:32:36 +11:00
pScriptMgr - > onBNpcKill ( * getAsPlayer ( ) , nameId ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : freePlayerSpawnId ( uint32_t actorId )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
auto spawnId = m_actorSpawnIndexAllocator . freeUsedSpawnIndex ( actorId ) ;
2017-08-08 13:53:47 +02:00
2019-01-28 20:29:30 +11:00
// actor was never spawned for this player
if ( spawnId = = m_actorSpawnIndexAllocator . getAllocFailId ( ) )
return ;
2018-08-29 21:40:59 +02:00
auto freeActorSpawnPacket = makeZonePacket < FFXIVIpcActorFreeSpawn > ( getId ( ) ) ;
freeActorSpawnPacket - > data ( ) . actorId = actorId ;
freeActorSpawnPacket - > data ( ) . spawnId = spawnId ;
queuePacket ( freeActorSpawnPacket ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint8_t * Sapphire : : Entity : : Player : : getAetheryteArray ( )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_aetheryte ;
2017-08-08 13:53:47 +02:00
}
/*! set homepoint */
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setHomepoint ( uint8_t aetheryteId )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
m_homePoint = aetheryteId ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
queuePacket ( makeActorControl143 ( getId ( ) , SetHomepoint , aetheryteId ) ) ;
2017-08-08 13:53:47 +02:00
}
/*! get homepoint */
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getHomepoint ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_homePoint ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint16_t * Sapphire : : Entity : : Player : : getClassArray ( )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_classArray ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
const uint16_t * Sapphire : : Entity : : Player : : getClassArray ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_classArray ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint32_t * Sapphire : : Entity : : Player : : getExpArray ( )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_expArray ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
const uint32_t * Sapphire : : Entity : : Player : : getExpArray ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_expArray ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint8_t * Sapphire : : Entity : : Player : : getHowToArray ( )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_howTo ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
const uint8_t * Sapphire : : Entity : : Player : : getHowToArray ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_howTo ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
const uint8_t * Sapphire : : Entity : : Player : : getUnlockBitmask ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_unlocks ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
const uint8_t * Sapphire : : Entity : : Player : : getOrchestrionBitmask ( ) const
2017-10-09 20:09:49 +02:00
{
2018-08-29 21:40:59 +02:00
return m_orchestrion ;
2017-10-09 20:09:49 +02:00
}
2018-11-29 16:55:48 +01:00
const uint8_t * Sapphire : : Entity : : Player : : getMountGuideBitmask ( ) const
2017-12-03 17:24:11 +01:00
{
2018-08-29 21:40:59 +02:00
return m_mountGuide ;
2017-12-03 17:24:11 +01:00
}
2018-11-29 16:55:48 +01:00
uint64_t Sapphire : : Entity : : Player : : getContentId ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_contentId ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getVoiceId ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_voice ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getGc ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_gc ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
const uint8_t * Sapphire : : Entity : : Player : : getGcRankArray ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_gcRank ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : queuePacket ( Network : : Packets : : FFXIVPacketBasePtr pPacket )
2017-08-08 13:53:47 +02:00
{
2018-12-25 01:57:50 +01:00
auto pServerZone = m_pFw - > get < World : : ServerMgr > ( ) ;
2018-08-29 21:40:59 +02:00
auto pSession = pServerZone - > getSession ( m_id ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
if ( ! pSession )
return ;
2017-11-28 00:09:36 +01:00
2018-08-29 21:40:59 +02:00
auto pZoneCon = pSession - > getZoneConnection ( ) ;
2017-11-28 00:09:36 +01:00
2018-08-29 21:40:59 +02:00
if ( pZoneCon )
pZoneCon - > queueOutPacket ( pPacket ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : queueChatPacket ( Network : : Packets : : FFXIVPacketBasePtr pPacket )
2017-08-22 23:53:20 +02:00
{
2018-12-25 01:57:50 +01:00
auto pServerZone = m_pFw - > get < World : : ServerMgr > ( ) ;
2018-08-29 21:40:59 +02:00
auto pSession = pServerZone - > getSession ( m_id ) ;
2017-08-22 23:53:20 +02:00
2018-08-29 21:40:59 +02:00
if ( ! pSession )
return ;
2017-08-22 23:53:20 +02:00
2018-08-29 21:40:59 +02:00
auto pChatCon = pSession - > getChatConnection ( ) ;
2017-11-28 00:09:36 +01:00
2018-08-29 21:40:59 +02:00
if ( pChatCon )
pChatCon - > queueOutPacket ( pPacket ) ;
2017-08-22 23:53:20 +02:00
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : isLoadingComplete ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_bLoadingComplete ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setLoadingComplete ( bool bComplete )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
m_bLoadingComplete = bComplete ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : performZoning ( uint16_t zoneId , const Common : : FFXIVARR_POSITION3 & pos , float rotation )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
m_pos = pos ;
2018-12-02 15:32:22 +11:00
m_territoryTypeId = zoneId ;
2018-08-29 21:40:59 +02:00
m_bMarkedForZoning = true ;
setRot ( rotation ) ;
setZone ( zoneId ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : isMarkedForZoning ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_bMarkedForZoning ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
ZoneingType Sapphire : : Entity : : Player : : getZoningType ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_zoningType ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setZoningType ( Common : : ZoneingType zoneingType )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
m_zoningType = zoneingType ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setSearchInfo ( uint8_t selectRegion , uint8_t selectClass , const char * searchMessage )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
m_searchSelectRegion = selectRegion ;
m_searchSelectClass = selectClass ;
memset ( & m_searchMessage [ 0 ] , 0 , sizeof ( searchMessage ) ) ;
strcpy ( & m_searchMessage [ 0 ] , searchMessage ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
const char * Sapphire : : Entity : : Player : : getSearchMessage ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return & m_searchMessage [ 0 ] ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getSearchSelectRegion ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_searchSelectRegion ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getSearchSelectClass ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_searchSelectClass ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : sendNotice ( const std : : string & message ) //Purple Text
2017-08-08 13:53:47 +02:00
{
2018-10-25 12:44:51 +11:00
queuePacket ( std : : make_shared < ServerNoticePacket > ( getId ( ) , message ) ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : sendUrgent ( const std : : string & message ) //Red Text
2017-08-08 13:53:47 +02:00
{
2018-10-25 12:44:51 +11:00
queuePacket ( std : : make_shared < ChatPacket > ( * getAsPlayer ( ) , ChatType : : ServerUrgent , message ) ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : sendDebug ( const std : : string & message ) //Grey Text
2017-08-08 13:53:47 +02:00
{
2018-10-25 12:44:51 +11:00
queuePacket ( std : : make_shared < ChatPacket > ( * getAsPlayer ( ) , ChatType : : ServerDebug , message ) ) ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : sendLogMessage ( uint32_t messageId , uint32_t param2 , uint32_t param3 ,
2018-11-28 21:59:28 +11:00
uint32_t param4 , uint32_t param5 , uint32_t param6 )
{
queuePacket ( makeActorControl144 ( getId ( ) , ActorControlType : : LogMsg , messageId , param2 , param3 , param4 , param5 , param6 ) ) ;
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : updateHowtosSeen ( uint32_t howToId )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
uint8_t index = howToId / 8 ;
uint8_t bitIndex = howToId % 8 ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
uint8_t value = 1 < < bitIndex ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
m_howTo [ index ] | = value ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : initHateSlotQueue ( )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
m_freeHateSlotQueue = std : : queue < uint8_t > ( ) ;
for ( int32_t i = 1 ; i < 26 ; i + + )
m_freeHateSlotQueue . push ( i ) ;
2017-08-08 13:53:47 +02:00
}
2019-01-19 22:56:07 +01:00
void Sapphire : : Entity : : Player : : hateListAdd ( BNpcPtr pBNpc )
{
if ( ! m_freeHateSlotQueue . empty ( ) )
{
uint8_t hateId = m_freeHateSlotQueue . front ( ) ;
m_freeHateSlotQueue . pop ( ) ;
m_actorIdTohateSlotMap [ pBNpc - > getId ( ) ] = hateId ;
sendHateList ( ) ;
}
}
void Sapphire : : Entity : : Player : : hateListRemove ( BNpcPtr pBNpc )
{
auto it = m_actorIdTohateSlotMap . begin ( ) ;
for ( ; it ! = m_actorIdTohateSlotMap . end ( ) ; + + it )
{
if ( it - > first = = pBNpc - > getId ( ) )
{
uint8_t hateSlot = it - > second ;
m_freeHateSlotQueue . push ( hateSlot ) ;
m_actorIdTohateSlotMap . erase ( it ) ;
sendHateList ( ) ;
return ;
}
}
}
bool Sapphire : : Entity : : Player : : hateListHasEntry ( BNpcPtr pBNpc )
{
for ( const auto & entry : m_actorIdTohateSlotMap )
{
if ( entry . first = = pBNpc - > getId ( ) )
return true ;
}
return false ;
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : sendHateList ( )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
auto hateListPacket = makeZonePacket < FFXIVIpcHateList > ( getId ( ) ) ;
hateListPacket - > data ( ) . numEntries = m_actorIdTohateSlotMap . size ( ) ;
auto it = m_actorIdTohateSlotMap . begin ( ) ;
for ( int32_t i = 0 ; it ! = m_actorIdTohateSlotMap . end ( ) ; + + it , i + + )
{
hateListPacket - > data ( ) . entry [ i ] . actorId = it - > first ;
hateListPacket - > data ( ) . entry [ i ] . hatePercent = 100 ;
}
queuePacket ( hateListPacket ) ;
2017-08-08 13:53:47 +02:00
}
2019-01-19 22:56:07 +01:00
void Sapphire : : Entity : : Player : : onMobAggro ( BNpcPtr pBNpc )
{
hateListAdd ( pBNpc ) ;
queuePacket ( makeActorControl142 ( getId ( ) , ToggleAggro , 1 ) ) ;
}
void Sapphire : : Entity : : Player : : onMobDeaggro ( BNpcPtr pBNpc )
{
hateListRemove ( pBNpc ) ;
if ( m_actorIdTohateSlotMap . empty ( ) )
queuePacket ( makeActorControl142 ( getId ( ) , ToggleAggro ) ) ;
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : isLogin ( ) const
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
return m_bIsLogin ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setIsLogin ( bool bIsLogin )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
m_bIsLogin = bIsLogin ;
2017-08-08 13:53:47 +02:00
}
2018-11-29 16:55:48 +01:00
uint8_t * Sapphire : : Entity : : Player : : getTitleList ( )
2017-10-09 00:31:31 -03:00
{
2018-08-29 21:40:59 +02:00
return m_titleList ;
2017-10-09 00:31:31 -03:00
}
2018-11-29 16:55:48 +01:00
const uint8_t * Sapphire : : Entity : : Player : : getTitleList ( ) const
2018-02-17 01:20:40 +01:00
{
2018-08-29 21:40:59 +02:00
return m_titleList ;
2018-02-17 01:20:40 +01:00
}
2018-11-29 16:55:48 +01:00
uint16_t Sapphire : : Entity : : Player : : getTitle ( ) const
2017-10-09 02:06:31 -03:00
{
2018-08-29 21:40:59 +02:00
return m_activeTitle ;
2017-10-09 02:06:31 -03:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : addTitle ( uint16_t titleId )
2017-10-09 00:31:31 -03:00
{
2018-08-29 21:40:59 +02:00
uint16_t index ;
uint8_t value ;
Util : : valueToFlagByteIndexValue ( titleId , value , index ) ;
2017-10-09 00:31:31 -03:00
2018-08-29 21:40:59 +02:00
m_titleList [ index ] | = value ;
2017-10-09 00:31:31 -03:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setTitle ( uint16_t titleId )
2017-10-04 23:19:38 -03:00
{
2018-08-29 21:40:59 +02:00
uint16_t index ;
uint8_t value ;
Util : : valueToFlagByteIndexValue ( titleId , value , index ) ;
2017-10-09 01:56:47 -03:00
2018-08-29 21:40:59 +02:00
if ( ( m_titleList [ index ] & value ) = = 0 ) // Player doesn't have title - bail
return ;
2017-10-09 01:56:47 -03:00
2018-08-29 21:40:59 +02:00
m_activeTitle = titleId ;
2017-10-09 01:56:47 -03:00
2018-08-29 21:40:59 +02:00
sendToInRangeSet ( makeActorControl142 ( getId ( ) , SetTitle , titleId ) , true ) ;
2017-10-04 23:19:38 -03:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setEquipDisplayFlags ( uint8_t state )
2017-10-05 20:24:58 +02:00
{
2018-08-29 21:40:59 +02:00
m_equipDisplayFlags = state ;
auto paramPacket = makeZonePacket < FFXIVIpcEquipDisplayFlags > ( getId ( ) ) ;
paramPacket - > data ( ) . bitmask = m_equipDisplayFlags ;
sendToInRangeSet ( paramPacket , true ) ;
2017-10-05 20:24:58 +02:00
}
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getEquipDisplayFlags ( ) const
2017-10-05 20:24:58 +02:00
{
2018-08-29 21:40:59 +02:00
return m_equipDisplayFlags ;
2017-10-05 20:24:58 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : mount ( uint32_t id )
2017-10-17 21:31:00 +02:00
{
2018-08-29 21:40:59 +02:00
m_mount = id ;
sendToInRangeSet ( makeActorControl142 ( getId ( ) , ActorControlType : : SetStatus ,
static_cast < uint8_t > ( Common : : ActorStatus : : Mounted ) ) , true ) ;
sendToInRangeSet ( makeActorControl143 ( getId ( ) , 0x39e , 12 ) , true ) ; //?
2017-10-18 17:54:17 +02:00
2018-08-29 21:40:59 +02:00
auto mountPacket = makeZonePacket < FFXIVIpcMount > ( getId ( ) ) ;
mountPacket - > data ( ) . id = id ;
sendToInRangeSet ( mountPacket , true ) ;
2017-10-18 17:54:17 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : dismount ( )
2017-10-18 17:54:17 +02:00
{
2018-08-29 21:40:59 +02:00
sendToInRangeSet ( makeActorControl142 ( getId ( ) , ActorControlType : : SetStatus ,
static_cast < uint8_t > ( Common : : ActorStatus : : Idle ) ) , true ) ;
sendToInRangeSet ( makeActorControl143 ( getId ( ) , ActorControlType : : Dismount , 1 ) , true ) ;
m_mount = 0 ;
2017-10-18 17:54:17 +02:00
}
2019-02-02 23:06:57 +11:00
void Sapphire : : Entity : : Player : : spawnCompanion ( uint16_t id )
{
auto exdData = m_pFw - > get < Data : : ExdDataGenerated > ( ) ;
assert ( exdData ) ;
auto companion = exdData - > get < Data : : Companion > ( id ) ;
if ( ! id )
return ;
m_companionId = id ;
sendToInRangeSet ( makeActorControl142 ( getId ( ) , ActorControlType : : ToggleCompanion , id ) , true ) ;
}
uint16_t Sapphire : : Entity : : Player : : getCurrentCompanion ( ) const
{
return m_companionId ;
}
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getCurrentMount ( ) const
2017-10-18 17:54:17 +02:00
{
2018-08-29 21:40:59 +02:00
return m_mount ;
2017-10-17 21:31:00 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setPersistentEmote ( uint32_t emoteId )
2018-07-09 01:19:42 -03:00
{
2018-08-29 21:40:59 +02:00
m_emoteMode = emoteId ;
2018-07-09 01:19:42 -03:00
}
2018-11-29 16:55:48 +01:00
uint32_t Sapphire : : Entity : : Player : : getPersistentEmote ( ) const
2018-07-09 01:19:42 -03:00
{
2018-08-29 21:40:59 +02:00
return m_emoteMode ;
2018-07-09 01:19:42 -03:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : autoAttack ( CharaPtr pTarget )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
auto mainWeap = getItemAt ( Common : : GearSet0 , Common : : GearSetSlot : : MainHand ) ;
2017-08-11 00:58:35 -03:00
2019-01-20 13:36:34 +01:00
pTarget - > onActionHostile ( getAsChara ( ) ) ;
2018-08-29 21:40:59 +02:00
//uint64_t tick = Util::getTimeMs();
//srand(static_cast< uint32_t >(tick));
2017-08-11 00:58:35 -03:00
2018-08-29 21:40:59 +02:00
uint32_t damage = static_cast < uint32_t > ( mainWeap - > getAutoAttackDmg ( ) ) ;
uint32_t variation = 0 + rand ( ) % 3 ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
if ( getClass ( ) = = ClassJob : : Machinist | | getClass ( ) = = ClassJob : : Bard | | getClass ( ) = = ClassJob : : Archer )
{
2018-10-25 12:44:51 +11:00
auto effectPacket = std : : make_shared < Server : : EffectPacket > ( getId ( ) , pTarget - > getId ( ) , 8 ) ;
2018-12-02 02:01:41 +01:00
effectPacket - > setRotation ( Util : : floatToUInt16Rot ( getRot ( ) ) ) ;
2018-07-21 23:32:10 +10:00
2019-01-19 01:15:17 +01:00
Server : : EffectEntry entry { } ;
2018-08-29 21:40:59 +02:00
entry . value = damage ;
entry . effectType = Common : : ActionEffectType : : Damage ;
entry . hitSeverity = Common : : ActionHitSeverityType : : NormalDamage ;
2018-07-21 23:32:10 +10:00
2018-08-29 21:40:59 +02:00
effectPacket - > addEffect ( entry ) ;
2018-07-21 23:32:10 +10:00
2018-08-29 21:40:59 +02:00
sendToInRangeSet ( effectPacket , true ) ;
}
else
{
2018-10-25 12:44:51 +11:00
auto effectPacket = std : : make_shared < Server : : EffectPacket > ( getId ( ) , pTarget - > getId ( ) , 7 ) ;
2018-12-02 02:01:41 +01:00
effectPacket - > setRotation ( Util : : floatToUInt16Rot ( getRot ( ) ) ) ;
2018-07-21 23:32:10 +10:00
2019-01-19 01:15:17 +01:00
Server : : EffectEntry entry { } ;
2018-08-29 21:40:59 +02:00
entry . value = damage ;
entry . effectType = Common : : ActionEffectType : : Damage ;
entry . hitSeverity = Common : : ActionHitSeverityType : : NormalDamage ;
2018-07-21 23:32:10 +10:00
2018-08-29 21:40:59 +02:00
effectPacket - > addEffect ( entry ) ;
2018-07-21 23:32:10 +10:00
2018-08-29 21:40:59 +02:00
sendToInRangeSet ( effectPacket , true ) ;
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
}
2017-08-08 13:53:47 +02:00
2018-08-29 21:40:59 +02:00
pTarget - > takeDamage ( damage ) ;
2017-08-19 11:28:04 +09:00
2017-08-08 13:53:47 +02:00
}
2017-08-14 17:10:19 +02:00
2017-08-19 11:28:04 +09:00
/////////////////////////////
// Content Finder
/////////////////////////////
2018-11-29 16:55:48 +01:00
uint32_t Sapphire : : Entity : : Player : : getCFPenaltyTimestamp ( ) const
2017-08-19 11:28:04 +09:00
{
2018-08-29 21:40:59 +02:00
return m_cfPenaltyUntil ;
2017-08-19 11:28:04 +09:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setCFPenaltyTimestamp ( uint32_t timestamp )
2017-08-19 11:28:04 +09:00
{
2018-08-29 21:40:59 +02:00
m_cfPenaltyUntil = timestamp ;
2017-08-19 11:28:04 +09:00
}
2018-11-29 16:55:48 +01:00
uint32_t Sapphire : : Entity : : Player : : getCFPenaltyMinutes ( ) const
2017-08-19 11:28:04 +09:00
{
2018-11-29 16:55:48 +01:00
auto currentTimestamp = Sapphire : : Util : : getTimeSeconds ( ) ;
2018-08-29 21:40:59 +02:00
auto endTimestamp = getCFPenaltyTimestamp ( ) ;
2017-08-19 11:28:04 +09:00
2018-08-29 21:40:59 +02:00
// check if penalty timestamp already passed current time
if ( currentTimestamp > endTimestamp )
return 0 ;
2017-08-19 11:28:04 +09:00
2018-08-29 21:40:59 +02:00
auto deltaTime = endTimestamp - currentTimestamp ;
2018-10-26 14:11:02 +02:00
return static_cast < uint32_t > ( std : : ceil ( static_cast < float > ( deltaTime ) / 60 ) ) ;
2017-08-19 11:28:04 +09:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setCFPenaltyMinutes ( uint32_t minutes )
2017-08-19 11:28:04 +09:00
{
2018-11-29 16:55:48 +01:00
auto currentTimestamp = Sapphire : : Util : : getTimeSeconds ( ) ;
2019-01-19 21:20:23 -02:00
setCFPenaltyTimestamp ( currentTimestamp + minutes * 60 ) ;
2017-08-19 11:28:04 +09:00
}
2017-08-20 02:24:19 +02:00
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getOpeningSequence ( ) const
2017-08-20 02:24:19 +02:00
{
2018-08-29 21:40:59 +02:00
return m_openingSequence ;
2017-08-20 02:24:19 +02:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setOpeningSequence ( uint8_t seq )
2017-08-20 02:24:19 +02:00
{
2018-08-29 21:40:59 +02:00
m_openingSequence = seq ;
2017-09-22 22:03:57 +09:00
}
2018-11-29 16:55:48 +01:00
uint16_t Sapphire : : Entity : : Player : : getItemLevel ( ) const
2017-11-16 00:03:36 -02:00
{
2018-08-29 21:40:59 +02:00
return m_itemLevel ;
2017-11-16 00:03:36 -02:00
}
2017-09-22 22:03:57 +09:00
/// Tells client to offset their eorzean time by given timestamp.
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setEorzeaTimeOffset ( uint64_t timestamp )
2017-09-22 22:03:57 +09:00
{
2018-08-29 21:40:59 +02:00
// TODO: maybe change to persistent?
auto packet = makeZonePacket < FFXIVIpcEorzeaTimeOffset > ( getId ( ) ) ;
packet - > data ( ) . timestamp = timestamp ;
2017-09-22 22:03:57 +09:00
2018-08-29 21:40:59 +02:00
// Send to single player
queuePacket ( packet ) ;
2017-09-22 22:03:57 +09:00
}
2018-01-28 22:36:43 +01:00
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setTerritoryTypeId ( uint32_t territoryTypeId )
2018-01-28 22:36:43 +01:00
{
2018-12-02 15:32:22 +11:00
m_territoryTypeId = territoryTypeId ;
2018-01-28 22:36:43 +01:00
}
2018-11-29 16:55:48 +01:00
uint32_t Sapphire : : Entity : : Player : : getTerritoryTypeId ( ) const
2018-01-28 22:36:43 +01:00
{
2018-12-02 15:32:22 +11:00
return m_territoryTypeId ;
2018-01-28 22:36:43 +01:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : sendZonePackets ( )
2018-01-28 22:36:43 +01:00
{
2018-11-23 11:46:39 +01:00
if ( isLogin ( ) )
{
//Update player map in servermgr - in case player name has been changed
2018-12-25 01:57:50 +01:00
auto pServerMgr = m_pFw - > get < World : : ServerMgr > ( ) ;
2018-11-23 11:46:39 +01:00
pServerMgr - > updatePlayerName ( getId ( ) , getName ( ) ) ;
}
2018-08-29 21:40:59 +02:00
getCurrentZone ( ) - > onBeforePlayerZoneIn ( * this ) ;
2018-02-23 23:47:21 +01:00
2018-08-29 21:40:59 +02:00
auto initPacket = makeZonePacket < FFXIVIpcInit > ( getId ( ) ) ;
initPacket - > data ( ) . charId = getId ( ) ;
queuePacket ( initPacket ) ;
2018-01-28 22:36:43 +01:00
2018-08-29 21:40:59 +02:00
sendInventory ( ) ;
2018-01-28 22:36:43 +01:00
2018-08-29 21:40:59 +02:00
if ( isLogin ( ) )
{
queuePacket ( makeActorControl143 ( getId ( ) , SetCharaGearParamUI , m_equipDisplayFlags , 1 ) ) ;
}
2018-01-28 22:36:43 +01:00
2018-08-29 21:40:59 +02:00
// set flags, will be reset automatically by zoning ( only on client side though )
//setStateFlag( PlayerStateFlag::BetweenAreas );
//setStateFlag( PlayerStateFlag::BetweenAreas1 );
2018-01-28 22:36:43 +01:00
2018-08-29 21:40:59 +02:00
sendStats ( ) ;
2018-01-28 22:36:43 +01:00
2018-08-29 21:40:59 +02:00
// only initialize the UI if the player in fact just logged in.
if ( isLogin ( ) )
{
auto contentFinderList = makeZonePacket < FFXIVIpcCFAvailableContents > ( getId ( ) ) ;
2018-06-28 00:07:07 +02:00
2018-08-29 21:40:59 +02:00
for ( auto i = 0 ; i < sizeof ( contentFinderList - > data ( ) . contents ) ; i + + )
{
// unlock all contents for now
contentFinderList - > data ( ) . contents [ i ] = 0xFF ;
}
queuePacket ( contentFinderList ) ;
2018-01-28 22:36:43 +01:00
2018-10-25 12:44:51 +11:00
queuePacket ( std : : make_shared < InitUIPacket > ( * this ) ) ;
2018-01-28 22:36:43 +01:00
2018-08-29 21:40:59 +02:00
auto classInfoPacket = makeZonePacket < FFXIVIpcPlayerClassInfo > ( getId ( ) ) ;
classInfoPacket - > data ( ) . classId = static_cast < uint8_t > ( getClass ( ) ) ;
classInfoPacket - > data ( ) . unknown = 1 ;
2018-10-20 15:39:20 +03:00
classInfoPacket - > data ( ) . syncedLevel = getLevel ( ) ;
classInfoPacket - > data ( ) . classLevel = getLevel ( ) ;
2018-08-29 21:40:59 +02:00
queuePacket ( classInfoPacket ) ;
2018-01-28 22:36:43 +01:00
2018-08-29 21:40:59 +02:00
m_itemLevel = calculateEquippedGearItemLevel ( ) ;
sendItemLevel ( ) ;
}
2018-01-28 22:36:43 +01:00
2018-12-25 01:57:50 +01:00
auto pHousingMgr = m_pFw - > get < HousingMgr > ( ) ;
2018-11-29 16:55:48 +01:00
if ( Sapphire : : LandPtr pLand = pHousingMgr - > getLandByOwnerId ( getId ( ) ) )
2018-11-10 19:00:13 +01:00
{
2018-11-27 22:18:50 +11:00
uint32_t state = 0 ;
if ( pLand - > getHouse ( ) )
{
2018-11-28 20:32:05 +01:00
state | = EstateBuilt ;
2018-11-27 22:18:50 +11:00
// todo: remove this, debug for now
2018-11-28 20:32:05 +01:00
state | = HasAetheryte ;
2018-11-27 22:18:50 +11:00
}
2018-12-21 22:23:49 +11:00
setLandFlags ( LandFlagsSlot : : Private , state , pLand - > getLandIdent ( ) ) ;
2018-11-10 19:00:13 +01:00
}
2018-11-27 23:12:26 +11:00
sendLandFlags ( ) ;
2018-11-06 23:25:37 +01:00
2018-08-29 21:40:59 +02:00
auto initZonePacket = makeZonePacket < FFXIVIpcInitZone > ( getId ( ) ) ;
2018-11-05 23:07:39 +01:00
initZonePacket - > data ( ) . zoneId = getCurrentZone ( ) - > getTerritoryTypeId ( ) ;
2018-08-29 21:40:59 +02:00
initZonePacket - > data ( ) . weatherId = static_cast < uint8_t > ( getCurrentZone ( ) - > getCurrentWeather ( ) ) ;
2018-11-06 23:25:37 +01:00
initZonePacket - > data ( ) . bitmask = 0x1 ; //Setting this to 16 (decimal) makes it so you can fly in the area (more research needed!)
2018-08-29 21:40:59 +02:00
initZonePacket - > data ( ) . unknown5 = 0x2A ;
2018-09-01 20:55:28 +10:00
initZonePacket - > data ( ) . festivalId = getCurrentZone ( ) - > getCurrentFestival ( ) . first ;
initZonePacket - > data ( ) . additionalFestivalId = getCurrentZone ( ) - > getCurrentFestival ( ) . second ;
2018-08-29 21:40:59 +02:00
initZonePacket - > data ( ) . pos . x = getPos ( ) . x ;
initZonePacket - > data ( ) . pos . y = getPos ( ) . y ;
initZonePacket - > data ( ) . pos . z = getPos ( ) . z ;
queuePacket ( initZonePacket ) ;
2018-01-28 22:36:43 +01:00
2018-11-06 13:05:39 +01:00
getCurrentZone ( ) - > onPlayerZoneIn ( * this ) ;
2018-08-29 21:40:59 +02:00
if ( isLogin ( ) )
{
auto unk322 = makeZonePacket < FFXIVARR_IPC_UNK322 > ( getId ( ) ) ;
queuePacket ( unk322 ) ;
2018-01-28 22:36:43 +01:00
2018-08-29 21:40:59 +02:00
auto unk320 = makeZonePacket < FFXIVARR_IPC_UNK320 > ( getId ( ) ) ;
queuePacket ( unk320 ) ;
}
2018-01-28 22:36:43 +01:00
2018-11-06 23:36:34 +01:00
// if( getLastPing() == 0 )
// sendQuestInfo();
2018-01-28 22:36:43 +01:00
2018-08-29 21:40:59 +02:00
m_bMarkedForZoning = false ;
2018-01-28 22:36:43 +01:00
}
2018-02-07 00:00:48 +01:00
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setDirectorInitialized ( bool isInitialized )
2018-02-07 00:00:48 +01:00
{
2018-08-29 21:40:59 +02:00
m_directorInitialized = isInitialized ;
2018-02-07 00:00:48 +01:00
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : isDirectorInitialized ( ) const
2018-02-07 00:00:48 +01:00
{
2018-08-29 21:40:59 +02:00
return m_directorInitialized ;
2018-02-07 00:00:48 +01:00
}
2018-02-17 01:20:40 +01:00
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : sendTitleList ( )
2018-02-17 01:20:40 +01:00
{
2018-08-29 21:40:59 +02:00
auto titleListPacket = makeZonePacket < FFXIVIpcPlayerTitleList > ( getId ( ) ) ;
memcpy ( titleListPacket - > data ( ) . titleList , getTitleList ( ) , sizeof ( titleListPacket - > data ( ) . titleList ) ) ;
2018-02-17 01:20:40 +01:00
2018-08-29 21:40:59 +02:00
queuePacket ( titleListPacket ) ;
2018-02-17 01:20:40 +01:00
}
2018-02-18 01:50:20 +01:00
2018-08-29 21:40:59 +02:00
void
2018-11-29 16:55:48 +01:00
Sapphire : : Entity : : Player : : sendZoneInPackets ( uint32_t param1 , uint32_t param2 = 0 , uint32_t param3 = 0 , uint32_t param4 = 0 ,
2019-01-09 23:57:49 +01:00
bool shouldSetStatus = false )
2018-04-19 22:22:20 +10:00
{
2018-08-29 21:40:59 +02:00
auto zoneInPacket = makeActorControl143 ( getId ( ) , ZoneIn , param1 , param2 , param3 , param4 ) ;
auto SetStatusPacket = makeActorControl142 ( getId ( ) , SetStatus , static_cast < uint8_t > ( Common : : ActorStatus : : Idle ) ) ;
2018-04-19 22:22:20 +10:00
2018-08-29 21:40:59 +02:00
if ( ! getGmInvis ( ) )
2019-01-09 23:57:49 +01:00
sendToInRangeSet ( zoneInPacket ) ;
2018-08-29 21:40:59 +02:00
if ( shouldSetStatus )
2019-01-09 23:57:49 +01:00
sendToInRangeSet ( SetStatusPacket , true ) ;
queuePacket ( zoneInPacket ) ;
2018-04-19 22:22:20 +10:00
2018-08-29 21:40:59 +02:00
setZoningType ( Common : : ZoneingType : : None ) ;
unsetStateFlag ( PlayerStateFlag : : BetweenAreas ) ;
2018-04-19 22:22:20 +10:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : finishZoning ( )
2018-02-18 01:50:20 +01:00
{
2018-08-29 21:40:59 +02:00
switch ( getZoningType ( ) )
{
case ZoneingType : : None :
sendZoneInPackets ( 0x01 ) ;
break ;
2018-02-18 01:50:20 +01:00
2018-08-29 21:40:59 +02:00
case ZoneingType : : Teleport :
sendZoneInPackets ( 0x01 , 0 , 0 , 110 ) ;
break ;
2018-02-18 01:50:20 +01:00
2018-08-29 21:40:59 +02:00
case ZoneingType : : Return :
case ZoneingType : : ReturnDead :
{
if ( getStatus ( ) = = Common : : ActorStatus : : Dead )
2018-02-18 01:50:20 +01:00
{
2018-08-29 21:40:59 +02:00
resetHp ( ) ;
resetMp ( ) ;
setStatus ( Common : : ActorStatus : : Idle ) ;
sendZoneInPackets ( 0x01 , 0x01 , 0 , 111 , true ) ;
2018-02-18 01:50:20 +01:00
}
2018-08-29 21:40:59 +02:00
else
sendZoneInPackets ( 0x01 , 0x00 , 0 , 111 ) ;
}
2018-04-19 22:22:20 +10:00
break ;
2018-02-18 01:50:20 +01:00
2018-08-29 21:40:59 +02:00
case ZoneingType : : FadeIn :
break ;
}
2018-02-18 01:50:20 +01:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : emote ( uint32_t emoteId , uint64_t targetId , bool isSilent )
2018-02-18 01:50:20 +01:00
{
2018-08-29 21:40:59 +02:00
sendToInRangeSet ( makeActorControl144 ( getId ( ) , ActorControlType : : Emote ,
emoteId , 0 , isSilent ? 1 : 0 , 0 , targetId ) ) ;
2018-02-18 01:50:20 +01:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : emoteInterrupt ( )
2018-07-08 23:44:37 +02:00
{
2018-08-29 21:40:59 +02:00
sendToInRangeSet ( makeActorControl142 ( getId ( ) , ActorControlType : : EmoteInterrupt ) ) ;
2018-07-08 23:44:37 +02:00
}
2018-12-25 01:57:50 +01:00
void Sapphire : : Entity : : Player : : teleportQuery ( uint16_t aetheryteId , FrameworkPtr pFw )
2018-02-18 01:50:20 +01:00
{
2019-02-08 21:18:01 +11:00
// auto pExdData = pFw->get< Data::ExdDataGenerated >();
// // TODO: only register this action if enough gil is in possession
// auto targetAetheryte = pExdData->get< Sapphire::Data::Aetheryte >( aetheryteId );
//
// if( targetAetheryte )
// {
// auto fromAetheryte = pExdData->get< Sapphire::Data::Aetheryte >(
// pExdData->get< Sapphire::Data::TerritoryType >( getZoneId() )->aetheryte );
//
// // calculate cost - does not apply for favorite points or homepoints neither checks for aether tickets
// auto cost = static_cast< uint16_t > (
// ( std::sqrt( std::pow( fromAetheryte->aetherstreamX - targetAetheryte->aetherstreamX, 2 ) +
// std::pow( fromAetheryte->aetherstreamY - targetAetheryte->aetherstreamY, 2 ) ) / 2 ) + 100 );
//
// // cap at 999 gil
// cost = cost > uint16_t{ 999 } ? uint16_t{ 999 } : cost;
//
// bool insufficientGil = getCurrency( Common::CurrencyType::Gil ) < cost;
// // TODO: figure out what param1 really does
// queuePacket( makeActorControl143( getId(), TeleportStart, insufficientGil ? 2 : 0, aetheryteId ) );
//
// if( !insufficientGil )
// {
// Action::ActionPtr pActionTeleport;
// pActionTeleport = Action::make_ActionTeleport( getAsPlayer(), aetheryteId, cost, pFw );
// setCurrentAction( pActionTeleport );
// }
// }
2018-02-18 01:50:20 +01:00
}
2018-02-23 23:47:21 +01:00
2018-11-29 16:55:48 +01:00
uint8_t Sapphire : : Entity : : Player : : getNextObjSpawnIndexForActorId ( uint32_t actorId )
2018-02-23 23:47:21 +01:00
{
2019-01-28 21:02:51 +11:00
auto index = m_objSpawnIndexAllocator . getNextFreeSpawnIndex ( actorId ) ;
if ( index = = m_objSpawnIndexAllocator . getAllocFailId ( ) )
{
Logger : : warn ( " Failed to spawn EObj#{0} for Player#{1} - no remaining spawn indexes available. "
" Consider lowering InRangeDistance in world config. " ,
actorId , getId ( ) ) ;
sendUrgent ( " Failed to spawn EObj#{0} for you - no remaining spawn slots. See world log. " , actorId ) ;
return index ;
}
return index ;
2018-02-28 23:53:20 +11:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : resetObjSpawnIndex ( )
2018-02-28 23:53:20 +11:00
{
2018-08-29 21:40:59 +02:00
m_objSpawnIndexAllocator . freeAllSpawnIndexes ( ) ;
2018-02-28 23:53:20 +11:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : freeObjSpawnIndexForActorId ( uint32_t actorId )
2018-02-28 23:53:20 +11:00
{
2018-08-29 21:40:59 +02:00
auto spawnId = m_objSpawnIndexAllocator . freeUsedSpawnIndex ( actorId ) ;
2018-03-01 23:17:35 +01:00
2019-01-28 20:29:30 +11:00
// obj was never spawned for this player
if ( spawnId = = m_objSpawnIndexAllocator . getAllocFailId ( ) )
return ;
2018-08-29 21:40:59 +02:00
auto freeObjectSpawnPacket = makeZonePacket < FFXIVIpcObjectDespawn > ( getId ( ) ) ;
freeObjectSpawnPacket - > data ( ) . spawnIndex = spawnId ;
queuePacket ( freeObjectSpawnPacket ) ;
2018-03-02 02:55:02 +11:00
}
2018-02-28 23:53:20 +11:00
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : isObjSpawnIndexValid ( uint8_t index )
2018-03-02 02:55:02 +11:00
{
2018-08-29 21:40:59 +02:00
return m_objSpawnIndexAllocator . isSpawnIndexValid ( index ) ;
2018-02-24 23:53:32 +01:00
}
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : setOnEnterEventDone ( bool isDone )
2018-02-24 23:53:32 +01:00
{
2018-08-29 21:40:59 +02:00
m_onEnterEventDone = isDone ;
2018-02-24 23:53:32 +01:00
}
2018-11-29 16:55:48 +01:00
bool Sapphire : : Entity : : Player : : isOnEnterEventDone ( ) const
2018-02-24 23:53:32 +01:00
{
2018-08-29 21:40:59 +02:00
return m_onEnterEventDone ;
2018-02-24 23:53:32 +01:00
}
2018-11-07 11:59:59 +01:00
2018-12-21 22:23:49 +11:00
void Sapphire : : Entity : : Player : : setLandFlags ( uint8_t flagSlot , uint32_t landFlags , Common : : LandIdent ident )
2018-11-07 11:59:59 +01:00
{
2018-12-21 22:23:49 +11:00
m_landFlags [ flagSlot ] . landIdent = ident ;
// todo: leave this in for now but we really need to handle this world id shit properly
2018-11-28 23:29:55 +11:00
m_landFlags [ flagSlot ] . landIdent . worldId = 67 ;
m_landFlags [ flagSlot ] . landFlags = landFlags ;
m_landFlags [ flagSlot ] . unkown1 = 0 ;
2018-11-10 22:04:40 +01:00
}
2018-11-07 11:59:59 +01:00
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : sendLandFlags ( )
2018-11-07 11:59:59 +01:00
{
2018-11-28 23:29:55 +11:00
auto landFlags = makeZonePacket < FFXIVIpcHousingLandFlags > ( getId ( ) ) ;
2018-11-07 11:59:59 +01:00
2018-11-28 23:29:55 +11:00
landFlags - > data ( ) . freeCompanyHouse = m_landFlags [ Common : : LandFlagsSlot : : FreeCompany ] ;
landFlags - > data ( ) . privateHouse = m_landFlags [ Common : : LandFlagsSlot : : Private ] ;
landFlags - > data ( ) . apartment = m_landFlags [ Common : : LandFlagsSlot : : Apartment ] ;
landFlags - > data ( ) . sharedHouse [ 0 ] = m_landFlags [ Common : : LandFlagsSlot : : SharedHouse1 ] ;
landFlags - > data ( ) . sharedHouse [ 1 ] = m_landFlags [ Common : : LandFlagsSlot : : SharedHouse2 ] ;
2018-11-07 11:59:59 +01:00
2018-11-28 23:29:55 +11:00
queuePacket ( landFlags ) ;
2018-11-10 19:15:04 +01:00
}
2018-11-15 22:30:59 +01:00
2018-11-29 16:55:48 +01:00
void Sapphire : : Entity : : Player : : sendLandFlagsSlot ( Common : : LandFlagsSlot slot )
2018-11-15 22:30:59 +01:00
{
2018-11-28 23:29:55 +11:00
auto landFlags = makeZonePacket < FFXIVIpcHousingUpdateLandFlagsSlot > ( getId ( ) ) ;
2018-11-27 22:18:50 +11:00
2018-11-28 23:29:55 +11:00
uint32_t type = 0 ;
2018-11-27 22:18:50 +11:00
2018-11-28 23:29:55 +11:00
switch ( slot )
{
case LandFlagsSlot : : Private :
type = static_cast < uint32_t > ( LandType : : Private ) ;
break ;
case LandFlagsSlot : : FreeCompany :
type = static_cast < uint32_t > ( LandType : : FreeCompany ) ;
break ;
default :
// todo: other/unsupported land types
return ;
}
landFlags - > data ( ) . type = type ;
landFlags - > data ( ) . flagSet = m_landFlags [ slot ] ;
2018-11-15 22:30:59 +01:00
2018-11-28 23:29:55 +11:00
queuePacket ( landFlags ) ;
2019-01-04 12:34:19 +01:00
}