diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9f3f22ab..da0c7441 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,10 +33,10 @@ switch( commandId ) case 0x01: // Toggle sheathe { if ( param11 == 1 ) - pPlayer->setStance( Entity::Actor::Stance::Active ); + pPlayer->setStance( Entity::Chara::Stance::Active ); else { - pPlayer->setStance( Entity::Actor::Stance::Passive ); + pPlayer->setStance( Entity::Chara::Stance::Passive ); pPlayer->setAutoattack( false ); } diff --git a/src/servers/sapphire_api/Forwards.h b/src/servers/sapphire_api/Forwards.h index bdffff9f..cbc8d820 100644 --- a/src/servers/sapphire_api/Forwards.h +++ b/src/servers/sapphire_api/Forwards.h @@ -34,11 +34,11 @@ namespace Core namespace Entity { - class Actor; + class Chara; class Player; class BattleNpc; - typedef boost::shared_ptr ActorPtr; + typedef boost::shared_ptr ActorPtr; typedef boost::shared_ptr PlayerPtr; typedef boost::shared_ptr BattleNpcPtr; } diff --git a/src/servers/sapphire_zone/Action/Action.cpp b/src/servers/sapphire_zone/Action/Action.cpp index 56512f09..ed3c3e36 100644 --- a/src/servers/sapphire_zone/Action/Action.cpp +++ b/src/servers/sapphire_zone/Action/Action.cpp @@ -22,7 +22,7 @@ Core::Common::HandleActionType Core::Action::Action::getHandleActionType() const return m_handleActionType; } -Core::Entity::ActorPtr Core::Action::Action::getTargetActor() const +Core::Entity::CharaPtr Core::Action::Action::getTargetChara() const { return m_pTarget; } @@ -57,7 +57,7 @@ void Core::Action::Action::setCastTime( uint32_t castTime ) m_castTime = castTime; } -Core::Entity::ActorPtr Core::Action::Action::getActionSource() const +Core::Entity::CharaPtr Core::Action::Action::getActionSource() const { return m_pSource; } diff --git a/src/servers/sapphire_zone/Action/Action.h b/src/servers/sapphire_zone/Action/Action.h index 8cd4c3cc..995835dd 100644 --- a/src/servers/sapphire_zone/Action/Action.h +++ b/src/servers/sapphire_zone/Action/Action.h @@ -18,7 +18,7 @@ namespace Action { Common::HandleActionType getHandleActionType() const; - Entity::ActorPtr getTargetActor() const; + Entity::CharaPtr getTargetChara() const; bool isInterrupted() const; @@ -32,7 +32,7 @@ namespace Action { void setCastTime( uint32_t castTime ); - Entity::ActorPtr getActionSource() const; + Entity::CharaPtr getActionSource() const; virtual void onStart() {}; virtual void onFinish() {}; @@ -48,8 +48,8 @@ namespace Action { uint64_t m_startTime; uint32_t m_castTime; - Entity::ActorPtr m_pSource; - Entity::ActorPtr m_pTarget; + Entity::CharaPtr m_pSource; + Entity::CharaPtr m_pTarget; bool m_bInterrupt; diff --git a/src/servers/sapphire_zone/Action/ActionCast.cpp b/src/servers/sapphire_zone/Action/ActionCast.cpp index 00e0e966..fbdd780e 100644 --- a/src/servers/sapphire_zone/Action/ActionCast.cpp +++ b/src/servers/sapphire_zone/Action/ActionCast.cpp @@ -26,7 +26,7 @@ Core::Action::ActionCast::ActionCast() m_handleActionType = Common::HandleActionType::Event; } -Core::Action::ActionCast::ActionCast( Entity::ActorPtr pActor, Entity::ActorPtr pTarget, uint16_t actionId ) +Core::Action::ActionCast::ActionCast( Entity::CharaPtr pActor, Entity::CharaPtr pTarget, uint16_t actionId ) { m_startTime = 0; m_id = actionId; diff --git a/src/servers/sapphire_zone/Action/ActionCast.h b/src/servers/sapphire_zone/Action/ActionCast.h index b656b391..c1dac482 100644 --- a/src/servers/sapphire_zone/Action/ActionCast.h +++ b/src/servers/sapphire_zone/Action/ActionCast.h @@ -15,7 +15,7 @@ namespace Action { ActionCast(); ~ActionCast(); - ActionCast( Entity::ActorPtr pActor, Entity::ActorPtr pTarget, uint16_t actionId ); + ActionCast( Entity::CharaPtr pActor, Entity::CharaPtr pTarget, uint16_t actionId ); void onStart() override; void onFinish() override; diff --git a/src/servers/sapphire_zone/Action/ActionCollision.cpp b/src/servers/sapphire_zone/Action/ActionCollision.cpp index a66d234c..c13a3e29 100644 --- a/src/servers/sapphire_zone/Action/ActionCollision.cpp +++ b/src/servers/sapphire_zone/Action/ActionCollision.cpp @@ -2,7 +2,7 @@ #include #include "ActionCollision.h" -#include "Actor/Actor.h" +#include "Actor/Chara.h" #include "Actor/Player.h" #include @@ -13,7 +13,7 @@ using namespace Core::Common; // todo: add AoE actor limits (16, 32) -bool ActionCollision::isActorApplicable( Actor& actor, TargetFilter targetFilter ) +bool ActionCollision::isActorApplicable( Chara& chara, TargetFilter targetFilter ) { bool actorApplicable = false; switch( targetFilter ) @@ -25,37 +25,37 @@ bool ActionCollision::isActorApplicable( Actor& actor, TargetFilter targetFilter } case TargetFilter::Players: { - actorApplicable = actor.isPlayer(); + actorApplicable = chara.isPlayer(); break; } case TargetFilter::Allies: { // todo: implement ally NPCs - actorApplicable = !actor.isBattleNpc(); + actorApplicable = !chara.isBattleNpc(); break; } case TargetFilter::Party: { // todo: implement party - actorApplicable = actor.isPlayer(); + actorApplicable = chara.isPlayer(); break; } case TargetFilter::Enemies: { - actorApplicable = actor.isBattleNpc(); + actorApplicable = chara.isBattleNpc(); break; } } - return ( actorApplicable && actor.isAlive() ); + return ( actorApplicable && chara.isAlive() ); } -std::set< Core::Entity::ActorPtr > ActionCollision::getActorsHitFromAction( FFXIVARR_POSITION3 aoePosition, - std::set< ActorPtr > actorsInRange, +std::set< Core::Entity::CharaPtr > ActionCollision::getActorsHitFromAction( FFXIVARR_POSITION3 aoePosition, + std::set< CharaPtr > actorsInRange, boost::shared_ptr< Core::Data::Action > actionInfo, TargetFilter targetFilter ) { - std::set< ActorPtr > actorsCollided; + std::set< CharaPtr > actorsCollided; switch( static_cast< ActionCollisionType >( actionInfo->castType ) ) { diff --git a/src/servers/sapphire_zone/Action/ActionCollision.h b/src/servers/sapphire_zone/Action/ActionCollision.h index 0c0da597..470a31f2 100644 --- a/src/servers/sapphire_zone/Action/ActionCollision.h +++ b/src/servers/sapphire_zone/Action/ActionCollision.h @@ -4,7 +4,7 @@ #include #include -#include "Actor/Actor.h" +#include "Actor/Chara.h" #include "Action.h" namespace Core { @@ -23,9 +23,9 @@ namespace Entity { { public: - static bool isActorApplicable( Actor& actor, TargetFilter targetFilter ); - static std::set< ActorPtr > getActorsHitFromAction( Common::FFXIVARR_POSITION3 aoePosition, - std::set< ActorPtr > actorsInRange, + static bool isActorApplicable( Chara& actor, TargetFilter targetFilter ); + static std::set< CharaPtr > getActorsHitFromAction( Common::FFXIVARR_POSITION3 aoePosition, + std::set< CharaPtr > actorsInRange, boost::shared_ptr< Data::Action > actionInfo, TargetFilter targetFilter ); diff --git a/src/servers/sapphire_zone/Action/ActionMount.cpp b/src/servers/sapphire_zone/Action/ActionMount.cpp index 9ec4588e..53d72eca 100644 --- a/src/servers/sapphire_zone/Action/ActionMount.cpp +++ b/src/servers/sapphire_zone/Action/ActionMount.cpp @@ -24,7 +24,7 @@ Core::Action::ActionMount::ActionMount() m_handleActionType = HandleActionType::Event; } -Core::Action::ActionMount::ActionMount( Entity::ActorPtr pActor, uint16_t mountId ) +Core::Action::ActionMount::ActionMount( Entity::CharaPtr pActor, uint16_t mountId ) { m_startTime = 0; m_id = mountId; diff --git a/src/servers/sapphire_zone/Action/ActionMount.h b/src/servers/sapphire_zone/Action/ActionMount.h index ba32817d..3450a2b2 100644 --- a/src/servers/sapphire_zone/Action/ActionMount.h +++ b/src/servers/sapphire_zone/Action/ActionMount.h @@ -15,7 +15,7 @@ namespace Action { ActionMount(); ~ActionMount(); - ActionMount( Entity::ActorPtr pActor, uint16_t mountId ); + ActionMount( Entity::CharaPtr pActor, uint16_t mountId ); void onStart() override; void onFinish() override; diff --git a/src/servers/sapphire_zone/Action/ActionTeleport.cpp b/src/servers/sapphire_zone/Action/ActionTeleport.cpp index 6151b2cd..18c41dee 100644 --- a/src/servers/sapphire_zone/Action/ActionTeleport.cpp +++ b/src/servers/sapphire_zone/Action/ActionTeleport.cpp @@ -21,7 +21,7 @@ Core::Action::ActionTeleport::ActionTeleport() m_handleActionType = HandleActionType::Event; } -Core::Action::ActionTeleport::ActionTeleport( Entity::ActorPtr pActor, uint16_t targetZone, uint16_t cost ) +Core::Action::ActionTeleport::ActionTeleport( Entity::CharaPtr pActor, uint16_t targetZone, uint16_t cost ) { m_startTime = 0; m_id = 5; diff --git a/src/servers/sapphire_zone/Action/ActionTeleport.h b/src/servers/sapphire_zone/Action/ActionTeleport.h index 480090eb..fab98d06 100644 --- a/src/servers/sapphire_zone/Action/ActionTeleport.h +++ b/src/servers/sapphire_zone/Action/ActionTeleport.h @@ -17,7 +17,7 @@ namespace Action { ActionTeleport(); ~ActionTeleport(); - ActionTeleport( Entity::ActorPtr pActor, uint16_t action, uint16_t cost ); + ActionTeleport( Entity::CharaPtr pActor, uint16_t action, uint16_t cost ); void onStart() override; void onFinish() override; diff --git a/src/servers/sapphire_zone/Action/EventAction.cpp b/src/servers/sapphire_zone/Action/EventAction.cpp index 47b9895f..5bdef79c 100644 --- a/src/servers/sapphire_zone/Action/EventAction.cpp +++ b/src/servers/sapphire_zone/Action/EventAction.cpp @@ -21,7 +21,7 @@ Core::Action::EventAction::EventAction() m_handleActionType = HandleActionType::Event; } -Core::Action::EventAction::EventAction( Entity::ActorPtr pActor, uint32_t eventId, uint16_t action, +Core::Action::EventAction::EventAction( Entity::CharaPtr pActor, uint32_t eventId, uint16_t action, ActionCallback finishRef, ActionCallback interruptRef, uint64_t additional ) { m_additional = additional; diff --git a/src/servers/sapphire_zone/Action/EventAction.h b/src/servers/sapphire_zone/Action/EventAction.h index f0857d34..a92831ef 100644 --- a/src/servers/sapphire_zone/Action/EventAction.h +++ b/src/servers/sapphire_zone/Action/EventAction.h @@ -16,7 +16,7 @@ namespace Action { EventAction(); ~EventAction(); - EventAction( Entity::ActorPtr pActor, uint32_t eventId, uint16_t action, + EventAction( Entity::CharaPtr pActor, uint32_t eventId, uint16_t action, ActionCallback finishRef, ActionCallback interruptRef, uint64_t additional ); void onStart() override; diff --git a/src/servers/sapphire_zone/Action/EventItemAction.cpp b/src/servers/sapphire_zone/Action/EventItemAction.cpp index 28ddd8fb..742a40ae 100644 --- a/src/servers/sapphire_zone/Action/EventItemAction.cpp +++ b/src/servers/sapphire_zone/Action/EventItemAction.cpp @@ -22,7 +22,7 @@ Core::Action::EventItemAction::EventItemAction() m_handleActionType = HandleActionType::Event; } -Core::Action::EventItemAction::EventItemAction( Entity::ActorPtr pActor, uint32_t eventId, uint16_t action, +Core::Action::EventItemAction::EventItemAction( Entity::CharaPtr pActor, uint32_t eventId, uint16_t action, ActionCallback finishRef, ActionCallback interruptRef, uint64_t additional ) { m_additional = additional; diff --git a/src/servers/sapphire_zone/Action/EventItemAction.h b/src/servers/sapphire_zone/Action/EventItemAction.h index bd9eee9d..6c69e1aa 100644 --- a/src/servers/sapphire_zone/Action/EventItemAction.h +++ b/src/servers/sapphire_zone/Action/EventItemAction.h @@ -14,7 +14,7 @@ namespace Action { EventItemAction(); ~EventItemAction(); - EventItemAction( Entity::ActorPtr pActor, uint32_t eventId, uint16_t action, + EventItemAction( Entity::CharaPtr pActor, uint32_t eventId, uint16_t action, ActionCallback finishRef, ActionCallback interruptRef, uint64_t additional ); void onStart() override; diff --git a/src/servers/sapphire_zone/Actor/Actor.cpp b/src/servers/sapphire_zone/Actor/Actor.cpp index 45b076a6..5fa1cc69 100644 --- a/src/servers/sapphire_zone/Actor/Actor.cpp +++ b/src/servers/sapphire_zone/Actor/Actor.cpp @@ -1,974 +1,94 @@ -#include -#include -#include -#include -#include - -#include "Forwards.h" -#include "Action/Action.h" - -#include "Zone/Zone.h" - -#include "Network/GameConnection.h" -#include "Network/PacketWrappers/ActorControlPacket142.h" -#include "Network/PacketWrappers/ActorControlPacket143.h" -#include "Network/PacketWrappers/ActorControlPacket144.h" -#include "Network/PacketWrappers/UpdateHpMpTpPacket.h" - -#include "StatusEffect/StatusEffect.h" -#include "Action/ActionCollision.h" -#include "ServerZone.h" -#include "Session.h" -#include "Math/CalcBattle.h" #include "Actor.h" + #include "Player.h" -#include "Zone/TerritoryMgr.h" - -extern Core::ServerZone g_serverZone; -extern Core::Data::ExdDataGenerated g_exdDataGen; -extern Core::TerritoryMgr g_territoryMgr; - -using namespace Core::Common; -using namespace Core::Network::Packets; -using namespace Core::Network::Packets::Server; +#include "Chara.h" +#include "BattleNpc.h" +#include "EventNpc.h" Core::Entity::Actor::Actor( ObjKind type ) : - GameObject( type ) + m_objKind( type ) { - // initialize the free slot queue - for( uint8_t i = 0; i < MAX_STATUS_EFFECTS; i++ ) - { - m_statusEffectFreeSlotQueue.push( i ); - } -} - -Core::Entity::Actor::~Actor() -{ -} - -/*! \return the actors name */ -std::string Core::Entity::Actor::getName() const -{ - return std::string( m_name ); -} - -/*! \return list of actors currently in range */ -std::set< Core::Entity::ActorPtr > Core::Entity::Actor::getInRangeActors( bool includeSelf ) -{ - auto tempInRange = m_inRangeActors; - - if( includeSelf ) - tempInRange.insert( getAsActor() ); - - return tempInRange; - } - -/*! \return current stance of the actors */ -Core::Entity::Actor::Stance Core::Entity::Actor::getStance() const -{ - return m_currentStance; -} - -/*! \return actor stats */ -Core::Entity::Actor::ActorStats Core::Entity::Actor::getStats() const -{ - return m_baseStats; -} - -/*! \return current HP */ -uint32_t Core::Entity::Actor::getHp() const -{ - return m_hp; -} - -/*! \return current MP */ -uint32_t Core::Entity::Actor::getMp() const -{ - return m_mp; -} - -/*! \return current TP */ -uint16_t Core::Entity::Actor::getTp() const -{ - return m_tp; -} - -/*! \return current GP */ -uint16_t Core::Entity::Actor::getGp() const -{ - return m_gp; -} - -/*! \return current invincibility type */ -InvincibilityType Core::Entity::Actor::getInvincibilityType() const -{ - return m_invincibilityType; -} - -/*! \return current class or job */ -Core::Common::ClassJob Core::Entity::Actor::getClass() const -{ - return m_class; -} - -/*! \return current class or job as int32_t ( this feels pointless ) */ -uint8_t Core::Entity::Actor::getClassAsInt() const -{ - return static_cast< uint8_t >( m_class ); -} - -/*! \param ClassJob to set */ -void Core::Entity::Actor::setClass( Common::ClassJob classJob ) -{ - m_class = classJob; -} - -/*! \param Id of the target to set */ -void Core::Entity::Actor::setTargetId( uint64_t targetId ) -{ - m_targetId = targetId; -} - -/*! \return Id of the current target */ -uint64_t Core::Entity::Actor::getTargetId() const -{ - return m_targetId; -} - -/*! \return True if the actor is alive */ -bool Core::Entity::Actor::isAlive() const -{ - return ( m_hp > 0 ); -} - -/*! \return max hp for the actor */ -uint32_t Core::Entity::Actor::getMaxHp() const -{ - return m_baseStats.max_hp; -} - -/*! \return max mp for the actor */ -uint32_t Core::Entity::Actor::getMaxMp() const -{ - return m_baseStats.max_mp; -} - -/*! \return reset hp to current max hp */ -void Core::Entity::Actor::resetHp() -{ - m_hp = getMaxHp(); - sendStatusUpdate( true ); -} - -/*! \return reset mp to current max mp */ -void Core::Entity::Actor::resetMp() -{ - m_mp = getMaxMp(); - sendStatusUpdate( true ); -} - -/*! \param hp amount to set ( caps to maxHp ) */ -void Core::Entity::Actor::setHp( uint32_t hp ) -{ - m_hp = hp < getMaxHp() ? hp : getMaxHp(); - sendStatusUpdate( true ); -} - -/*! \param mp amount to set ( caps to maxMp ) */ -void Core::Entity::Actor::setMp( uint32_t mp ) -{ - m_mp = mp < getMaxMp() ? mp : getMaxMp(); - sendStatusUpdate( true ); -} - -/*! \param gp amount to set*/ -void Core::Entity::Actor::setGp( uint32_t gp ) -{ - m_gp = gp; - sendStatusUpdate( true ); -} - -/*! \param type invincibility type to set */ -void Core::Entity::Actor::setInvincibilityType( Common::InvincibilityType type ) -{ - m_invincibilityType = type; -} - -/*! \return current status of the actor */ -Core::Entity::Actor::ActorStatus Core::Entity::Actor::getStatus() const -{ - return m_status; -} - -/*! \param status to set */ -void Core::Entity::Actor::setStatus( ActorStatus status ) -{ - m_status = status; -} - -/*! -Performs necessary steps to mark an actor dead. -Sets hp/mp/tp, sets status, plays animation and fires onDeath event -*/ -void Core::Entity::Actor::die() -{ - m_status = ActorStatus::Dead; - m_hp = 0; - m_mp = 0; - m_tp = 0; - - // fire onDeath event - onDeath(); - - // if the actor is a player, the update needs to be send to himself too - bool selfNeedsUpdate = isPlayer(); - - sendToInRangeSet( ActorControlPacket142( m_id, SetStatus, static_cast< uint8_t >( ActorStatus::Dead ) ), selfNeedsUpdate ); - - // TODO: not all actor show the death animation when they die, some quest npcs might just despawn - // although that might be handled by setting the HP to 1 and doing some script magic - sendToInRangeSet( ActorControlPacket142( m_id, DeathAnimation, 0, 0, 0, 0x20 ), selfNeedsUpdate ); } -/*! -Calculates and sets the rotation to look towards a specified -position - -\param Position to look towards -*/ -bool Core::Entity::Actor::face( const Common::FFXIVARR_POSITION3& p ) +uint32_t Core::Entity::Actor::getId() const { - float oldRot = getRotation(); - float rot = Math::Util::calcAngFrom( getPos().x, getPos().z, p.x, p.z ); - float newRot = PI - rot + ( PI / 2 ); - - m_pCell = nullptr; - - setRotation( newRot ); - - return oldRot != newRot ? true : false; + return m_id; } -/*! -Sets the actors position and notifies the zone to propagate the change - -\param Position to set -*/ -void Core::Entity::Actor::setPosition( const Common::FFXIVARR_POSITION3& pos ) +Core::Entity::Actor::ObjKind Core::Entity::Actor::getObjKind() const { - m_pos = pos; - m_pCurrentZone->updateActorPosition( *this ); + return m_objKind; } -void Core::Entity::Actor::setPosition( float x, float y, float z ) +Core::Common::FFXIVARR_POSITION3& Core::Entity::Actor::getPos() +{ + return m_pos; +} + +void Core::Entity::Actor::setPos( float x, float y, float z ) { m_pos.x = x; m_pos.y = y; m_pos.z = z; - m_pCurrentZone->updateActorPosition( *this ); } -/*! -Set and propagate the actor stance to in range players -( not the actor himself ) - -\param stance to set -*/ -void Core::Entity::Actor::setStance( Stance stance ) +void Core::Entity::Actor::setPos( const Core::Common::FFXIVARR_POSITION3& pos ) { - m_currentStance = stance; - - sendToInRangeSet( ActorControlPacket142( m_id, ToggleAggro, stance, 1 ) ); + m_pos = pos; } -/*! -Check if an action is queued for execution, if so update it -and if fully performed, clean up again. - -\return true if a queued action has been updated -*/ -bool Core::Entity::Actor::checkAction() -{ - - if( m_pCurrentAction == nullptr ) - return false; - - if( m_pCurrentAction->update() ) - m_pCurrentAction.reset(); - - return true; - -} - -/*! -Change the current target and propagate to in range players - -\param target actor id -*/ -void Core::Entity::Actor::changeTarget( uint64_t targetId ) -{ - setTargetId( targetId ); - sendToInRangeSet( ActorControlPacket144( m_id, SetTarget, 0, 0, 0, 0, targetId ) ); -} - -/*! -Dummy function \return 0 -*/ -uint8_t Core::Entity::Actor::getLevel() const -{ - return 0; -} - -/*! -Let an actor take damage and perform necessary steps -according to resulting hp, propagates new hp value to players -in range -TODO: eventually this needs to distinguish between physical and -magical dmg and take status effects into account - -\param amount of damage to be taken -*/ -void Core::Entity::Actor::takeDamage( uint32_t damage ) -{ - if( damage >= m_hp ) - { - switch( m_invincibilityType ) { - case InvincibilityNone: - setHp( 0 ); - die(); - break; - case InvincibilityRefill: - resetHp(); - break; - case InvincibilityStayAlive: - setHp( 0 ); - break; - } - } - else - m_hp -= damage; - - sendStatusUpdate( false ); -} - -/*! -Let an actor get healed and perform necessary steps -according to resulting hp, propagates new hp value to players -in range - -\param amount of hp to be healed -*/ -void Core::Entity::Actor::heal( uint32_t amount ) -{ - if( ( m_hp + amount ) > getMaxHp() ) - { - m_hp = getMaxHp(); - } - else - m_hp += amount; - - sendStatusUpdate( false ); -} - -/*! -Send an HpMpTp update to players in range ( and potentially to self ) -TODO: poor naming, should be changed. Status is not HP. Also should be virtual -so players can have their own version and we can abolish the param. - -\param true if the update should also be sent to the actor ( player ) himself -*/ -void Core::Entity::Actor::sendStatusUpdate( bool toSelf ) -{ - UpdateHpMpTpPacket updateHpPacket( *this ); - sendToInRangeSet( updateHpPacket ); -} - -/*! \return ActionPtr of the currently registered action, or nullptr */ -Core::Action::ActionPtr Core::Entity::Actor::getCurrentAction() const -{ - return m_pCurrentAction; -} - -/*! \param ActionPtr of the action to be registered */ -void Core::Entity::Actor::setCurrentAction( Core::Action::ActionPtr pAction ) -{ - m_pCurrentAction = pAction; -} - -/*! -check if a given actor is in the actors in range set - -\param ActorPtr to be checked for -\return true if the actor was found -*/ -bool Core::Entity::Actor::isInRangeSet( ActorPtr pActor ) const -{ - return !( m_inRangeActors.find( pActor ) == m_inRangeActors.end() ); -} - -/*! \return ActorPtr of the closest actor in range, if none, nullptr */ -Core::Entity::ActorPtr Core::Entity::Actor::getClosestActor() -{ - if( m_inRangeActors.empty() ) - // no actors in range, don't bother - return nullptr; - - ActorPtr tmpActor = nullptr; - - // arbitrary high number - float minDistance = 10000; - - for( const auto& pCurAct : m_inRangeActors ) - { - float distance = Math::Util::distance( getPos().x, - getPos().y, - getPos().z, - pCurAct->getPos().x, - pCurAct->getPos().y, - pCurAct->getPos().z ); - - if( distance < minDistance ) - { - minDistance = distance; - tmpActor = pCurAct; - } - } - - return tmpActor; -} - -/*! -Send a packet to all players in range, potentially to self if set and is player - -\param GamePacketPtr to send -\param bool should be send to self? -*/ -void Core::Entity::Actor::sendToInRangeSet( Network::Packets::GamePacketPtr pPacket, bool bToSelf ) -{ - - if( bToSelf && isPlayer() ) - { - auto pPlayer = getAsPlayer(); - - auto pSession = g_serverZone.getSession( pPlayer->getId() ); - - // it might be that the player DC'd in which case the session would be invalid - if( pSession ) - pSession->getZoneConnection()->queueOutPacket( pPacket ); - } - - if( m_inRangePlayers.empty() ) - return; - - for( const auto &pCurAct : m_inRangePlayers ) - { - assert( pCurAct ); - pPacket->setValAt< uint32_t >( 0x04, m_id ); - pPacket->setValAt< uint32_t >( 0x08, pCurAct->m_id ); - // it might be that the player DC'd in which case the session would be invalid - pCurAct->queuePacket( pPacket ); - } -} - -/*! -Add a given actor to the fitting in range set according to type -but also to the global actor map - -\param ActorPtr to add -*/ -void Core::Entity::Actor::addInRangeActor( ActorPtr pActor ) -{ - - // if this is null, something went wrong - assert( pActor ); - - // add actor to in range set - m_inRangeActors.insert( pActor ); - - if( pActor->isPlayer() ) - { - auto pPlayer = pActor->getAsPlayer(); - - // if actor is a player, add it to the in range player set - m_inRangePlayers.insert( pPlayer ); - } -} - -/*! -Remove a given actor from the matching in range set according to type -but also to the global actor map - -\param ActorPtr to remove -*/ -void Core::Entity::Actor::removeInRangeActor( Actor& actor ) -{ - // call virtual event - onRemoveInRangeActor( actor ); - - // remove actor from in range actor set - m_inRangeActors.erase( actor.getAsActor() ); - - // if actor is a player, despawn ourself for him - // TODO: move to virtual onRemove? - if( isPlayer() ) - actor.despawn( getAsPlayer() ); - - if( actor.isPlayer() ) - m_inRangePlayers.erase( actor.getAsPlayer() ); -} - -/*! \return true if there is at least one actor in the in range set */ -bool Core::Entity::Actor::hasInRangeActor() const -{ - return ( m_inRangeActors.size() > 0 ); -} - -void Core::Entity::Actor::removeFromInRange() -{ - if( !hasInRangeActor() ) - return; - - Entity::ActorPtr pCurAct; - - for( auto& pCurAct : m_inRangeActors ) - { - pCurAct->removeInRangeActor( *this ); - } - -} - -/*! Clear the whole in range set, this does no cleanup */ -void Core::Entity::Actor::clearInRangeSet() -{ - m_inRangeActors.clear(); - m_inRangePlayers.clear(); -} - -/*! \return ZonePtr to the current zone, nullptr if not set */ -Core::ZonePtr Core::Entity::Actor::getCurrentZone() const -{ - return m_pCurrentZone; -} - -/*! \param ZonePtr to the zone to be set as current */ -void Core::Entity::Actor::setCurrentZone( ZonePtr currZone ) -{ - m_pCurrentZone = currZone; -} - -/*! -Get the current cell of a region the actor is in - -\return Cell* -*/ -Core::Cell * Core::Entity::Actor::getCell() const -{ - return m_pCell; -} - -/*! -Set the current cell the actor is in - -\param Cell* for the cell to be set -*/ -void Core::Entity::Actor::setCell( Cell * pCell ) -{ - m_pCell = pCell; -} - -/*! -Autoattack prototype implementation -TODO: move the check if the autoAttack can be performed to the callee -also rename autoAttack to autoAttack as that is more elaborate -On top of that, this only solves attacks from melee classes. -Will have to be extended for ranged attacks. - -\param ActorPtr the autoAttack is performed on -*/ -void Core::Entity::Actor::autoAttack( ActorPtr pTarget ) -{ - - uint64_t tick = Util::getTimeMs(); - - if( ( tick - m_lastAttack ) > 2500 ) - { - pTarget->onActionHostile( *this ); - m_lastAttack = tick; - srand( static_cast< uint32_t >( tick ) ); - - uint16_t damage = static_cast< uint16_t >( 10 + rand() % 12 ); - uint32_t variation = static_cast< uint32_t >( 0 + rand() % 4 ); - - ZoneChannelPacket< FFXIVIpcEffect > effectPacket( getId() ); - effectPacket.data().targetId = pTarget->getId(); - effectPacket.data().actionAnimationId = 0x366; - effectPacket.data().unknown_2 = variation; -// effectPacket.data().unknown_3 = 1; - effectPacket.data().actionTextId = 0x366; - effectPacket.data().numEffects = 1; - effectPacket.data().rotation = Math::Util::floatToUInt16Rot( getRotation() ); - effectPacket.data().effectTarget = pTarget->getId(); - effectPacket.data().effects[0].value = damage; - effectPacket.data().effects[0].effectType = ActionEffectType::Damage; - effectPacket.data().effects[0].hitSeverity = static_cast< ActionHitSeverityType >( variation ); - effectPacket.data().effects[0].unknown_3 = 7; - - sendToInRangeSet( effectPacket ); - - if( this->isPlayer() ) - this->getAsPlayer()->queuePacket( effectPacket ); - - pTarget->takeDamage( damage ); - } -} - -/*! -ChaiScript Skill Handler. - -\param GamePacketPtr to send -\param bool should be send to self? -*/ -void Core::Entity::Actor::handleScriptSkill( uint32_t type, uint16_t actionId, uint64_t param1, - uint64_t param2, Entity::Actor& target ) -{ - - if( isPlayer() ) - { - getAsPlayer()->sendDebug( std::to_string( target.getId() ) ); - getAsPlayer()->sendDebug( "Handle script skill type: " + std::to_string( type ) ); - } - - auto actionInfoPtr = g_exdDataGen.get< Core::Data::Action >( actionId ); - - // Todo: Effect packet generator. 90% of this is basically setting params and it's basically unreadable. - // Prepare packet. This is seemingly common for all packets in the action handler. - - ZoneChannelPacket< FFXIVIpcEffect > effectPacket( getId() ); - effectPacket.data().targetId = target.getId(); - effectPacket.data().actionAnimationId = actionId; - effectPacket.data().unknown_62 = 1; // Affects displaying action name next to number in floating text - effectPacket.data().unknown_2 = 1; // This seems to have an effect on the "double-cast finish" animation - effectPacket.data().actionTextId = actionId; - effectPacket.data().numEffects = 1; - effectPacket.data().rotation = Math::Util::floatToUInt16Rot( getRotation() ); - effectPacket.data().effectTarget = target.getId(); - - // Todo: for each actor, calculate how much damage the calculated value should deal to them - 2-step damage calc. we only have 1-step - switch( type ) - { - - case ActionEffectType::Damage: - { - effectPacket.data().effects[0].value = static_cast< uint16_t >( param1 ); - effectPacket.data().effects[0].effectType = ActionEffectType::Damage; - effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalDamage; - effectPacket.data().effects[0].unknown_3 = 7; - - if( actionInfoPtr->castType == 1 && actionInfoPtr->effectRange != 0 || actionInfoPtr->castType != 1 ) - { - // If action on this specific target is valid... - if ( isPlayer() && !ActionCollision::isActorApplicable( target, TargetFilter::Enemies ) ) - break; - - sendToInRangeSet( effectPacket, true ); - - if ( target.isAlive() ) - target.onActionHostile( *this ); - - target.takeDamage( static_cast< uint32_t >( param1 ) ); - - } - else - { - - auto actorsCollided = ActionCollision::getActorsHitFromAction( target.getPos(), getInRangeActors( true ), - actionInfoPtr, TargetFilter::Enemies ); - - for( const auto& pHitActor : actorsCollided ) - { - effectPacket.data().targetId = pHitActor->getId(); - effectPacket.data().effectTarget = pHitActor->getId(); - - // todo: send to range of what? ourselves? when mob script hits this is going to be lacking - sendToInRangeSet( effectPacket, true ); - - - if( pHitActor->isAlive() ) - pHitActor->onActionHostile( *this ); - - pHitActor->takeDamage( static_cast< uint32_t >( param1 ) ); - - // Debug - if ( isPlayer() ) - { - if ( pHitActor->isPlayer() ) - getAsPlayer()->sendDebug( "AoE hit actor " + std::to_string( pHitActor->getId() ) + " (" + pHitActor->getName() + ")" ); - else - getAsPlayer()->sendDebug( "AoE hit actor " + std::to_string( pHitActor->getId() ) ); - } - } - } - - break; - } - - case ActionEffectType::Heal: - { - uint32_t calculatedHeal = Math::CalcBattle::calculateHealValue( getAsPlayer(), static_cast< uint32_t >( param1 ) ); - - effectPacket.data().effects[0].value = calculatedHeal; - effectPacket.data().effects[0].effectType = ActionEffectType::Heal; - effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalHeal; - - if( actionInfoPtr->castType == 1 && actionInfoPtr->effectRange != 0 || actionInfoPtr->castType != 1 ) - { - if( isPlayer() && !ActionCollision::isActorApplicable( target, TargetFilter::Allies ) ) - break; - - sendToInRangeSet( effectPacket, true ); - target.heal( calculatedHeal ); - } - else - { - // todo: get proper packets: the following was just kind of thrown together from what we know. - // atm buggy (packets look "delayed" from client) - - auto actorsCollided = ActionCollision::getActorsHitFromAction( target.getPos(), getInRangeActors( true ), - actionInfoPtr, TargetFilter::Allies ); - - for( auto pHitActor : actorsCollided ) - { - effectPacket.data().targetId = target.getId(); - effectPacket.data().effectTarget = pHitActor->getId(); - - sendToInRangeSet( effectPacket, true ); - pHitActor->heal( calculatedHeal ); - - // Debug - if( isPlayer() ) - { - if( pHitActor->isPlayer() ) - getAsPlayer()->sendDebug( "AoE hit actor " + std::to_string( pHitActor->getId() ) + " (" + pHitActor->getName() + ")" ); - else - getAsPlayer()->sendDebug( "AoE hit actor " + std::to_string( pHitActor->getId() ) ); - } - } - } - break; - } - - default: - break; - } -} - -/*! \param StatusEffectPtr to be applied to the actor */ -void Core::Entity::Actor::addStatusEffect( StatusEffect::StatusEffectPtr pEffect ) -{ - int8_t nextSlot = getStatusEffectFreeSlot(); - // if there is no slot left, do not add the effect - if( nextSlot == -1 ) - return; - - pEffect->applyStatus(); - m_statusEffectMap[nextSlot] = pEffect; - - ZoneChannelPacket< Server::FFXIVIpcAddStatusEffect > statusEffectAdd( getId() ); - statusEffectAdd.data().actor_id = pEffect->getTargetActorId(); - statusEffectAdd.data().actor_id1 = pEffect->getSrcActorId(); - statusEffectAdd.data().current_hp = getHp(); - statusEffectAdd.data().current_mp = getMp(); - statusEffectAdd.data().current_tp = getTp(); - statusEffectAdd.data().duration = static_cast< float >( pEffect->getDuration() ) / 1000; - statusEffectAdd.data().effect_id = pEffect->getId(); - statusEffectAdd.data().effect_index = nextSlot; - statusEffectAdd.data().max_hp = getMaxHp(); - statusEffectAdd.data().max_mp = getMaxMp(); - statusEffectAdd.data().max_something = 1; - //statusEffectAdd.data().unknown2 = 28; - statusEffectAdd.data().param = pEffect->getParam(); - - sendToInRangeSet( statusEffectAdd, isPlayer() ); -} - -/*! \param StatusEffectPtr to be applied to the actor */ -void Core::Entity::Actor::addStatusEffectById( uint32_t id, int32_t duration, Entity::Actor& source, uint16_t param ) -{ - auto effect = StatusEffect::make_StatusEffect( id, source.getAsActor(), getAsActor(), duration, 3000 ); - effect->setParam( param ); - addStatusEffect( effect ); -} - -/*! \param StatusEffectPtr to be applied to the actor */ -void Core::Entity::Actor::addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Actor& source, uint16_t param ) -{ - if( hasStatusEffect( id ) ) - return; - - auto effect = StatusEffect::make_StatusEffect( id, source.getAsActor(), getAsActor(), duration, 3000 ); - effect->setParam( param ); - addStatusEffect( effect ); - -} - -float Core::Entity::Actor::getRotation() const +float Core::Entity::Actor::getRot() const { return m_rot; } -void Core::Entity::Actor::setRotation( float rot ) +void Core::Entity::Actor::setRot( float rot ) { m_rot = rot; } -int8_t Core::Entity::Actor::getStatusEffectFreeSlot() +bool Core::Entity::Actor::isPlayer() const { - int8_t freeEffectSlot = -1; - - if( m_statusEffectFreeSlotQueue.empty() ) - return freeEffectSlot; - - freeEffectSlot = m_statusEffectFreeSlotQueue.front(); - m_statusEffectFreeSlotQueue.pop(); - - return freeEffectSlot; + return m_objKind == ObjKind::Player; } -void Core::Entity::Actor::statusEffectFreeSlot( uint8_t slotId ) +bool Core::Entity::Actor::isBattleNpc() const { - m_statusEffectFreeSlotQueue.push( slotId ); + return m_objKind == ObjKind::BattleNpc; } -void Core::Entity::Actor::removeSingleStatusEffectById( uint32_t id ) +bool Core::Entity::Actor::isEventNpc() const { - for( auto effectIt : m_statusEffectMap ) - { - if( effectIt.second->getId() == id ) - { - removeStatusEffect( effectIt.first ); - break; - } - } + return m_objKind == ObjKind::EventNpc; } -void Core::Entity::Actor::removeStatusEffect( uint8_t effectSlotId ) +/*! \return pointer to this instance as ActorPtr */ +Core::Entity::CharaPtr Core::Entity::Actor::getAsChara() { - auto pEffectIt = m_statusEffectMap.find( effectSlotId ); - if( pEffectIt == m_statusEffectMap.end() ) - return; - - statusEffectFreeSlot( effectSlotId ); - - auto pEffect = pEffectIt->second; - pEffect->removeStatus(); - - sendToInRangeSet( ActorControlPacket142( getId(), StatusEffectLose, pEffect->getId() ), isPlayer() ); - - m_statusEffectMap.erase( effectSlotId ); - - sendStatusEffectUpdate(); + return boost::dynamic_pointer_cast< Entity::Chara, Entity::Actor >( shared_from_this() ); } -std::map< uint8_t, Core::StatusEffect::StatusEffectPtr > Core::Entity::Actor::getStatusEffectMap() const +/*! \return pointer to this instance as PlayerPtr */ +Core::Entity::PlayerPtr Core::Entity::Actor::getAsPlayer() { - return m_statusEffectMap; + if( !isPlayer() ) + return nullptr; + return boost::dynamic_pointer_cast< Entity::Player, Entity::Actor >( shared_from_this() ); } -void Core::Entity::Actor::sendStatusEffectUpdate() +/*! \return pointer to this instance as BattleNpcPtr */ +Core::Entity::BattleNpcPtr Core::Entity::Actor::getAsBattleNpc() { - uint64_t currentTimeMs = Util::getTimeMs(); - - ZoneChannelPacket< Server::FFXIVIpcStatusEffectList > statusEffectList( getId() ); - - statusEffectList.data().current_hp = getHp(); - statusEffectList.data().current_mp = getMp(); - statusEffectList.data().currentTp = getTp(); - statusEffectList.data().max_hp = getMaxHp(); - statusEffectList.data().max_mp = getMaxMp(); - uint8_t slot = 0; - for( auto effectIt : m_statusEffectMap ) - { - float timeLeft = static_cast< float >( effectIt.second->getDuration() - - ( currentTimeMs - effectIt.second->getStartTimeMs() ) ) / 1000; - statusEffectList.data().effect[slot].duration = timeLeft; - statusEffectList.data().effect[slot].effect_id = effectIt.second->getId(); - statusEffectList.data().effect[slot].sourceActorId = effectIt.second->getSrcActorId(); - slot++; - } - - sendToInRangeSet( statusEffectList, isPlayer() ); - + if( !isBattleNpc() ) + return nullptr; + return boost::dynamic_pointer_cast< Entity::BattleNpc, Entity::Actor >( shared_from_this() ); } -void Core::Entity::Actor::updateStatusEffects() +/*! \return pointer to this instance as EventNpcPtr */ +Core::Entity::EventNpcPtr Core::Entity::Actor::getAsEventNpc() { - uint64_t currentTimeMs = Util::getTimeMs(); - - uint32_t thisTickDmg = 0; - uint32_t thisTickHeal = 0; - - for( auto effectIt : m_statusEffectMap ) - { - uint8_t effectIndex = effectIt.first; - auto effect = effectIt.second; - - uint64_t lastTick = effect->getLastTickMs(); - uint64_t startTime = effect->getStartTimeMs(); - uint32_t duration = effect->getDuration(); - uint32_t tickRate = effect->getTickRate(); - - if( ( currentTimeMs - startTime ) > duration ) - { - // remove status effect - removeStatusEffect( effectIndex ); - // break because removing invalidates iterators - break; - } - - if( ( currentTimeMs - lastTick ) > tickRate ) - { - effect->setLastTick( currentTimeMs ); - effect->onTick(); - - auto thisEffect = effect->getTickEffect(); - - switch( thisEffect.first ) - { - - case 1: - { - thisTickDmg += thisEffect.second; - break; - } - - case 2: - { - thisTickHeal += thisEffect.second; - break; - } - - } - } - - } - - if( thisTickDmg != 0 ) - { - takeDamage( thisTickDmg ); - sendToInRangeSet( ActorControlPacket142( getId(), HPFloatingText, 0, static_cast< uint8_t >( ActionEffectType::Damage ), thisTickDmg ) ); - } - - if( thisTickHeal != 0 ) - { - heal( thisTickDmg ); - sendToInRangeSet( ActorControlPacket142( getId(), HPFloatingText, 0, static_cast< uint8_t >( ActionEffectType::Heal ), thisTickHeal ) ); - } -} - -bool Core::Entity::Actor::hasStatusEffect( uint32_t id ) -{ - if( m_statusEffectMap.find( id ) != m_statusEffectMap.end() ) - return true; - return false; + if( !isEventNpc() ) + return nullptr; + return boost::dynamic_pointer_cast< Entity::EventNpc, Entity::Actor >( shared_from_this() ); } diff --git a/src/servers/sapphire_zone/Actor/Actor.h b/src/servers/sapphire_zone/Actor/Actor.h index cb2142af..ccd5996c 100644 --- a/src/servers/sapphire_zone/Actor/Actor.h +++ b/src/servers/sapphire_zone/Actor/Actor.h @@ -1,11 +1,10 @@ -#ifndef _ACTOR_H_ -#define _ACTOR_H_ +#ifndef _GAME_OBJECT_H_ +#define _GAME_OBJECT_H_ #include #include #include "Forwards.h" -#include "GameObject.h" #include #include #include @@ -14,282 +13,70 @@ namespace Core { namespace Entity { /*! -\class Actor -\brief Base class for all actors +\class GameObject +\brief Base class for all actor/objects */ -class Actor : public GameObject -{ -public: - enum Stance : uint8_t + class Actor : public boost::enable_shared_from_this< Actor > { - Passive = 0, - Active = 1, + public: + enum ObjKind : uint8_t + { + None = 0x00, + Player = 0x01, + BattleNpc = 0x02, + EventNpc = 0x03, + Treasure = 0x04, + Aetheryte = 0x05, + GatheringPoint = 0x06, + EventObj = 0x07, + Mount = 0x08, + Companion = 0x09, + Retainer = 0x0A, + Area = 0x0B, + Housing = 0x0C, + Cutscene = 0x0D, + CardStand = 0x0E, + }; + + protected: + /*! Position of the object */ + Common::FFXIVARR_POSITION3 m_pos; + /*! Rotation of the object */ + float m_rot; + /*! Id of the actor */ + uint32_t m_id; + /*! Type of the actor */ + ObjKind m_objKind; + + public: + explicit Actor( ObjKind type ); + virtual ~Actor() {}; + + virtual void spawn( PlayerPtr pTarget ) {} + virtual void despawn( PlayerPtr pTarget ) {} + + uint32_t getId() const; + + ObjKind getObjKind() const; + + Common::FFXIVARR_POSITION3& getPos(); + void setPos( const Common::FFXIVARR_POSITION3& pos ); + void setPos( float x, float y, float z ); + + float getRot() const; + void setRot( float rot ); + + bool isPlayer() const; + bool isBattleNpc() const; + bool isEventNpc() const; + + CharaPtr getAsChara(); + PlayerPtr getAsPlayer(); + BattleNpcPtr getAsBattleNpc(); + EventNpcPtr getAsEventNpc(); }; - enum DisplayFlags : uint16_t - { - ActiveStance = 0x001, - Invisible = 0x020, - HideHead = 0x040, - HideWeapon = 0x080, - Faded = 0x100, - Visor = 0x800, - }; - - enum struct ActorStatus : uint8_t - { - Idle = 0x01, - Dead = 0x02, - Sitting = 0x03, - Mounted = 0x04, - Crafting = 0x05, - Gathering = 0x06, - Melding = 0x07, - SMachine = 0x08 - }; - - struct ActorStats - { - uint32_t max_mp = 0; - uint32_t max_hp = 0; - - uint32_t str = 0; - uint32_t dex = 0; - uint32_t vit = 0; - uint32_t inte = 0; - uint32_t mnd = 0; - uint32_t pie = 0; - - uint32_t tenacity = 0; - uint32_t attack = 0; - uint32_t defense = 0; - uint32_t accuracy = 0; - uint32_t spellSpeed = 0; - uint32_t magicDefense = 0; - uint32_t critHitRate = 0; - uint32_t resistSlash = 0; - uint32_t resistPierce = 0; - uint32_t resistBlunt = 0; - uint32_t attackPotMagic = 0; - uint32_t healingPotMagic = 0; - uint32_t determination = 0; - uint32_t skillSpeed = 0; - - uint32_t resistSlow = 0; - uint32_t resistSilence = 0; - uint32_t resistBlind = 0; - uint32_t resistPoison = 0; - uint32_t resistStun = 0; - uint32_t resistSleep = 0; - uint32_t resistBind = 0; - uint32_t resistHeavy = 0; - - uint32_t resistFire = 0; - uint32_t resistIce = 0; - uint32_t resistWind = 0; - uint32_t resistEarth = 0; - uint32_t resistLightning = 0; - uint32_t resistWater = 0; - - } m_baseStats; - -protected: - char m_name[34]; - /*! Id of the zone the actor currently is in */ - uint32_t m_zoneId; - /*! Ptr to the ZoneObj the actor belongs to */ - ZonePtr m_pCurrentZone; - /*! Last tick time for the actor ( in ms ) */ - uint64_t m_lastTickTime; - /*! Last time the actor performed an autoAttack ( in ms ) */ - uint64_t m_lastAttack; - /*! Last time the actor was updated ( in ms ) */ - uint64_t m_lastUpdate; - /*! Current stance of the actor */ - Stance m_currentStance; - /*! Current staus of the actor */ - ActorStatus m_status; - /*! Max HP of the actor ( based on job / class ) */ - uint32_t m_maxHp; - /*! Max MP of the actor ( based on job / class ) */ - uint32_t m_maxMp; - /*! Current HP of the actor */ - uint32_t m_hp; - /*! Current MP of the actor */ - uint32_t m_mp; - /*! Current TP of the actor */ - uint16_t m_tp; - /*! Current GP of the actor */ - uint16_t m_gp; - /*! Additional look info of the actor */ - uint8_t m_customize[26]; - /*! Current class of the actor */ - Common::ClassJob m_class; - /*! Id of the currently selected target actor */ - uint64_t m_targetId; - /*! Ptr to a queued action */ - Action::ActionPtr m_pCurrentAction; - /*! Invincibility type */ - Common::InvincibilityType m_invincibilityType; - - /*! Status effects */ - const uint8_t MAX_STATUS_EFFECTS = 30; - std::queue< uint8_t > m_statusEffectFreeSlotQueue; - std::vector< std::pair< uint8_t, uint32_t> > m_statusEffectList; - std::map< uint8_t, StatusEffect::StatusEffectPtr > m_statusEffectMap; - - std::set< ActorPtr > m_inRangeActors; - std::set< PlayerPtr > m_inRangePlayers; - -public: - Actor( ObjKind type ); - - virtual ~Actor() override; - - virtual void calculateStats() {}; - - /// Status effect functions - void addStatusEffect( StatusEffect::StatusEffectPtr pEffect ); - void removeStatusEffect( uint8_t effectSlotId ); - void removeSingleStatusEffectById( uint32_t id ); - void updateStatusEffects(); - - bool hasStatusEffect( uint32_t id ); - - int8_t getStatusEffectFreeSlot(); - void statusEffectFreeSlot( uint8_t slotId ); - - std::map< uint8_t, Core::StatusEffect::StatusEffectPtr > getStatusEffectMap() const; - - void sendStatusEffectUpdate(); - // add a status effect by id - void addStatusEffectById( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param = 0 ); - - // add a status effect by id if it doesn't exist - void addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Actor& pSource, uint16_t param = 0 ); - - // remove a status effect by id - void removeSingleStatusEffectFromId( uint32_t id ); - /// End Status Effect Functions - - void setPosition( const Common::FFXIVARR_POSITION3& pos ); - void setPosition( float x, float y, float z ); - - void setRotation( float rot ); - - float getRotation() const; - - std::string getName() const; - - std::set< ActorPtr > getInRangeActors( bool includeSelf = false ); - - bool face( const Common::FFXIVARR_POSITION3& p ); - - Stance getStance() const; - - void setStance( Stance stance ); - - ActorStats getStats() const; - - uint32_t getHp() const; - uint32_t getMp() const; - uint16_t getTp() const; - uint16_t getGp() const; - - Common::InvincibilityType getInvincibilityType() const; - - Common::ClassJob getClass() const; - - uint8_t getClassAsInt() const; - - void setClass( Common::ClassJob classJob ); - - void setTargetId( uint64_t targetId ); - - uint64_t getTargetId() const; - - bool isAlive() const; - - virtual uint32_t getMaxHp() const; - virtual uint32_t getMaxMp() const; - - void resetHp(); - void resetMp(); - - void setHp( uint32_t hp ); - void setMp( uint32_t mp ); - void setGp( uint32_t gp ); - - void setInvincibilityType( Common::InvincibilityType type ); - - void die(); - - ActorStatus getStatus() const; - - void setStatus( ActorStatus status ); - - void handleScriptSkill( uint32_t type, uint16_t actionId, uint64_t param1, uint64_t param2, Entity::Actor& target ); - - virtual void autoAttack( ActorPtr pTarget ); - - virtual void onRemoveInRangeActor( Actor& pActor ) {} - - virtual void onDeath() {}; - virtual void onDamageTaken( Actor& pSource ) {}; - virtual void onActionHostile( Actor& source ) {}; - virtual void onActionFriendly( Actor& pSource ) {}; - virtual void onTick() {}; - - virtual void changeTarget( uint64_t targetId ); - virtual uint8_t getLevel() const; - virtual void sendStatusUpdate( bool toSelf = true ); - virtual void takeDamage( uint32_t damage ); - virtual void heal( uint32_t amount ); - virtual bool checkAction(); - virtual void update( int64_t currTime ) {}; - - Action::ActionPtr getCurrentAction() const; - - void setCurrentAction( Action::ActionPtr pAction ); - - ///// IN RANGE LOGIC ///// - - // check if another actor is in the actors in range set - bool isInRangeSet( ActorPtr pActor ) const; - - ActorPtr getClosestActor(); - - void sendToInRangeSet( Network::Packets::GamePacketPtr pPacket, bool bToSelf = false ); - - // add an actor to in range set - void addInRangeActor( ActorPtr pActor ); - - // remove an actor from the in range set - void removeInRangeActor( Actor& pActor ); - - // return true if there is at least one actor in the in range set - bool hasInRangeActor() const; - - void removeFromInRange(); - - // clear the whole in range set, this does no cleanup - virtual void clearInRangeSet(); - - ZonePtr getCurrentZone() const; - - void setCurrentZone( ZonePtr currZone ); - - // get the current cell of a region the actor is in - Cell* getCell() const; - - // set the current cell - void setCell( Cell* pCell ); - - Core::Cell* m_pCell; - -}; - } } #endif diff --git a/src/servers/sapphire_zone/Actor/BattleNpc.cpp b/src/servers/sapphire_zone/Actor/BattleNpc.cpp index 5b43728b..26d76f4a 100644 --- a/src/servers/sapphire_zone/Actor/BattleNpc.cpp +++ b/src/servers/sapphire_zone/Actor/BattleNpc.cpp @@ -26,7 +26,7 @@ extern Core::Data::ExdDataGenerated g_exdDataGen; uint32_t Core::Entity::BattleNpc::m_nextID = 1149241694; Core::Entity::BattleNpc::BattleNpc() : - Actor( ObjKind::BattleNpc ) + Chara( ObjKind::BattleNpc ) { m_id = 0; m_status = ActorStatus::Idle; @@ -40,7 +40,7 @@ Core::Entity::BattleNpc::~BattleNpc() Core::Entity::BattleNpc::BattleNpc( uint16_t modelId, uint16_t nameid, const Common::FFXIVARR_POSITION3& spawnPos, uint16_t bnpcBaseId, uint32_t type, uint8_t level, uint8_t behaviour, uint32_t mobType ) : - Actor( ObjKind::BattleNpc ) + Chara( ObjKind::BattleNpc ) { BattleNpc::m_nextID++; m_id = BattleNpc::m_nextID; @@ -177,16 +177,16 @@ uint8_t Core::Entity::BattleNpc::getbehavior() const return m_behavior; } -void Core::Entity::BattleNpc::hateListAdd( Actor& actor, int32_t hateAmount ) +void Core::Entity::BattleNpc::hateListAdd( Chara& actor, int32_t hateAmount ) { auto hateEntry = new HateListEntry(); hateEntry->m_hateAmount = hateAmount; - hateEntry->m_pActor = actor.getAsActor(); + hateEntry->m_pChara = actor.getAsChara(); m_hateList.insert( hateEntry ); } -Core::Entity::ActorPtr Core::Entity::BattleNpc::hateListGetHighest() +Core::Entity::CharaPtr Core::Entity::BattleNpc::hateListGetHighest() { auto it = m_hateList.begin(); @@ -202,7 +202,7 @@ Core::Entity::ActorPtr Core::Entity::BattleNpc::hateListGetHighest() } if( entry && maxHate != 0 ) - return entry->m_pActor; + return entry->m_pChara; return nullptr; } @@ -274,7 +274,7 @@ bool Core::Entity::BattleNpc::moveTo( Common::FFXIVARR_POSITION3& pos ) } -void Core::Entity::BattleNpc::aggro( Actor& actor ) +void Core::Entity::BattleNpc::aggro( Chara& actor ) { m_lastAttack = Util::getTimeMs(); @@ -292,7 +292,7 @@ void Core::Entity::BattleNpc::aggro( Actor& actor ) } } -void Core::Entity::BattleNpc::deaggro( Actor& actor ) +void Core::Entity::BattleNpc::deaggro( Chara& actor ) { if( !hateListHasActor( actor ) ) hateListRemove( actor ); @@ -309,8 +309,8 @@ void Core::Entity::BattleNpc::hateListClear() auto it = m_hateList.begin(); for( ; it != m_hateList.end(); ++it ) { - if( isInRangeSet( ( *it )->m_pActor ) ) - deaggro( *( *it )->m_pActor ); + if( isInRangeSet( ( *it )->m_pChara ) ) + deaggro( *( *it )->m_pChara ); HateListEntry* tmpListEntry = ( *it ); delete tmpListEntry; } @@ -318,12 +318,12 @@ void Core::Entity::BattleNpc::hateListClear() } -void Core::Entity::BattleNpc::hateListRemove( Actor& actor ) +void Core::Entity::BattleNpc::hateListRemove( Chara& actor ) { auto it = m_hateList.begin(); for( ; it != m_hateList.end(); ++it ) { - if( ( *it )->m_pActor->getId() == actor.getId() ) + if( ( *it )->m_pChara->getId() == actor.getId() ) { HateListEntry* pEntry = *it; m_hateList.erase( it ); @@ -338,12 +338,12 @@ void Core::Entity::BattleNpc::hateListRemove( Actor& actor ) } } -bool Core::Entity::BattleNpc::hateListHasActor( Actor& actor ) +bool Core::Entity::BattleNpc::hateListHasActor( Chara& actor ) { auto it = m_hateList.begin(); for( ; it != m_hateList.end(); ++it ) { - if( ( *it )->m_pActor->getId() == actor.getId() ) + if( ( *it )->m_pChara->getId() == actor.getId() ) return true; } return false; @@ -359,13 +359,13 @@ uint32_t Core::Entity::BattleNpc::getNameId() const return m_nameId; } -void Core::Entity::BattleNpc::hateListUpdate( Actor& actor, int32_t hateAmount ) +void Core::Entity::BattleNpc::hateListUpdate( Chara& actor, int32_t hateAmount ) { auto it = m_hateList.begin(); for( ; it != m_hateList.end(); ++it ) { - if( ( *it )->m_pActor->getId() == actor.getId() ) + if( ( *it )->m_pChara->getId() == actor.getId() ) { ( *it )->m_hateAmount += hateAmount; return; @@ -374,7 +374,7 @@ void Core::Entity::BattleNpc::hateListUpdate( Actor& actor, int32_t hateAmount ) auto hateEntry = new HateListEntry(); hateEntry->m_hateAmount = hateAmount; - hateEntry->m_pActor = actor.getAsActor(); + hateEntry->m_pChara = actor.getAsChara(); m_hateList.insert( hateEntry ); } @@ -396,7 +396,7 @@ void Core::Entity::BattleNpc::onDeath() uint32_t totalHate = 0; for( auto& pHateEntry : m_hateList ) { - if( pHateEntry->m_pActor->isPlayer() ) + if( pHateEntry->m_pChara->isPlayer() ) { if( pHateEntry->m_hateAmount < minHate ) minHate = pHateEntry->m_hateAmount; @@ -412,9 +412,9 @@ void Core::Entity::BattleNpc::onDeath() { // todo: this is pure retarded // todo: check for companion - if( pHateEntry->m_pActor->isPlayer() ) // && pHateEntry->m_hateAmount >= plsBeHatedThisMuchAtLeast ) + if( pHateEntry->m_pChara->isPlayer() ) // && pHateEntry->m_hateAmount >= plsBeHatedThisMuchAtLeast ) { - uint8_t level = pHateEntry->m_pActor->getLevel(); + uint8_t level = pHateEntry->m_pChara->getLevel(); auto levelDiff = static_cast< int32_t >( this->m_level ) - level; auto cappedLevelDiff = Math::Util::clamp( levelDiff, 1, 6 ); @@ -439,7 +439,7 @@ void Core::Entity::BattleNpc::onDeath() // todo: this is actually retarded, we need real rand() srand( static_cast< uint32_t > ( time( nullptr ) ) ); - auto pPlayer = pHateEntry->m_pActor->getAsPlayer(); + auto pPlayer = pHateEntry->m_pChara->getAsPlayer(); pPlayer->gainExp( exp ); pPlayer->onMobKill( m_nameId ); } @@ -448,7 +448,7 @@ void Core::Entity::BattleNpc::onDeath() hateListClear(); } -void Core::Entity::BattleNpc::onActionHostile( Actor& source ) +void Core::Entity::BattleNpc::onActionHostile( Chara& source ) { if( hateListGetHighest() == nullptr ) @@ -458,7 +458,7 @@ void Core::Entity::BattleNpc::onActionHostile( Actor& source ) setOwner( source.getAsPlayer() ); } -Core::Entity::ActorPtr Core::Entity::BattleNpc::getClaimer() const +Core::Entity::CharaPtr Core::Entity::BattleNpc::getClaimer() const { return m_pOwner; } @@ -501,46 +501,46 @@ void Core::Entity::BattleNpc::update( int64_t currTime ) case MODE_IDLE: { - ActorPtr pClosestActor = getClosestActor(); + CharaPtr pClosestChara = getClosestChara(); - if( pClosestActor && pClosestActor->isAlive() ) + if( pClosestChara && pClosestChara->isAlive() ) { distance = Math::Util::distance( getPos().x, getPos().y, getPos().z, - pClosestActor->getPos().x, - pClosestActor->getPos().y, - pClosestActor->getPos().z ); + pClosestChara->getPos().x, + pClosestChara->getPos().y, + pClosestChara->getPos().z ); //if( distance < 8 && getbehavior() == 2 ) - // aggro( pClosestActor ); + // aggro( pClosestChara ); } } break; case MODE_COMBAT: { - ActorPtr pClosestActor = hateListGetHighest(); + CharaPtr pClosestChara = hateListGetHighest(); - if( pClosestActor != nullptr && !pClosestActor->isAlive() ) + if( pClosestChara != nullptr && !pClosestChara->isAlive() ) { - hateListRemove( *pClosestActor ); - pClosestActor = hateListGetHighest(); + hateListRemove( *pClosestChara ); + pClosestChara = hateListGetHighest(); } - if( pClosestActor != nullptr ) + if( pClosestChara != nullptr ) { distance = Math::Util::distance( getPos().x, getPos().y, getPos().z, - pClosestActor->getPos().x, - pClosestActor->getPos().y, - pClosestActor->getPos().z ); + pClosestChara->getPos().x, + pClosestChara->getPos().y, + pClosestChara->getPos().z ); if( distance > 4 ) - moveTo( pClosestActor->getPos() ); + moveTo( pClosestChara->getPos() ); else { - if( face( pClosestActor->getPos() ) ) + if( face( pClosestChara->getPos() ) ) sendPositionUpdate(); // in combat range. ATTACK! - autoAttack( pClosestActor ); + autoAttack( pClosestChara ); } } else diff --git a/src/servers/sapphire_zone/Actor/BattleNpc.h b/src/servers/sapphire_zone/Actor/BattleNpc.h index b80e6340..a072bca1 100644 --- a/src/servers/sapphire_zone/Actor/BattleNpc.h +++ b/src/servers/sapphire_zone/Actor/BattleNpc.h @@ -1,7 +1,7 @@ #ifndef _BATTLENPC_H #define _BATTLENPC_H -#include "Actor.h" +#include "Chara.h" namespace Core { namespace Entity { @@ -16,11 +16,11 @@ enum StateMode typedef struct { uint32_t m_hateAmount; - ActorPtr m_pActor; + CharaPtr m_pChara; } HateListEntry; -// class for Mobs inheriting from Actor -class BattleNpc : public Actor +// class for Mobs inheriting from Chara +class BattleNpc : public Chara { public: BattleNpc(); @@ -52,12 +52,12 @@ public: uint8_t getbehavior() const; - void hateListAdd( Actor& actor, int32_t hateAmount ); + void hateListAdd( Chara& actor, int32_t hateAmount ); - void hateListUpdate( Actor& actor, int32_t hateAmount ); - void hateListRemove( Actor& actor ); + void hateListUpdate( Chara& actor, int32_t hateAmount ); + void hateListRemove( Chara& actor ); - bool hateListHasActor( Actor& actor ); + bool hateListHasActor( Chara& actor ); void resetPos(); @@ -65,19 +65,19 @@ public: void hateListClear(); - ActorPtr hateListGetHighest(); + CharaPtr hateListGetHighest(); - void aggro( Actor& actor ); + void aggro( Chara& actor ); - void deaggro( Actor& actor ); + void deaggro( Chara& actor ); void setOwner( PlayerPtr pPlayer ); void onDeath() override; - void onActionHostile( Actor& source ) override; + void onActionHostile( Chara& source ) override; - ActorPtr getClaimer() const; + CharaPtr getClaimer() const; void sendPositionUpdate(); @@ -103,7 +103,7 @@ private: uint32_t m_unk1; uint32_t m_unk2; std::set< HateListEntry* > m_hateList; - ActorPtr m_pOwner; + CharaPtr m_pOwner; uint32_t m_timeOfDeath; uint32_t m_mobType; diff --git a/src/servers/sapphire_zone/Actor/Chara.cpp b/src/servers/sapphire_zone/Actor/Chara.cpp new file mode 100644 index 00000000..a7162f4e --- /dev/null +++ b/src/servers/sapphire_zone/Actor/Chara.cpp @@ -0,0 +1,974 @@ +#include +#include +#include +#include +#include + +#include "Forwards.h" +#include "Action/Action.h" + +#include "Zone/Zone.h" + +#include "Network/GameConnection.h" +#include "Network/PacketWrappers/ActorControlPacket142.h" +#include "Network/PacketWrappers/ActorControlPacket143.h" +#include "Network/PacketWrappers/ActorControlPacket144.h" +#include "Network/PacketWrappers/UpdateHpMpTpPacket.h" + +#include "StatusEffect/StatusEffect.h" +#include "Action/ActionCollision.h" +#include "ServerZone.h" +#include "Session.h" +#include "Math/CalcBattle.h" +#include "Chara.h" +#include "Player.h" +#include "Zone/TerritoryMgr.h" + +extern Core::ServerZone g_serverZone; +extern Core::Data::ExdDataGenerated g_exdDataGen; +extern Core::TerritoryMgr g_territoryMgr; + +using namespace Core::Common; +using namespace Core::Network::Packets; +using namespace Core::Network::Packets::Server; + +Core::Entity::Chara::Chara( ObjKind type ) : + Actor( type ) +{ + // initialize the free slot queue + for( uint8_t i = 0; i < MAX_STATUS_EFFECTS; i++ ) + { + m_statusEffectFreeSlotQueue.push( i ); + } +} + +Core::Entity::Chara::~Chara() +{ +} + +/*! \return the actors name */ +std::string Core::Entity::Chara::getName() const +{ + return std::string( m_name ); +} + +/*! \return list of actors currently in range */ +std::set< Core::Entity::CharaPtr > Core::Entity::Chara::getInRangeCharas( bool includeSelf ) +{ + auto tempInRange = m_inRangeCharas; + + if( includeSelf ) + tempInRange.insert( getAsChara() ); + + return tempInRange; + } + +/*! \return current stance of the actors */ +Core::Entity::Chara::Stance Core::Entity::Chara::getStance() const +{ + return m_currentStance; +} + +/*! \return actor stats */ +Core::Entity::Chara::ActorStats Core::Entity::Chara::getStats() const +{ + return m_baseStats; +} + +/*! \return current HP */ +uint32_t Core::Entity::Chara::getHp() const +{ + return m_hp; +} + +/*! \return current MP */ +uint32_t Core::Entity::Chara::getMp() const +{ + return m_mp; +} + +/*! \return current TP */ +uint16_t Core::Entity::Chara::getTp() const +{ + return m_tp; +} + +/*! \return current GP */ +uint16_t Core::Entity::Chara::getGp() const +{ + return m_gp; +} + +/*! \return current invincibility type */ +InvincibilityType Core::Entity::Chara::getInvincibilityType() const +{ + return m_invincibilityType; +} + +/*! \return current class or job */ +Core::Common::ClassJob Core::Entity::Chara::getClass() const +{ + return m_class; +} + +/*! \return current class or job as int32_t ( this feels pointless ) */ +uint8_t Core::Entity::Chara::getClassAsInt() const +{ + return static_cast< uint8_t >( m_class ); +} + +/*! \param ClassJob to set */ +void Core::Entity::Chara::setClass( Common::ClassJob classJob ) +{ + m_class = classJob; +} + +/*! \param Id of the target to set */ +void Core::Entity::Chara::setTargetId( uint64_t targetId ) +{ + m_targetId = targetId; +} + +/*! \return Id of the current target */ +uint64_t Core::Entity::Chara::getTargetId() const +{ + return m_targetId; +} + +/*! \return True if the actor is alive */ +bool Core::Entity::Chara::isAlive() const +{ + return ( m_hp > 0 ); +} + +/*! \return max hp for the actor */ +uint32_t Core::Entity::Chara::getMaxHp() const +{ + return m_baseStats.max_hp; +} + +/*! \return max mp for the actor */ +uint32_t Core::Entity::Chara::getMaxMp() const +{ + return m_baseStats.max_mp; +} + +/*! \return reset hp to current max hp */ +void Core::Entity::Chara::resetHp() +{ + m_hp = getMaxHp(); + sendStatusUpdate( true ); +} + +/*! \return reset mp to current max mp */ +void Core::Entity::Chara::resetMp() +{ + m_mp = getMaxMp(); + sendStatusUpdate( true ); +} + +/*! \param hp amount to set ( caps to maxHp ) */ +void Core::Entity::Chara::setHp( uint32_t hp ) +{ + m_hp = hp < getMaxHp() ? hp : getMaxHp(); + sendStatusUpdate( true ); +} + +/*! \param mp amount to set ( caps to maxMp ) */ +void Core::Entity::Chara::setMp( uint32_t mp ) +{ + m_mp = mp < getMaxMp() ? mp : getMaxMp(); + sendStatusUpdate( true ); +} + +/*! \param gp amount to set*/ +void Core::Entity::Chara::setGp( uint32_t gp ) +{ + m_gp = gp; + sendStatusUpdate( true ); +} + +/*! \param type invincibility type to set */ +void Core::Entity::Chara::setInvincibilityType( Common::InvincibilityType type ) +{ + m_invincibilityType = type; +} + +/*! \return current status of the actor */ +Core::Entity::Chara::ActorStatus Core::Entity::Chara::getStatus() const +{ + return m_status; +} + +/*! \param status to set */ +void Core::Entity::Chara::setStatus( ActorStatus status ) +{ + m_status = status; +} + +/*! +Performs necessary steps to mark an actor dead. +Sets hp/mp/tp, sets status, plays animation and fires onDeath event +*/ +void Core::Entity::Chara::die() +{ + m_status = ActorStatus::Dead; + m_hp = 0; + m_mp = 0; + m_tp = 0; + + // fire onDeath event + onDeath(); + + // if the actor is a player, the update needs to be send to himself too + bool selfNeedsUpdate = isPlayer(); + + sendToInRangeSet( ActorControlPacket142( m_id, SetStatus, static_cast< uint8_t >( ActorStatus::Dead ) ), selfNeedsUpdate ); + + // TODO: not all actor show the death animation when they die, some quest npcs might just despawn + // although that might be handled by setting the HP to 1 and doing some script magic + sendToInRangeSet( ActorControlPacket142( m_id, DeathAnimation, 0, 0, 0, 0x20 ), selfNeedsUpdate ); + +} + +/*! +Calculates and sets the rotation to look towards a specified +position + +\param Position to look towards +*/ +bool Core::Entity::Chara::face( const Common::FFXIVARR_POSITION3& p ) +{ + float oldRot = getRotation(); + float rot = Math::Util::calcAngFrom( getPos().x, getPos().z, p.x, p.z ); + float newRot = PI - rot + ( PI / 2 ); + + m_pCell = nullptr; + + setRotation( newRot ); + + return oldRot != newRot ? true : false; +} + +/*! +Sets the actors position and notifies the zone to propagate the change + +\param Position to set +*/ +void Core::Entity::Chara::setPosition( const Common::FFXIVARR_POSITION3& pos ) +{ + m_pos = pos; + m_pCurrentZone->updateActorPosition( *this ); +} + +void Core::Entity::Chara::setPosition( float x, float y, float z ) +{ + m_pos.x = x; + m_pos.y = y; + m_pos.z = z; + m_pCurrentZone->updateActorPosition( *this ); +} + +/*! +Set and propagate the actor stance to in range players +( not the actor himself ) + +\param stance to set +*/ +void Core::Entity::Chara::setStance( Stance stance ) +{ + m_currentStance = stance; + + sendToInRangeSet( ActorControlPacket142( m_id, ToggleAggro, stance, 1 ) ); +} + +/*! +Check if an action is queued for execution, if so update it +and if fully performed, clean up again. + +\return true if a queued action has been updated +*/ +bool Core::Entity::Chara::checkAction() +{ + + if( m_pCurrentAction == nullptr ) + return false; + + if( m_pCurrentAction->update() ) + m_pCurrentAction.reset(); + + return true; + +} + +/*! +Change the current target and propagate to in range players + +\param target actor id +*/ +void Core::Entity::Chara::changeTarget( uint64_t targetId ) +{ + setTargetId( targetId ); + sendToInRangeSet( ActorControlPacket144( m_id, SetTarget, 0, 0, 0, 0, targetId ) ); +} + +/*! +Dummy function \return 0 +*/ +uint8_t Core::Entity::Chara::getLevel() const +{ + return 0; +} + +/*! +Let an actor take damage and perform necessary steps +according to resulting hp, propagates new hp value to players +in range +TODO: eventually this needs to distinguish between physical and +magical dmg and take status effects into account + +\param amount of damage to be taken +*/ +void Core::Entity::Chara::takeDamage( uint32_t damage ) +{ + if( damage >= m_hp ) + { + switch( m_invincibilityType ) { + case InvincibilityNone: + setHp( 0 ); + die(); + break; + case InvincibilityRefill: + resetHp(); + break; + case InvincibilityStayAlive: + setHp( 0 ); + break; + } + } + else + m_hp -= damage; + + sendStatusUpdate( false ); +} + +/*! +Let an actor get healed and perform necessary steps +according to resulting hp, propagates new hp value to players +in range + +\param amount of hp to be healed +*/ +void Core::Entity::Chara::heal( uint32_t amount ) +{ + if( ( m_hp + amount ) > getMaxHp() ) + { + m_hp = getMaxHp(); + } + else + m_hp += amount; + + sendStatusUpdate( false ); +} + +/*! +Send an HpMpTp update to players in range ( and potentially to self ) +TODO: poor naming, should be changed. Status is not HP. Also should be virtual +so players can have their own version and we can abolish the param. + +\param true if the update should also be sent to the actor ( player ) himself +*/ +void Core::Entity::Chara::sendStatusUpdate( bool toSelf ) +{ + UpdateHpMpTpPacket updateHpPacket( *this ); + sendToInRangeSet( updateHpPacket ); +} + +/*! \return ActionPtr of the currently registered action, or nullptr */ +Core::Action::ActionPtr Core::Entity::Chara::getCurrentAction() const +{ + return m_pCurrentAction; +} + +/*! \param ActionPtr of the action to be registered */ +void Core::Entity::Chara::setCurrentAction( Core::Action::ActionPtr pAction ) +{ + m_pCurrentAction = pAction; +} + +/*! +check if a given actor is in the actors in range set + +\param ActorPtr to be checked for +\return true if the actor was found +*/ +bool Core::Entity::Chara::isInRangeSet( CharaPtr pChara ) const +{ + return !( m_inRangeCharas.find( pChara ) == m_inRangeCharas.end() ); +} + +/*! \return ActorPtr of the closest actor in range, if none, nullptr */ +Core::Entity::CharaPtr Core::Entity::Chara::getClosestChara() +{ + if( m_inRangeCharas.empty() ) + // no actors in range, don't bother + return nullptr; + + CharaPtr tmpActor = nullptr; + + // arbitrary high number + float minDistance = 10000; + + for( const auto& pCurAct : m_inRangeCharas ) + { + float distance = Math::Util::distance( getPos().x, + getPos().y, + getPos().z, + pCurAct->getPos().x, + pCurAct->getPos().y, + pCurAct->getPos().z ); + + if( distance < minDistance ) + { + minDistance = distance; + tmpActor = pCurAct; + } + } + + return tmpActor; +} + +/*! +Send a packet to all players in range, potentially to self if set and is player + +\param GamePacketPtr to send +\param bool should be send to self? +*/ +void Core::Entity::Chara::sendToInRangeSet( Network::Packets::GamePacketPtr pPacket, bool bToSelf ) +{ + + if( bToSelf && isPlayer() ) + { + auto pPlayer = getAsPlayer(); + + auto pSession = g_serverZone.getSession( pPlayer->getId() ); + + // it might be that the player DC'd in which case the session would be invalid + if( pSession ) + pSession->getZoneConnection()->queueOutPacket( pPacket ); + } + + if( m_inRangePlayers.empty() ) + return; + + for( const auto &pCurAct : m_inRangePlayers ) + { + assert( pCurAct ); + pPacket->setValAt< uint32_t >( 0x04, m_id ); + pPacket->setValAt< uint32_t >( 0x08, pCurAct->m_id ); + // it might be that the player DC'd in which case the session would be invalid + pCurAct->queuePacket( pPacket ); + } +} + +/*! +Add a given actor to the fitting in range set according to type +but also to the global actor map + +\param ActorPtr to add +*/ +void Core::Entity::Chara::addInRangeChara( CharaPtr pChara ) +{ + + // if this is null, something went wrong + assert( pChara ); + + // add actor to in range set + m_inRangeCharas.insert( pChara ); + + if( pChara->isPlayer() ) + { + auto pPlayer = pChara->getAsPlayer(); + + // if actor is a player, add it to the in range player set + m_inRangePlayers.insert( pPlayer ); + } +} + +/*! +Remove a given actor from the matching in range set according to type +but also to the global actor map + +\param ActorPtr to remove +*/ +void Core::Entity::Chara::removeInRangeChara( Chara& chara ) +{ + // call virtual event + onRemoveInRangeChara( chara ); + + // remove actor from in range actor set + m_inRangeCharas.erase( chara.getAsChara() ); + + // if actor is a player, despawn ourself for him + // TODO: move to virtual onRemove? + if( isPlayer() ) + chara.despawn( getAsPlayer() ); + + if( chara.isPlayer() ) + m_inRangePlayers.erase( chara.getAsPlayer() ); +} + +/*! \return true if there is at least one actor in the in range set */ +bool Core::Entity::Chara::hasInRangeActor() const +{ + return ( m_inRangeCharas.size() > 0 ); +} + +void Core::Entity::Chara::removeFromInRange() +{ + if( !hasInRangeActor() ) + return; + + Entity::ActorPtr pCurAct; + + for( auto& pCurAct : m_inRangeCharas ) + { + pCurAct->removeInRangeChara( *this ); + } + +} + +/*! Clear the whole in range set, this does no cleanup */ +void Core::Entity::Chara::clearInRangeSet() +{ + m_inRangeCharas.clear(); + m_inRangePlayers.clear(); +} + +/*! \return ZonePtr to the current zone, nullptr if not set */ +Core::ZonePtr Core::Entity::Chara::getCurrentZone() const +{ + return m_pCurrentZone; +} + +/*! \param ZonePtr to the zone to be set as current */ +void Core::Entity::Chara::setCurrentZone( ZonePtr currZone ) +{ + m_pCurrentZone = currZone; +} + +/*! +Get the current cell of a region the actor is in + +\return Cell* +*/ +Core::Cell * Core::Entity::Chara::getCell() const +{ + return m_pCell; +} + +/*! +Set the current cell the actor is in + +\param Cell* for the cell to be set +*/ +void Core::Entity::Chara::setCell( Cell * pCell ) +{ + m_pCell = pCell; +} + +/*! +Autoattack prototype implementation +TODO: move the check if the autoAttack can be performed to the callee +also rename autoAttack to autoAttack as that is more elaborate +On top of that, this only solves attacks from melee classes. +Will have to be extended for ranged attacks. + +\param ActorPtr the autoAttack is performed on +*/ +void Core::Entity::Chara::autoAttack( CharaPtr pTarget ) +{ + + uint64_t tick = Util::getTimeMs(); + + if( ( tick - m_lastAttack ) > 2500 ) + { + pTarget->onActionHostile( *this ); + m_lastAttack = tick; + srand( static_cast< uint32_t >( tick ) ); + + uint16_t damage = static_cast< uint16_t >( 10 + rand() % 12 ); + uint32_t variation = static_cast< uint32_t >( 0 + rand() % 4 ); + + ZoneChannelPacket< FFXIVIpcEffect > effectPacket( getId() ); + effectPacket.data().targetId = pTarget->getId(); + effectPacket.data().actionAnimationId = 0x366; + effectPacket.data().unknown_2 = variation; +// effectPacket.data().unknown_3 = 1; + effectPacket.data().actionTextId = 0x366; + effectPacket.data().numEffects = 1; + effectPacket.data().rotation = Math::Util::floatToUInt16Rot( getRotation() ); + effectPacket.data().effectTarget = pTarget->getId(); + effectPacket.data().effects[0].value = damage; + effectPacket.data().effects[0].effectType = ActionEffectType::Damage; + effectPacket.data().effects[0].hitSeverity = static_cast< ActionHitSeverityType >( variation ); + effectPacket.data().effects[0].unknown_3 = 7; + + sendToInRangeSet( effectPacket ); + + if( isPlayer() ) + getAsPlayer()->queuePacket( effectPacket ); + + pTarget->takeDamage( damage ); + } +} + +/*! +ChaiScript Skill Handler. + +\param GamePacketPtr to send +\param bool should be send to self? +*/ +void Core::Entity::Chara::handleScriptSkill( uint32_t type, uint16_t actionId, uint64_t param1, + uint64_t param2, Entity::Chara& target ) +{ + + if( isPlayer() ) + { + getAsPlayer()->sendDebug( std::to_string( target.getId() ) ); + getAsPlayer()->sendDebug( "Handle script skill type: " + std::to_string( type ) ); + } + + auto actionInfoPtr = g_exdDataGen.get< Core::Data::Action >( actionId ); + + // Todo: Effect packet generator. 90% of this is basically setting params and it's basically unreadable. + // Prepare packet. This is seemingly common for all packets in the action handler. + + ZoneChannelPacket< FFXIVIpcEffect > effectPacket( getId() ); + effectPacket.data().targetId = target.getId(); + effectPacket.data().actionAnimationId = actionId; + effectPacket.data().unknown_62 = 1; // Affects displaying action name next to number in floating text + effectPacket.data().unknown_2 = 1; // This seems to have an effect on the "double-cast finish" animation + effectPacket.data().actionTextId = actionId; + effectPacket.data().numEffects = 1; + effectPacket.data().rotation = Math::Util::floatToUInt16Rot( getRotation() ); + effectPacket.data().effectTarget = target.getId(); + + // Todo: for each actor, calculate how much damage the calculated value should deal to them - 2-step damage calc. we only have 1-step + switch( type ) + { + + case ActionEffectType::Damage: + { + effectPacket.data().effects[0].value = static_cast< uint16_t >( param1 ); + effectPacket.data().effects[0].effectType = ActionEffectType::Damage; + effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalDamage; + effectPacket.data().effects[0].unknown_3 = 7; + + if( actionInfoPtr->castType == 1 && actionInfoPtr->effectRange != 0 || actionInfoPtr->castType != 1 ) + { + // If action on this specific target is valid... + if ( isPlayer() && !ActionCollision::isActorApplicable( target, TargetFilter::Enemies ) ) + break; + + sendToInRangeSet( effectPacket, true ); + + if ( target.isAlive() ) + target.onActionHostile( *this ); + + target.takeDamage( static_cast< uint32_t >( param1 ) ); + + } + else + { + + auto actorsCollided = ActionCollision::getActorsHitFromAction( target.getPos(), getInRangeCharas(true), + actionInfoPtr, TargetFilter::Enemies ); + + for( const auto& pHitActor : actorsCollided ) + { + effectPacket.data().targetId = pHitActor->getId(); + effectPacket.data().effectTarget = pHitActor->getId(); + + // todo: send to range of what? ourselves? when mob script hits this is going to be lacking + sendToInRangeSet( effectPacket, true ); + + + if( pHitActor->isAlive() ) + pHitActor->onActionHostile( *this ); + + pHitActor->takeDamage( static_cast< uint32_t >( param1 ) ); + + // Debug + if ( isPlayer() ) + { + if ( pHitActor->isPlayer() ) + getAsPlayer()->sendDebug( "AoE hit actor " + std::to_string( pHitActor->getId() ) + " (" + pHitActor->getName() + ")" ); + else + getAsPlayer()->sendDebug( "AoE hit actor " + std::to_string( pHitActor->getId() ) ); + } + } + } + + break; + } + + case ActionEffectType::Heal: + { + uint32_t calculatedHeal = Math::CalcBattle::calculateHealValue( getAsPlayer(), static_cast< uint32_t >( param1 ) ); + + effectPacket.data().effects[0].value = calculatedHeal; + effectPacket.data().effects[0].effectType = ActionEffectType::Heal; + effectPacket.data().effects[0].hitSeverity = ActionHitSeverityType::NormalHeal; + + if( actionInfoPtr->castType == 1 && actionInfoPtr->effectRange != 0 || actionInfoPtr->castType != 1 ) + { + if( isPlayer() && !ActionCollision::isActorApplicable( target, TargetFilter::Allies ) ) + break; + + sendToInRangeSet( effectPacket, true ); + target.heal( calculatedHeal ); + } + else + { + // todo: get proper packets: the following was just kind of thrown together from what we know. + // atm buggy (packets look "delayed" from client) + + auto actorsCollided = ActionCollision::getActorsHitFromAction( target.getPos(), getInRangeCharas(true), + actionInfoPtr, TargetFilter::Allies ); + + for( auto pHitActor : actorsCollided ) + { + effectPacket.data().targetId = target.getId(); + effectPacket.data().effectTarget = pHitActor->getId(); + + sendToInRangeSet( effectPacket, true ); + pHitActor->heal( calculatedHeal ); + + // Debug + if( isPlayer() ) + { + if( pHitActor->isPlayer() ) + getAsPlayer()->sendDebug( "AoE hit actor " + std::to_string( pHitActor->getId() ) + " (" + pHitActor->getName() + ")" ); + else + getAsPlayer()->sendDebug( "AoE hit actor " + std::to_string( pHitActor->getId() ) ); + } + } + } + break; + } + + default: + break; + } +} + +/*! \param StatusEffectPtr to be applied to the actor */ +void Core::Entity::Chara::addStatusEffect( StatusEffect::StatusEffectPtr pEffect ) +{ + int8_t nextSlot = getStatusEffectFreeSlot(); + // if there is no slot left, do not add the effect + if( nextSlot == -1 ) + return; + + pEffect->applyStatus(); + m_statusEffectMap[nextSlot] = pEffect; + + ZoneChannelPacket< Server::FFXIVIpcAddStatusEffect > statusEffectAdd( getId() ); + statusEffectAdd.data().actor_id = pEffect->getTargetActorId(); + statusEffectAdd.data().actor_id1 = pEffect->getSrcActorId(); + statusEffectAdd.data().current_hp = getHp(); + statusEffectAdd.data().current_mp = getMp(); + statusEffectAdd.data().current_tp = getTp(); + statusEffectAdd.data().duration = static_cast< float >( pEffect->getDuration() ) / 1000; + statusEffectAdd.data().effect_id = pEffect->getId(); + statusEffectAdd.data().effect_index = nextSlot; + statusEffectAdd.data().max_hp = getMaxHp(); + statusEffectAdd.data().max_mp = getMaxMp(); + statusEffectAdd.data().max_something = 1; + //statusEffectAdd.data().unknown2 = 28; + statusEffectAdd.data().param = pEffect->getParam(); + + sendToInRangeSet( statusEffectAdd, isPlayer() ); +} + +/*! \param StatusEffectPtr to be applied to the actor */ +void Core::Entity::Chara::addStatusEffectById( uint32_t id, int32_t duration, Entity::Chara& source, uint16_t param ) +{ + auto effect = StatusEffect::make_StatusEffect( id, source.getAsChara(), getAsChara(), duration, 3000 ); + effect->setParam( param ); + addStatusEffect( effect ); +} + +/*! \param StatusEffectPtr to be applied to the actor */ +void Core::Entity::Chara::addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Chara& source, uint16_t param ) +{ + if( hasStatusEffect( id ) ) + return; + + auto effect = StatusEffect::make_StatusEffect( id, source.getAsChara(), getAsChara(), duration, 3000 ); + effect->setParam( param ); + addStatusEffect( effect ); + +} + +float Core::Entity::Chara::getRotation() const +{ + return m_rot; +} + +void Core::Entity::Chara::setRotation( float rot ) +{ + m_rot = rot; +} + +int8_t Core::Entity::Chara::getStatusEffectFreeSlot() +{ + int8_t freeEffectSlot = -1; + + if( m_statusEffectFreeSlotQueue.empty() ) + return freeEffectSlot; + + freeEffectSlot = m_statusEffectFreeSlotQueue.front(); + m_statusEffectFreeSlotQueue.pop(); + + return freeEffectSlot; +} + +void Core::Entity::Chara::statusEffectFreeSlot( uint8_t slotId ) +{ + m_statusEffectFreeSlotQueue.push( slotId ); +} + +void Core::Entity::Chara::removeSingleStatusEffectById( uint32_t id ) +{ + for( auto effectIt : m_statusEffectMap ) + { + if( effectIt.second->getId() == id ) + { + removeStatusEffect( effectIt.first ); + break; + } + } +} + +void Core::Entity::Chara::removeStatusEffect( uint8_t effectSlotId ) +{ + auto pEffectIt = m_statusEffectMap.find( effectSlotId ); + if( pEffectIt == m_statusEffectMap.end() ) + return; + + statusEffectFreeSlot( effectSlotId ); + + auto pEffect = pEffectIt->second; + pEffect->removeStatus(); + + sendToInRangeSet( ActorControlPacket142( getId(), StatusEffectLose, pEffect->getId() ), isPlayer() ); + + m_statusEffectMap.erase( effectSlotId ); + + sendStatusEffectUpdate(); +} + +std::map< uint8_t, Core::StatusEffect::StatusEffectPtr > Core::Entity::Chara::getStatusEffectMap() const +{ + return m_statusEffectMap; +} + +void Core::Entity::Chara::sendStatusEffectUpdate() +{ + uint64_t currentTimeMs = Util::getTimeMs(); + + ZoneChannelPacket< Server::FFXIVIpcStatusEffectList > statusEffectList( getId() ); + + statusEffectList.data().current_hp = getHp(); + statusEffectList.data().current_mp = getMp(); + statusEffectList.data().currentTp = getTp(); + statusEffectList.data().max_hp = getMaxHp(); + statusEffectList.data().max_mp = getMaxMp(); + uint8_t slot = 0; + for( auto effectIt : m_statusEffectMap ) + { + float timeLeft = static_cast< float >( effectIt.second->getDuration() - + ( currentTimeMs - effectIt.second->getStartTimeMs() ) ) / 1000; + statusEffectList.data().effect[slot].duration = timeLeft; + statusEffectList.data().effect[slot].effect_id = effectIt.second->getId(); + statusEffectList.data().effect[slot].sourceActorId = effectIt.second->getSrcActorId(); + slot++; + } + + sendToInRangeSet( statusEffectList, isPlayer() ); + +} + +void Core::Entity::Chara::updateStatusEffects() +{ + uint64_t currentTimeMs = Util::getTimeMs(); + + uint32_t thisTickDmg = 0; + uint32_t thisTickHeal = 0; + + for( auto effectIt : m_statusEffectMap ) + { + uint8_t effectIndex = effectIt.first; + auto effect = effectIt.second; + + uint64_t lastTick = effect->getLastTickMs(); + uint64_t startTime = effect->getStartTimeMs(); + uint32_t duration = effect->getDuration(); + uint32_t tickRate = effect->getTickRate(); + + if( ( currentTimeMs - startTime ) > duration ) + { + // remove status effect + removeStatusEffect( effectIndex ); + // break because removing invalidates iterators + break; + } + + if( ( currentTimeMs - lastTick ) > tickRate ) + { + effect->setLastTick( currentTimeMs ); + effect->onTick(); + + auto thisEffect = effect->getTickEffect(); + + switch( thisEffect.first ) + { + + case 1: + { + thisTickDmg += thisEffect.second; + break; + } + + case 2: + { + thisTickHeal += thisEffect.second; + break; + } + + } + } + + } + + if( thisTickDmg != 0 ) + { + takeDamage( thisTickDmg ); + sendToInRangeSet( ActorControlPacket142( getId(), HPFloatingText, 0, static_cast< uint8_t >( ActionEffectType::Damage ), thisTickDmg ) ); + } + + if( thisTickHeal != 0 ) + { + heal( thisTickDmg ); + sendToInRangeSet( ActorControlPacket142( getId(), HPFloatingText, 0, static_cast< uint8_t >( ActionEffectType::Heal ), thisTickHeal ) ); + } +} + +bool Core::Entity::Chara::hasStatusEffect( uint32_t id ) +{ + if( m_statusEffectMap.find( id ) != m_statusEffectMap.end() ) + return true; + return false; +} diff --git a/src/servers/sapphire_zone/Actor/Chara.h b/src/servers/sapphire_zone/Actor/Chara.h new file mode 100644 index 00000000..116288f5 --- /dev/null +++ b/src/servers/sapphire_zone/Actor/Chara.h @@ -0,0 +1,295 @@ +#ifndef _ACTOR_H_ +#define _ACTOR_H_ + +#include +#include + +#include "Forwards.h" +#include "Actor.h" +#include +#include +#include + +namespace Core { +namespace Entity { + +/*! +\class Chara +\brief Base class for all animate actors + +*/ +class Chara : public Actor +{ +public: + enum Stance : uint8_t + { + Passive = 0, + Active = 1, + }; + + enum DisplayFlags : uint16_t + { + ActiveStance = 0x001, + Invisible = 0x020, + HideHead = 0x040, + HideWeapon = 0x080, + Faded = 0x100, + Visor = 0x800, + }; + + enum struct ActorStatus : uint8_t + { + Idle = 0x01, + Dead = 0x02, + Sitting = 0x03, + Mounted = 0x04, + Crafting = 0x05, + Gathering = 0x06, + Melding = 0x07, + SMachine = 0x08 + }; + + struct ActorStats + { + uint32_t max_mp = 0; + uint32_t max_hp = 0; + + uint32_t str = 0; + uint32_t dex = 0; + uint32_t vit = 0; + uint32_t inte = 0; + uint32_t mnd = 0; + uint32_t pie = 0; + + uint32_t tenacity = 0; + uint32_t attack = 0; + uint32_t defense = 0; + uint32_t accuracy = 0; + uint32_t spellSpeed = 0; + uint32_t magicDefense = 0; + uint32_t critHitRate = 0; + uint32_t resistSlash = 0; + uint32_t resistPierce = 0; + uint32_t resistBlunt = 0; + uint32_t attackPotMagic = 0; + uint32_t healingPotMagic = 0; + uint32_t determination = 0; + uint32_t skillSpeed = 0; + + uint32_t resistSlow = 0; + uint32_t resistSilence = 0; + uint32_t resistBlind = 0; + uint32_t resistPoison = 0; + uint32_t resistStun = 0; + uint32_t resistSleep = 0; + uint32_t resistBind = 0; + uint32_t resistHeavy = 0; + + uint32_t resistFire = 0; + uint32_t resistIce = 0; + uint32_t resistWind = 0; + uint32_t resistEarth = 0; + uint32_t resistLightning = 0; + uint32_t resistWater = 0; + + } m_baseStats; + +protected: + char m_name[34]; + /*! Id of the zone the actor currently is in */ + uint32_t m_zoneId; + /*! Ptr to the ZoneObj the actor belongs to */ + ZonePtr m_pCurrentZone; + /*! Last tick time for the actor ( in ms ) */ + uint64_t m_lastTickTime; + /*! Last time the actor performed an autoAttack ( in ms ) */ + uint64_t m_lastAttack; + /*! Last time the actor was updated ( in ms ) */ + uint64_t m_lastUpdate; + /*! Current stance of the actor */ + Stance m_currentStance; + /*! Current staus of the actor */ + ActorStatus m_status; + /*! Max HP of the actor ( based on job / class ) */ + uint32_t m_maxHp; + /*! Max MP of the actor ( based on job / class ) */ + uint32_t m_maxMp; + /*! Current HP of the actor */ + uint32_t m_hp; + /*! Current MP of the actor */ + uint32_t m_mp; + /*! Current TP of the actor */ + uint16_t m_tp; + /*! Current GP of the actor */ + uint16_t m_gp; + /*! Additional look info of the actor */ + uint8_t m_customize[26]; + /*! Current class of the actor */ + Common::ClassJob m_class; + /*! Id of the currently selected target actor */ + uint64_t m_targetId; + /*! Ptr to a queued action */ + Action::ActionPtr m_pCurrentAction; + /*! Invincibility type */ + Common::InvincibilityType m_invincibilityType; + + /*! Status effects */ + const uint8_t MAX_STATUS_EFFECTS = 30; + std::queue< uint8_t > m_statusEffectFreeSlotQueue; + std::vector< std::pair< uint8_t, uint32_t> > m_statusEffectList; + std::map< uint8_t, StatusEffect::StatusEffectPtr > m_statusEffectMap; + + std::set< CharaPtr > m_inRangeCharas; + std::set< PlayerPtr > m_inRangePlayers; + +public: + Chara( ObjKind type ); + + virtual ~Chara() override; + + virtual void calculateStats() {}; + + /// Status effect functions + void addStatusEffect( StatusEffect::StatusEffectPtr pEffect ); + void removeStatusEffect( uint8_t effectSlotId ); + void removeSingleStatusEffectById( uint32_t id ); + void updateStatusEffects(); + + bool hasStatusEffect( uint32_t id ); + + int8_t getStatusEffectFreeSlot(); + void statusEffectFreeSlot( uint8_t slotId ); + + std::map< uint8_t, Core::StatusEffect::StatusEffectPtr > getStatusEffectMap() const; + + void sendStatusEffectUpdate(); + // add a status effect by id + void addStatusEffectById( uint32_t id, int32_t duration, Entity::Chara& source, uint16_t param = 0 ); + + // add a status effect by id if it doesn't exist + void addStatusEffectByIdIfNotExist( uint32_t id, int32_t duration, Entity::Chara& source, uint16_t param = 0 ); + + // remove a status effect by id + void removeSingleStatusEffectFromId( uint32_t id ); + /// End Status Effect Functions + + void setPosition( const Common::FFXIVARR_POSITION3& pos ); + void setPosition( float x, float y, float z ); + + void setRotation( float rot ); + + float getRotation() const; + + std::string getName() const; + + std::set< CharaPtr > getInRangeCharas( bool includeSelf = false ); + + bool face( const Common::FFXIVARR_POSITION3& p ); + + Stance getStance() const; + + void setStance( Stance stance ); + + ActorStats getStats() const; + + uint32_t getHp() const; + uint32_t getMp() const; + uint16_t getTp() const; + uint16_t getGp() const; + + Common::InvincibilityType getInvincibilityType() const; + + Common::ClassJob getClass() const; + + uint8_t getClassAsInt() const; + + void setClass( Common::ClassJob classJob ); + + void setTargetId( uint64_t targetId ); + + uint64_t getTargetId() const; + + bool isAlive() const; + + virtual uint32_t getMaxHp() const; + virtual uint32_t getMaxMp() const; + + void resetHp(); + void resetMp(); + + void setHp( uint32_t hp ); + void setMp( uint32_t mp ); + void setGp( uint32_t gp ); + + void setInvincibilityType( Common::InvincibilityType type ); + + void die(); + + ActorStatus getStatus() const; + + void setStatus( ActorStatus status ); + + void handleScriptSkill( uint32_t type, uint16_t actionId, uint64_t param1, uint64_t param2, Entity::Chara& target ); + + virtual void autoAttack( CharaPtr pTarget ); + + virtual void onRemoveInRangeChara( Chara& pActor ) {} + + virtual void onDeath() {}; + virtual void onDamageTaken( Chara& pSource ) {}; + virtual void onActionHostile( Chara& source ) {}; + virtual void onActionFriendly( Chara& pSource ) {}; + virtual void onTick() {}; + + virtual void changeTarget( uint64_t targetId ); + virtual uint8_t getLevel() const; + virtual void sendStatusUpdate( bool toSelf = true ); + virtual void takeDamage( uint32_t damage ); + virtual void heal( uint32_t amount ); + virtual bool checkAction(); + virtual void update( int64_t currTime ) {}; + + Action::ActionPtr getCurrentAction() const; + + void setCurrentAction( Action::ActionPtr pAction ); + + ///// IN RANGE LOGIC ///// + + // check if another actor is in the actors in range set + bool isInRangeSet( CharaPtr pChara ) const; + + CharaPtr getClosestChara(); + + void sendToInRangeSet( Network::Packets::GamePacketPtr pPacket, bool bToSelf = false ); + + // add an actor to in range set + void addInRangeChara( CharaPtr pChara ); + + // remove an actor from the in range set + void removeInRangeChara( Chara& chara ); + + // return true if there is at least one actor in the in range set + bool hasInRangeActor() const; + + void removeFromInRange(); + + // clear the whole in range set, this does no cleanup + virtual void clearInRangeSet(); + + ZonePtr getCurrentZone() const; + + void setCurrentZone( ZonePtr currZone ); + + // get the current cell of a region the actor is in + Cell* getCell() const; + + // set the current cell + void setCell( Cell* pCell ); + + Core::Cell* m_pCell; + +}; + +} +} +#endif diff --git a/src/servers/sapphire_zone/Actor/EventNpc.cpp b/src/servers/sapphire_zone/Actor/EventNpc.cpp index af3eb0a3..47555f8b 100644 --- a/src/servers/sapphire_zone/Actor/EventNpc.cpp +++ b/src/servers/sapphire_zone/Actor/EventNpc.cpp @@ -24,7 +24,7 @@ extern Core::Logger g_log; uint32_t Core::Entity::EventNpc::m_nextID = 1249241694; Core::Entity::EventNpc::EventNpc() : - Actor( ObjKind::EventNpc ) + Chara( ObjKind::EventNpc ) { m_id = 0; m_status = ActorStatus::Idle; @@ -36,7 +36,7 @@ Core::Entity::EventNpc::~EventNpc() } Core::Entity::EventNpc::EventNpc( uint32_t enpcId, const Common::FFXIVARR_POSITION3& spawnPos, float rotation ) : - Actor( ObjKind::EventNpc ) + Chara( ObjKind::EventNpc ) { EventNpc::m_nextID++; m_id = EventNpc::m_nextID; diff --git a/src/servers/sapphire_zone/Actor/EventNpc.h b/src/servers/sapphire_zone/Actor/EventNpc.h index 726eae94..854e4453 100644 --- a/src/servers/sapphire_zone/Actor/EventNpc.h +++ b/src/servers/sapphire_zone/Actor/EventNpc.h @@ -1,13 +1,13 @@ #ifndef _EVENTNPC_H #define _EVENTNPC_H -#include "Actor.h" +#include "Chara.h" namespace Core { namespace Entity { -// class for Mobs inheriting from Actor -class EventNpc : public Actor +// class for Mobs inheriting from Chara +class EventNpc : public Chara { public: EventNpc(); diff --git a/src/servers/sapphire_zone/Actor/GameObject.cpp b/src/servers/sapphire_zone/Actor/GameObject.cpp deleted file mode 100644 index 16c042ab..00000000 --- a/src/servers/sapphire_zone/Actor/GameObject.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "GameObject.h" - -#include "Player.h" -#include "Actor.h" -#include "BattleNpc.h" -#include "EventNpc.h" - -Core::Entity::GameObject::GameObject( ObjKind type ) : - m_objKind( type ) -{ - -} - -uint32_t Core::Entity::GameObject::getId() const -{ - return m_id; -} - -Core::Entity::GameObject::ObjKind Core::Entity::GameObject::getObjKind() const -{ - return m_objKind; -} - -Core::Common::FFXIVARR_POSITION3& Core::Entity::GameObject::getPos() -{ - return m_pos; -} - -void Core::Entity::GameObject::setPos( float x, float y, float z ) -{ - m_pos.x = x; - m_pos.y = y; - m_pos.z = z; -} - -void Core::Entity::GameObject::setPos( const Core::Common::FFXIVARR_POSITION3& pos ) -{ - m_pos = pos; -} - -float Core::Entity::GameObject::getRot() const -{ - return m_rot; -} - -void Core::Entity::GameObject::setRot( float rot ) -{ - m_rot = rot; -} - -bool Core::Entity::GameObject::isPlayer() const -{ - return m_objKind == ObjKind::Player; -} - -bool Core::Entity::GameObject::isBattleNpc() const -{ - return m_objKind == ObjKind::BattleNpc; -} - -bool Core::Entity::GameObject::isEventNpc() const -{ - return m_objKind == ObjKind::EventNpc; -} - -/*! \return pointer to this instance as ActorPtr */ -Core::Entity::ActorPtr Core::Entity::GameObject::getAsActor() -{ - return boost::dynamic_pointer_cast< Entity::Actor, Entity::GameObject >( shared_from_this() ); -} - -/*! \return pointer to this instance as PlayerPtr */ -Core::Entity::PlayerPtr Core::Entity::GameObject::getAsPlayer() -{ - if( !isPlayer() ) - return nullptr; - return boost::dynamic_pointer_cast< Entity::Player, Entity::GameObject >( shared_from_this() ); -} - -/*! \return pointer to this instance as BattleNpcPtr */ -Core::Entity::BattleNpcPtr Core::Entity::GameObject::getAsBattleNpc() -{ - if( !isBattleNpc() ) - return nullptr; - return boost::dynamic_pointer_cast< Entity::BattleNpc, Entity::GameObject >( shared_from_this() ); -} - -/*! \return pointer to this instance as EventNpcPtr */ -Core::Entity::EventNpcPtr Core::Entity::GameObject::getAsEventNpc() -{ - if( !isEventNpc() ) - return nullptr; - return boost::dynamic_pointer_cast< Entity::EventNpc, Entity::GameObject >( shared_from_this() ); -} diff --git a/src/servers/sapphire_zone/Actor/GameObject.h b/src/servers/sapphire_zone/Actor/GameObject.h deleted file mode 100644 index d1f70b3b..00000000 --- a/src/servers/sapphire_zone/Actor/GameObject.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef _GAME_OBJECT_H_ -#define _GAME_OBJECT_H_ - -#include -#include - -#include "Forwards.h" -#include -#include -#include - -namespace Core { -namespace Entity { - -/*! -\class GameObject -\brief Base class for all actor/objects - -*/ - class GameObject : public boost::enable_shared_from_this< GameObject > - { - public: - enum ObjKind : uint8_t - { - None = 0x00, - Player = 0x01, - BattleNpc = 0x02, - EventNpc = 0x03, - Treasure = 0x04, - Aetheryte = 0x05, - GatheringPoint = 0x06, - EventObj = 0x07, - Mount = 0x08, - Companion = 0x09, - Retainer = 0x0A, - Area = 0x0B, - Housing = 0x0C, - Cutscene = 0x0D, - CardStand = 0x0E, - }; - - protected: - /*! Position of the object */ - Common::FFXIVARR_POSITION3 m_pos; - /*! Rotation of the object */ - float m_rot; - /*! Id of the actor */ - uint32_t m_id; - /*! Type of the actor */ - ObjKind m_objKind; - - public: - explicit GameObject( ObjKind type ); - virtual ~GameObject() {}; - - virtual void spawn( PlayerPtr pTarget ) {} - virtual void despawn( PlayerPtr pTarget ) {} - - uint32_t getId() const; - - ObjKind getObjKind() const; - - Common::FFXIVARR_POSITION3& getPos(); - void setPos( const Common::FFXIVARR_POSITION3& pos ); - void setPos( float x, float y, float z ); - - float getRot() const; - void setRot( float rot ); - - bool isPlayer() const; - bool isBattleNpc() const; - bool isEventNpc() const; - - ActorPtr getAsActor(); - PlayerPtr getAsPlayer(); - BattleNpcPtr getAsBattleNpc(); - EventNpcPtr getAsEventNpc(); - }; - -} -} -#endif diff --git a/src/servers/sapphire_zone/Actor/InstanceObject.cpp b/src/servers/sapphire_zone/Actor/InstanceObject.cpp index a182b66b..17b75497 100644 --- a/src/servers/sapphire_zone/Actor/InstanceObject.cpp +++ b/src/servers/sapphire_zone/Actor/InstanceObject.cpp @@ -2,7 +2,7 @@ #include "Zone/InstanceContent.h" Core::Entity::InstanceObject::InstanceObject( uint32_t objectId, uint32_t mapLinkId ) : - Core::Entity::GameObject( ObjKind::EventObj ), + Core::Entity::Actor( ObjKind::EventObj ), m_mapLinkId( mapLinkId ), m_state( 0 ) { diff --git a/src/servers/sapphire_zone/Actor/InstanceObject.h b/src/servers/sapphire_zone/Actor/InstanceObject.h index 6bd61e0f..ed7d4d1a 100644 --- a/src/servers/sapphire_zone/Actor/InstanceObject.h +++ b/src/servers/sapphire_zone/Actor/InstanceObject.h @@ -1,13 +1,13 @@ #ifndef SAPPHIRE_INSTANCEOBJECT_H #define SAPPHIRE_INSTANCEOBJECT_H -#include "GameObject.h" +#include "Actor.h" namespace Core { namespace Entity { - class InstanceObject : public GameObject + class InstanceObject : public Actor { public: InstanceObject( uint32_t objectId, uint32_t mapLinkId ); diff --git a/src/servers/sapphire_zone/Actor/Player.cpp b/src/servers/sapphire_zone/Actor/Player.cpp index 4c7c3df8..e3cf4b3c 100644 --- a/src/servers/sapphire_zone/Actor/Player.cpp +++ b/src/servers/sapphire_zone/Actor/Player.cpp @@ -55,7 +55,7 @@ using namespace Core::Network::Packets::Server; // player constructor Core::Entity::Player::Player() : - Actor( ObjKind::Player ), + Chara( ObjKind::Player ), m_lastWrite( 0 ), m_lastPing( 0 ), m_bIsLogin( false ), @@ -250,7 +250,7 @@ void Core::Entity::Player::calculateStats() } -void Core::Entity::Player::setAutoattack(bool mode) +void Core::Entity::Player::setAutoattack( bool mode ) { m_bAutoattack = mode; m_lastAttack = Util::getTimeMs(); @@ -829,10 +829,10 @@ void Core::Entity::Player::despawn( Entity::PlayerPtr pTarget ) pPlayer->queuePacket( ActorControlPacket143( getId(), DespawnZoneScreenMsg, 0x04, getId(), 0x01 ) ); } -Core::Entity::ActorPtr Core::Entity::Player::lookupTargetById( uint64_t targetId ) +Core::Entity::CharaPtr Core::Entity::Player::lookupTargetById( uint64_t targetId ) { - ActorPtr targetActor; - auto inRange = getInRangeActors( true ); + CharaPtr targetActor; + auto inRange = getInRangeCharas(true); for( auto actor : inRange ) { if( actor->getId() == targetId ) @@ -1000,12 +1000,12 @@ void Core::Entity::Player::update( int64_t currTime ) if( !checkAction() ) { - if( m_targetId && m_currentStance == Entity::Actor::Stance::Active && isAutoattackOn() ) + if( m_targetId && m_currentStance == Entity::Chara::Stance::Active && isAutoattackOn() ) { auto mainWeap = m_pInventory->getItemAt( Inventory::GearSet0, Inventory::EquipSlot::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_inRangeActors ) + for( auto actor : m_inRangeCharas ) { if( actor->getId() == m_targetId && actor->isAlive() && mainWeap ) { @@ -1408,7 +1408,7 @@ uint8_t Core::Entity::Player::getEquipDisplayFlags() const void Core::Entity::Player::mount( uint32_t id ) { m_mount = id; - sendToInRangeSet( ActorControlPacket142( getId(), ActorControlType::SetStatus, static_cast< uint8_t >( Entity::Actor::ActorStatus::Mounted )), true ); + sendToInRangeSet( ActorControlPacket142( getId(), ActorControlType::SetStatus, static_cast< uint8_t >( Entity::Chara::ActorStatus::Mounted )), true ); sendToInRangeSet( ActorControlPacket143( getId(), 0x39e, 12 ), true ); //? ZoneChannelPacket< FFXIVIpcMount > mountPacket( getId() ); @@ -1419,7 +1419,7 @@ void Core::Entity::Player::mount( uint32_t id ) void Core::Entity::Player::dismount() { sendToInRangeSet( ActorControlPacket142( getId(), ActorControlType::SetStatus, - static_cast< uint8_t >( Entity::Actor::ActorStatus::Idle )), true ); + static_cast< uint8_t >( Entity::Chara::ActorStatus::Idle )), true ); sendToInRangeSet( ActorControlPacket143( getId(), ActorControlType::Dismount, 1 ), true ); m_mount = 0; } @@ -1429,7 +1429,7 @@ uint8_t Core::Entity::Player::getCurrentMount() const return m_mount; } -void Core::Entity::Player::autoAttack( ActorPtr pTarget ) +void Core::Entity::Player::autoAttack( CharaPtr pTarget ) { auto mainWeap = m_pInventory->getItemAt( Inventory::GearSet0, @@ -1663,15 +1663,15 @@ void Core::Entity::Player::finishZoning() case ZoneingType::Return: case ZoneingType::ReturnDead: { - if( getStatus() == Entity::Actor::ActorStatus::Dead ) + if( getStatus() == Entity::Chara::ActorStatus::Dead ) { resetHp(); resetMp(); - setStatus( Entity::Actor::ActorStatus::Idle ); + setStatus( Entity::Chara::ActorStatus::Idle ); sendToInRangeSet( ActorControlPacket143( getId(), ZoneIn, 0x01, 0x01, 0, 111 ), true ); sendToInRangeSet( ActorControlPacket142( getId(), SetStatus, - static_cast< uint8_t >( Entity::Actor::ActorStatus::Idle ) ), true ); + static_cast< uint8_t >( Entity::Chara::ActorStatus::Idle ) ), true ); } else sendToInRangeSet( ActorControlPacket143( getId(), ZoneIn, 0x01, 0x00, 0, 111 ), true ); diff --git a/src/servers/sapphire_zone/Actor/Player.h b/src/servers/sapphire_zone/Actor/Player.h index 7fb80e58..291091c0 100644 --- a/src/servers/sapphire_zone/Actor/Player.h +++ b/src/servers/sapphire_zone/Actor/Player.h @@ -5,7 +5,7 @@ #include -#include "Actor.h" +#include "Chara.h" #include "Inventory/Inventory.h" #include "Event/EventHandler.h" #include @@ -33,7 +33,7 @@ struct QueuedZoning * Inheriting from Actor * */ -class Player : public Actor +class Player : public Chara { public: /*! Contructor */ @@ -42,7 +42,7 @@ public: /*! Destructor */ ~Player(); - void autoAttack( ActorPtr pTarget ) override; + void autoAttack( CharaPtr pTarget ) override; // EventHandlers ////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -526,7 +526,7 @@ public: bool actionHasCastTime( uint32_t actionId ); - Core::Entity::ActorPtr lookupTargetById( uint64_t targetId ); + Core::Entity::CharaPtr lookupTargetById( uint64_t targetId ); bool isLogin() const; void setIsLogin( bool bIsLogin ); diff --git a/src/servers/sapphire_zone/Actor/PlayerEvent.cpp b/src/servers/sapphire_zone/Actor/PlayerEvent.cpp index aeeb5ad9..b0ba4679 100644 --- a/src/servers/sapphire_zone/Actor/PlayerEvent.cpp +++ b/src/servers/sapphire_zone/Actor/PlayerEvent.cpp @@ -227,7 +227,7 @@ void Core::Entity::Player::eventActionStart( uint32_t eventId, ActionCallback interruptCallback, uint64_t additional ) { - auto pEventAction = Action::make_EventAction( getAsActor(), eventId, action, + auto pEventAction = Action::make_EventAction( getAsChara(), eventId, action, finishCallback, interruptCallback, additional ); setCurrentAction( pEventAction ); @@ -257,7 +257,7 @@ void Core::Entity::Player::eventItemActionStart( uint32_t eventId, ActionCallback interruptCallback, uint64_t additional ) { - Action::ActionPtr pEventItemAction = Action::make_EventItemAction( getAsActor(), eventId, action, + Action::ActionPtr pEventItemAction = Action::make_EventItemAction( getAsChara(), eventId, action, finishCallback, interruptCallback, additional ); setCurrentAction( pEventItemAction ); diff --git a/src/servers/sapphire_zone/Forwards.h b/src/servers/sapphire_zone/Forwards.h index fa387adb..85e07eef 100644 --- a/src/servers/sapphire_zone/Forwards.h +++ b/src/servers/sapphire_zone/Forwards.h @@ -34,8 +34,8 @@ namespace Core namespace Entity { - TYPE_FORWARD( GameObject ); TYPE_FORWARD( Actor ); + TYPE_FORWARD( Chara ); TYPE_FORWARD( Player ); TYPE_FORWARD( BattleNpc ); TYPE_FORWARD( EventNpc ); diff --git a/src/servers/sapphire_zone/Math/CalcBattle.cpp b/src/servers/sapphire_zone/Math/CalcBattle.cpp index fb95cddc..9b1bc1a4 100644 --- a/src/servers/sapphire_zone/Math/CalcBattle.cpp +++ b/src/servers/sapphire_zone/Math/CalcBattle.cpp @@ -2,7 +2,7 @@ #include #include -#include "Actor/Actor.h" +#include "Actor/Chara.h" #include "Actor/Player.h" #include "CalcBattle.h" diff --git a/src/servers/sapphire_zone/Math/CalcBattle.h b/src/servers/sapphire_zone/Math/CalcBattle.h index 8c43107f..72a160c0 100644 --- a/src/servers/sapphire_zone/Math/CalcBattle.h +++ b/src/servers/sapphire_zone/Math/CalcBattle.h @@ -2,7 +2,7 @@ #define _CALCBATTLE_H #include -#include "Actor/Actor.h" +#include "Actor/Chara.h" using namespace Core::Entity; diff --git a/src/servers/sapphire_zone/Math/CalcStats.cpp b/src/servers/sapphire_zone/Math/CalcStats.cpp index d15814dd..52213552 100644 --- a/src/servers/sapphire_zone/Math/CalcStats.cpp +++ b/src/servers/sapphire_zone/Math/CalcStats.cpp @@ -2,7 +2,7 @@ #include #include -#include "Actor/Actor.h" +#include "Actor/Chara.h" #include "Actor/Player.h" #include "CalcStats.h" diff --git a/src/servers/sapphire_zone/Math/CalcStats.h b/src/servers/sapphire_zone/Math/CalcStats.h index 2bf17da5..868d86f4 100644 --- a/src/servers/sapphire_zone/Math/CalcStats.h +++ b/src/servers/sapphire_zone/Math/CalcStats.h @@ -2,7 +2,7 @@ #define _CALCSTATS_H #include -#include "Actor/Actor.h" +#include "Actor/Chara.h" using namespace Core::Entity; diff --git a/src/servers/sapphire_zone/Network/Handlers/ActionHandler.cpp b/src/servers/sapphire_zone/Network/Handlers/ActionHandler.cpp index 70ce5885..9739756a 100644 --- a/src/servers/sapphire_zone/Network/Handlers/ActionHandler.cpp +++ b/src/servers/sapphire_zone/Network/Handlers/ActionHandler.cpp @@ -119,10 +119,10 @@ void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& in case ClientTrigger::ToggleSeathe: // Toggle sheathe { if ( param11 == 1 ) - player.setStance( Entity::Actor::Stance::Active ); + player.setStance( Entity::Chara::Stance::Active ); else { - player.setStance( Entity::Actor::Stance::Passive ); + player.setStance( Entity::Chara::Stance::Passive ); player.setAutoattack( false ); } @@ -135,7 +135,7 @@ void Core::Network::GameConnection::actionHandler( const Packets::GamePacket& in if ( param11 == 1 ) { player.setAutoattack( true ); - player.setStance( Entity::Actor::Stance::Active ); + player.setStance( Entity::Chara::Stance::Active ); } else player.setAutoattack( false ); diff --git a/src/servers/sapphire_zone/Network/Handlers/EventHandlers.cpp b/src/servers/sapphire_zone/Network/Handlers/EventHandlers.cpp index 399fdf9b..692fc1a5 100644 --- a/src/servers/sapphire_zone/Network/Handlers/EventHandlers.cpp +++ b/src/servers/sapphire_zone/Network/Handlers/EventHandlers.cpp @@ -37,7 +37,7 @@ void Core::Network::GameConnection::eventHandlerTalk( const Packets::GamePacket& std::string eventName = "onTalk"; std::string objName = Event::getEventName( eventId ); - player.sendDebug( "Actor: " + + player.sendDebug( "Chara: " + std::to_string( actorId ) + " -> " + std::to_string( Event::mapEventActorToRealActor( static_cast< uint32_t >( actorId ) ) ) + " \neventId: " + @@ -72,7 +72,7 @@ void Core::Network::GameConnection::eventHandlerEmote( const Packets::GamePacket std::string eventName = "onEmote"; std::string objName = Event::getEventName( eventId ); - player.sendDebug( "Actor: " + + player.sendDebug( "Chara: " + std::to_string( actorId ) + " -> " + std::to_string( Event::mapEventActorToRealActor( static_cast< uint32_t >( actorId ) ) ) + " \neventId: " + diff --git a/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp b/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp index 865ffdc1..63c19006 100644 --- a/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp +++ b/src/servers/sapphire_zone/Network/Handlers/GMCommandHandlers.cpp @@ -104,7 +104,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac ", params: " + std::to_string( param1 ) + ", " + std::to_string( param2 ) + ", " + std::to_string( param3 ) ); - Core::Entity::ActorPtr targetActor; + Core::Entity::CharaPtr targetActor; if( player.getId() == param3 ) @@ -113,7 +113,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac } else { - auto inRange = player.getInRangeActors(); + auto inRange = player.getInRangeCharas(); for( auto actor : inRange ) { if( actor->getId() == param3 ) @@ -138,7 +138,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac targetPlayer->setLookAt( CharaLook::Race, param1 ); player.sendNotice( "Race for " + targetPlayer->getName() + " was set to " + std::to_string( param1 ) ); targetPlayer->spawn( targetPlayer ); - auto inRange = targetPlayer->getInRangeActors(); + auto inRange = targetPlayer->getInRangeCharas(); for( auto actor : inRange ) { targetPlayer->despawn( actor->getAsPlayer() ); @@ -151,7 +151,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac targetPlayer->setLookAt( CharaLook::Tribe, param1 ); player.sendNotice( "Tribe for " + targetPlayer->getName() + " was set to " + std::to_string( param1 ) ); targetPlayer->spawn( targetPlayer ); - auto inRange = targetPlayer->getInRangeActors(); + auto inRange = targetPlayer->getInRangeCharas(); for( auto actor : inRange ) { targetPlayer->despawn( actor->getAsPlayer() ); @@ -164,7 +164,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac targetPlayer->setLookAt( CharaLook::Gender, param1 ); player.sendNotice( "Sex for " + targetPlayer->getName() + " was set to " + std::to_string( param1 ) ); targetPlayer->spawn( targetPlayer ); - auto inRange = targetActor->getInRangeActors(); + auto inRange = targetActor->getInRangeCharas(); for( auto actor : inRange ) { targetPlayer->despawn( actor->getAsPlayer() ); @@ -439,7 +439,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::GamePacket& inPac case GmCommand::Jump: { - auto inRange = player.getInRangeActors(); + auto inRange = player.getInRangeCharas(); player.changePosition( targetActor->getPos().x, targetActor->getPos().y, targetActor->getPos().z, targetActor->getRotation() ); @@ -466,7 +466,7 @@ void Core::Network::GameConnection::gm2Handler( const Packets::GamePacket& inPac g_log.debug( player.getName() + " used GM2 commandId: " + std::to_string( commandId ) + ", params: " + param1 ); auto targetSession = g_serverZone.getSession( param1 ); - Core::Entity::ActorPtr targetActor; + Core::Entity::CharaPtr targetActor; if( targetSession != nullptr ) { @@ -496,11 +496,11 @@ void Core::Network::GameConnection::gm2Handler( const Packets::GamePacket& inPac { targetPlayer->resetHp(); targetPlayer->resetMp(); - targetPlayer->setStatus( Entity::Actor::ActorStatus::Idle ); + targetPlayer->setStatus( Entity::Chara::ActorStatus::Idle ); targetPlayer->sendToInRangeSet( ActorControlPacket143( player.getId(), ZoneIn, 0x01, 0x01, 0, 113 ), true ); targetPlayer->sendToInRangeSet( ActorControlPacket142( player.getId(), SetStatus, - static_cast< uint8_t >( Entity::Actor::ActorStatus::Idle ) ), true ); + static_cast< uint8_t >( Entity::Chara::ActorStatus::Idle ) ), true ); player.sendNotice( "Raised " + targetPlayer->getName() ); break; } diff --git a/src/servers/sapphire_zone/Network/Handlers/SkillHandler.cpp b/src/servers/sapphire_zone/Network/Handlers/SkillHandler.cpp index a47a4988..ac964471 100644 --- a/src/servers/sapphire_zone/Network/Handlers/SkillHandler.cpp +++ b/src/servers/sapphire_zone/Network/Handlers/SkillHandler.cpp @@ -75,7 +75,7 @@ void Core::Network::GameConnection::skillHandler( const Packets::GamePacket& inP } else { - Core::Entity::ActorPtr targetActor = player.getAsPlayer(); + Core::Entity::CharaPtr targetActor = player.getAsPlayer(); if( targetId != player.getId() ) { targetActor = player.lookupTargetById( targetId ); diff --git a/src/servers/sapphire_zone/Network/PacketWrappers/MoveActorPacket.h b/src/servers/sapphire_zone/Network/PacketWrappers/MoveActorPacket.h index 1771d801..ee671e85 100644 --- a/src/servers/sapphire_zone/Network/PacketWrappers/MoveActorPacket.h +++ b/src/servers/sapphire_zone/Network/PacketWrappers/MoveActorPacket.h @@ -21,14 +21,14 @@ class MoveActorPacket : public ZoneChannelPacket< FFXIVIpcActorMove > { public: - MoveActorPacket( Entity::Actor& actor, uint8_t unk1, uint8_t unk2, uint8_t unk3, uint16_t unk4 ) : + MoveActorPacket( Entity::Chara& actor, uint8_t unk1, uint8_t unk2, uint8_t unk3, uint16_t unk4 ) : ZoneChannelPacket< FFXIVIpcActorMove >( actor.getId(), actor.getId() ) { initialize( actor, unk1, unk2, unk3, unk4 ); }; private: - void initialize( Entity::Actor& actor, uint8_t unk1, uint8_t unk2, uint8_t unk3, uint16_t unk4 ) + void initialize( Entity::Chara& actor, uint8_t unk1, uint8_t unk2, uint8_t unk3, uint16_t unk4 ) { m_data.rotation = Math::Util::floatToUInt8Rot( actor.getRotation() ); diff --git a/src/servers/sapphire_zone/Network/PacketWrappers/PlayerSpawnPacket.h b/src/servers/sapphire_zone/Network/PacketWrappers/PlayerSpawnPacket.h index 9c367aa9..e940e53a 100644 --- a/src/servers/sapphire_zone/Network/PacketWrappers/PlayerSpawnPacket.h +++ b/src/servers/sapphire_zone/Network/PacketWrappers/PlayerSpawnPacket.h @@ -90,22 +90,22 @@ namespace Server { if( player.getZoningType() != Common::ZoneingType::None ) { - m_data.displayFlags |= Entity::Actor::DisplayFlags::Invisible; + m_data.displayFlags |= Entity::Chara::DisplayFlags::Invisible; } if( player.getEquipDisplayFlags() & Core::Common::EquipDisplayFlags::HideHead ) { - m_data.displayFlags |= Entity::Actor::DisplayFlags::HideHead; + m_data.displayFlags |= Entity::Chara::DisplayFlags::HideHead; } if( player.getEquipDisplayFlags() & Core::Common::EquipDisplayFlags::HideWeapon ) { - m_data.displayFlags |= Entity::Actor::DisplayFlags::HideWeapon; + m_data.displayFlags |= Entity::Chara::DisplayFlags::HideWeapon; } if( player.getEquipDisplayFlags() & Core::Common::EquipDisplayFlags::Visor ) { - m_data.displayFlags |= Entity::Actor::DisplayFlags::Visor; + m_data.displayFlags |= Entity::Chara::DisplayFlags::Visor; } m_data.currentMount = player.getCurrentMount(); diff --git a/src/servers/sapphire_zone/Network/PacketWrappers/UpdateHpMpTpPacket.h b/src/servers/sapphire_zone/Network/PacketWrappers/UpdateHpMpTpPacket.h index e880a4da..64952593 100644 --- a/src/servers/sapphire_zone/Network/PacketWrappers/UpdateHpMpTpPacket.h +++ b/src/servers/sapphire_zone/Network/PacketWrappers/UpdateHpMpTpPacket.h @@ -2,7 +2,7 @@ #define _UPDATEHPMPTP_H #include -#include +#include #include "Forwards.h" namespace Core { @@ -17,14 +17,14 @@ class UpdateHpMpTpPacket : public ZoneChannelPacket< FFXIVIpcUpdateHpMpTp > { public: - UpdateHpMpTpPacket( Entity::Actor& actor ) : + UpdateHpMpTpPacket( Entity::Chara& actor ) : ZoneChannelPacket< FFXIVIpcUpdateHpMpTp >( actor.getId(), actor.getId() ) { initialize( actor ); }; private: - void initialize( Entity::Actor& actor ) + void initialize( Entity::Chara& actor ) { m_data.hp = actor.getHp(); m_data.mp = actor.getMp(); diff --git a/src/servers/sapphire_zone/Script/NativeScriptApi.h b/src/servers/sapphire_zone/Script/NativeScriptApi.h index 893dc6cd..1d5e5b22 100644 --- a/src/servers/sapphire_zone/Script/NativeScriptApi.h +++ b/src/servers/sapphire_zone/Script/NativeScriptApi.h @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include #include @@ -53,14 +53,14 @@ public: ScriptObject( effectId, typeid( StatusEffectScript ).hash_code() ) { } - virtual void onTick( Entity::Actor& actor ) { } - virtual void onApply( Entity::Actor& actor ) { } - virtual void onRemove( Entity::Actor& actor ) { } - virtual void onExpire( Entity::Actor& actor ) { } - virtual void onPlayerCollision( Entity::Actor& actor, Entity::Actor& actorHit ) { } - virtual void onPlayerFinishCast( Entity::Actor& actor ) { } - virtual void onPlayerDamaged( Entity::Actor& actor ) { } - virtual void onPlayerDeath( Entity::Actor& actor ) { } + virtual void onTick( Entity::Chara& actor ) { } + virtual void onApply( Entity::Chara& actor ) { } + virtual void onRemove( Entity::Chara& actor ) { } + virtual void onExpire( Entity::Chara& actor ) { } + virtual void onPlayerCollision( Entity::Chara& actor, Entity::Chara& actorHit ) { } + virtual void onPlayerFinishCast( Entity::Chara& actor ) { } + virtual void onPlayerDamaged( Entity::Chara& actor ) { } + virtual void onPlayerDeath( Entity::Chara& actor ) { } }; @@ -71,9 +71,9 @@ public: ScriptObject( abilityId, typeid( ActionScript ).hash_code() ) { } - virtual void onStart( Entity::Actor& sourceActor, Entity::Actor& targetActor ) { } - virtual void onCastFinish( Entity::Player& player, Entity::Actor& targetActor ) { } - virtual void onInterrupt( Entity::Actor& sourceActor/*, Core::Entity::Actor targetActor*/ ) { } + virtual void onStart( Entity::Chara& sourceActor, Entity::Chara& targetActor ) { } + virtual void onCastFinish( Entity::Player& player, Entity::Chara& targetActor ) { } + virtual void onInterrupt( Entity::Chara& sourceActor/*, Core::Entity::Chara targetActor*/ ) { } }; diff --git a/src/servers/sapphire_zone/Script/ScriptManager.cpp b/src/servers/sapphire_zone/Script/ScriptManager.cpp index 1e569918..07f0b18f 100644 --- a/src/servers/sapphire_zone/Script/ScriptManager.cpp +++ b/src/servers/sapphire_zone/Script/ScriptManager.cpp @@ -275,7 +275,7 @@ bool Core::Scripting::ScriptManager::onMobKill( Entity::Player& player, uint16_t return true; } -bool Core::Scripting::ScriptManager::onCastFinish( Entity::Player& player, Entity::ActorPtr pTarget, uint32_t actionId ) +bool Core::Scripting::ScriptManager::onCastFinish( Entity::Player& player, Entity::CharaPtr pTarget, uint32_t actionId ) { auto script = m_nativeScriptManager->getScript< ActionScript >( actionId ); @@ -284,7 +284,7 @@ bool Core::Scripting::ScriptManager::onCastFinish( Entity::Player& player, Entit return true; } -bool Core::Scripting::ScriptManager::onStatusReceive( Entity::ActorPtr pActor, uint32_t effectId ) +bool Core::Scripting::ScriptManager::onStatusReceive( Entity::CharaPtr pActor, uint32_t effectId ) { auto script = m_nativeScriptManager->getScript< StatusEffectScript >( effectId ); @@ -300,30 +300,30 @@ bool Core::Scripting::ScriptManager::onStatusReceive( Entity::ActorPtr pActor, u return false; } -bool Core::Scripting::ScriptManager::onStatusTick( Entity::ActorPtr pActor, Core::StatusEffect::StatusEffect& effect ) +bool Core::Scripting::ScriptManager::onStatusTick( Entity::CharaPtr pChara, Core::StatusEffect::StatusEffect& effect ) { auto script = m_nativeScriptManager->getScript< StatusEffectScript >( effect.getId() ); if( script ) { - if( pActor->isPlayer() ) - pActor->getAsPlayer()->sendDebug( "Calling status tick for statusid: " + std::to_string( effect.getId() ) ); + if( pChara->isPlayer() ) + pChara->getAsPlayer()->sendDebug( "Calling status tick for statusid: " + std::to_string( effect.getId() ) ); - script->onTick( *pActor ); + script->onTick( *pChara ); return true; } return false; } -bool Core::Scripting::ScriptManager::onStatusTimeOut( Entity::ActorPtr pActor, uint32_t effectId ) +bool Core::Scripting::ScriptManager::onStatusTimeOut( Entity::CharaPtr pChara, uint32_t effectId ) { auto script = m_nativeScriptManager->getScript< StatusEffectScript >( effectId ); if( script ) { - if( pActor->isPlayer() ) - pActor->getAsPlayer()->sendDebug( "Calling status timeout for statusid: " + std::to_string( effectId ) ); + if( pChara->isPlayer() ) + pChara->getAsPlayer()->sendDebug( "Calling status timeout for statusid: " + std::to_string( effectId ) ); - script->onExpire( *pActor ); + script->onExpire( *pChara ); return true; } diff --git a/src/servers/sapphire_zone/Script/ScriptManager.h b/src/servers/sapphire_zone/Script/ScriptManager.h index 634afefb..ac423b39 100644 --- a/src/servers/sapphire_zone/Script/ScriptManager.h +++ b/src/servers/sapphire_zone/Script/ScriptManager.h @@ -48,11 +48,11 @@ namespace Core bool onMobKill( Entity::Player& player, uint16_t nameId ); - bool onCastFinish( Entity::Player& pPlayer, Entity::ActorPtr pTarget, uint32_t actionId ); + bool onCastFinish( Entity::Player& pPlayer, Entity::CharaPtr pTarget, uint32_t actionId ); - bool onStatusReceive( Entity::ActorPtr pActor, uint32_t effectId ); - bool onStatusTick( Entity::ActorPtr pActor, Core::StatusEffect::StatusEffect& effect ); - bool onStatusTimeOut( Entity::ActorPtr pActor, uint32_t effectId ); + bool onStatusReceive( Entity::CharaPtr pActor, uint32_t effectId ); + bool onStatusTick( Entity::CharaPtr pActor, Core::StatusEffect::StatusEffect& effect ); + bool onStatusTimeOut( Entity::CharaPtr pActor, uint32_t effectId ); bool onZoneInit( ZonePtr pZone ); diff --git a/src/servers/sapphire_zone/Script/Scripts/ScriptObject.h b/src/servers/sapphire_zone/Script/Scripts/ScriptObject.h index 17da1520..3848b55c 100644 --- a/src/servers/sapphire_zone/Script/Scripts/ScriptObject.h +++ b/src/servers/sapphire_zone/Script/Scripts/ScriptObject.h @@ -3,7 +3,7 @@ #include