From edd050ece9c35d13be57ed704df0d085c00cd983 Mon Sep 17 00:00:00 2001 From: NotAdam Date: Sat, 26 Jan 2019 13:40:02 +1100 Subject: [PATCH] heal npcs when retreating, set hp to max when retreat finishes, cleanup --- src/common/Common.h | 1 + src/world/Actor/BNpc.cpp | 32 ++++++++++++++++++- src/world/Actor/Chara.cpp | 19 ++++++----- src/world/Actor/Chara.h | 2 +- src/world/Actor/Player.cpp | 4 +-- src/world/Actor/Player.h | 2 +- .../Network/Handlers/GMCommandHandlers.cpp | 9 ++++-- 7 files changed, 54 insertions(+), 15 deletions(-) diff --git a/src/common/Common.h b/src/common/Common.h index 6dfc5e70..1735d54b 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -615,6 +615,7 @@ namespace Sapphire::Common InvincibilityNone, InvincibilityRefill, InvincibilityStayAlive, + InvincibilityIgnoreDamage, }; enum PlayerStateFlag : uint8_t diff --git a/src/world/Actor/BNpc.cpp b/src/world/Actor/BNpc.cpp index 2179e591..53b15876 100644 --- a/src/world/Actor/BNpc.cpp +++ b/src/world/Actor/BNpc.cpp @@ -370,8 +370,39 @@ void Sapphire::Entity::BNpc::update( int64_t currTime ) case BNpcState::Retreat: { + setInvincibilityType( InvincibilityType::InvincibilityIgnoreDamage ); + + // slowly restore hp every tick + + if( std::difftime( currTime, m_lastTickTime ) > 3000 ) + { + m_lastTickTime = currTime; + + if( m_hp < getMaxHp() ) + { + auto addHp = static_cast< uint32_t >( getMaxHp() * 0.1f + 1 ); + + if( m_hp + addHp < getMaxHp() ) + m_hp += addHp; + else + m_hp = getMaxHp(); + } + + sendStatusUpdate(); + } + if( moveTo( m_spawnPos ) ) + { + setInvincibilityType( InvincibilityType::InvincibilityNone ); + + // retail doesn't seem to roam straight after retreating + // todo: perhaps requires more investigation? + m_lastRoamTargetReached = Util::getTimeSeconds(); + + setHp( getMaxHp() ); + m_state = BNpcState::Idle; + } } break; @@ -475,7 +506,6 @@ void Sapphire::Entity::BNpc::update( int64_t currTime ) } } } - } void Sapphire::Entity::BNpc::onActionHostile( Sapphire::Entity::CharaPtr pSource ) diff --git a/src/world/Actor/Chara.cpp b/src/world/Actor/Chara.cpp index 066a6355..6e2272cc 100644 --- a/src/world/Actor/Chara.cpp +++ b/src/world/Actor/Chara.cpp @@ -151,35 +151,35 @@ uint32_t Sapphire::Entity::Chara::getMaxMp() const void Sapphire::Entity::Chara::resetHp() { m_hp = getMaxHp(); - sendStatusUpdate( true ); + sendStatusUpdate(); } /*! \return reset mp to current max mp */ void Sapphire::Entity::Chara::resetMp() { m_mp = getMaxMp(); - sendStatusUpdate( true ); + sendStatusUpdate(); } /*! \param hp amount to set ( caps to maxHp ) */ void Sapphire::Entity::Chara::setHp( uint32_t hp ) { m_hp = hp < getMaxHp() ? hp : getMaxHp(); - sendStatusUpdate( true ); + sendStatusUpdate(); } /*! \param mp amount to set ( caps to maxMp ) */ void Sapphire::Entity::Chara::setMp( uint32_t mp ) { m_mp = mp < getMaxMp() ? mp : getMaxMp(); - sendStatusUpdate( true ); + sendStatusUpdate(); } /*! \param gp amount to set*/ void Sapphire::Entity::Chara::setGp( uint32_t gp ) { m_gp = gp; - sendStatusUpdate( true ); + sendStatusUpdate(); } /*! \param type invincibility type to set */ @@ -325,12 +325,14 @@ void Sapphire::Entity::Chara::takeDamage( uint32_t damage ) case InvincibilityStayAlive: setHp( 0 ); break; + case InvincibilityIgnoreDamage: + break; } } else m_hp -= damage; - sendStatusUpdate( false ); + sendStatusUpdate(); } /*! @@ -349,7 +351,7 @@ void Sapphire::Entity::Chara::heal( uint32_t amount ) else m_hp += amount; - sendStatusUpdate( false ); + sendStatusUpdate(); } /*! @@ -359,7 +361,7 @@ 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 Sapphire::Entity::Chara::sendStatusUpdate( bool toSelf ) +void Sapphire::Entity::Chara::sendStatusUpdate() { FFXIVPacketBasePtr packet = std::make_shared< UpdateHpMpTpPacket >( *this ); sendToInRangeSet( packet ); @@ -391,6 +393,7 @@ void Sapphire::Entity::Chara::autoAttack( CharaPtr pTarget ) uint64_t tick = Util::getTimeMs(); + // todo: this needs to use the auto attack delay for the equipped weapon if( ( tick - m_lastAttack ) > 2500 ) { pTarget->onActionHostile( getAsChara() ); diff --git a/src/world/Actor/Chara.h b/src/world/Actor/Chara.h index 94de7845..1adf919b 100644 --- a/src/world/Actor/Chara.h +++ b/src/world/Actor/Chara.h @@ -229,7 +229,7 @@ namespace Sapphire::Entity virtual uint8_t getLevel() const; - virtual void sendStatusUpdate( bool toSelf = true ); + virtual void sendStatusUpdate(); virtual void takeDamage( uint32_t damage ); diff --git a/src/world/Actor/Player.cpp b/src/world/Actor/Player.cpp index 9af7e25e..db5e56fb 100644 --- a/src/world/Actor/Player.cpp +++ b/src/world/Actor/Player.cpp @@ -739,7 +739,7 @@ void Sapphire::Entity::Player::gainLevel() } -void Sapphire::Entity::Player::sendStatusUpdate( bool toSelf ) +void Sapphire::Entity::Player::sendStatusUpdate() { sendToInRangeSet( std::make_shared< UpdateHpMpTpPacket >( *this ), true ); } @@ -810,7 +810,7 @@ void Sapphire::Entity::Player::setClassJob( Common::ClassJob classJob ) sendToInRangeSet( makeActorControl142( getId(), ClassJobChange, 0x04 ), true ); - sendStatusUpdate( true ); + sendStatusUpdate(); } void Sapphire::Entity::Player::setLevel( uint8_t level ) diff --git a/src/world/Actor/Player.h b/src/world/Actor/Player.h index 3c4382da..02e1c282 100644 --- a/src/world/Actor/Player.h +++ b/src/world/Actor/Player.h @@ -707,7 +707,7 @@ namespace Sapphire::Entity void sendStateFlags(); /*! send status update */ - void sendStatusUpdate( bool toSelf = true ) override; + void sendStatusUpdate() override; /*! send the entire inventory sequence */ void sendInventory(); diff --git a/src/world/Network/Handlers/GMCommandHandlers.cpp b/src/world/Network/Handlers/GMCommandHandlers.cpp index 8291d24d..1526789b 100644 --- a/src/world/Network/Handlers/GMCommandHandlers.cpp +++ b/src/world/Network/Handlers/GMCommandHandlers.cpp @@ -275,8 +275,13 @@ void Sapphire::Network::GameConnection::gm1Handler( FrameworkPtr pFw, } case GmCommand::Hp: { - targetPlayer->setHp( param1 ); - player.sendNotice( "Hp for {0} was set to {1}", targetPlayer->getName(), param1 ); + auto chara = targetActor->getAsChara(); + if( chara ) + { + chara->setHp( param1 ); + player.sendNotice( "Hp for {0} was set to {1}", chara->getName(), param1 ); + } + break; } case GmCommand::Mp: