From 77c4403a2c960f0fefb906c470de6627cd6d2adc Mon Sep 17 00:00:00 2001 From: Mordred Date: Thu, 17 Jan 2019 23:54:47 +0100 Subject: [PATCH] Make sure to reinit DB -> Various small fixes and refactors --- src/world/Actor/Actor.cpp | 6 +- src/world/Actor/Actor.h | 2 +- src/world/Actor/BNpc.cpp | 258 +++++++++++++++++++++++++- src/world/Actor/BNpc.h | 42 ++++- src/world/Manager/DebugCommandMgr.cpp | 2 +- src/world/Territory/Zone.cpp | 31 ++-- src/world/Territory/Zone.h | 2 +- 7 files changed, 318 insertions(+), 25 deletions(-) diff --git a/src/world/Actor/Actor.cpp b/src/world/Actor/Actor.cpp index 37dfa204..f3a70534 100644 --- a/src/world/Actor/Actor.cpp +++ b/src/world/Actor/Actor.cpp @@ -251,13 +251,13 @@ bool Sapphire::Entity::Actor::isInRangeSet( ActorPtr pActor ) const /*! \return ActorPtr of the closest actor in range, if none, nullptr */ -Sapphire::Entity::ActorPtr Sapphire::Entity::Actor::getClosestActor() +Sapphire::Entity::CharaPtr Sapphire::Entity::Actor::getClosestChara() { if( m_inRangeActor.empty() ) // no actors in range, don't bother return nullptr; - ActorPtr tmpActor = nullptr; + CharaPtr tmpActor = nullptr; // arbitrary high number float minDistance = 10000; @@ -270,7 +270,7 @@ Sapphire::Entity::ActorPtr Sapphire::Entity::Actor::getClosestActor() if( distance < minDistance ) { minDistance = distance; - tmpActor = pCurAct; + tmpActor = pCurAct->getAsChara(); } } diff --git a/src/world/Actor/Actor.h b/src/world/Actor/Actor.h index 5f20797d..62d47765 100644 --- a/src/world/Actor/Actor.h +++ b/src/world/Actor/Actor.h @@ -91,7 +91,7 @@ namespace Sapphire::Entity // check if another actor is in the actors in range set bool isInRangeSet( ActorPtr pActor ) const; - ActorPtr getClosestActor(); + CharaPtr getClosestChara(); void sendToInRangeSet( Network::Packets::FFXIVPacketBasePtr pPacket, bool bToSelf = false ); diff --git a/src/world/Actor/BNpc.cpp b/src/world/Actor/BNpc.cpp index 7b42324c..b9250e66 100644 --- a/src/world/Actor/BNpc.cpp +++ b/src/world/Actor/BNpc.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "Forwards.h" #include "Action/Action.h" @@ -17,6 +18,7 @@ #include "Network/PacketWrappers/ActorControlPacket144.h" #include "Network/PacketWrappers/UpdateHpMpTpPacket.h" #include "Network/PacketWrappers/NpcSpawnPacket.h" +#include "Network/PacketWrappers/MoveActorPacket.h" #include "StatusEffect/StatusEffect.h" #include "Action/ActionCollision.h" @@ -41,7 +43,7 @@ Sapphire::Entity::BNpc::BNpc( FrameworkPtr pFw ) : } Sapphire::Entity::BNpc::BNpc( uint32_t id, BNpcTemplatePtr pTemplate, float posX, float posY, float posZ, float rot, - uint8_t level, uint32_t maxHp, FrameworkPtr pFw ) : + uint8_t level, uint32_t maxHp, ZonePtr pZone, FrameworkPtr pFw ) : Npc( ObjKind::BattleNpc, pFw ) { m_id = id; @@ -60,11 +62,17 @@ Sapphire::Entity::BNpc::BNpc( uint32_t id, BNpcTemplatePtr pTemplate, float posX m_rot = rot; m_level = level; + m_pCurrentZone = pZone; + + m_spawnPos = m_pos; + m_maxHp = maxHp; m_maxMp = 200; m_hp = maxHp; m_mp = 200; + m_state = BNpcState::Idle; + m_baseStats.max_hp = maxHp; m_baseStats.max_mp = 200; @@ -121,3 +129,251 @@ void Sapphire::Entity::BNpc::spawn( PlayerPtr pTarget ) { pTarget->queuePacket( std::make_shared< NpcSpawnPacket >( *getAsBNpc(), *pTarget ) ); } + +Sapphire::Entity::BNpcState Sapphire::Entity::BNpc::getState() const +{ + return m_state; +} + +void Sapphire::Entity::BNpc::setState( BNpcState state ) +{ + m_state = state; +} + +bool Sapphire::Entity::BNpc::moveTo( const FFXIVARR_POSITION3& pos ) +{ + if( Util::distance( getPos().x, getPos().y, getPos().z, pos.x, pos.y, pos.z ) <= 4 ) + // reached destination + return true; + + float rot = Util::calcAngFrom( getPos().x, getPos().z, pos.x, pos.z ); + float newRot = PI - rot + ( PI / 2 ); + + face( pos ); + float angle = Util::calcAngFrom( getPos().x, getPos().z, pos.x, pos.z ) + PI; + + auto x = ( cosf( angle ) * 1.1f ); + auto y = ( getPos().y + pos.y ) * 0.5f; // fake value while there is no collision + auto z = ( sinf( angle ) * 1.1f ); + + Common::FFXIVARR_POSITION3 newPos{ getPos().x + x, y, getPos().z + z }; + setPos( newPos ); + + Common::FFXIVARR_POSITION3 tmpPos{ getPos().x + x, y, getPos().z + z }; + + setPos( tmpPos ); + setRot( newRot ); + + sendPositionUpdate(); + + return false; +} + +void Sapphire::Entity::BNpc::sendPositionUpdate() +{ + auto movePacket = std::make_shared< MoveActorPacket >( *getAsChara(), 0x3A, 0, 0, 0x5A ); + sendToInRangeSet( movePacket ); +} + +void Sapphire::Entity::BNpc::hateListClear() +{ + auto it = m_hateList.begin(); + for( auto listEntry : m_hateList ) + { + //if( isInRangeSet( listEntry->m_pActor ) ) + //deaggro( listEntry->m_pActor ); + } + m_hateList.clear(); +} + +Sapphire::Entity::ActorPtr Sapphire::Entity::BNpc::hateListGetHighest() +{ + auto it = m_hateList.begin(); + uint32_t maxHate = 0; + std::shared_ptr< HateListEntry > entry; + for( ; it != m_hateList.end(); ++it ) + { + if( ( *it )->m_hateAmount > maxHate ) + { + maxHate = ( *it )->m_hateAmount; + entry = *it; + } + } + + if( entry && maxHate != 0 ) + return entry->m_pActor; + + return nullptr; +} + +void Sapphire::Entity::BNpc::hateListAdd( Sapphire::Entity::ActorPtr pActor, int32_t hateAmount ) +{ + auto hateEntry = std::make_shared< HateListEntry >(); + hateEntry->m_hateAmount = hateAmount; + hateEntry->m_pActor = pActor; + + m_hateList.insert( hateEntry ); +} + +void Sapphire::Entity::BNpc::hateListUpdate( Sapphire::Entity::ActorPtr pActor, int32_t hateAmount ) +{ + for( auto listEntry : m_hateList ) + { + if( listEntry->m_pActor == pActor ) + { + listEntry->m_hateAmount += hateAmount; + return; + } + } + + auto hateEntry = std::make_shared< HateListEntry >(); + hateEntry->m_hateAmount = hateAmount; + hateEntry->m_pActor = pActor; + m_hateList.insert( hateEntry ); +} + +void Sapphire::Entity::BNpc::hateListRemove( Sapphire::Entity::ActorPtr pActor ) +{ + for( auto listEntry : m_hateList ) + { + if( listEntry->m_pActor == pActor ) + { + + m_hateList.erase( listEntry ); + if( pActor->isPlayer() ) + { + PlayerPtr tmpPlayer = pActor->getAsPlayer(); + //tmpPlayer->onMobDeaggro( getAsBattleNpc() ); + } + return; + } + } +} + +bool Sapphire::Entity::BNpc::hateListHasActor( Sapphire::Entity::ActorPtr pActor ) +{ + for( auto listEntry : m_hateList ) + { + if( listEntry->m_pActor == pActor ) + return true; + } + return false; +} + +void Sapphire::Entity::BNpc::aggro( Sapphire::Entity::ActorPtr pActor ) +{ + m_lastAttack = Util::getTimeMs(); + hateListUpdate( pActor, 1 ); + + changeTarget( pActor->getId() ); + setStance( Stance::Active ); + m_state = BNpcState::Combat; + + if( pActor->isPlayer() ) + { + PlayerPtr tmpPlayer = pActor->getAsPlayer(); + tmpPlayer->queuePacket( makeActorControl142( getId(), ActorControlType::ToggleWeapon, 0, 1, 1 ) ); + //tmpPlayer->onMobAggro( getAsBattleNpc() ); + } +} + +void Sapphire::Entity::BNpc::deaggro( Sapphire::Entity::ActorPtr pActor ) +{ + if( !hateListHasActor( pActor ) ) + hateListRemove( pActor ); + + if( pActor->isPlayer() ) + { + PlayerPtr tmpPlayer = pActor->getAsPlayer(); + //tmpPlayer->onMobDeaggro( getAsBattleNpc() ); + } +} + +void Sapphire::Entity::BNpc::update( int64_t currTime ) +{ + switch( m_state ) + { + case BNpcState::Retreat: + { + if( moveTo( m_spawnPos ) ) + m_state = BNpcState::Idle; + } + break; + + case BNpcState::Idle: + { + CharaPtr pClosestActor = getClosestChara(); + + if( ( pClosestActor != nullptr ) && pClosestActor->isAlive() ) + { + auto distance = Util::distance( getPos().x, getPos().y, getPos().z, + pClosestActor->getPos().x, + pClosestActor->getPos().y, + pClosestActor->getPos().z ); + + if( distance < 8 && pClosestActor->isPlayer() ) + aggro( pClosestActor ); + //if( distance < 8 && getbehavior() == 2 ) + // aggro( pClosestActor ); + } + } + + case BNpcState::Combat: + { + auto pActor = hateListGetHighest(); + if( !pActor ) + return; + auto pClosestActor = pActor->getAsChara(); + + auto distanceOrig = Util::distance( getPos().x, getPos().y, getPos().z, + m_spawnPos.x, + m_spawnPos.y, + m_spawnPos.z ); + + if( pClosestActor && !pClosestActor->isAlive() ) + { + hateListRemove( pClosestActor ); + pActor = hateListGetHighest(); + if( pActor ) + pClosestActor = pActor->getAsChara(); + else + pClosestActor.reset(); + } + + if( pClosestActor != nullptr ) + { + auto distance = Util::distance( getPos().x, getPos().y, getPos().z, + pClosestActor->getPos().x, + pClosestActor->getPos().y, + pClosestActor->getPos().z ); + + if( distanceOrig > 30 ) + { + hateListClear(); + changeTarget( INVALID_GAME_OBJECT_ID ); + setStance( Stance::Passive ); + //setOwner( nullptr ); + m_state = BNpcState::Retreat; + break; + } + + if( distance > 4 ) + moveTo( pClosestActor->getPos() ); + else + { + if( face( pClosestActor->getPos() ) ) + sendPositionUpdate(); + // in combat range. ATTACK! + autoAttack( pClosestActor ); + } + } + else + { + changeTarget( INVALID_GAME_OBJECT_ID ); + setStance( Stance::Passive ); + //setOwner( nullptr ); + m_state = BNpcState::Retreat; + } + } + } +} diff --git a/src/world/Actor/BNpc.h b/src/world/Actor/BNpc.h index f87f66eb..59cc750b 100644 --- a/src/world/Actor/BNpc.h +++ b/src/world/Actor/BNpc.h @@ -13,6 +13,21 @@ namespace Sapphire::Entity { + typedef struct + { + uint32_t m_hateAmount; + ActorPtr m_pActor; + } HateListEntry; + + enum class BNpcState + { + Idle, + Combat, + Retreat, + JustDied, + Dead, + }; + /*! \class BNpc \brief Base class for all BNpcs @@ -24,7 +39,7 @@ namespace Sapphire::Entity public: BNpc( FrameworkPtr pFw ); BNpc( uint32_t id, BNpcTemplatePtr pTemplate, float posX, float posY, float posZ, float rot, - uint8_t level, uint32_t maxHp, FrameworkPtr pFw ); + uint8_t level, uint32_t maxHp, ZonePtr pZone,FrameworkPtr pFw ); virtual ~BNpc() override; @@ -43,6 +58,26 @@ namespace Sapphire::Entity uint8_t getAggressionMode() const; + // return true if it reached the position + bool moveTo( const Common::FFXIVARR_POSITION3& pos ); + + void sendPositionUpdate(); + + BNpcState getState() const; + void setState( BNpcState state ); + + void hateListClear(); + ActorPtr hateListGetHighest(); + void hateListAdd( ActorPtr pActor, int32_t hateAmount ); + void hateListUpdate( ActorPtr pActor, int32_t hateAmount ); + void hateListRemove( ActorPtr pActor ); + bool hateListHasActor( ActorPtr pActor ); + + void aggro( ActorPtr pActor ); + void deaggro( ActorPtr pActor ); + + void update( int64_t currTime ) override; + private: uint32_t m_bNpcBaseId; uint32_t m_bNpcNameId; @@ -56,6 +91,11 @@ namespace Sapphire::Entity uint32_t m_displayFlags; uint8_t m_level; + Common::FFXIVARR_POSITION3 m_spawnPos; + + BNpcState m_state; + std::set< std::shared_ptr< HateListEntry > > m_hateList; + }; } diff --git a/src/world/Manager/DebugCommandMgr.cpp b/src/world/Manager/DebugCommandMgr.cpp index 4d234541..957b1320 100644 --- a/src/world/Manager/DebugCommandMgr.cpp +++ b/src/world/Manager/DebugCommandMgr.cpp @@ -439,7 +439,7 @@ void Sapphire::World::Manager::DebugCommandMgr::add( char* data, Entity::Player& player.getPos().y, player.getPos().z, player.getRot(), - 1, 1000, framework() ); + 1, 1000, playerZone, framework() ); diff --git a/src/world/Territory/Zone.cpp b/src/world/Territory/Zone.cpp index 80ea84db..99cb2fad 100644 --- a/src/world/Territory/Zone.cpp +++ b/src/world/Territory/Zone.cpp @@ -376,8 +376,7 @@ bool Sapphire::Zone::checkWeather() return false; } -/* -void Sapphire::Zone::updateBnpcs( int64_t tickCount ) +void Sapphire::Zone::updateBNpcs( int64_t tickCount ) { if( ( tickCount - m_lastMobUpdate ) > 250 ) { @@ -385,7 +384,7 @@ void Sapphire::Zone::updateBnpcs( int64_t tickCount ) m_lastMobUpdate = tickCount; uint32_t currTime = static_cast< uint32_t >( time( nullptr ) ); - for( auto it3 = m_BattleNpcDeadMap.begin(); it3 != m_BattleNpcDeadMap.end(); ++it3 ) + /*for( auto it3 = m_BattleNpcDeadMap.begin(); it3 != m_BattleNpcDeadMap.end(); ++it3 ) { Entity::BattleNpcPtr pBNpc = *it3; @@ -402,29 +401,29 @@ void Sapphire::Zone::updateBnpcs( int64_t tickCount ) break; } - } + }*/ - for( auto entry : m_BattleNpcMap ) + for( auto entry : m_bNpcMap ) { - Entity::BattleNpcPtr pBNpc = entry.second; + Entity::BNpcPtr pBNpc = entry.second; if( !pBNpc ) continue; - if( !pBNpc->isAlive() && currTime - pBNpc->getTimeOfDeath() > ( 10 ) ) - { - removeActor( pBNpc ); - m_BattleNpcDeadMap.insert( pBNpc ); - break; - } + //if( !pBNpc->isAlive() && currTime - pBNpc->getTimeOfDeath() > ( 10 ) ) + //{ + // removeActor( pBNpc ); + // m_BattleNpcDeadMap.insert( pBNpc ); + // break; + //} pBNpc->update( tickCount ); } } } -*/ + bool Sapphire::Zone::update( uint32_t currTime ) { @@ -434,7 +433,7 @@ bool Sapphire::Zone::update( uint32_t currTime ) bool changedWeather = checkWeather(); updateSessions( changedWeather ); - //updateBnpcs( tickCount ); + updateBNpcs( tickCount ); onUpdate( currTime ); updateSpawnPoints(); @@ -832,8 +831,6 @@ void Sapphire::Zone::updateSpawnPoints() continue; } - uint32_t random = rand() % 20; - auto pBNpc = std::make_shared< Entity::BNpc >( getNextActorId(), bNpcTemplate, point->getPosX(), @@ -841,7 +838,7 @@ void Sapphire::Zone::updateSpawnPoints() point->getPosZ(), dist( mt ), group.getLevel(), - group.getMaxHp(), m_pFw ); + group.getMaxHp(), shared_from_this(), m_pFw ); point->setLinkedBNpc( pBNpc ); pushActor( pBNpc ); diff --git a/src/world/Territory/Zone.h b/src/world/Territory/Zone.h index 4a6a5197..657b99c9 100644 --- a/src/world/Territory/Zone.h +++ b/src/world/Territory/Zone.h @@ -142,7 +142,7 @@ namespace Sapphire bool loadSpawnGroups(); bool checkWeather(); - //void updateBnpcs( int64_t tickCount ); + void updateBNpcs( int64_t tickCount ); bool update( uint32_t currTime );