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>
2019-10-27 08:26:48 +01:00
# include <datReader/DatCategories/bg/LgbTypes.h>
2020-01-06 20:19:42 +11:00
# include <datReader/DatCategories/bg/lgb.h>
2019-10-27 08:26:48 +01:00
2018-03-06 22:22:19 +01:00
# 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-04-17 22:36:23 +02:00
# include "Manager/RNGMgr.h"
2019-01-13 17:32:43 +01:00
2019-07-21 22:33:33 +10:00
# include "Territory/Territory.h"
2018-12-01 00:27:16 +11:00
# include "Territory/ZonePosition.h"
2019-01-13 17:32:43 +01:00
# include "Territory/InstanceContent.h"
2019-10-21 23:24:26 +02:00
# include "Territory/InstanceObjectCache.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"
2019-10-09 18:14:53 +02:00
# include "Network/PacketWrappers/ActorControlPacket.h"
# include "Network/PacketWrappers/ActorControlSelfPacket.h"
# include "Network/PacketWrappers/ActorControlTargetPacket.h"
2019-06-20 14:48:24 +10:00
# include "Network/PacketWrappers/PlayerSetupPacket.h"
2017-12-08 15:38:25 +01:00
# 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
2019-03-07 21:58:12 +11:00
# include "Action/Action.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 ) ,
2020-01-05 17:09:27 +09:00
m_falling ( false ) ,
m_pQueuedAction ( nullptr )
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 ;
2019-04-21 23:52:41 +10:00
m_radius = 1.f ;
2018-08-29 21:40:59 +02:00
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
{
2019-07-29 22:22:45 +10:00
auto preparePacket = makeZonePacket < FFXIVIpcPrepareZoning > ( getId ( ) ) ;
2018-08-29 21:40:59 +02:00
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
2019-04-24 23:25:07 +10:00
float base = Math : : CalcStats : : calculateBaseStat ( * this ) ;
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 ) ;
2020-01-05 17:41:38 +09:00
/*m_baseStats.pie = static_cast< uint32_t >( base * ( static_cast< float >( classInfo->modifierPiety ) / 100 ) +
tribeInfo - > pIE ) ; */
2018-01-31 11:43:22 +01:00
2019-03-20 21:29:34 +01:00
m_baseStats . determination = static_cast < uint32_t > ( base ) ;
m_baseStats . pie = static_cast < uint32_t > ( base ) ;
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
2019-03-20 21:29:34 +01:00
m_baseStats . attack = m_baseStats . str ;
m_baseStats . attackPotMagic = m_baseStats . inte ;
m_baseStats . healingPotMagic = m_baseStats . mnd ;
2019-07-06 14:51:58 +10:00
m_baseStats . max_mp = 10000 ;
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-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
{
2019-07-29 22:22:45 +10:00
auto statPacket = makeZonePacket < FFXIVIpcPlayerStats > ( getId ( ) ) ;
2019-07-25 23:21:42 +10:00
2019-04-25 21:57:41 +10:00
statPacket - > data ( ) . strength = getStatValue ( Common : : BaseParam : : Strength ) ;
statPacket - > data ( ) . dexterity = getStatValue ( Common : : BaseParam : : Dexterity ) ;
statPacket - > data ( ) . vitality = getStatValue ( Common : : BaseParam : : Vitality ) ;
statPacket - > data ( ) . intelligence = getStatValue ( Common : : BaseParam : : Intelligence ) ;
statPacket - > data ( ) . mind = getStatValue ( Common : : BaseParam : : Mind ) ;
statPacket - > data ( ) . piety = getStatValue ( Common : : BaseParam : : Piety ) ;
statPacket - > data ( ) . determination = getStatValue ( Common : : BaseParam : : Determination ) ;
statPacket - > data ( ) . hp = getStatValue ( Common : : BaseParam : : HP ) ;
statPacket - > data ( ) . mp = getStatValue ( Common : : BaseParam : : MP ) ;
2019-07-25 23:21:42 +10:00
statPacket - > data ( ) . directHitRate = getStatValue ( Common : : BaseParam : : DirectHitRate ) ;
statPacket - > data ( ) . attackPower = getStatValue ( Common : : BaseParam : : AttackPower ) ;
2019-04-25 21:57:41 +10:00
statPacket - > data ( ) . attackMagicPotency = getStatValue ( Common : : BaseParam : : AttackMagicPotency ) ;
statPacket - > data ( ) . healingMagicPotency = getStatValue ( Common : : BaseParam : : HealingMagicPotency ) ;
statPacket - > data ( ) . skillSpeed = getStatValue ( Common : : BaseParam : : SkillSpeed ) ;
statPacket - > data ( ) . spellSpeed = getStatValue ( Common : : BaseParam : : SpellSpeed ) ;
2019-07-25 23:21:42 +10:00
statPacket - > data ( ) . haste = 100 ;
statPacket - > data ( ) . criticalHit = getStatValue ( Common : : BaseParam : : CriticalHit ) ;
2019-04-25 21:57:41 +10:00
statPacket - > data ( ) . defense = getStatValue ( Common : : BaseParam : : Defense ) ;
statPacket - > data ( ) . magicDefense = getStatValue ( Common : : BaseParam : : MagicDefense ) ;
statPacket - > data ( ) . tenacity = getStatValue ( Common : : BaseParam : : Tenacity ) ;
2018-08-29 21:40:59 +02:00
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 ) ;
2019-10-21 23:24:26 +02:00
auto pInstanceObjectCache = m_pFw - > get < InstanceObjectCache > ( ) ;
auto pop = pInstanceObjectCache - > getPopRange ( data - > territory , data - > level [ 0 ] ) ;
2018-08-29 21:40:59 +02:00
Common : : FFXIVARR_POSITION3 pos ;
pos . x = 0 ;
pos . y = 0 ;
pos . z = 0 ;
float rot = 0 ;
2019-10-27 08:26:48 +01:00
if ( pop )
{
sendDebug ( " Teleport: popRange {0} found! " , data - > level . at ( 0 ) ) ;
pos . x = pop - > header . transform . translation . x ;
pos . y = pop - > header . transform . translation . y ;
pos . z = pop - > header . transform . translation . z ;
2019-10-28 22:18:23 +01:00
rot = pop - > header . transform . rotation . y ;
2019-10-27 08:26:48 +01:00
}
else
2018-08-29 21:40:59 +02:00
{
2019-10-27 08:26:48 +01:00
sendDebug ( " Teleport: popRange {0} not found in {1}! " , data - > level [ 0 ] , data - > territory ) ;
2018-08-29 21:40:59 +02:00
}
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
{
2020-01-03 22:31:55 +09:00
prepareZoning ( data - > territory , true , 1 , 0 ) ; // TODO: Really?
2019-10-09 18:42:25 +02:00
sendToInRangeSet ( makeActorControl ( getId ( ) , ActorDespawnEffect , 0x04 ) ) ;
2018-08-29 21:40:59 +02:00
setZoningType ( Common : : ZoneingType : : Teleport ) ;
}
else if ( type = = 2 ) // aethernet
{
prepareZoning ( data - > territory , true , 1 , 112 ) ;
2019-10-09 18:42:25 +02:00
sendToInRangeSet ( makeActorControl ( getId ( ) , ActorDespawnEffect , 0x04 ) ) ;
2018-08-29 21:40:59 +02:00
setZoningType ( Common : : ZoneingType : : Teleport ) ;
}
else if ( type = = 3 ) // return
{
prepareZoning ( data - > territory , true , 1 , 111 ) ;
2019-10-09 18:42:25 +02:00
sendToInRangeSet ( makeActorControl ( getId ( ) , ActorDespawnEffect , 0x03 ) ) ;
2018-08-29 21:40:59 +02:00
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 > ( ) ;
2019-05-07 22:10:55 +10:00
auto instance = pTeriMgr - > getTerritoryByGuId ( instanceContentId ) ;
2018-08-29 21:40:59 +02:00
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
}
2019-07-21 22:33:33 +10:00
bool Sapphire : : Entity : : Player : : setInstance ( TerritoryPtr 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 > ( ) ;
2019-07-21 22:50:11 +10:00
auto currentZone = getCurrentTerritory ( ) ;
2018-12-02 15:32:22 +11:00
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
}
2019-07-21 22:33:33 +10:00
bool Sapphire : : Entity : : Player : : setInstance ( TerritoryPtr instance , Common : : FFXIVARR_POSITION3 pos )
2018-12-30 18:48:45 +11:00
{
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 > ( ) ;
2019-07-21 22:50:11 +10:00
auto currentZone = getCurrentTerritory ( ) ;
2018-12-30 18:48:45 +11:00
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-07-21 22:50:11 +10:00
auto pZone = getCurrentTerritory ( ) ;
2019-01-13 17:32:43 +01:00
auto pInstance = pZone - > getAsInstanceContent ( ) ;
2019-04-09 23:17:00 +02:00
resetHp ( ) ;
resetMp ( ) ;
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 ;
2019-10-09 18:42:25 +02:00
queuePacket ( makeActorControlSelf ( 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 > (
2019-07-21 22:50:11 +10:00
pExdData - > get < Sapphire : : Data : : TerritoryType > ( getCurrentTerritory ( ) - > 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
2019-10-09 18:42:25 +02:00
queuePacket ( makeActorControlSelf ( 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
2019-10-09 18:42:25 +02:00
queuePacket ( makeActorControlSelf ( 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
2019-10-09 18:42:25 +02:00
queuePacket ( makeActorControlSelf ( getId ( ) , GainExpMsg , static_cast < uint8_t > ( getClass ( ) ) , amount ) ) ;
2017-08-08 13:53:47 +02:00
2019-06-30 19:51:18 +10:00
if ( level > = Common : : MAX_PLAYER_LEVEL ) // temporary fix for leveling over levelcap
2018-08-29 21:40:59 +02:00
{
2019-10-09 18:42:25 +02:00
queuePacket ( makeActorControlSelf ( getId ( ) , UpdateUiExp , static_cast < uint8_t > ( getClass ( ) ) , amount ) ) ;
2018-08-29 21:40:59 +02:00
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 ( ) ;
2019-10-09 18:42:25 +02:00
queuePacket ( makeActorControlSelf ( 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 (
2019-10-09 18:42:25 +02:00
makeActorControlSelf ( getId ( ) , UpdateUiExp , static_cast < uint8_t > ( getClass ( ) ) , currentExp + amount ) ) ;
2018-08-29 21:40:59 +02:00
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
2019-07-29 22:22:45 +10:00
auto effectListPacket = makeZonePacket < FFXIVIpcStatusEffectList > ( getId ( ) ) ;
2018-08-29 21:40:59 +02:00
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
2019-10-09 18:42:25 +02:00
sendToInRangeSet ( makeActorControl ( getId ( ) , LevelUpEffect , static_cast < uint8_t > ( getClass ( ) ) ,
getLevel ( ) , getLevel ( ) - 1 ) , true ) ;
2017-08-08 13:53:47 +02:00
2019-07-29 22:22:45 +10:00
auto classInfoPacket = makeZonePacket < FFXIVIpcUpdateClassInfo > ( getId ( ) ) ;
2018-08-29 21:40:59 +02:00
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
2019-07-29 22:22:45 +10:00
auto classInfoPacket = makeZonePacket < FFXIVIpcPlayerClassInfo > ( getId ( ) ) ;
2018-08-29 21:40:59 +02:00
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
2019-10-09 18:42:25 +02:00
sendToInRangeSet ( makeActorControl ( 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
2019-10-09 18:42:25 +02:00
pPlayer - > queuePacket ( makeActorControlSelf ( 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
2019-07-29 22:22:45 +10:00
auto gcAffPacket = makeZonePacket < FFXIVGCAffiliation > ( getId ( ) ) ;
2018-08-29 21:40:59 +02:00
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
2019-07-29 22:22:45 +10:00
auto gcAffPacket = makeZonePacket < FFXIVGCAffiliation > ( getId ( ) ) ;
2018-08-29 21:40:59 +02:00
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 )
2019-10-09 18:42:25 +02:00
sendToInRangeSet ( makeActorControl ( 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 )
2019-10-09 18:42:25 +02:00
sendToInRangeSet ( makeActorControl ( getId ( ) , SetStatusIcon , static_cast < uint8_t > ( getOnlineStatus ( ) ) ) , true ) ;
2017-08-08 13:53:47 +02:00
}
2019-04-04 23:29:52 +02:00
void Sapphire : : Entity : : Player : : update ( uint64_t tickCount )
2017-08-08 13:53:47 +02:00
{
2018-08-29 21:40:59 +02:00
// a zoning is pending, lets do it
2019-04-04 23:29:52 +02:00
if ( m_queuedZoneing & & ( tickCount - m_queuedZoneing - > m_queueTime ) > 800 )
2018-08-29 21:40:59 +02:00
{
Common : : FFXIVARR_POSITION3 targetPos = m_queuedZoneing - > m_targetPosition ;
2019-07-21 22:50:11 +10:00
if ( getCurrentTerritory ( ) - > getTerritoryTypeId ( ) ! = m_queuedZoneing - > m_targetZone )
2018-08-29 21:40:59 +02:00
{
performZoning ( m_queuedZoneing - > m_targetZone , targetPos , m_queuedZoneing - > m_targetRotation ) ;
}
else
{
2019-07-29 22:22:45 +10:00
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 ( ) ;
2019-04-04 23:29:52 +02:00
m_lastUpdate = tickCount ;
2018-08-29 21:40:59 +02:00
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 )
{
2019-04-25 22:45:23 +10:00
auto chara = actor - > getAsChara ( ) ;
2018-08-29 21:40:59 +02:00
// default autoattack range
2019-04-25 22:45:23 +10:00
float range = 3.f + chara - > getRadius ( ) ;
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
2019-04-04 23:29:52 +02:00
if ( ( tickCount - m_lastAttack ) > mainWeap - > getDelay ( ) )
2017-08-08 13:53:47 +02:00
{
2019-04-04 23:29:52 +02:00
m_lastAttack = tickCount ;
2018-08-29 21:40:59 +02:00
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-04-04 23:29:52 +02:00
Chara : : update ( tickCount ) ;
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 ) ;
2019-03-28 22:58:40 +01:00
if ( isActionLearned ( static_cast < uint8_t > ( Common : : UnlockEntry : : HuntingLog ) ) )
{
updateHuntingLog ( 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 ;
2019-07-29 22:22:45 +10:00
auto freeActorSpawnPacket = makeZonePacket < FFXIVIpcActorFreeSpawn > ( getId ( ) ) ;
2018-08-29 21:40:59 +02:00
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
2019-10-09 18:42:25 +02:00
queuePacket ( makeActorControlSelf ( 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 )
{
2019-10-09 18:42:25 +02:00
queuePacket ( makeActorControlTarget ( getId ( ) , ActorControlType : : LogMsg , messageId , param2 , param3 , param4 , param5 , param6 ) ) ;
2018-11-28 21:59:28 +11:00
}
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
{
2019-07-29 22:22:45 +10:00
auto hateListPacket = makeZonePacket < FFXIVIpcHateList > ( getId ( ) ) ;
2018-08-29 21:40:59 +02:00
hateListPacket - > data ( ) . numEntries = m_actorIdTohateSlotMap . size ( ) ;
2019-07-29 22:22:45 +10:00
auto hateRankPacket = makeZonePacket < FFXIVIpcHateRank > ( getId ( ) ) ;
2019-04-30 22:54:35 +02:00
hateRankPacket - > data ( ) . numEntries = m_actorIdTohateSlotMap . size ( ) ;
2018-08-29 21:40:59 +02:00
auto it = m_actorIdTohateSlotMap . begin ( ) ;
for ( int32_t i = 0 ; it ! = m_actorIdTohateSlotMap . end ( ) ; + + it , i + + )
{
2019-04-30 22:54:35 +02:00
// TODO: get actual hate values for these
2018-08-29 21:40:59 +02:00
hateListPacket - > data ( ) . entry [ i ] . actorId = it - > first ;
hateListPacket - > data ( ) . entry [ i ] . hatePercent = 100 ;
2019-04-30 22:54:35 +02:00
hateRankPacket - > data ( ) . entry [ i ] . actorId = it - > first ;
hateRankPacket - > data ( ) . entry [ i ] . hateAmount = 1 ;
2018-08-29 21:40:59 +02:00
}
2019-04-30 22:54:35 +02:00
queuePacket ( hateRankPacket ) ;
2018-08-29 21:40:59 +02:00
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 ) ;
2019-10-09 18:42:25 +02:00
queuePacket ( makeActorControl ( getId ( ) , ToggleAggro , 1 ) ) ;
2019-01-19 22:56:07 +01:00
}
void Sapphire : : Entity : : Player : : onMobDeaggro ( BNpcPtr pBNpc )
{
hateListRemove ( pBNpc ) ;
if ( m_actorIdTohateSlotMap . empty ( ) )
2019-10-09 18:42:25 +02:00
queuePacket ( makeActorControl ( getId ( ) , ToggleAggro ) ) ;
2019-01-19 22:56:07 +01:00
}
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
2019-10-09 18:42:25 +02:00
sendToInRangeSet ( makeActorControl ( 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 ;
2019-07-29 22:22:45 +10:00
auto paramPacket = makeZonePacket < FFXIVIpcEquipDisplayFlags > ( getId ( ) ) ;
2018-08-29 21:40:59 +02:00
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 ;
2019-10-09 18:42:25 +02:00
sendToInRangeSet ( makeActorControl ( getId ( ) , ActorControlType : : SetStatus ,
2018-08-29 21:40:59 +02:00
static_cast < uint8_t > ( Common : : ActorStatus : : Mounted ) ) , true ) ;
2019-10-09 18:42:25 +02:00
sendToInRangeSet ( makeActorControlSelf ( getId ( ) , 0x39e , 12 ) , true ) ; //?
2017-10-18 17:54:17 +02:00
2019-07-29 22:22:45 +10:00
auto mountPacket = makeZonePacket < FFXIVIpcMount > ( getId ( ) ) ;
2018-08-29 21:40:59 +02:00
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
{
2019-10-09 18:42:25 +02:00
sendToInRangeSet ( makeActorControl ( getId ( ) , ActorControlType : : SetStatus ,
2018-08-29 21:40:59 +02:00
static_cast < uint8_t > ( Common : : ActorStatus : : Idle ) ) , true ) ;
2019-10-09 18:42:25 +02:00
sendToInRangeSet ( makeActorControlSelf ( getId ( ) , ActorControlType : : Dismount , 1 ) , true ) ;
2018-08-29 21:40:59 +02:00
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 ;
2019-10-09 18:42:25 +02:00
sendToInRangeSet ( makeActorControl ( getId ( ) , ActorControlType : : ToggleCompanion , id ) , true ) ;
2019-02-02 23:06:57 +11:00
}
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
2019-04-17 22:36:23 +02:00
auto pRNGMgr = m_pFw - > get < World : : Manager : : RNGMgr > ( ) ;
auto variation = static_cast < uint32_t > ( pRNGMgr - > getRandGenerator < float > ( 0 , 3 ) . next ( ) ) ;
2019-07-27 00:37:40 +10:00
auto damage = Math : : CalcStats : : calcAutoAttackDamage ( * this ) ;
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-02-09 17:07:53 +11:00
Common : : EffectEntry entry { } ;
2020-01-07 19:08:13 +09:00
entry . value = damage . first ;
2018-08-29 21:40:59 +02:00
entry . effectType = Common : : ActionEffectType : : Damage ;
2020-01-07 19:08:13 +09:00
entry . hitSeverity = damage . second ;
2019-04-30 22:54:35 +02:00
entry . param = 0x72 ;
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-02-09 17:07:53 +11:00
Common : : EffectEntry entry { } ;
2020-01-07 19:08:13 +09:00
entry . value = damage . first ;
2018-08-29 21:40:59 +02:00
entry . effectType = Common : : ActionEffectType : : Damage ;
2020-01-07 19:08:13 +09:00
entry . hitSeverity = damage . second ;
2019-04-30 22:54:35 +02:00
entry . param = 0x73 ;
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
2020-01-07 19:08:13 +09:00
pTarget - > takeDamage ( damage . first ) ;
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
{
2019-06-02 00:34:22 +10:00
auto currentTimestamp = Common : : 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
{
2019-06-02 00:34:22 +10:00
auto currentTimestamp = Common : : 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?
2019-07-29 22:22:45 +10:00
auto packet = makeZonePacket < FFXIVIpcEorzeaTimeOffset > ( getId ( ) ) ;
2018-08-29 21:40:59 +02:00
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 ( ) ) ;
}
2019-07-21 22:50:11 +10:00
getCurrentTerritory ( ) - > onBeforePlayerZoneIn ( * this ) ;
2018-02-23 23:47:21 +01:00
2019-07-29 22:22:45 +10:00
auto initPacket = makeZonePacket < FFXIVIpcInit > ( getId ( ) ) ;
2018-08-29 21:40:59 +02:00
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 ( ) )
{
2019-10-09 18:42:25 +02:00
queuePacket ( makeActorControlSelf ( getId ( ) , SetCharaGearParamUI , m_equipDisplayFlags , 1 ) ) ;
2018-08-29 21:40:59 +02:00
}
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
2019-03-26 23:08:34 +01:00
if ( isActionLearned ( static_cast < uint8_t > ( Common : : UnlockEntry : : HuntingLog ) ) )
sendHuntingLog ( ) ;
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 ( ) )
{
2019-07-29 22:22:45 +10:00
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
2019-06-20 14:48:24 +10:00
queuePacket ( std : : make_shared < PlayerSetupPacket > ( * this ) ) ;
2018-01-28 22:36:43 +01:00
2019-07-29 22:22:45 +10:00
auto classInfoPacket = makeZonePacket < FFXIVIpcPlayerClassInfo > ( getId ( ) ) ;
2018-08-29 21:40:59 +02:00
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
2019-07-29 22:22:45 +10:00
auto initZonePacket = makeZonePacket < FFXIVIpcInitZone > ( getId ( ) ) ;
2019-07-21 22:50:11 +10:00
initZonePacket - > data ( ) . zoneId = getCurrentTerritory ( ) - > getTerritoryTypeId ( ) ;
initZonePacket - > data ( ) . weatherId = static_cast < uint8_t > ( getCurrentTerritory ( ) - > getCurrentWeather ( ) ) ;
2019-04-02 23:56:47 +02:00
initZonePacket - > data ( ) . bitmask = 0x1 ;
2019-07-21 22:50:11 +10:00
initZonePacket - > data ( ) . festivalId = getCurrentTerritory ( ) - > getCurrentFestival ( ) . first ;
initZonePacket - > data ( ) . additionalFestivalId = getCurrentTerritory ( ) - > 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
2019-07-21 22:50:11 +10:00
getCurrentTerritory ( ) - > onPlayerZoneIn ( * this ) ;
2018-11-06 13:05:39 +01:00
2018-08-29 21:40:59 +02:00
if ( isLogin ( ) )
{
2019-07-29 22:22:45 +10:00
auto unk322 = makeZonePacket < FFXIVARR_IPC_UNK322 > ( getId ( ) ) ;
2018-08-29 21:40:59 +02:00
queuePacket ( unk322 ) ;
2018-01-28 22:36:43 +01:00
2019-07-29 22:22:45 +10:00
auto unk320 = makeZonePacket < FFXIVARR_IPC_UNK320 > ( getId ( ) ) ;
2018-08-29 21:40:59 +02:00
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
{
2019-07-29 22:22:45 +10:00
auto titleListPacket = makeZonePacket < FFXIVIpcPlayerTitleList > ( getId ( ) ) ;
2018-08-29 21:40:59 +02:00
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
{
2019-10-09 18:42:25 +02:00
auto zoneInPacket = makeActorControlSelf ( getId ( ) , ZoneIn , param1 , param2 , param3 , param4 ) ;
auto SetStatusPacket = makeActorControl ( 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
{
2019-10-09 18:42:25 +02:00
sendToInRangeSet ( makeActorControlTarget ( getId ( ) , ActorControlType : : Emote ,
2018-08-29 21:40:59 +02:00
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
{
2019-10-09 18:42:25 +02:00
sendToInRangeSet ( makeActorControl ( getId ( ) , ActorControlType : : EmoteInterrupt ) ) ;
2018-07-08 23:44:37 +02:00
}
2019-02-08 21:20:53 +11:00
void Sapphire : : Entity : : Player : : teleportQuery ( uint16_t aetheryteId )
{
2019-03-07 21:58:12 +11:00
auto pExdData = m_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 = std : : min < uint16_t > ( 999 , cost ) ;
bool insufficientGil = getCurrency ( Common : : CurrencyType : : Gil ) < cost ;
// TODO: figure out what param1 really does
2019-10-09 18:42:25 +02:00
queuePacket ( makeActorControlSelf ( getId ( ) , TeleportStart , insufficientGil ? 2 : 0 , aetheryteId ) ) ;
2019-03-07 21:58:12 +11:00
if ( ! insufficientGil )
{
m_teleportQuery . targetAetheryte = aetheryteId ;
m_teleportQuery . cost = cost ;
}
else
{
clearTeleportQuery ( ) ;
}
}
}
Sapphire : : Common : : PlayerTeleportQuery Sapphire : : Entity : : Player : : getTeleportQuery ( ) const
{
return m_teleportQuery ;
}
void Sapphire : : Entity : : Player : : clearTeleportQuery ( )
{
memset ( & m_teleportQuery , 0x0 , sizeof ( Common : : PlayerTeleportQuery ) ) ;
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 ;
2019-07-29 22:22:45 +10:00
auto freeObjectSpawnPacket = makeZonePacket < FFXIVIpcObjectDespawn > ( getId ( ) ) ;
2018-08-29 21:40:59 +02:00
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
{
2019-07-29 22:22:45 +10: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
{
2019-07-29 22:22:45 +10: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
}
2019-03-26 00:04:27 +01:00
Sapphire : : Common : : HuntingLogEntry & Sapphire : : Entity : : Player : : getHuntingLogEntry ( uint8_t index )
{
assert ( index < m_huntingLogEntries . size ( ) ) ;
return m_huntingLogEntries [ index ] ;
}
2019-03-26 23:08:34 +01:00
void Sapphire : : Entity : : Player : : sendHuntingLog ( )
{
auto pExdData = m_pFw - > get < Data : : ExdDataGenerated > ( ) ;
uint8_t count = 0 ;
for ( const auto & entry : m_huntingLogEntries )
{
uint64_t completionFlag = 0 ;
2019-07-29 22:22:45 +10:00
auto huntPacket = makeZonePacket < FFXIVIpcHuntingLogEntry > ( getId ( ) ) ;
2019-03-26 23:08:34 +01:00
huntPacket - > data ( ) . u0 = - 1 ;
huntPacket - > data ( ) . rank = entry . rank ;
huntPacket - > data ( ) . index = count ;
for ( int i = 1 ; i < = 10 ; + + i )
{
auto index0 = i - 1 ;
bool allComplete = true ;
auto monsterNoteId = ( count + 1 ) * 10000 + entry . rank * 10 + i ;
auto monsterNote = pExdData - > get < Data : : MonsterNote > ( monsterNoteId ) ;
if ( ! monsterNote )
continue ;
const auto huntEntry = entry . entries [ index0 ] ;
for ( int x = 0 ; x < 3 ; + + x )
{
if ( ( huntEntry [ x ] = = monsterNote - > count [ x ] ) & & monsterNote - > count [ x ] ! = 0 )
completionFlag | = ( 1ull < < ( index0 * 5 + x ) ) ;
else if ( monsterNote - > count [ x ] ! = 0 )
allComplete = false ;
}
if ( allComplete )
completionFlag | = ( 1ull < < ( index0 * 5 + 4 ) ) ;
}
memcpy ( huntPacket - > data ( ) . entries , entry . entries , sizeof ( entry . entries ) ) ;
huntPacket - > data ( ) . completeFlags = completionFlag ;
+ + count ;
queuePacket ( huntPacket ) ;
}
}
2019-03-28 22:58:40 +01:00
void Sapphire : : Entity : : Player : : updateHuntingLog ( uint16_t id )
{
std : : vector < uint32_t > rankRewards { 2500 , 10000 , 20000 , 30000 , 40000 } ;
const auto maxRank = 4 ;
auto pExdData = m_pFw - > get < Data : : ExdDataGenerated > ( ) ;
auto & logEntry = m_huntingLogEntries [ static_cast < uint8_t > ( getClass ( ) ) - 1 ] ;
bool logChanged = false ;
2019-04-06 17:17:56 +02:00
// make sure we get the matching base-class if a job is being used
auto currentClass = static_cast < uint8_t > ( getClass ( ) ) ;
auto classJobInfo = pExdData - > get < Sapphire : : Data : : ClassJob > ( currentClass ) ;
if ( ! classJobInfo )
return ;
2019-03-28 22:58:40 +01:00
bool allSectionsComplete = true ;
for ( int i = 1 ; i < = 10 ; + + i )
{
bool sectionComplete = true ;
bool sectionChanged = false ;
2019-04-06 17:17:56 +02:00
uint32_t monsterNoteId = static_cast < uint32_t > ( classJobInfo - > classJobParent * 10000 + logEntry . rank * 10 + i ) ;
2019-03-28 22:58:40 +01:00
auto note = pExdData - > get < Sapphire : : Data : : MonsterNote > ( monsterNoteId ) ;
2019-04-06 11:44:06 +11:00
// for classes that don't have entries, if the first fails the rest will fail
if ( ! note )
break ;
2019-03-28 22:58:40 +01:00
for ( auto x = 0 ; x < 4 ; + + x )
{
auto note1 = pExdData - > get < Sapphire : : Data : : MonsterNoteTarget > ( note - > monsterNoteTarget [ x ] ) ;
if ( note1 - > bNpcName = = id & & logEntry . entries [ i - 1 ] [ x ] < note - > count [ x ] )
{
logEntry . entries [ i - 1 ] [ x ] + + ;
2019-10-09 18:42:25 +02:00
queuePacket ( makeActorControlSelf ( getId ( ) , HuntingLogEntryUpdate , monsterNoteId , x , logEntry . entries [ i - 1 ] [ x ] ) ) ;
2019-03-28 22:58:40 +01:00
logChanged = true ;
sectionChanged = true ;
}
if ( logEntry . entries [ i - 1 ] [ x ] ! = note - > count [ x ] )
sectionComplete = false ;
}
if ( logChanged & & sectionComplete & & sectionChanged )
{
2019-10-09 18:42:25 +02:00
queuePacket ( makeActorControlSelf ( getId ( ) , HuntingLogSectionFinish , monsterNoteId , i , 0 ) ) ;
2019-03-28 22:58:40 +01:00
gainExp ( note - > reward ) ;
}
if ( ! sectionComplete )
{
allSectionsComplete = false ;
}
}
if ( logChanged & & allSectionsComplete )
{
2019-10-09 18:42:25 +02:00
queuePacket ( makeActorControlSelf ( getId ( ) , HuntingLogRankFinish , 4 , 0 , 0 ) ) ;
2019-03-28 22:58:40 +01:00
gainExp ( rankRewards [ logEntry . rank ] ) ;
if ( logEntry . rank < 4 )
{
logEntry . rank + + ;
memset ( logEntry . entries , 0 , 40 ) ;
2019-10-09 18:42:25 +02:00
queuePacket ( makeActorControlSelf ( getId ( ) , HuntingLogRankUnlock ,
2019-03-28 22:58:40 +01:00
static_cast < uint8_t > ( getClass ( ) ) , logEntry . rank + 1 , 0 ) ) ;
}
}
2019-04-07 16:04:36 +10:00
2019-04-06 11:44:06 +11:00
if ( logChanged )
sendHuntingLog ( ) ;
2019-03-28 22:58:40 +01:00
}
2019-04-07 13:27:56 +02:00
Sapphire : : World : : SessionPtr Sapphire : : Entity : : Player : : getSession ( )
{
return m_pSession ;
}
2019-04-24 23:25:07 +10:00
void Sapphire : : Entity : : Player : : setActiveLand ( uint8_t land , uint8_t ward )
{
m_activeLand . plot = land ;
m_activeLand . ward = ward ;
}
Sapphire : : Common : : ActiveLand Sapphire : : Entity : : Player : : getActiveLand ( ) const
{
return m_activeLand ;
}
2020-01-05 17:09:27 +09:00
bool Sapphire : : Entity : : Player : : hasQueuedAction ( ) const
{
return m_pQueuedAction ! = nullptr ;
}
void Sapphire : : Entity : : Player : : setQueuedAction ( Sapphire : : World : : Action : : ActionPtr pAction )
{
2020-01-05 20:49:50 +09:00
m_pQueuedAction = std : : move ( pAction ) ; // overwrite previous queued action if any
2020-01-05 17:09:27 +09:00
}
bool Sapphire : : Entity : : Player : : checkAction ( )
{
if ( m_pCurrentAction = = nullptr )
return false ;
if ( m_pCurrentAction - > update ( ) )
{
if ( m_pCurrentAction - > isInterrupted ( ) & & m_pCurrentAction - > getInterruptType ( ) ! = Common : : ActionInterruptType : : DamageInterrupt )
{
// we moved (or whatever not damage interrupt) so we don't want to execute queued cast
m_pQueuedAction = nullptr ;
}
m_pCurrentAction = nullptr ;
if ( hasQueuedAction ( ) )
{
sendDebug ( " Queued skill start: {0} " , m_pQueuedAction - > getId ( ) ) ;
if ( m_pQueuedAction - > hasCastTime ( ) )
{
setCurrentAction ( m_pQueuedAction ) ;
}
m_pQueuedAction - > start ( ) ;
m_pQueuedAction = nullptr ;
}
}
return true ;
}