From 658d2fa7aad3f51a1cc8b8f635ce6e0f196fe0a8 Mon Sep 17 00:00:00 2001 From: Mordred Date: Mon, 13 Mar 2023 23:26:50 +0100 Subject: [PATCH 01/30] minor cleanup of actionResultBuilder --- src/world/Action/ActionResultBuilder.cpp | 24 ++++++++----------- .../Network/PacketWrappers/EffectPacket.h | 6 +++++ .../Network/PacketWrappers/EffectPacket1.h | 5 ++++ 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/world/Action/ActionResultBuilder.cpp b/src/world/Action/ActionResultBuilder.cpp index 898a7c18d..d6bc36a4c 100644 --- a/src/world/Action/ActionResultBuilder.cpp +++ b/src/world/Action/ActionResultBuilder.cpp @@ -124,19 +124,17 @@ std::shared_ptr< FFXIVPacketBase > ActionResultBuilder::createActionResultPacket if( targetCount > 1 ) // use AoeEffect packets { - auto actionResult = std::make_shared< EffectPacket >( m_sourceChara->getId(), targetList[ 0 ]->getId(), m_actionId ); + auto actionResult = makeEffectPacket( m_sourceChara->getId(), targetList[ 0 ]->getId(), m_actionId ); actionResult->setRotation( Common::Util::floatToUInt16Rot( m_sourceChara->getRot() ) ); actionResult->setRequestId( m_requestId ); actionResult->setResultId( m_resultId ); uint8_t targetIndex = 0; - for( auto it = m_actorResultsMap.begin(); it != m_actorResultsMap.end(); ++it ) + for( auto& [ actor, actorResultList ] : m_actorResultsMap ) { - // get all effect results for an actor - auto actorResultList = it->second; - if( it->first ) - taskMgr.queueTask( World::makeActionIntegrityTask( m_resultId, it->first, actorResultList, 300 ) ); + if( actor ) + taskMgr.queueTask( World::makeActionIntegrityTask( m_resultId, actor, actorResultList, 300 ) ); for( auto& result : actorResultList ) { @@ -157,23 +155,21 @@ std::shared_ptr< FFXIVPacketBase > ActionResultBuilder::createActionResultPacket else // use Effect for single target { uint32_t mainTargetId = targetList.empty() ? m_sourceChara->getId() : targetList[ 0 ]->getId(); - auto actionResult = std::make_shared< EffectPacket1 >( m_sourceChara->getId(), mainTargetId, m_actionId ); + auto actionResult = makeEffectPacket1( m_sourceChara->getId(), mainTargetId, m_actionId ); actionResult->setRotation( Common::Util::floatToUInt16Rot( m_sourceChara->getRot() ) ); actionResult->setRequestId( m_requestId ); actionResult->setResultId( m_resultId ); - for( auto it = m_actorResultsMap.begin(); it != m_actorResultsMap.end(); ++it ) + for( auto& [ actor, actorResultList ] : m_actorResultsMap ) { - // get all effect results for an actor - auto actorResultList = it->second; - - if( it->first ) - taskMgr.queueTask( World::makeActionIntegrityTask( m_resultId, it->first, actorResultList, 300 ) ); + if( actor ) + taskMgr.queueTask( World::makeActionIntegrityTask( m_resultId, actor, actorResultList, 300 ) ); for( auto& result : actorResultList ) { auto effect = result->getCalcResultParam(); - if( result->getTarget() == m_sourceChara && result->getCalcResultParam().Type != Common::ActionEffectType::CALC_RESULT_TYPE_SET_STATUS_ME ) + if( result->getTarget() == m_sourceChara && + result->getCalcResultParam().Type != Common::ActionEffectType::CALC_RESULT_TYPE_SET_STATUS_ME ) actionResult->addSourceEffect( effect ); else actionResult->addTargetEffect( effect ); diff --git a/src/world/Network/PacketWrappers/EffectPacket.h b/src/world/Network/PacketWrappers/EffectPacket.h index 82f73c1b9..9e190a344 100644 --- a/src/world/Network/PacketWrappers/EffectPacket.h +++ b/src/world/Network/PacketWrappers/EffectPacket.h @@ -92,4 +92,10 @@ namespace Sapphire::Network::Packets::WorldPackets::Server uint8_t m_sourceEffectCount{ 0 }; }; + template< typename... Args > + std::shared_ptr< EffectPacket > makeEffectPacket( Args... args ) + { + return std::make_shared< EffectPacket >( args... ); + } + } \ No newline at end of file diff --git a/src/world/Network/PacketWrappers/EffectPacket1.h b/src/world/Network/PacketWrappers/EffectPacket1.h index 37393d370..b6752374d 100644 --- a/src/world/Network/PacketWrappers/EffectPacket1.h +++ b/src/world/Network/PacketWrappers/EffectPacket1.h @@ -83,5 +83,10 @@ namespace Sapphire::Network::Packets::WorldPackets::Server uint8_t m_sourceEffectCount{ 0 }; }; + template< typename... Args > + std::shared_ptr< EffectPacket1 > makeEffectPacket1( Args... args ) + { + return std::make_shared< EffectPacket1 >( args... ); + } } From 5fb62b75ec97b4611583960432e2ee6c846e87ac Mon Sep 17 00:00:00 2001 From: collett Date: Tue, 14 Mar 2023 18:06:02 +0900 Subject: [PATCH 02/30] support 3.x crit damage and remove direct hit --- src/world/Action/ActionResult.cpp | 10 ++++++---- src/world/Math/CalcStats.cpp | 29 ----------------------------- src/world/Math/CalcStats.h | 5 ----- 3 files changed, 6 insertions(+), 38 deletions(-) diff --git a/src/world/Action/ActionResult.cpp b/src/world/Action/ActionResult.cpp index aefdc2e3d..999c05aae 100644 --- a/src/world/Action/ActionResult.cpp +++ b/src/world/Action/ActionResult.cpp @@ -37,18 +37,18 @@ uint64_t ActionResult::getDelay() void ActionResult::damage( uint32_t amount, Common::ActionHitSeverityType severity, Common::ActionResultFlag flag ) { - m_result.Arg0 = static_cast< uint8_t >( severity ); + //m_result.Arg0 = static_cast< uint8_t >( severity ); m_result.Value = static_cast< int16_t >( amount ); m_result.Flag = static_cast< uint8_t >( flag ); - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP; + m_result.Type = severity == Common::ActionHitSeverityType::CritDamage ? Common::ActionEffectType::CALC_RESULT_TYPE_CRITICAL_DAMAGE_HP : Common::ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP; } void ActionResult::heal( uint32_t amount, Common::ActionHitSeverityType severity, Common::ActionResultFlag flag ) { - m_result.Arg1 = static_cast< uint8_t >( severity ); + //m_result.Arg1 = static_cast< uint8_t >( severity ); m_result.Value = static_cast< int16_t >( amount ); m_result.Flag = static_cast< uint8_t >( flag ); - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_RECOVER_HP; + m_result.Type = severity == Common::ActionHitSeverityType::CritHeal ? Common::ActionEffectType::CALC_RESULT_TYPE_CRITICAL_RECOVER_HP : Common::ActionEffectType::CALC_RESULT_TYPE_RECOVER_HP; } void ActionResult::restoreMP( uint32_t amount, Common::ActionResultFlag flag ) @@ -119,12 +119,14 @@ void ActionResult::execute() switch( m_result.Type ) { case Common::ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP: + case Common::ActionEffectType::CALC_RESULT_TYPE_CRITICAL_DAMAGE_HP: { m_target->takeDamage( m_result.Value ); break; } case Common::ActionEffectType::CALC_RESULT_TYPE_RECOVER_HP: + case Common::ActionEffectType::CALC_RESULT_TYPE_CRITICAL_RECOVER_HP: { m_target->heal( m_result.Value ); break; diff --git a/src/world/Math/CalcStats.cpp b/src/world/Math/CalcStats.cpp index af58dad1b..7c7980e9c 100644 --- a/src/world/Math/CalcStats.cpp +++ b/src/world/Math/CalcStats.cpp @@ -287,19 +287,6 @@ float CalcStats::blockProbability( const Chara& chara ) return std::floor( ( 30 * blockRate ) / levelVal + 10 ); } -float CalcStats::directHitProbability( const Chara& chara ) -{ - const auto& baseStats = chara.getStats(); - auto level = chara.getLevel(); - - auto dhRate = chara.getStatValueFloat( Common::BaseParam::Accuracy ); - - auto divVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::DIV ] ); - auto subVal = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::SUB ] ); - - return std::floor( 550.f * ( dhRate - subVal ) / divVal ) / 10.f; -} - float CalcStats::criticalHitProbability( const Chara& chara ) { const auto& baseStats = chara.getStats(); @@ -589,14 +576,6 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcAutoA hitType = Sapphire::Common::ActionHitSeverityType::CritDamage; } - if( directHitProbability( chara ) > range100( rng ) ) - { - factor *= 1.25f; - hitType = hitType == Sapphire::Common::ActionHitSeverityType::CritDamage ? - Sapphire::Common::ActionHitSeverityType::CritDirectHitDamage : - Sapphire::Common::ActionHitSeverityType::DirectHitDamage; - } - factor *= 1.0f + ( ( range100( rng ) - 50.0f ) / 1000.0f ); // todo: buffs @@ -634,14 +613,6 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActio hitType = Sapphire::Common::ActionHitSeverityType::CritDamage; } - if( directHitProbability( chara ) > range100( rng ) ) - { - factor *= 1.25f; - hitType = hitType == Sapphire::Common::ActionHitSeverityType::CritDamage ? - Sapphire::Common::ActionHitSeverityType::CritDirectHitDamage : - Sapphire::Common::ActionHitSeverityType::DirectHitDamage; - } - factor *= 1.0f + ( ( range100( rng ) - 50.0f ) / 1000.0f ); // todo: buffs diff --git a/src/world/Math/CalcStats.h b/src/world/Math/CalcStats.h index 87625067b..1e80ca81e 100644 --- a/src/world/Math/CalcStats.h +++ b/src/world/Math/CalcStats.h @@ -34,11 +34,6 @@ namespace Sapphire::Math */ static float blockProbability( const Sapphire::Entity::Chara& chara ); - /*! - * @brief Calculates the probability of a direct hit happening - */ - static float directHitProbability( const Sapphire::Entity::Chara& chara ); - /*! * @brief Calculates the probability of a critical hit happening */ From 123dad2e23010b802256099a5fa112cffa554282 Mon Sep 17 00:00:00 2001 From: collett Date: Tue, 14 Mar 2023 18:22:41 +0900 Subject: [PATCH 03/30] update rng to RandGenerator --- src/world/Math/CalcStats.cpp | 25 ++++++++++++++++--------- src/world/Math/CalcStats.h | 8 ++++---- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/world/Math/CalcStats.cpp b/src/world/Math/CalcStats.cpp index 7c7980e9c..b08bd8331 100644 --- a/src/world/Math/CalcStats.cpp +++ b/src/world/Math/CalcStats.cpp @@ -85,9 +85,7 @@ const int levelTable[61][6] = { 218, 354, 858, 2600, 282, 215 }, }; -std::random_device CalcStats::dev; -std::mt19937 CalcStats::rng( dev() ); -std::uniform_int_distribution< std::mt19937::result_type > CalcStats::range100( 0, 99 ); +std::unique_ptr< RandGenerator< float > > CalcStats::rnd = nullptr; /* Class used for battle-related formulas and calculations. @@ -570,13 +568,13 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcAutoA factor = std::floor( factor * speed( chara ) ); - if( criticalHitProbability( chara ) > range100( rng ) ) + if( criticalHitProbability( chara ) > getRandomNumber0To100() ) { factor *= criticalHitBonus( chara ); hitType = Sapphire::Common::ActionHitSeverityType::CritDamage; } - factor *= 1.0f + ( ( range100( rng ) - 50.0f ) / 1000.0f ); + factor *= 1.0f + ( ( getRandomNumber0To100() - 50.0f ) / 1000.0f ); // todo: buffs @@ -607,13 +605,13 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActio auto factor = Common::Util::trunc( pot * wd * ap * det, 0 ); Sapphire::Common::ActionHitSeverityType hitType = Sapphire::Common::ActionHitSeverityType::NormalDamage; - if( criticalHitProbability( chara ) > range100( rng ) ) + if( criticalHitProbability( chara ) > getRandomNumber0To100() ) { factor *= criticalHitBonus( chara ); hitType = Sapphire::Common::ActionHitSeverityType::CritDamage; } - factor *= 1.0f + ( ( range100( rng ) - 50.0f ) / 1000.0f ); + factor *= 1.0f + ( ( getRandomNumber0To100() - 50.0f ) / 1000.0f ); // todo: buffs @@ -640,13 +638,13 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActio auto factor = std::floor( ( wepDmg * ( mnd / 200 ) + ( det / 10 ) ) * ( ptc / 100 ) * 1.3f ); Sapphire::Common::ActionHitSeverityType hitType = Sapphire::Common::ActionHitSeverityType::NormalHeal; - if( criticalHitProbability( chara ) > range100( rng ) ) + if( criticalHitProbability( chara ) > getRandomNumber0To100() ) { factor *= criticalHitBonus( chara ); hitType = Sapphire::Common::ActionHitSeverityType::CritHeal; } - factor *= 1.0f + ( ( range100( rng ) - 50.0f ) / 1000.0f ); + factor *= 1.0f + ( ( getRandomNumber0To100() - 50.0f ) / 1000.0f ); return std::pair( factor, hitType ); } @@ -654,4 +652,13 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActio uint32_t CalcStats::primaryStatValue( const Sapphire::Entity::Chara& chara ) { return chara.getStatValue( chara.getPrimaryStat() ); +} + +float CalcStats::getRandomNumber0To100() +{ + if( !rnd ) + { + rnd = std::make_unique< RandGenerator< float > >( Common::Service< RNGMgr >::ref().getRandGenerator< float >( 0, 100 ) ); + } + return rnd->next(); } \ No newline at end of file diff --git a/src/world/Math/CalcStats.h b/src/world/Math/CalcStats.h index 1e80ca81e..0d8f1cb49 100644 --- a/src/world/Math/CalcStats.h +++ b/src/world/Math/CalcStats.h @@ -1,11 +1,12 @@ #pragma once -#include #include #include "Forwards.h" +#include "Manager/RNGMgr.h" namespace Sapphire::Math { + using namespace Sapphire::World::Manager; class CalcStats { @@ -151,9 +152,8 @@ namespace Sapphire::Math */ static float calcAttackPower( const Sapphire::Entity::Chara& chara, uint32_t attackPower ); - static std::random_device dev; - static std::mt19937 rng; - static std::uniform_int_distribution< std::mt19937::result_type > range100; + static float getRandomNumber0To100(); + static std::unique_ptr< RandGenerator< float > > rnd; }; } From aafb77ecbb2495a2060fd45df8917aca94730448 Mon Sep 17 00:00:00 2001 From: Mordred Date: Tue, 14 Mar 2023 22:32:55 +0100 Subject: [PATCH 04/30] Use attack type for action hit effect, further simply action code. --- deps/datReader/Exd/Structs.h | 1 + src/world/Action/Action.cpp | 4 ++-- src/world/Action/Action.h | 4 ++-- src/world/Action/ActionResult.cpp | 22 +++++++----------- src/world/Action/ActionResult.h | 10 +++----- src/world/Action/ActionResultBuilder.cpp | 29 ++++++++++++++---------- src/world/Action/ActionResultBuilder.h | 4 ++-- src/world/Math/CalcStats.cpp | 19 ++++++++-------- src/world/Math/CalcStats.h | 6 ++--- 9 files changed, 48 insertions(+), 51 deletions(-) diff --git a/deps/datReader/Exd/Structs.h b/deps/datReader/Exd/Structs.h index 078d26fa4..28ed82a51 100644 --- a/deps/datReader/Exd/Structs.h +++ b/deps/datReader/Exd/Structs.h @@ -397,6 +397,7 @@ namespace Excel uint8_t UseClassJob; uint8_t Init; uint8_t Omen; + uint8_t Unknown; int8_t Learn; int8_t SelectRange; int8_t SelectCorpse; diff --git a/src/world/Action/Action.cpp b/src/world/Action/Action.cpp index cb93cd63b..944ae4cfb 100644 --- a/src/world/Action/Action.cpp +++ b/src/world/Action/Action.cpp @@ -454,7 +454,7 @@ void Action::Action::execute() } } -std::pair< uint32_t, Common::ActionHitSeverityType > Action::Action::calcDamage( uint32_t potency ) +std::pair< uint32_t, Common::ActionEffectType > Action::Action::calcDamage( uint32_t potency ) { // todo: what do for npcs? auto wepDmg = 1.f; @@ -478,7 +478,7 @@ std::pair< uint32_t, Common::ActionHitSeverityType > Action::Action::calcDamage( return Math::CalcStats::calcActionDamage( *m_pSource, potency, wepDmg ); } -std::pair< uint32_t, Common::ActionHitSeverityType > Action::Action::calcHealing( uint32_t potency ) +std::pair< uint32_t, Common::ActionEffectType > Action::Action::calcHealing( uint32_t potency ) { auto wepDmg = 1.f; diff --git a/src/world/Action/Action.h b/src/world/Action/Action.h index 90b49198e..83b5dbe33 100644 --- a/src/world/Action/Action.h +++ b/src/world/Action/Action.h @@ -122,9 +122,9 @@ namespace Sapphire::World::Action */ void addDefaultActorFilters(); - std::pair< uint32_t, Common::ActionHitSeverityType > calcDamage( uint32_t potency ); + std::pair< uint32_t, Common::ActionEffectType > calcDamage( uint32_t potency ); - std::pair< uint32_t, Common::ActionHitSeverityType > calcHealing( uint32_t potency ); + std::pair< uint32_t, Common::ActionEffectType > calcHealing( uint32_t potency ); std::vector< Entity::CharaPtr >& getHitCharas(); diff --git a/src/world/Action/ActionResult.cpp b/src/world/Action/ActionResult.cpp index 999c05aae..caedd31f1 100644 --- a/src/world/Action/ActionResult.cpp +++ b/src/world/Action/ActionResult.cpp @@ -13,9 +13,8 @@ using namespace Sapphire; using namespace Sapphire::World::Action; -ActionResult::ActionResult( Entity::CharaPtr target, uint64_t runAfter ) : - m_target( std::move( target ) ), - m_delayMs( runAfter ) +ActionResult::ActionResult( Entity::CharaPtr target ) : + m_target( std::move( target ) ) { m_result.Arg0 = 0; m_result.Arg1 = 0; @@ -30,25 +29,20 @@ Entity::CharaPtr ActionResult::getTarget() const return m_target; } -uint64_t ActionResult::getDelay() +void ActionResult::damage( uint32_t amount, Common::ActionEffectType hitType, uint8_t hitEffect, Common::ActionResultFlag flag ) { - return m_delayMs; -} - -void ActionResult::damage( uint32_t amount, Common::ActionHitSeverityType severity, Common::ActionResultFlag flag ) -{ - //m_result.Arg0 = static_cast< uint8_t >( severity ); + m_result.Arg0 = hitEffect; m_result.Value = static_cast< int16_t >( amount ); m_result.Flag = static_cast< uint8_t >( flag ); - m_result.Type = severity == Common::ActionHitSeverityType::CritDamage ? Common::ActionEffectType::CALC_RESULT_TYPE_CRITICAL_DAMAGE_HP : Common::ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP; + m_result.Type = hitType; } -void ActionResult::heal( uint32_t amount, Common::ActionHitSeverityType severity, Common::ActionResultFlag flag ) +void ActionResult::heal( uint32_t amount, Common::ActionEffectType hitType, uint8_t hitEffect, Common::ActionResultFlag flag ) { - //m_result.Arg1 = static_cast< uint8_t >( severity ); + m_result.Arg0 = hitEffect; m_result.Value = static_cast< int16_t >( amount ); m_result.Flag = static_cast< uint8_t >( flag ); - m_result.Type = severity == Common::ActionHitSeverityType::CritHeal ? Common::ActionEffectType::CALC_RESULT_TYPE_CRITICAL_RECOVER_HP : Common::ActionEffectType::CALC_RESULT_TYPE_RECOVER_HP; + m_result.Type = hitType; } void ActionResult::restoreMP( uint32_t amount, Common::ActionResultFlag flag ) diff --git a/src/world/Action/ActionResult.h b/src/world/Action/ActionResult.h index a2fbbf85e..f951fbb09 100644 --- a/src/world/Action/ActionResult.h +++ b/src/world/Action/ActionResult.h @@ -12,10 +12,10 @@ namespace Sapphire::World::Action class ActionResult { public: - explicit ActionResult( Entity::CharaPtr target, uint64_t delayMs ); + explicit ActionResult( Entity::CharaPtr target ); - void damage( uint32_t amount, Common::ActionHitSeverityType severity, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); - void heal( uint32_t amount, Common::ActionHitSeverityType severity, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); + void damage( uint32_t amount, Common::ActionEffectType hitType, uint8_t hitEffect, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); + void heal( uint32_t amount, Common::ActionEffectType hitType, uint8_t hitEffect, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); void restoreMP( uint32_t amount, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); void startCombo( uint16_t actionId ); void comboSucceed(); @@ -25,16 +25,12 @@ namespace Sapphire::World::Action Entity::CharaPtr getTarget() const; - uint64_t getDelay(); - const Common::CalcResultParam& getCalcResultParam() const; const Sapphire::StatusEffect::StatusEffectPtr getStatusEffect() const; void execute(); private: - uint64_t m_delayMs; - Entity::CharaPtr m_target; Common::CalcResultParam m_result; diff --git a/src/world/Action/ActionResultBuilder.cpp b/src/world/Action/ActionResultBuilder.cpp index d6bc36a4c..23e82c16e 100644 --- a/src/world/Action/ActionResultBuilder.cpp +++ b/src/world/Action/ActionResultBuilder.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -46,58 +47,62 @@ void ActionResultBuilder::addResultToActor( Entity::CharaPtr& chara, ActionResul it->second.push_back( std::move( result ) ); } -void ActionResultBuilder::heal( Entity::CharaPtr& effectTarget, Entity::CharaPtr& healingTarget, uint32_t amount, Common::ActionHitSeverityType severity, Common::ActionResultFlag flag ) +void ActionResultBuilder::heal( Entity::CharaPtr& effectTarget, Entity::CharaPtr& healingTarget, uint32_t amount, Common::ActionEffectType hitType, Common::ActionResultFlag flag ) { - ActionResultPtr nextResult = make_ActionResult( healingTarget, 0 ); - nextResult->heal( amount, severity, flag ); + ActionResultPtr nextResult = make_ActionResult( healingTarget ); + auto& exdData = Common::Service< Data::ExdData >::ref(); + auto actionData = exdData.getRow< Excel::Action >( m_actionId ); + nextResult->heal( amount, hitType, std::abs( actionData->data().AttackType ), flag ); addResultToActor( effectTarget, nextResult ); } void ActionResultBuilder::restoreMP( Entity::CharaPtr& target, Entity::CharaPtr& restoringTarget, uint32_t amount, Common::ActionResultFlag flag ) { - ActionResultPtr nextResult = make_ActionResult( restoringTarget, 0 ); // restore mp source actor + ActionResultPtr nextResult = make_ActionResult( restoringTarget ); // restore mp source actor nextResult->restoreMP( amount, flag ); addResultToActor( target, nextResult ); } -void ActionResultBuilder::damage( Entity::CharaPtr& effectTarget, Entity::CharaPtr& damagingTarget, uint32_t amount, Common::ActionHitSeverityType severity, Common::ActionResultFlag flag ) +void ActionResultBuilder::damage( Entity::CharaPtr& effectTarget, Entity::CharaPtr& damagingTarget, uint32_t amount, Common::ActionEffectType hitType, Common::ActionResultFlag flag ) { - ActionResultPtr nextResult = make_ActionResult( damagingTarget, 0 ); - nextResult->damage( amount, severity, flag ); + ActionResultPtr nextResult = make_ActionResult( damagingTarget ); + auto& exdData = Common::Service< Data::ExdData >::ref(); + auto actionData = exdData.getRow< Excel::Action >( m_actionId ); + nextResult->damage( amount, hitType, std::abs( actionData->data().AttackType ), flag ); addResultToActor( damagingTarget, nextResult ); } void ActionResultBuilder::startCombo( Entity::CharaPtr& target, uint16_t actionId ) { - ActionResultPtr nextResult = make_ActionResult( target, 0 ); + ActionResultPtr nextResult = make_ActionResult( target ); nextResult->startCombo( actionId ); addResultToActor( target, nextResult ); } void ActionResultBuilder::comboSucceed( Entity::CharaPtr& target ) { - ActionResultPtr nextResult = make_ActionResult( target, 0 ); + ActionResultPtr nextResult = make_ActionResult( target ); nextResult->comboSucceed(); addResultToActor( target, nextResult ); } void ActionResultBuilder::applyStatusEffect( Entity::CharaPtr& target, uint16_t statusId, uint32_t duration, uint8_t param, bool shouldOverride ) { - ActionResultPtr nextResult = make_ActionResult( target, 0 ); + ActionResultPtr nextResult = make_ActionResult( target ); nextResult->applyStatusEffect( statusId, duration, *m_sourceChara, param, shouldOverride ); addResultToActor( target, nextResult ); } void ActionResultBuilder::applyStatusEffectSelf( uint16_t statusId, uint32_t duration, uint8_t param, bool shouldOverride ) { - ActionResultPtr nextResult = make_ActionResult( m_sourceChara, 0 ); + ActionResultPtr nextResult = make_ActionResult( m_sourceChara ); nextResult->applyStatusEffectSelf( statusId, duration, param, shouldOverride ); addResultToActor( m_sourceChara, nextResult ); } void ActionResultBuilder::mount( Entity::CharaPtr& target, uint16_t mountId ) { - ActionResultPtr nextResult = make_ActionResult( target, 0 ); + ActionResultPtr nextResult = make_ActionResult( target ); nextResult->mount( mountId ); addResultToActor( target, nextResult ); } diff --git a/src/world/Action/ActionResultBuilder.h b/src/world/Action/ActionResultBuilder.h index 19e00ae2f..a70773e85 100644 --- a/src/world/Action/ActionResultBuilder.h +++ b/src/world/Action/ActionResultBuilder.h @@ -11,14 +11,14 @@ namespace Sapphire::World::Action ActionResultBuilder( Entity::CharaPtr source, uint32_t actionId, uint32_t resultId, uint16_t requestId ); void heal( Entity::CharaPtr& effectTarget, Entity::CharaPtr& healingTarget, uint32_t amount, - Common::ActionHitSeverityType severity = Common::ActionHitSeverityType::NormalHeal, + Common::ActionEffectType hitType = Common::ActionEffectType::CALC_RESULT_TYPE_RECOVER_HP, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); void restoreMP( Entity::CharaPtr& effectTarget, Entity::CharaPtr& restoringTarget, uint32_t amount, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); void damage( Entity::CharaPtr& effectTarget, Entity::CharaPtr& damagingTarget, uint32_t amount, - Common::ActionHitSeverityType severity = Common::ActionHitSeverityType::NormalDamage, + Common::ActionEffectType hitType = Common::ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); void startCombo( Entity::CharaPtr& target, uint16_t actionId ); diff --git a/src/world/Math/CalcStats.cpp b/src/world/Math/CalcStats.cpp index b08bd8331..4dbaa36e7 100644 --- a/src/world/Math/CalcStats.cpp +++ b/src/world/Math/CalcStats.cpp @@ -549,7 +549,7 @@ float CalcStats::healingMagicPotency( const Sapphire::Entity::Chara& chara ) return std::floor( 100.f * ( chara.getStatValue( Common::BaseParam::HealingMagicPotency ) - 292.f ) / 264.f + 100.f ) / 100.f; } -std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcAutoAttackDamage( const Sapphire::Entity::Chara& chara ) +std::pair< float, Sapphire::Common::ActionEffectType > CalcStats::calcAutoAttackDamage( const Sapphire::Entity::Chara& chara ) { // D = ⌊ f(ptc) × f(aa) × f(ap) × f(det) × f(tnc) × traits ⌋ × f(ss) ⌋ × // f(chr) ⌋ × f(dhr) ⌋ × rand[ 0.95, 1.05 ] ⌋ × buff_1 ⌋ × buff... ⌋ @@ -562,7 +562,7 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcAutoA // todo: everything after tenacity auto factor = Common::Util::trunc( pot * aa * ap * det, 0 ); - Sapphire::Common::ActionHitSeverityType hitType = Sapphire::Common::ActionHitSeverityType::NormalDamage; + Sapphire::Common::ActionEffectType hitType = Sapphire::Common::ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP; // todo: traits @@ -571,7 +571,7 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcAutoA if( criticalHitProbability( chara ) > getRandomNumber0To100() ) { factor *= criticalHitBonus( chara ); - hitType = Sapphire::Common::ActionHitSeverityType::CritDamage; + hitType = Sapphire::Common::ActionEffectType::CALC_RESULT_TYPE_CRITICAL_DAMAGE_HP; } factor *= 1.0f + ( ( getRandomNumber0To100() - 50.0f ) / 1000.0f ); @@ -592,7 +592,7 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcAutoA return std::pair( factor, hitType ); } -std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActionDamage( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ) +std::pair< float, Sapphire::Common::ActionEffectType > CalcStats::calcActionDamage( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ) { // D = ⌊ f(pot) × f(wd) × f(ap) × f(det) × f(tnc) × traits ⌋ // × f(chr) ⌋ × f(dhr) ⌋ × rand[ 0.95, 1.05 ] ⌋ buff_1 ⌋ × buff_1 ⌋ × buff... ⌋ @@ -603,12 +603,12 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActio auto det = determination( chara ); auto factor = Common::Util::trunc( pot * wd * ap * det, 0 ); - Sapphire::Common::ActionHitSeverityType hitType = Sapphire::Common::ActionHitSeverityType::NormalDamage; + Sapphire::Common::ActionEffectType hitType = Sapphire::Common::ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP; if( criticalHitProbability( chara ) > getRandomNumber0To100() ) { factor *= criticalHitBonus( chara ); - hitType = Sapphire::Common::ActionHitSeverityType::CritDamage; + hitType = Sapphire::Common::ActionEffectType::CALC_RESULT_TYPE_CRITICAL_DAMAGE_HP; } factor *= 1.0f + ( ( getRandomNumber0To100() - 50.0f ) / 1000.0f ); @@ -629,19 +629,20 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActio return std::pair( factor, hitType ); } -std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActionHealing( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ) +std::pair< float, Sapphire::Common::ActionEffectType > CalcStats::calcActionHealing( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ) { // lol just for testing float det = chara.getStatValue( Common::BaseParam::Determination ); float mnd = chara.getStatValue( Common::BaseParam::Mind ); auto factor = std::floor( ( wepDmg * ( mnd / 200 ) + ( det / 10 ) ) * ( ptc / 100 ) * 1.3f ); - Sapphire::Common::ActionHitSeverityType hitType = Sapphire::Common::ActionHitSeverityType::NormalHeal; + + Sapphire::Common::ActionEffectType hitType = Sapphire::Common::ActionEffectType::CALC_RESULT_TYPE_RECOVER_HP; if( criticalHitProbability( chara ) > getRandomNumber0To100() ) { factor *= criticalHitBonus( chara ); - hitType = Sapphire::Common::ActionHitSeverityType::CritHeal; + hitType = Sapphire::Common::ActionEffectType::CALC_RESULT_TYPE_CRITICAL_RECOVER_HP; } factor *= 1.0f + ( ( getRandomNumber0To100() - 50.0f ) / 1000.0f ); diff --git a/src/world/Math/CalcStats.h b/src/world/Math/CalcStats.h index 0d8f1cb49..a4c69ecc1 100644 --- a/src/world/Math/CalcStats.h +++ b/src/world/Math/CalcStats.h @@ -136,11 +136,11 @@ namespace Sapphire::Math //////////////////////////////////////////// - static std::pair< float, Common::ActionHitSeverityType > calcAutoAttackDamage( const Sapphire::Entity::Chara& chara ); + static std::pair< float, Common::ActionEffectType > calcAutoAttackDamage( const Sapphire::Entity::Chara& chara ); - static std::pair< float, Common::ActionHitSeverityType > calcActionDamage( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ); + static std::pair< float, Common::ActionEffectType > calcActionDamage( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ); - static std::pair< float, Common::ActionHitSeverityType > calcActionHealing( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ); + static std::pair< float, Common::ActionEffectType > calcActionHealing( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ); static uint32_t primaryStatValue( const Sapphire::Entity::Chara& chara ); private: From 33463f45a9fad006c8653ede65b142502c715f50 Mon Sep 17 00:00:00 2001 From: Mordred Date: Wed, 15 Mar 2023 15:21:03 +0100 Subject: [PATCH 05/30] More cleanup of actions --- src/common/Common.h | 126 +++++++++++------------ src/world/Action/Action.cpp | 4 +- src/world/Action/Action.h | 4 +- src/world/Action/ActionResult.cpp | 34 +++--- src/world/Action/ActionResult.h | 4 +- src/world/Action/ActionResultBuilder.cpp | 6 +- src/world/Action/ActionResultBuilder.h | 4 +- src/world/Action/ItemAction.cpp | 2 +- src/world/Actor/Chara.cpp | 8 +- src/world/Manager/DebugCommandMgr.cpp | 4 +- src/world/Math/CalcStats.cpp | 18 ++-- src/world/Math/CalcStats.h | 6 +- src/world/Task/ActionIntegrityTask.cpp | 4 +- 13 files changed, 107 insertions(+), 117 deletions(-) diff --git a/src/common/Common.h b/src/common/Common.h index 4e07628fe..18e529d17 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -948,74 +948,64 @@ namespace Sapphire::Common LimitBreak = 8, }; - enum ActionEffectType : uint8_t - { - CALC_RESULT_TYPE_NONE = 0x0, - CALC_RESULT_TYPE_MISS = 0x1, - CALC_RESULT_TYPE_RESIST = 0x2, - CALC_RESULT_TYPE_DAMAGE_HP = 0x3, - CALC_RESULT_TYPE_RECOVER_HP = 0x4, - CALC_RESULT_TYPE_CRITICAL_DAMAGE_HP = 0x5, - CALC_RESULT_TYPE_CRITICAL_RECOVER_HP = 0x6, - CALC_RESULT_TYPE_GUARD = 0x7, - CALC_RESULT_TYPE_PARRY = 0x8, - CALC_RESULT_TYPE_INVALID = 0x9, - CALC_RESULT_TYPE_UNEFFECTIVE = 0xA, - CALC_RESULT_TYPE_NEGLECT = 0xB, - CALC_RESULT_TYPE_DAMAGE_MP = 0xC, - CALC_RESULT_TYPE_RECOVER_MP = 0xD, - CALC_RESULT_TYPE_DAMAGE_TP = 0xE, - CALC_RESULT_TYPE_RECOVER_TP = 0xF, - CALC_RESULT_TYPE_RECOVER_GP = 0x10, - CALC_RESULT_TYPE_SET_STATUS = 0x11, - CALC_RESULT_TYPE_SET_STATUS_ME = 0x12, - CALC_RESULT_TYPE_RESET_STATUS = 0x13, - CALC_RESULT_TYPE_RESET_STATUS_ME = 0x14, - CALC_RESULT_TYPE_RESET_BAD_STATUS = 0x15, - CALC_RESULT_TYPE_UNEFFECTIVE_STATUS = 0x16, - CALC_RESULT_TYPE_HALF_GOOD_STATUS = 0x17, - CALC_RESULT_TYPE_HATE_DIRECT = 0x18, - CALC_RESULT_TYPE_HATE_INDIRECTION = 0x19, - CALC_RESULT_TYPE_HATE_TOP = 0x1A, - CALC_RESULT_TYPE_HATE_ADD = 0x1B, - CALC_RESULT_TYPE_HATE_MULT = 0x1C, - CALC_RESULT_TYPE_COMBO = 0x1D, - CALC_RESULT_TYPE_COMBO_HIT = 0x1E, - CALC_RESULT_TYPE_COUNTER = 0x1F, - CALC_RESULT_TYPE_DESTRUCT = 0x20, - CALC_RESULT_TYPE_PARALYSIS = 0x21, - CALC_RESULT_TYPE_KNOCK_BACK = 0x22, - CALC_RESULT_TYPE_DRAW_UP_CHAIRS = 0x23, - CALC_RESULT_TYPE_SUCKED = 0x24, - CALC_RESULT_TYPE_CT_DRAW_UP_CHAIRS = 0x25, - CALC_RESULT_TYPE_LIVE_CALLBACK = 0x26, - CALC_RESULT_TYPE_MOUNT = 0x27, - CALC_RESULT_ARCHER_DOT = 0x28, - CALC_RESULT_MASTER_DOT = 0x29, - CALC_RESULT_BLESSINGS_OF_GODDESS = 0x2A, - CALC_RESULT_BAD_BREATH = 0x2B, - CALC_RESULT_REVIVAL = 0x2C, - CALC_RESULT_PET = 0x2D, - CALC_RESULT_TYPE_BLOW = 0x2E, - CALC_RESULT_TYPE_STATUS_RESIST = 0x2F, - CALC_RESULT_TYPE_CLEAR_PHYSICAL = 0x30, - CALC_RESULT_BNPC_STATE = 0x31, - CALC_RESULT_TYPE_VFX = 0x32, - CALC_RESULT_TYPE_HARD_CODE = 0x33, - CALC_RESULT_CALC_ID = 0x34, - CALC_RESULT_TYPE_CLEAR_PVP_POINT = 0x35, - CALC_RESULT_TYPE_CHECK_BARRIER = 0x36, - CALC_RESULT_TYPE_REFLEC = 0x37, - }; - - enum class ActionHitSeverityType : uint8_t - { - NormalDamage = 0, - CritHeal = 0, - CritDamage = 1, - NormalHeal = 1, - DirectHitDamage = 2, - CritDirectHitDamage = 3 + enum CalcResultType : uint8_t + { + TypeNone = 0x0, + TypeMiss = 0x1, + TypeResist = 0x2, + TypeDamageHp = 0x3, + TypeRecoverHp = 0x4, + TypeCriticalDamageHp = 0x5, + TypeCriticalRecoverHp = 0x6, + TypeGuard = 0x7, + TypeParry = 0x8, + TypeInvalid = 0x9, + TypeUneffective = 0xA, + TypeNeglect = 0xB, + TypeDamageMp = 0xC, + TypeRecoverMp = 0xD, + TypeDamageTp = 0xE, + TypeRecoverTp = 0xF, + TypeRecoverGp = 0x10, + TypeSetStatus = 0x11, + TypeSetStatusMe = 0x12, + TypeResetStatus = 0x13, + TypeResetStatusMe = 0x14, + TypeResetBadStatus = 0x15, + TypeUneffectiveStatus = 0x16, + TypeHalfGoodStatus = 0x17, + TypeHateDirect = 0x18, + TypeHateIndirection = 0x19, + TypeHateTop = 0x1A, + TypeHateAdd = 0x1B, + TypeHateMult = 0x1C, + TypeCombo = 0x1D, + TypeComboHit = 0x1E, + TypeCounter = 0x1F, + TypeDestruct = 0x20, + TypeParalysis = 0x21, + TypeKnockBack = 0x22, + TypeDrawUpChairs = 0x23, + TypeSucked = 0x24, + TypeCtDrawUpChairs = 0x25, + TypeLiveCallback = 0x26, + TypeMount = 0x27, + TypeArcherDot = 0x28, + TypeMasterDot = 0x29, + TypeBlessingOfGoddess = 0x2A, + TypeBadBreath = 0x2B, + TypeRevival = 0x2C, + TypePet = 0x2D, + TypeBlow = 0x2E, + TypeStatusResist = 0x2F, + TypeClearPhysical = 0x30, + TypeBNpcState = 0x31, + TypeVfx = 0x32, + TypeHardCode = 0x33, + TypeCalcId = 0x34, + TypeClearPvpPoint = 0x35, + TypeCheckBarrier = 0x36, + TypeReflect = 0x37, }; enum class ActionResultFlag : uint8_t diff --git a/src/world/Action/Action.cpp b/src/world/Action/Action.cpp index 944ae4cfb..5ea83d071 100644 --- a/src/world/Action/Action.cpp +++ b/src/world/Action/Action.cpp @@ -454,7 +454,7 @@ void Action::Action::execute() } } -std::pair< uint32_t, Common::ActionEffectType > Action::Action::calcDamage( uint32_t potency ) +std::pair< uint32_t, Common::CalcResultType > Action::Action::calcDamage( uint32_t potency ) { // todo: what do for npcs? auto wepDmg = 1.f; @@ -478,7 +478,7 @@ std::pair< uint32_t, Common::ActionEffectType > Action::Action::calcDamage( uint return Math::CalcStats::calcActionDamage( *m_pSource, potency, wepDmg ); } -std::pair< uint32_t, Common::ActionEffectType > Action::Action::calcHealing( uint32_t potency ) +std::pair< uint32_t, Common::CalcResultType > Action::Action::calcHealing( uint32_t potency ) { auto wepDmg = 1.f; diff --git a/src/world/Action/Action.h b/src/world/Action/Action.h index 83b5dbe33..3b0e5a9d3 100644 --- a/src/world/Action/Action.h +++ b/src/world/Action/Action.h @@ -122,9 +122,9 @@ namespace Sapphire::World::Action */ void addDefaultActorFilters(); - std::pair< uint32_t, Common::ActionEffectType > calcDamage( uint32_t potency ); + std::pair< uint32_t, Common::CalcResultType > calcDamage( uint32_t potency ); - std::pair< uint32_t, Common::ActionEffectType > calcHealing( uint32_t potency ); + std::pair< uint32_t, Common::CalcResultType > calcHealing( uint32_t potency ); std::vector< Entity::CharaPtr >& getHitCharas(); diff --git a/src/world/Action/ActionResult.cpp b/src/world/Action/ActionResult.cpp index caedd31f1..e07c308c2 100644 --- a/src/world/Action/ActionResult.cpp +++ b/src/world/Action/ActionResult.cpp @@ -21,7 +21,7 @@ ActionResult::ActionResult( Entity::CharaPtr target ) : m_result.Arg2 = 0; m_result.Value = 0; m_result.Flag = static_cast< uint8_t >( Common::ActionResultFlag::None ); - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_NONE; + m_result.Type = Common::CalcResultType::TypeNone; } Entity::CharaPtr ActionResult::getTarget() const @@ -29,7 +29,7 @@ Entity::CharaPtr ActionResult::getTarget() const return m_target; } -void ActionResult::damage( uint32_t amount, Common::ActionEffectType hitType, uint8_t hitEffect, Common::ActionResultFlag flag ) +void ActionResult::damage( uint32_t amount, Common::CalcResultType hitType, uint8_t hitEffect, Common::ActionResultFlag flag ) { m_result.Arg0 = hitEffect; m_result.Value = static_cast< int16_t >( amount ); @@ -37,7 +37,7 @@ void ActionResult::damage( uint32_t amount, Common::ActionEffectType hitType, ui m_result.Type = hitType; } -void ActionResult::heal( uint32_t amount, Common::ActionEffectType hitType, uint8_t hitEffect, Common::ActionResultFlag flag ) +void ActionResult::heal( uint32_t amount, Common::CalcResultType hitType, uint8_t hitEffect, Common::ActionResultFlag flag ) { m_result.Arg0 = hitEffect; m_result.Value = static_cast< int16_t >( amount ); @@ -49,27 +49,27 @@ void ActionResult::restoreMP( uint32_t amount, Common::ActionResultFlag flag ) { m_result.Value = static_cast< int16_t >( amount ); m_result.Flag = static_cast< uint8_t >( flag ); - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_RECOVER_MP; + m_result.Type = Common::CalcResultType::TypeRecoverMp; } void ActionResult::startCombo( uint16_t actionId ) { m_result.Value = static_cast< int16_t >( actionId ); m_result.Flag = static_cast< uint8_t >( Common::ActionResultFlag::EffectOnSource ); - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_COMBO; + m_result.Type = Common::CalcResultType::TypeCombo; } void ActionResult::comboSucceed() { // no EffectOnSource flag on this - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_COMBO_HIT; + m_result.Type = Common::CalcResultType::TypeComboHit; } void ActionResult::applyStatusEffect( uint32_t id, int32_t duration, Entity::Chara& source, uint8_t param, bool shouldOverride ) { m_result.Value = static_cast< int16_t >( id ); m_result.Arg2 = param; - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_SET_STATUS; + m_result.Type = Common::CalcResultType::TypeSetStatus; m_bOverrideStatus = shouldOverride; m_pStatus = StatusEffect::make_StatusEffect( id, source.getAsChara(), m_target, duration, 3000 ); @@ -80,7 +80,7 @@ void ActionResult::applyStatusEffectSelf( uint32_t id, int32_t duration, uint8_t { m_result.Value = static_cast< int16_t >( id ); m_result.Arg2 = param; - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_SET_STATUS_ME; + m_result.Type = Common::CalcResultType::TypeSetStatusMe; m_result.Flag = static_cast< uint8_t >( Common::ActionResultFlag::EffectOnSource ); m_bOverrideStatus = shouldOverride; @@ -92,7 +92,7 @@ void ActionResult::mount( uint16_t mountId ) { m_result.Value = static_cast< int16_t >( mountId ); m_result.Arg0 = 1; - m_result.Type = Common::ActionEffectType::CALC_RESULT_TYPE_MOUNT; + m_result.Type = Common::CalcResultType::TypeMount; } const Common::CalcResultParam& ActionResult::getCalcResultParam() const @@ -112,28 +112,28 @@ void ActionResult::execute() switch( m_result.Type ) { - case Common::ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP: - case Common::ActionEffectType::CALC_RESULT_TYPE_CRITICAL_DAMAGE_HP: + case Common::CalcResultType::TypeDamageHp: + case Common::CalcResultType::TypeCriticalDamageHp: { m_target->takeDamage( m_result.Value ); break; } - case Common::ActionEffectType::CALC_RESULT_TYPE_RECOVER_HP: - case Common::ActionEffectType::CALC_RESULT_TYPE_CRITICAL_RECOVER_HP: + case Common::CalcResultType::TypeRecoverHp: + case Common::CalcResultType::TypeCriticalRecoverHp: { m_target->heal( m_result.Value ); break; } - case Common::ActionEffectType::CALC_RESULT_TYPE_RECOVER_MP: + case Common::CalcResultType::TypeRecoverMp: { m_target->restoreMP( m_result.Value ); break; } - case Common::ActionEffectType::CALC_RESULT_TYPE_SET_STATUS: - case Common::ActionEffectType::CALC_RESULT_TYPE_SET_STATUS_ME: + case Common::CalcResultType::TypeSetStatus: + case Common::CalcResultType::TypeSetStatusMe: { if( !m_bOverrideStatus ) m_target->addStatusEffectByIdIfNotExist( m_pStatus ); @@ -142,7 +142,7 @@ void ActionResult::execute() break; } - case Common::ActionEffectType::CALC_RESULT_TYPE_MOUNT: + case Common::CalcResultType::TypeMount: { auto pPlayer = m_target->getAsPlayer(); pPlayer->setMount( m_result.Value ); diff --git a/src/world/Action/ActionResult.h b/src/world/Action/ActionResult.h index f951fbb09..b4ba479e7 100644 --- a/src/world/Action/ActionResult.h +++ b/src/world/Action/ActionResult.h @@ -14,8 +14,8 @@ namespace Sapphire::World::Action public: explicit ActionResult( Entity::CharaPtr target ); - void damage( uint32_t amount, Common::ActionEffectType hitType, uint8_t hitEffect, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); - void heal( uint32_t amount, Common::ActionEffectType hitType, uint8_t hitEffect, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); + void damage( uint32_t amount, Common::CalcResultType hitType, uint8_t hitEffect, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); + void heal( uint32_t amount, Common::CalcResultType hitType, uint8_t hitEffect, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); void restoreMP( uint32_t amount, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); void startCombo( uint16_t actionId ); void comboSucceed(); diff --git a/src/world/Action/ActionResultBuilder.cpp b/src/world/Action/ActionResultBuilder.cpp index 23e82c16e..66ba8c6cd 100644 --- a/src/world/Action/ActionResultBuilder.cpp +++ b/src/world/Action/ActionResultBuilder.cpp @@ -47,7 +47,7 @@ void ActionResultBuilder::addResultToActor( Entity::CharaPtr& chara, ActionResul it->second.push_back( std::move( result ) ); } -void ActionResultBuilder::heal( Entity::CharaPtr& effectTarget, Entity::CharaPtr& healingTarget, uint32_t amount, Common::ActionEffectType hitType, Common::ActionResultFlag flag ) +void ActionResultBuilder::heal( Entity::CharaPtr& effectTarget, Entity::CharaPtr& healingTarget, uint32_t amount, Common::CalcResultType hitType, Common::ActionResultFlag flag ) { ActionResultPtr nextResult = make_ActionResult( healingTarget ); auto& exdData = Common::Service< Data::ExdData >::ref(); @@ -63,7 +63,7 @@ void ActionResultBuilder::restoreMP( Entity::CharaPtr& target, Entity::CharaPtr& addResultToActor( target, nextResult ); } -void ActionResultBuilder::damage( Entity::CharaPtr& effectTarget, Entity::CharaPtr& damagingTarget, uint32_t amount, Common::ActionEffectType hitType, Common::ActionResultFlag flag ) +void ActionResultBuilder::damage( Entity::CharaPtr& effectTarget, Entity::CharaPtr& damagingTarget, uint32_t amount, Common::CalcResultType hitType, Common::ActionResultFlag flag ) { ActionResultPtr nextResult = make_ActionResult( damagingTarget ); auto& exdData = Common::Service< Data::ExdData >::ref(); @@ -174,7 +174,7 @@ std::shared_ptr< FFXIVPacketBase > ActionResultBuilder::createActionResultPacket { auto effect = result->getCalcResultParam(); if( result->getTarget() == m_sourceChara && - result->getCalcResultParam().Type != Common::ActionEffectType::CALC_RESULT_TYPE_SET_STATUS_ME ) + result->getCalcResultParam().Type != Common::CalcResultType::TypeSetStatusMe ) actionResult->addSourceEffect( effect ); else actionResult->addTargetEffect( effect ); diff --git a/src/world/Action/ActionResultBuilder.h b/src/world/Action/ActionResultBuilder.h index a70773e85..a5d1b936a 100644 --- a/src/world/Action/ActionResultBuilder.h +++ b/src/world/Action/ActionResultBuilder.h @@ -11,14 +11,14 @@ namespace Sapphire::World::Action ActionResultBuilder( Entity::CharaPtr source, uint32_t actionId, uint32_t resultId, uint16_t requestId ); void heal( Entity::CharaPtr& effectTarget, Entity::CharaPtr& healingTarget, uint32_t amount, - Common::ActionEffectType hitType = Common::ActionEffectType::CALC_RESULT_TYPE_RECOVER_HP, + Common::CalcResultType hitType = Common::CalcResultType::TypeRecoverMp, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); void restoreMP( Entity::CharaPtr& effectTarget, Entity::CharaPtr& restoringTarget, uint32_t amount, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); void damage( Entity::CharaPtr& effectTarget, Entity::CharaPtr& damagingTarget, uint32_t amount, - Common::ActionEffectType hitType = Common::ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP, + Common::CalcResultType hitType = Common::CalcResultType::TypeDamageHp, Common::ActionResultFlag flag = Common::ActionResultFlag::None ); void startCombo( Entity::CharaPtr& target, uint16_t actionId ); diff --git a/src/world/Action/ItemAction.cpp b/src/world/Action/ItemAction.cpp index fdb09aeb2..ed096782d 100644 --- a/src/world/Action/ItemAction.cpp +++ b/src/world/Action/ItemAction.cpp @@ -78,7 +78,7 @@ void ItemAction::interrupt() void ItemAction::handleVFXItem() { Common::CalcResultParam effect{}; - effect.Type = Common::ActionEffectType::CALC_RESULT_TYPE_CHECK_BARRIER; + effect.Type = Common::CalcResultType::TypeCheckBarrier; effect.Value = m_itemAction->data().Calcu0Arg[ 0 ]; auto effectPacket = std::make_shared< EffectPacket >( getSourceChara()->getId(), getSourceChara()->getId(), getId() ); diff --git a/src/world/Actor/Chara.cpp b/src/world/Actor/Chara.cpp index 58fefc9e0..cf237326a 100644 --- a/src/world/Actor/Chara.cpp +++ b/src/world/Actor/Chara.cpp @@ -475,8 +475,8 @@ void Chara::autoAttack( CharaPtr pTarget ) Common::CalcResultParam effectEntry{}; effectEntry.Value = static_cast< int16_t >( damage ); - effectEntry.Type = ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP; - effectEntry.Arg0 = static_cast< uint8_t >( ActionHitSeverityType::NormalDamage ); + effectEntry.Type = CalcResultType::TypeDamageHp; + effectEntry.Arg0 = 1; effectEntry.Arg2 = 0x71; effectPacket->addTargetEffect( effectEntry ); @@ -763,13 +763,13 @@ void Chara::onTick() { takeDamage( thisTickDmg ); Network::Util::Packet::sendActorControl( getInRangePlayerIds( isPlayer() ), getId(), HPFloatingText, 0, - ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP, thisTickDmg ); + CalcResultType::TypeDamageHp, thisTickDmg ); } if( thisTickHeal != 0 ) { heal( thisTickHeal ); Network::Util::Packet::sendActorControl( getInRangePlayerIds( isPlayer() ), getId(), HPFloatingText, 0, - ActionEffectType::CALC_RESULT_TYPE_RECOVER_HP, thisTickHeal ); + CalcResultType::TypeRecoverMp, thisTickHeal ); } } \ No newline at end of file diff --git a/src/world/Manager/DebugCommandMgr.cpp b/src/world/Manager/DebugCommandMgr.cpp index 7dcbe84cf..2442c679a 100644 --- a/src/world/Manager/DebugCommandMgr.cpp +++ b/src/world/Manager/DebugCommandMgr.cpp @@ -534,8 +534,8 @@ void DebugCommandMgr::add( char* data, Entity::Player& player, std::shared_ptr< Common::CalcResultParam entry{}; entry.Value = static_cast< int16_t >( param1 ); - entry.Type = Common::ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP; - entry.Arg0 = static_cast< uint8_t >( Common::ActionHitSeverityType::NormalDamage ); + entry.Type = Common::CalcResultType::TypeDamageHp; + entry.Arg0 = 1; effectPacket->addTargetEffect( entry, static_cast< uint64_t >( player.getId() ) ); effectPacket->setResultId( pCurrentZone->getNextActionResultId() ); diff --git a/src/world/Math/CalcStats.cpp b/src/world/Math/CalcStats.cpp index 4dbaa36e7..e0b6fe283 100644 --- a/src/world/Math/CalcStats.cpp +++ b/src/world/Math/CalcStats.cpp @@ -549,7 +549,7 @@ float CalcStats::healingMagicPotency( const Sapphire::Entity::Chara& chara ) return std::floor( 100.f * ( chara.getStatValue( Common::BaseParam::HealingMagicPotency ) - 292.f ) / 264.f + 100.f ) / 100.f; } -std::pair< float, Sapphire::Common::ActionEffectType > CalcStats::calcAutoAttackDamage( const Sapphire::Entity::Chara& chara ) +std::pair< float, Sapphire::Common::CalcResultType > CalcStats::calcAutoAttackDamage( const Sapphire::Entity::Chara& chara ) { // D = ⌊ f(ptc) × f(aa) × f(ap) × f(det) × f(tnc) × traits ⌋ × f(ss) ⌋ × // f(chr) ⌋ × f(dhr) ⌋ × rand[ 0.95, 1.05 ] ⌋ × buff_1 ⌋ × buff... ⌋ @@ -562,7 +562,7 @@ std::pair< float, Sapphire::Common::ActionEffectType > CalcStats::calcAutoAttack // todo: everything after tenacity auto factor = Common::Util::trunc( pot * aa * ap * det, 0 ); - Sapphire::Common::ActionEffectType hitType = Sapphire::Common::ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP; + Sapphire::Common::CalcResultType hitType = Sapphire::Common::CalcResultType::TypeDamageHp; // todo: traits @@ -571,7 +571,7 @@ std::pair< float, Sapphire::Common::ActionEffectType > CalcStats::calcAutoAttack if( criticalHitProbability( chara ) > getRandomNumber0To100() ) { factor *= criticalHitBonus( chara ); - hitType = Sapphire::Common::ActionEffectType::CALC_RESULT_TYPE_CRITICAL_DAMAGE_HP; + hitType = Sapphire::Common::CalcResultType::TypeCriticalDamageHp; } factor *= 1.0f + ( ( getRandomNumber0To100() - 50.0f ) / 1000.0f ); @@ -592,7 +592,7 @@ std::pair< float, Sapphire::Common::ActionEffectType > CalcStats::calcAutoAttack return std::pair( factor, hitType ); } -std::pair< float, Sapphire::Common::ActionEffectType > CalcStats::calcActionDamage( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ) +std::pair< float, Sapphire::Common::CalcResultType > CalcStats::calcActionDamage( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ) { // D = ⌊ f(pot) × f(wd) × f(ap) × f(det) × f(tnc) × traits ⌋ // × f(chr) ⌋ × f(dhr) ⌋ × rand[ 0.95, 1.05 ] ⌋ buff_1 ⌋ × buff_1 ⌋ × buff... ⌋ @@ -603,12 +603,12 @@ std::pair< float, Sapphire::Common::ActionEffectType > CalcStats::calcActionDama auto det = determination( chara ); auto factor = Common::Util::trunc( pot * wd * ap * det, 0 ); - Sapphire::Common::ActionEffectType hitType = Sapphire::Common::ActionEffectType::CALC_RESULT_TYPE_DAMAGE_HP; + Sapphire::Common::CalcResultType hitType = Sapphire::Common::CalcResultType::TypeDamageHp; if( criticalHitProbability( chara ) > getRandomNumber0To100() ) { factor *= criticalHitBonus( chara ); - hitType = Sapphire::Common::ActionEffectType::CALC_RESULT_TYPE_CRITICAL_DAMAGE_HP; + hitType = Sapphire::Common::CalcResultType::TypeCriticalDamageHp; } factor *= 1.0f + ( ( getRandomNumber0To100() - 50.0f ) / 1000.0f ); @@ -629,7 +629,7 @@ std::pair< float, Sapphire::Common::ActionEffectType > CalcStats::calcActionDama return std::pair( factor, hitType ); } -std::pair< float, Sapphire::Common::ActionEffectType > CalcStats::calcActionHealing( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ) +std::pair< float, Sapphire::Common::CalcResultType > CalcStats::calcActionHealing( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ) { // lol just for testing float det = chara.getStatValue( Common::BaseParam::Determination ); @@ -637,12 +637,12 @@ std::pair< float, Sapphire::Common::ActionEffectType > CalcStats::calcActionHeal auto factor = std::floor( ( wepDmg * ( mnd / 200 ) + ( det / 10 ) ) * ( ptc / 100 ) * 1.3f ); - Sapphire::Common::ActionEffectType hitType = Sapphire::Common::ActionEffectType::CALC_RESULT_TYPE_RECOVER_HP; + Sapphire::Common::CalcResultType hitType = Sapphire::Common::CalcResultType::TypeRecoverHp; if( criticalHitProbability( chara ) > getRandomNumber0To100() ) { factor *= criticalHitBonus( chara ); - hitType = Sapphire::Common::ActionEffectType::CALC_RESULT_TYPE_CRITICAL_RECOVER_HP; + hitType = Sapphire::Common::CalcResultType::TypeCriticalRecoverHp; } factor *= 1.0f + ( ( getRandomNumber0To100() - 50.0f ) / 1000.0f ); diff --git a/src/world/Math/CalcStats.h b/src/world/Math/CalcStats.h index a4c69ecc1..ad1d5b94f 100644 --- a/src/world/Math/CalcStats.h +++ b/src/world/Math/CalcStats.h @@ -136,11 +136,11 @@ namespace Sapphire::Math //////////////////////////////////////////// - static std::pair< float, Common::ActionEffectType > calcAutoAttackDamage( const Sapphire::Entity::Chara& chara ); + static std::pair< float, Common::CalcResultType > calcAutoAttackDamage( const Sapphire::Entity::Chara& chara ); - static std::pair< float, Common::ActionEffectType > calcActionDamage( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ); + static std::pair< float, Common::CalcResultType > calcActionDamage( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ); - static std::pair< float, Common::ActionEffectType > calcActionHealing( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ); + static std::pair< float, Common::CalcResultType > calcActionHealing( const Sapphire::Entity::Chara& chara, uint32_t ptc, float wepDmg ); static uint32_t primaryStatValue( const Sapphire::Entity::Chara& chara ); private: diff --git a/src/world/Task/ActionIntegrityTask.cpp b/src/world/Task/ActionIntegrityTask.cpp index 7443a8396..3f2d0749c 100644 --- a/src/world/Task/ActionIntegrityTask.cpp +++ b/src/world/Task/ActionIntegrityTask.cpp @@ -52,8 +52,8 @@ void ActionIntegrityTask::execute() if( actionResult && actionResult->getTarget() ) actionResult->execute(); - if( ( actionResult->getCalcResultParam().Type == Common::CALC_RESULT_TYPE_SET_STATUS ) || - ( actionResult->getCalcResultParam().Type == Common::CALC_RESULT_TYPE_SET_STATUS_ME ) ) + if( ( actionResult->getCalcResultParam().Type == Common::TypeSetStatus ) || + ( actionResult->getCalcResultParam().Type == Common::TypeSetStatusMe ) ) { auto& status = data.Status[ statusIdx++ ]; auto pEffect = actionResult->getStatusEffect(); From fe9a2ef9746617de009993c2f44ace9b54071dfc Mon Sep 17 00:00:00 2001 From: Mordred Date: Thu, 16 Mar 2023 21:56:57 +0100 Subject: [PATCH 06/30] Cleanup cleanup cleanup --- src/world/AI/GambitTargetCondition.h | 11 ++++--- src/world/Action/ActionResult.cpp | 43 ++++++++++++++-------------- src/world/Actor/BNpc.cpp | 2 +- src/world/ForwardsZone.h | 2 +- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/world/AI/GambitTargetCondition.h b/src/world/AI/GambitTargetCondition.h index ec0cd7ae0..931b579d6 100644 --- a/src/world/AI/GambitTargetCondition.h +++ b/src/world/AI/GambitTargetCondition.h @@ -18,20 +18,19 @@ namespace Sapphire::World::AI class GambitTargetCondition { public: - GambitTargetCondition( GambitTargetType targetType ) : m_targetType( targetType ) {}; + GambitTargetCondition() = default; virtual ~GambitTargetCondition() = default; virtual bool isConditionMet( Sapphire::Entity::BNpc& src ) { return false; }; Sapphire::Entity::CharaPtr getTarget() const { return m_pTarget; }; protected: - GambitTargetType m_targetType; Sapphire::Entity::CharaPtr m_pTarget; }; class TopHateTargetCondition : public GambitTargetCondition { public: - TopHateTargetCondition() : GambitTargetCondition( PlayerAndAlly ) {}; + TopHateTargetCondition() = default; bool isConditionMet( Sapphire::Entity::BNpc& src ) override { @@ -45,12 +44,12 @@ namespace Sapphire::World::AI }; }; - class HPSelfPctLessThan : public GambitTargetCondition + class HPSelfPctLessThanTargetCondition : public GambitTargetCondition { public: - HPSelfPctLessThan( uint8_t pct ) : GambitTargetCondition( Self ), m_HpPct( pct ) {}; + HPSelfPctLessThanTargetCondition( uint8_t pct ) : m_HpPct( pct ) {}; - virtual bool isConditionMet( Sapphire::Entity::BNpc& src ) + bool isConditionMet( Sapphire::Entity::BNpc& src ) override { if( src.getHpPercent() < m_HpPct ) { diff --git a/src/world/Action/ActionResult.cpp b/src/world/Action/ActionResult.cpp index e07c308c2..31d82aed1 100644 --- a/src/world/Action/ActionResult.cpp +++ b/src/world/Action/ActionResult.cpp @@ -10,6 +10,7 @@ #include "StatusEffect/StatusEffect.h" using namespace Sapphire; +using namespace Sapphire::Common; using namespace Sapphire::World::Action; @@ -20,8 +21,8 @@ ActionResult::ActionResult( Entity::CharaPtr target ) : m_result.Arg1 = 0; m_result.Arg2 = 0; m_result.Value = 0; - m_result.Flag = static_cast< uint8_t >( Common::ActionResultFlag::None ); - m_result.Type = Common::CalcResultType::TypeNone; + m_result.Flag = static_cast< uint8_t >( ActionResultFlag::None ); + m_result.Type = CalcResultType::TypeNone; } Entity::CharaPtr ActionResult::getTarget() const @@ -29,7 +30,7 @@ Entity::CharaPtr ActionResult::getTarget() const return m_target; } -void ActionResult::damage( uint32_t amount, Common::CalcResultType hitType, uint8_t hitEffect, Common::ActionResultFlag flag ) +void ActionResult::damage( uint32_t amount, CalcResultType hitType, uint8_t hitEffect, ActionResultFlag flag ) { m_result.Arg0 = hitEffect; m_result.Value = static_cast< int16_t >( amount ); @@ -37,7 +38,7 @@ void ActionResult::damage( uint32_t amount, Common::CalcResultType hitType, uint m_result.Type = hitType; } -void ActionResult::heal( uint32_t amount, Common::CalcResultType hitType, uint8_t hitEffect, Common::ActionResultFlag flag ) +void ActionResult::heal( uint32_t amount, CalcResultType hitType, uint8_t hitEffect, ActionResultFlag flag ) { m_result.Arg0 = hitEffect; m_result.Value = static_cast< int16_t >( amount ); @@ -45,31 +46,31 @@ void ActionResult::heal( uint32_t amount, Common::CalcResultType hitType, uint8_ m_result.Type = hitType; } -void ActionResult::restoreMP( uint32_t amount, Common::ActionResultFlag flag ) +void ActionResult::restoreMP( uint32_t amount, ActionResultFlag flag ) { m_result.Value = static_cast< int16_t >( amount ); m_result.Flag = static_cast< uint8_t >( flag ); - m_result.Type = Common::CalcResultType::TypeRecoverMp; + m_result.Type = CalcResultType::TypeRecoverMp; } void ActionResult::startCombo( uint16_t actionId ) { m_result.Value = static_cast< int16_t >( actionId ); - m_result.Flag = static_cast< uint8_t >( Common::ActionResultFlag::EffectOnSource ); - m_result.Type = Common::CalcResultType::TypeCombo; + m_result.Flag = static_cast< uint8_t >( ActionResultFlag::EffectOnSource ); + m_result.Type = CalcResultType::TypeCombo; } void ActionResult::comboSucceed() { // no EffectOnSource flag on this - m_result.Type = Common::CalcResultType::TypeComboHit; + m_result.Type = CalcResultType::TypeComboHit; } void ActionResult::applyStatusEffect( uint32_t id, int32_t duration, Entity::Chara& source, uint8_t param, bool shouldOverride ) { m_result.Value = static_cast< int16_t >( id ); m_result.Arg2 = param; - m_result.Type = Common::CalcResultType::TypeSetStatus; + m_result.Type = CalcResultType::TypeSetStatus; m_bOverrideStatus = shouldOverride; m_pStatus = StatusEffect::make_StatusEffect( id, source.getAsChara(), m_target, duration, 3000 ); @@ -80,8 +81,8 @@ void ActionResult::applyStatusEffectSelf( uint32_t id, int32_t duration, uint8_t { m_result.Value = static_cast< int16_t >( id ); m_result.Arg2 = param; - m_result.Type = Common::CalcResultType::TypeSetStatusMe; - m_result.Flag = static_cast< uint8_t >( Common::ActionResultFlag::EffectOnSource ); + m_result.Type = CalcResultType::TypeSetStatusMe; + m_result.Flag = static_cast< uint8_t >( ActionResultFlag::EffectOnSource ); m_bOverrideStatus = shouldOverride; m_pStatus = StatusEffect::make_StatusEffect( id, m_target, m_target, duration, 3000 ); @@ -92,7 +93,7 @@ void ActionResult::mount( uint16_t mountId ) { m_result.Value = static_cast< int16_t >( mountId ); m_result.Arg0 = 1; - m_result.Type = Common::CalcResultType::TypeMount; + m_result.Type = CalcResultType::TypeMount; } const Common::CalcResultParam& ActionResult::getCalcResultParam() const @@ -112,28 +113,28 @@ void ActionResult::execute() switch( m_result.Type ) { - case Common::CalcResultType::TypeDamageHp: - case Common::CalcResultType::TypeCriticalDamageHp: + case CalcResultType::TypeDamageHp: + case CalcResultType::TypeCriticalDamageHp: { m_target->takeDamage( m_result.Value ); break; } - case Common::CalcResultType::TypeRecoverHp: - case Common::CalcResultType::TypeCriticalRecoverHp: + case CalcResultType::TypeRecoverHp: + case CalcResultType::TypeCriticalRecoverHp: { m_target->heal( m_result.Value ); break; } - case Common::CalcResultType::TypeRecoverMp: + case CalcResultType::TypeRecoverMp: { m_target->restoreMP( m_result.Value ); break; } - case Common::CalcResultType::TypeSetStatus: - case Common::CalcResultType::TypeSetStatusMe: + case CalcResultType::TypeSetStatus: + case CalcResultType::TypeSetStatusMe: { if( !m_bOverrideStatus ) m_target->addStatusEffectByIdIfNotExist( m_pStatus ); @@ -142,7 +143,7 @@ void ActionResult::execute() break; } - case Common::CalcResultType::TypeMount: + case CalcResultType::TypeMount: { auto pPlayer = m_target->getAsPlayer(); pPlayer->setMount( m_result.Value ); diff --git a/src/world/Actor/BNpc.cpp b/src/world/Actor/BNpc.cpp index 4a9c95e6e..30a3235c1 100644 --- a/src/world/Actor/BNpc.cpp +++ b/src/world/Actor/BNpc.cpp @@ -1056,7 +1056,7 @@ void BNpc::init() //setup a test gambit auto testGambitRule = AI::make_GambitRule( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 88, 0 ), 5000 ); - auto testGambitRule1 = AI::make_GambitRule( AI::make_HPSelfPctLessThan( 50 ), Action::make_Action( getAsChara(), 120, 0 ), 5000 ); + auto testGambitRule1 = AI::make_GambitRule( AI::make_HPSelfPctLessThanTargetCondition( 50 ), Action::make_Action( getAsChara(), 120, 0 ), 5000 ); m_gambits.push_back( testGambitRule ); m_gambits.push_back( testGambitRule1 ); diff --git a/src/world/ForwardsZone.h b/src/world/ForwardsZone.h index 02bbc8a62..ef95ab0a6 100644 --- a/src/world/ForwardsZone.h +++ b/src/world/ForwardsZone.h @@ -51,7 +51,7 @@ namespace World::AI { TYPE_FORWARD( GambitTargetCondition ); TYPE_FORWARD( TopHateTargetCondition ); - TYPE_FORWARD( HPSelfPctLessThan ); + TYPE_FORWARD( HPSelfPctLessThanTargetCondition ); TYPE_FORWARD( GambitRule ); } From e72fe535f65d907a88ef0218511bcbe156b018ae Mon Sep 17 00:00:00 2001 From: Mordred Date: Fri, 17 Mar 2023 15:43:44 +0100 Subject: [PATCH 07/30] Added the framework for a fsm for future use on bnpcs. --- src/world/AI/Fsm.cpp | 38 ++++++++++++++++++ src/world/AI/Fsm.h | 23 +++++++++++ src/world/AI/FsmCondition.h | 23 +++++++++++ src/world/AI/FsmState.h | 37 ++++++++++++++++++ src/world/AI/FsmTransition.h | 22 +++++++++++ src/world/Actor/BNpc.cpp | 76 ++++++++++++++++++------------------ src/world/ForwardsZone.h | 5 +++ 7 files changed, 186 insertions(+), 38 deletions(-) create mode 100644 src/world/AI/Fsm.cpp create mode 100644 src/world/AI/Fsm.h create mode 100644 src/world/AI/FsmCondition.h create mode 100644 src/world/AI/FsmState.h create mode 100644 src/world/AI/FsmTransition.h diff --git a/src/world/AI/Fsm.cpp b/src/world/AI/Fsm.cpp new file mode 100644 index 000000000..ce78c6d51 --- /dev/null +++ b/src/world/AI/Fsm.cpp @@ -0,0 +1,38 @@ +#include +#include +#include +#include "Fsm.h" +#include "FsmState.h" + +#pragma once + +using namespace Sapphire; +using namespace Sapphire::World; + +AI::FsmStatePtr AI::Fsm::addState( FsmStatePtr state ) +{ + m_states.push_back( state ); + return state; +} + +void AI::Fsm::setCurrentState( FsmStatePtr state ) +{ + m_pCurrentState = state; +} + +void AI::Fsm::update( Entity::BNpc& bnpc, float deltaTime ) +{ + if( !m_pCurrentState ) + return; + + FsmTransitionPtr transition = m_pCurrentState->getTriggeredTransition( bnpc ); + + if( transition ) + { + m_pCurrentState->onExit( bnpc ); + m_pCurrentState = transition->getTargetState(); + m_pCurrentState->onEnter( bnpc ); + } + + m_pCurrentState->onUpdate( bnpc, deltaTime ); +} diff --git a/src/world/AI/Fsm.h b/src/world/AI/Fsm.h new file mode 100644 index 000000000..4477f8dec --- /dev/null +++ b/src/world/AI/Fsm.h @@ -0,0 +1,23 @@ +#include +#include +#include + +#pragma once + +namespace Sapphire::World::AI +{ + class Fsm + { + public: + Fsm() = default; + ~Fsm() = default; + + FsmStatePtr addState( FsmStatePtr state ); + void setCurrentState( FsmStatePtr state ); + virtual void update( Entity::BNpc& bnpc, float deltaTime ); + + protected: + std::vector< FsmStatePtr > m_states; + FsmStatePtr m_pCurrentState; + }; +} \ No newline at end of file diff --git a/src/world/AI/FsmCondition.h b/src/world/AI/FsmCondition.h new file mode 100644 index 000000000..41619ac01 --- /dev/null +++ b/src/world/AI/FsmCondition.h @@ -0,0 +1,23 @@ +#include +#include +#include + +#pragma once + +namespace Sapphire::World::AI +{ + class FsmCondition + { + public: + FsmCondition() = default; + virtual ~FsmCondition() = default; + + virtual bool isConditionMet( Sapphire::Entity::BNpc& src ) const = 0; + virtual bool update( Sapphire::Entity::BNpc& src, float time ) + { + if( isConditionMet( src ) ) + return true; + return false; + }; + }; +} \ No newline at end of file diff --git a/src/world/AI/FsmState.h b/src/world/AI/FsmState.h new file mode 100644 index 000000000..cb1b74664 --- /dev/null +++ b/src/world/AI/FsmState.h @@ -0,0 +1,37 @@ +#include +#include +#include +#include "FsmTransition.h" + +#pragma once + +namespace Sapphire::World::AI +{ + class FsmState + { + public: + virtual ~FsmState() = default; + + virtual void onUpdate( Entity::BNpc& bnpc, float deltaTime ) = 0; + virtual void onEnter( Entity::BNpc& bnpc ) { } + virtual void onExit( Entity::BNpc& bnpc ) { } + + void addTransition( FsmTransitionPtr transition ) + { + m_transitions.push_back( transition ); + } + + FsmTransitionPtr getTriggeredTransition( Entity::BNpc& bnpc ) + { + for( auto transition : m_transitions ) + { + if( transition->hasTriggered( bnpc ) ) + return transition; + } + return nullptr; + } + + private: + std::vector< FsmTransitionPtr > m_transitions; + }; +} \ No newline at end of file diff --git a/src/world/AI/FsmTransition.h b/src/world/AI/FsmTransition.h new file mode 100644 index 000000000..982dd8744 --- /dev/null +++ b/src/world/AI/FsmTransition.h @@ -0,0 +1,22 @@ +#include +#include +#include +#include "FsmCondition.h" + +#pragma once + +namespace Sapphire::World::AI +{ + class FsmTransition + { + public: + FsmTransition( FsmStatePtr targetState, FsmConditionPtr condition ) : m_pTargetState( targetState ), m_pCondition( condition ) { } + virtual ~FsmTransition() = default; + + FsmStatePtr getTargetState() { return m_pTargetState; } + bool hasTriggered( Entity::BNpc& bnpc ) { return m_pCondition->isConditionMet( bnpc ); } + private: + FsmStatePtr m_pTargetState; + FsmConditionPtr m_pCondition; + }; +} \ No newline at end of file diff --git a/src/world/Actor/BNpc.cpp b/src/world/Actor/BNpc.cpp index 30a3235c1..dd38c7846 100644 --- a/src/world/Actor/BNpc.cpp +++ b/src/world/Actor/BNpc.cpp @@ -649,6 +649,8 @@ void BNpc::update( uint64_t tickCount ) if( !pNaviProvider ) return; + Chara::update( tickCount ); + if( !checkAction() ) processGambits( tickCount ); @@ -740,63 +742,61 @@ void BNpc::update( uint64_t tickCount ) auto distanceOrig = Common::Util::distance( getPos(), m_spawnPos ); - if( pHatedActor && !pHatedActor->isAlive() ) + if( !pHatedActor->isAlive() || getTerritoryId() != pHatedActor->getTerritoryId() ) { hateListRemove( pHatedActor ); pHatedActor = hateListGetHighest(); } - if( pHatedActor ) + if( !pHatedActor ) { - auto distance = Common::Util::distance( getPos(), pHatedActor->getPos() ); + changeTarget( INVALID_GAME_OBJECT_ID64 ); + setStance( Stance::Passive ); + //setOwner( nullptr ); + m_state = BNpcState::Retreat; + pNaviProvider->updateAgentParameters( *this ); + break; + } - if( !hasFlag( NoDeaggro ) && ( ( distanceOrig > maxDistanceToOrigin ) || distance > 30.0f ) ) - { - hateListClear(); - changeTarget( INVALID_GAME_OBJECT_ID64 ); - setStance( Stance::Passive ); - setOwner( nullptr ); - m_state = BNpcState::Retreat; - break; - } + auto distance = Common::Util::distance( getPos(), pHatedActor->getPos() ); - if( distance > ( getNaviTargetReachedDistance() + pHatedActor->getRadius() ) ) - { - if( hasFlag( Immobile ) ) - break; + if( !hasFlag( NoDeaggro ) && ( ( distanceOrig > maxDistanceToOrigin ) || distance > 30.0f ) ) + { + hateListClear(); + changeTarget( INVALID_GAME_OBJECT_ID64 ); + setStance( Stance::Passive ); + setOwner( nullptr ); + m_state = BNpcState::Retreat; + break; + } - if( pNaviProvider ) - pNaviProvider->setMoveTarget( *this, pHatedActor->getPos() ); + if( distance > ( getNaviTargetReachedDistance() + pHatedActor->getRadius() ) ) + { + if( hasFlag( Immobile ) ) + break; - moveTo( *pHatedActor ); - } + if( pNaviProvider ) + pNaviProvider->setMoveTarget( *this, pHatedActor->getPos() ); - if( pNaviProvider->syncPosToChara( *this ) ) - sendPositionUpdate(); + moveTo( *pHatedActor ); + } - if( distance < ( getNaviTargetReachedDistance() + pHatedActor->getRadius() ) ) - { - if( !hasFlag( TurningDisabled ) && face( pHatedActor->getPos() ) ) - sendPositionUpdate(); + if( pNaviProvider->syncPosToChara( *this ) ) + sendPositionUpdate(); - // in combat range. ATTACK! - autoAttack( pHatedActor ); - } - } - else + if( distance < ( getNaviTargetReachedDistance() + pHatedActor->getRadius() ) ) { - changeTarget( INVALID_GAME_OBJECT_ID64 ); - setStance( Stance::Passive ); - //setOwner( nullptr ); - m_state = BNpcState::Retreat; - pNaviProvider->updateAgentParameters( *this ); + if( !hasFlag( TurningDisabled ) && face( pHatedActor->getPos() ) ) + sendPositionUpdate(); + + // in combat range. ATTACK! + autoAttack( pHatedActor ); } + } break; } - - Chara::update( tickCount ); } void BNpc::restHp() diff --git a/src/world/ForwardsZone.h b/src/world/ForwardsZone.h index ef95ab0a6..e17eb9163 100644 --- a/src/world/ForwardsZone.h +++ b/src/world/ForwardsZone.h @@ -54,6 +54,11 @@ namespace World::AI TYPE_FORWARD( HPSelfPctLessThanTargetCondition ); TYPE_FORWARD( GambitRule ); + + TYPE_FORWARD( FsmCondition ); + TYPE_FORWARD( FsmState ); + TYPE_FORWARD( FsmTransition ); + TYPE_FORWARD( Fsm ); } namespace Inventory From c7b50ca1e9172708d8658f3239d06c5efcbc404d Mon Sep 17 00:00:00 2001 From: Mordred Date: Fri, 17 Mar 2023 22:01:06 +0100 Subject: [PATCH 08/30] Keep cells active for 20 seconds even after all players left. Also reset target and autoattack state on player on change zone. --- src/world/Task/MoveTerritoryTask.cpp | 4 ++++ src/world/Territory/Cell.cpp | 9 +++++++++ src/world/Territory/Cell.h | 4 ++++ src/world/Territory/Territory.cpp | 8 +++++--- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/world/Task/MoveTerritoryTask.cpp b/src/world/Task/MoveTerritoryTask.cpp index 30194d9d6..b7d9c061b 100644 --- a/src/world/Task/MoveTerritoryTask.cpp +++ b/src/world/Task/MoveTerritoryTask.cpp @@ -41,6 +41,10 @@ void MoveTerritoryTask::execute() if( !pPlayer ) return; + pPlayer->setTargetId( 0 ); + pPlayer->setStance( Common::Stance::Passive ); + pPlayer->setAutoattack( false ); + auto inRangePlayerIds = pPlayer->getInRangePlayerIds( true ); auto warpStart = makeActorControlSelf( pPlayer->getId(), WarpStart, m_warpInfo.m_warpType, 1, 0, m_warpInfo.m_targetTerritoryId, 1 ); diff --git a/src/world/Territory/Cell.cpp b/src/world/Territory/Cell.cpp index 2eebc7a78..42bda6674 100644 --- a/src/world/Territory/Cell.cpp +++ b/src/world/Territory/Cell.cpp @@ -102,3 +102,12 @@ void Sapphire::Cell::unload() removeActors(); } +uint32_t Sapphire::Cell::getLastActiveTime() const +{ + return m_lastActiveTime; +} + +void Sapphire::Cell::setLastActiveTime( uint32_t lastActiveTime ) +{ + m_lastActiveTime = lastActiveTime; +} \ No newline at end of file diff --git a/src/world/Territory/Cell.h b/src/world/Territory/Cell.h index 07c0cfc37..4aca5791e 100644 --- a/src/world/Territory/Cell.h +++ b/src/world/Territory/Cell.h @@ -20,6 +20,7 @@ class Cell bool m_bActive; uint16_t m_playerCount; + uint32_t m_lastActiveTime; public: Cell(); @@ -82,6 +83,9 @@ class Cell { return m_posY; } + + uint32_t getLastActiveTime() const; + void setLastActiveTime( uint32_t lastActiveTime ); }; } diff --git a/src/world/Territory/Territory.cpp b/src/world/Territory/Territory.cpp index 375c7071e..de4a5c4f5 100644 --- a/src/world/Territory/Territory.cpp +++ b/src/world/Territory/Territory.cpp @@ -528,6 +528,7 @@ bool Territory::isCellActive( uint32_t x, uint32_t y ) uint32_t posY; CellPtr pCell; + uint32_t time = Common::Util::getTimeSeconds(); for( posX = startX; posX <= endX; posX++ ) { @@ -535,7 +536,7 @@ bool Territory::isCellActive( uint32_t x, uint32_t y ) { pCell = getCellPtr( posX, posY ); - if( pCell && ( pCell->hasPlayers() || pCell->isForcedActive() ) ) + if( pCell && ( pCell->hasPlayers() || pCell->isForcedActive() || ( time - pCell->getLastActiveTime() ) < 20 ) ) return true; } } @@ -566,13 +567,13 @@ void Territory::updateCellActivity( uint32_t x, uint32_t y, int32_t radius ) { pCell = create( posX, posY ); pCell->init( posX, posY ); - pCell->setActivity( true ); - + pCell->setLastActiveTime( Common::Util::getTimeSeconds() ); } } else { + pCell->setLastActiveTime( Common::Util::getTimeSeconds() ); //Cell is now active if( isCellActive( posX, posY ) && !pCell->isActive() ) { @@ -581,6 +582,7 @@ void Territory::updateCellActivity( uint32_t x, uint32_t y, int32_t radius ) else if( !isCellActive( posX, posY ) && pCell->isActive() ) pCell->setActivity( false ); } + } } } From c97a67ffe67fef56436bf26f582ba0246dd80c06 Mon Sep 17 00:00:00 2001 From: Mordred Date: Mon, 20 Mar 2023 10:29:56 +0100 Subject: [PATCH 09/30] Implementation of the state machine for bnpcs, missing hp recovering after lost hate. --- src/world/AI/Fsm.cpp | 38 ----- src/world/AI/Fsm.h | 23 --- src/world/AI/Fsm/Condition.h | 95 ++++++++++++ src/world/AI/Fsm/State.h | 43 ++++++ src/world/AI/Fsm/StateCombat.cpp | 79 ++++++++++ src/world/AI/Fsm/StateCombat.h | 20 +++ src/world/AI/Fsm/StateDead.cpp | 26 ++++ src/world/AI/Fsm/StateDead.h | 20 +++ src/world/AI/Fsm/StateIdle.cpp | 20 +++ src/world/AI/Fsm/StateIdle.h | 20 +++ src/world/AI/Fsm/StateMachine.cpp | 38 +++++ src/world/AI/Fsm/StateMachine.h | 23 +++ src/world/AI/Fsm/StateRetreat.cpp | 41 +++++ src/world/AI/Fsm/StateRetreat.h | 20 +++ src/world/AI/Fsm/StateRoam.cpp | 49 ++++++ src/world/AI/Fsm/StateRoam.h | 20 +++ src/world/AI/Fsm/Transition.h | 22 +++ src/world/AI/FsmCondition.h | 23 --- src/world/AI/FsmState.h | 37 ----- src/world/AI/FsmTransition.h | 22 --- src/world/Actor/BNpc.cpp | 243 ++++++++++-------------------- src/world/Actor/BNpc.h | 18 ++- src/world/CMakeLists.txt | 1 + src/world/ForwardsZone.h | 28 +++- 24 files changed, 660 insertions(+), 309 deletions(-) delete mode 100644 src/world/AI/Fsm.cpp delete mode 100644 src/world/AI/Fsm.h create mode 100644 src/world/AI/Fsm/Condition.h create mode 100644 src/world/AI/Fsm/State.h create mode 100644 src/world/AI/Fsm/StateCombat.cpp create mode 100644 src/world/AI/Fsm/StateCombat.h create mode 100644 src/world/AI/Fsm/StateDead.cpp create mode 100644 src/world/AI/Fsm/StateDead.h create mode 100644 src/world/AI/Fsm/StateIdle.cpp create mode 100644 src/world/AI/Fsm/StateIdle.h create mode 100644 src/world/AI/Fsm/StateMachine.cpp create mode 100644 src/world/AI/Fsm/StateMachine.h create mode 100644 src/world/AI/Fsm/StateRetreat.cpp create mode 100644 src/world/AI/Fsm/StateRetreat.h create mode 100644 src/world/AI/Fsm/StateRoam.cpp create mode 100644 src/world/AI/Fsm/StateRoam.h create mode 100644 src/world/AI/Fsm/Transition.h delete mode 100644 src/world/AI/FsmCondition.h delete mode 100644 src/world/AI/FsmState.h delete mode 100644 src/world/AI/FsmTransition.h diff --git a/src/world/AI/Fsm.cpp b/src/world/AI/Fsm.cpp deleted file mode 100644 index ce78c6d51..000000000 --- a/src/world/AI/Fsm.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include -#include "Fsm.h" -#include "FsmState.h" - -#pragma once - -using namespace Sapphire; -using namespace Sapphire::World; - -AI::FsmStatePtr AI::Fsm::addState( FsmStatePtr state ) -{ - m_states.push_back( state ); - return state; -} - -void AI::Fsm::setCurrentState( FsmStatePtr state ) -{ - m_pCurrentState = state; -} - -void AI::Fsm::update( Entity::BNpc& bnpc, float deltaTime ) -{ - if( !m_pCurrentState ) - return; - - FsmTransitionPtr transition = m_pCurrentState->getTriggeredTransition( bnpc ); - - if( transition ) - { - m_pCurrentState->onExit( bnpc ); - m_pCurrentState = transition->getTargetState(); - m_pCurrentState->onEnter( bnpc ); - } - - m_pCurrentState->onUpdate( bnpc, deltaTime ); -} diff --git a/src/world/AI/Fsm.h b/src/world/AI/Fsm.h deleted file mode 100644 index 4477f8dec..000000000 --- a/src/world/AI/Fsm.h +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include -#include - -#pragma once - -namespace Sapphire::World::AI -{ - class Fsm - { - public: - Fsm() = default; - ~Fsm() = default; - - FsmStatePtr addState( FsmStatePtr state ); - void setCurrentState( FsmStatePtr state ); - virtual void update( Entity::BNpc& bnpc, float deltaTime ); - - protected: - std::vector< FsmStatePtr > m_states; - FsmStatePtr m_pCurrentState; - }; -} \ No newline at end of file diff --git a/src/world/AI/Fsm/Condition.h b/src/world/AI/Fsm/Condition.h new file mode 100644 index 000000000..11fb48046 --- /dev/null +++ b/src/world/AI/Fsm/Condition.h @@ -0,0 +1,95 @@ +#include +#include "ForwardsZone.h" +#include "Actor/BNpc.h" +#include +#include + +#pragma once + +namespace Sapphire::World::AI::Fsm +{ + class Condition + { + public: + Condition() = default; + virtual ~Condition() = default; + + virtual bool isConditionMet( Sapphire::Entity::BNpc& src ) const = 0; + virtual bool update( Sapphire::Entity::BNpc& src, float time ) + { + if( isConditionMet( src ) ) + return true; + return false; + }; + }; + + class RoamNextTimeReachedCondition : public Condition + { + public: + bool isConditionMet( Sapphire::Entity::BNpc& src ) const override + { + if( ( Common::Util::getTimeSeconds() - src.getLastRoamTargetReachedTime() ) > 20 ) + return true; + return false; + } + }; + + class RoamTargetReachedCondition : public Condition + { + public: + bool isConditionMet( Sapphire::Entity::BNpc& src ) const override + { + if( src.isRoamTargetReached() ) + return true; + return false; + } + }; + + class HateListEmptyCondition : public Condition + { + public: + bool isConditionMet( Sapphire::Entity::BNpc& src ) const override + { + if( src.hateListGetHighest() ) + return false; + return true; + } + }; + + class HateListHasEntriesCondition : public Condition + { + public: + bool isConditionMet( Sapphire::Entity::BNpc& src ) const override + { + if( src.hateListGetHighest() ) + return true; + return false; + } + }; + + class SpawnPointDistanceGtMaxDistanceCondition : public Condition + { + public: + bool isConditionMet( Sapphire::Entity::BNpc& src ) const override + { + auto distanceOrig = Common::Util::distance( src.getPos(), src.getSpawnPos() ); + if( distanceOrig > 40 ) + return true; + + return false; + } + }; + + class IsDeadCondition : public Condition + { + public: + bool isConditionMet( Sapphire::Entity::BNpc& src ) const override + { + if( !src.isAlive() ) + return true; + + return false; + } + }; + +} \ No newline at end of file diff --git a/src/world/AI/Fsm/State.h b/src/world/AI/Fsm/State.h new file mode 100644 index 000000000..d5739e038 --- /dev/null +++ b/src/world/AI/Fsm/State.h @@ -0,0 +1,43 @@ +#include +#include "ForwardsZone.h" +#include "Actor/BNpc.h" +#include "Transition.h" + +#pragma once + +namespace Sapphire::World::AI::Fsm +{ + class State + { + public: + virtual ~State() = default; + + virtual void onUpdate( Entity::BNpc& bnpc, uint64_t tickCount ) = 0; + virtual void onEnter( Entity::BNpc& bnpc ) { } + virtual void onExit( Entity::BNpc& bnpc ) { } + + void addTransition( TransitionPtr transition ) + { + m_transitions.push_back( transition ); + } + + void addTransition( StatePtr targetState, ConditionPtr condition ) + { + m_transitions.push_back( make_Transition( targetState, condition ) ); + } + + + TransitionPtr getTriggeredTransition( Entity::BNpc& bnpc ) + { + for( auto transition : m_transitions ) + { + if( transition->hasTriggered( bnpc ) ) + return transition; + } + return nullptr; + } + + private: + std::vector< TransitionPtr > m_transitions; + }; +} \ No newline at end of file diff --git a/src/world/AI/Fsm/StateCombat.cpp b/src/world/AI/Fsm/StateCombat.cpp new file mode 100644 index 000000000..5bcefd58b --- /dev/null +++ b/src/world/AI/Fsm/StateCombat.cpp @@ -0,0 +1,79 @@ +#include "StateCombat.h" +#include "Actor/BNpc.h" +#include "Logging/Logger.h" +#include + +#include +#include +#include + +using namespace Sapphire::World; + +void AI::Fsm::StateCombat::onUpdate( Entity::BNpc& bnpc, uint64_t tickCount ) +{ + + auto& teriMgr = Common::Service< World::Manager::TerritoryMgr >::ref(); + auto pZone = teriMgr.getTerritoryByGuId( bnpc.getTerritoryId() ); + auto pNaviProvider = pZone->getNaviProvider(); + + auto pHatedActor = bnpc.hateListGetHighest(); + if( !pHatedActor ) + return; + + pNaviProvider->updateAgentParameters( bnpc ); + + auto distanceOrig = Common::Util::distance( bnpc.getPos(), bnpc.getSpawnPos() ); + + if( !pHatedActor->isAlive() || bnpc.getTerritoryId() != pHatedActor->getTerritoryId() ) + { + bnpc.hateListRemove( pHatedActor ); + pHatedActor = bnpc.hateListGetHighest(); + } + + if( !pHatedActor ) + return; + + auto distance = Common::Util::distance( bnpc.getPos(), pHatedActor->getPos() ); + + if( !bnpc.hasFlag( Entity::NoDeaggro ) ) + { + + } + + if( !bnpc.hasFlag( Entity::Immobile ) && distance > ( bnpc.getNaviTargetReachedDistance() + pHatedActor->getRadius() ) ) + { + if( pNaviProvider ) + pNaviProvider->setMoveTarget( bnpc, pHatedActor->getPos() ); + + bnpc.moveTo( *pHatedActor ); + } + + if( pNaviProvider->syncPosToChara( bnpc ) ) + bnpc.sendPositionUpdate(); + + if( distance < ( bnpc.getNaviTargetReachedDistance() + pHatedActor->getRadius() ) ) + { + if( !bnpc.hasFlag( Entity::TurningDisabled ) && bnpc.face( pHatedActor->getPos() ) ) + bnpc.sendPositionUpdate(); + + if( !bnpc.checkAction() ) + bnpc.processGambits( tickCount ); + + // in combat range. ATTACK! + bnpc.autoAttack( pHatedActor ); + } + +} + +void AI::Fsm::StateCombat::onEnter( Entity::BNpc& bnpc ) +{ +} + +void AI::Fsm::StateCombat::onExit( Entity::BNpc& bnpc ) +{ + bnpc.hateListClear(); + bnpc.changeTarget( Common::INVALID_GAME_OBJECT_ID64 ); + bnpc.setStance( Common::Stance::Passive ); + bnpc.setOwner( nullptr ); +} + diff --git a/src/world/AI/Fsm/StateCombat.h b/src/world/AI/Fsm/StateCombat.h new file mode 100644 index 000000000..9030331c9 --- /dev/null +++ b/src/world/AI/Fsm/StateCombat.h @@ -0,0 +1,20 @@ +#include +#include "ForwardsZone.h" +#include "Actor/BNpc.h" +#include "State.h" + +#pragma once + +namespace Sapphire::World::AI::Fsm +{ + class StateCombat : public State + { + public: + virtual ~StateCombat() = default; + + void onUpdate( Entity::BNpc& bnpc, uint64_t tickCount ); + void onEnter( Entity::BNpc& bnpc ); + void onExit( Entity::BNpc& bnpc ); + + }; +} \ No newline at end of file diff --git a/src/world/AI/Fsm/StateDead.cpp b/src/world/AI/Fsm/StateDead.cpp new file mode 100644 index 000000000..15b3a6656 --- /dev/null +++ b/src/world/AI/Fsm/StateDead.cpp @@ -0,0 +1,26 @@ +#include "StateDead.h" +#include "Actor/BNpc.h" +#include "Logging/Logger.h" +#include +#include + +#include +#include + +using namespace Sapphire::World; + +void AI::Fsm::StateDead::onUpdate( Entity::BNpc& bnpc, uint64_t tickCount ) +{ + +} + +void AI::Fsm::StateDead::onEnter( Entity::BNpc& bnpc ) +{ + +} + +void AI::Fsm::StateDead::onExit( Entity::BNpc& bnpc ) +{ + +} + diff --git a/src/world/AI/Fsm/StateDead.h b/src/world/AI/Fsm/StateDead.h new file mode 100644 index 000000000..9051288a2 --- /dev/null +++ b/src/world/AI/Fsm/StateDead.h @@ -0,0 +1,20 @@ +#include +#include "ForwardsZone.h" +#include "Actor/BNpc.h" +#include "State.h" + +#pragma once + +namespace Sapphire::World::AI::Fsm +{ + class StateDead : public State + { + public: + virtual ~StateDead() = default; + + void onUpdate( Entity::BNpc& bnpc, uint64_t tickCount ); + void onEnter( Entity::BNpc& bnpc ); + void onExit( Entity::BNpc& bnpc ); + + }; +} \ No newline at end of file diff --git a/src/world/AI/Fsm/StateIdle.cpp b/src/world/AI/Fsm/StateIdle.cpp new file mode 100644 index 000000000..957e4c885 --- /dev/null +++ b/src/world/AI/Fsm/StateIdle.cpp @@ -0,0 +1,20 @@ +#include "StateIdle.h" +#include "Actor/BNpc.h" +#include "Logging/Logger.h" + +using namespace Sapphire::World; + +void AI::Fsm::StateIdle::onUpdate( Entity::BNpc& bnpc, uint64_t tickCount ) +{ + +} + +void AI::Fsm::StateIdle::onEnter( Entity::BNpc& bnpc ) +{ + bnpc.setLastRoamTargetReachedTime( Common::Util::getTimeSeconds() ); +} + +void AI::Fsm::StateIdle::onExit( Entity::BNpc& bnpc ) +{ +} + diff --git a/src/world/AI/Fsm/StateIdle.h b/src/world/AI/Fsm/StateIdle.h new file mode 100644 index 000000000..fe145bfe8 --- /dev/null +++ b/src/world/AI/Fsm/StateIdle.h @@ -0,0 +1,20 @@ +#include +#include "ForwardsZone.h" +#include "Actor/BNpc.h" +#include "State.h" + +#pragma once + +namespace Sapphire::World::AI::Fsm +{ + class StateIdle : public State + { + public: + virtual ~StateIdle() = default; + + void onUpdate( Entity::BNpc& bnpc, uint64_t tickCount ); + void onEnter( Entity::BNpc& bnpc ); + void onExit( Entity::BNpc& bnpc ); + + }; +} \ No newline at end of file diff --git a/src/world/AI/Fsm/StateMachine.cpp b/src/world/AI/Fsm/StateMachine.cpp new file mode 100644 index 000000000..ac67ab860 --- /dev/null +++ b/src/world/AI/Fsm/StateMachine.cpp @@ -0,0 +1,38 @@ +#include +#include "ForwardsZone.h" +#include "Actor/BNpc.h" +#include "StateMachine.h" +#include "State.h" + +#pragma once + +using namespace Sapphire; +using namespace Sapphire::World; + +AI::Fsm::StatePtr AI::Fsm::StateMachine::addState( Fsm::StatePtr state ) +{ + m_states.push_back( state ); + return state; +} + +void AI::Fsm::StateMachine::setCurrentState( Fsm::StatePtr state ) +{ + m_pCurrentState = state; +} + +void AI::Fsm::StateMachine::update( Entity::BNpc& bnpc, uint64_t tickCount ) +{ + if( !m_pCurrentState ) + return; + + TransitionPtr transition = m_pCurrentState->getTriggeredTransition( bnpc ); + + if( transition ) + { + m_pCurrentState->onExit( bnpc ); + m_pCurrentState = transition->getTargetState(); + m_pCurrentState->onEnter( bnpc ); + } + + m_pCurrentState->onUpdate( bnpc, tickCount ); +} diff --git a/src/world/AI/Fsm/StateMachine.h b/src/world/AI/Fsm/StateMachine.h new file mode 100644 index 000000000..3156b846c --- /dev/null +++ b/src/world/AI/Fsm/StateMachine.h @@ -0,0 +1,23 @@ +#include +#include "ForwardsZone.h" +#include "Actor/BNpc.h" + +#pragma once + +namespace Sapphire::World::AI::Fsm +{ + class StateMachine + { + public: + StateMachine() = default; + ~StateMachine() = default; + + StatePtr addState( StatePtr state ); + void setCurrentState( StatePtr state ); + virtual void update( Entity::BNpc& bnpc, uint64_t tickCount ); + + protected: + std::vector< StatePtr > m_states; + StatePtr m_pCurrentState; + }; +} \ No newline at end of file diff --git a/src/world/AI/Fsm/StateRetreat.cpp b/src/world/AI/Fsm/StateRetreat.cpp new file mode 100644 index 000000000..1f1e937da --- /dev/null +++ b/src/world/AI/Fsm/StateRetreat.cpp @@ -0,0 +1,41 @@ +#include "StateRetreat.h" +#include "Actor/BNpc.h" +#include "Logging/Logger.h" +#include +#include + +#include +#include + +using namespace Sapphire::World; + +void AI::Fsm::StateRetreat::onUpdate( Entity::BNpc& bnpc, uint64_t tickCount ) +{ + if( bnpc.moveTo( bnpc.getSpawnPos() ) ) + { + bnpc.setRoamTargetReached( true ); + bnpc.setLastRoamTargetReachedTime( Common::Util::getTimeSeconds() ); + } +} + +void AI::Fsm::StateRetreat::onEnter( Entity::BNpc& bnpc ) +{ + bnpc.setRoamTargetReached( false ); + + auto& teriMgr = Common::Service< World::Manager::TerritoryMgr >::ref(); + auto pZone = teriMgr.getTerritoryByGuId( bnpc.getTerritoryId() ); + auto pNaviProvider = pZone->getNaviProvider(); + + bnpc.setInvincibilityType( Common::InvincibilityType::InvincibilityIgnoreDamage ); + + if( pNaviProvider ) + pNaviProvider->setMoveTarget( bnpc, bnpc.getSpawnPos() ); +} + +void AI::Fsm::StateRetreat::onExit( Entity::BNpc& bnpc ) +{ + bnpc.setOwner( nullptr ); + bnpc.setRoamTargetReached( false ); + bnpc.setInvincibilityType( Common::InvincibilityType::InvincibilityNone ); +} + diff --git a/src/world/AI/Fsm/StateRetreat.h b/src/world/AI/Fsm/StateRetreat.h new file mode 100644 index 000000000..00cfe4277 --- /dev/null +++ b/src/world/AI/Fsm/StateRetreat.h @@ -0,0 +1,20 @@ +#include +#include "ForwardsZone.h" +#include "Actor/BNpc.h" +#include "State.h" + +#pragma once + +namespace Sapphire::World::AI::Fsm +{ + class StateRetreat : public State + { + public: + virtual ~StateRetreat() = default; + + void onUpdate( Entity::BNpc& bnpc, uint64_t tickCount ); + void onEnter( Entity::BNpc& bnpc ); + void onExit( Entity::BNpc& bnpc ); + + }; +} \ No newline at end of file diff --git a/src/world/AI/Fsm/StateRoam.cpp b/src/world/AI/Fsm/StateRoam.cpp new file mode 100644 index 000000000..1b6848179 --- /dev/null +++ b/src/world/AI/Fsm/StateRoam.cpp @@ -0,0 +1,49 @@ +#include "StateRoam.h" +#include "Actor/BNpc.h" +#include "Logging/Logger.h" +#include +#include + +#include +#include + +using namespace Sapphire::World; + +void AI::Fsm::StateRoam::onUpdate( Entity::BNpc& bnpc, uint64_t tickCount ) +{ + auto& teriMgr = Common::Service< World::Manager::TerritoryMgr >::ref(); + auto pZone = teriMgr.getTerritoryByGuId( bnpc.getTerritoryId() ); + auto pNaviProvider = pZone->getNaviProvider(); + + if( pNaviProvider ) + pNaviProvider->setMoveTarget( bnpc, bnpc.getRoamTargetPos() ); + + if( bnpc.moveTo( bnpc.getRoamTargetPos() ) ) + { + bnpc.setRoamTargetReached( true ); + bnpc.setLastRoamTargetReachedTime( Common::Util::getTimeSeconds() ); + } + +} + +void AI::Fsm::StateRoam::onEnter( Entity::BNpc& bnpc ) +{ + auto& teriMgr = Common::Service< World::Manager::TerritoryMgr >::ref(); + auto pZone = teriMgr.getTerritoryByGuId( bnpc.getTerritoryId() ); + auto pNaviProvider = pZone->getNaviProvider(); + + if( !pNaviProvider ) + { + bnpc.setRoamTargetReached( true ); + return; + } + + auto pos = pNaviProvider->findRandomPositionInCircle( bnpc.getSpawnPos(), bnpc.getInstanceObjectInfo()->WanderingRange ); + bnpc.setRoamTargetPos( pos ); +} + +void AI::Fsm::StateRoam::onExit( Entity::BNpc& bnpc ) +{ + bnpc.setRoamTargetReached( false ); +} + diff --git a/src/world/AI/Fsm/StateRoam.h b/src/world/AI/Fsm/StateRoam.h new file mode 100644 index 000000000..6f9ba3ca9 --- /dev/null +++ b/src/world/AI/Fsm/StateRoam.h @@ -0,0 +1,20 @@ +#include +#include "ForwardsZone.h" +#include "Actor/BNpc.h" +#include "State.h" + +#pragma once + +namespace Sapphire::World::AI::Fsm +{ + class StateRoam : public State + { + public: + virtual ~StateRoam() = default; + + void onUpdate( Entity::BNpc& bnpc, uint64_t tickCount ); + void onEnter( Entity::BNpc& bnpc ); + void onExit( Entity::BNpc& bnpc ); + + }; +} \ No newline at end of file diff --git a/src/world/AI/Fsm/Transition.h b/src/world/AI/Fsm/Transition.h new file mode 100644 index 000000000..f5bd3b2fe --- /dev/null +++ b/src/world/AI/Fsm/Transition.h @@ -0,0 +1,22 @@ +#include +#include "ForwardsZone.h" +#include "Actor/BNpc.h" +#include "AI/Fsm/Condition.h" + +#pragma once + +namespace Sapphire::World::AI::Fsm +{ + class Transition + { + public: + Transition( StatePtr targetState, ConditionPtr condition ) : m_pTargetState( targetState ), m_pCondition( condition ) { } + virtual ~Transition() = default; + + StatePtr getTargetState() { return m_pTargetState; } + bool hasTriggered( Entity::BNpc& bnpc ) { return m_pCondition->isConditionMet( bnpc ); } + private: + StatePtr m_pTargetState; + ConditionPtr m_pCondition; + }; +} \ No newline at end of file diff --git a/src/world/AI/FsmCondition.h b/src/world/AI/FsmCondition.h deleted file mode 100644 index 41619ac01..000000000 --- a/src/world/AI/FsmCondition.h +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include -#include - -#pragma once - -namespace Sapphire::World::AI -{ - class FsmCondition - { - public: - FsmCondition() = default; - virtual ~FsmCondition() = default; - - virtual bool isConditionMet( Sapphire::Entity::BNpc& src ) const = 0; - virtual bool update( Sapphire::Entity::BNpc& src, float time ) - { - if( isConditionMet( src ) ) - return true; - return false; - }; - }; -} \ No newline at end of file diff --git a/src/world/AI/FsmState.h b/src/world/AI/FsmState.h deleted file mode 100644 index cb1b74664..000000000 --- a/src/world/AI/FsmState.h +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include -#include "FsmTransition.h" - -#pragma once - -namespace Sapphire::World::AI -{ - class FsmState - { - public: - virtual ~FsmState() = default; - - virtual void onUpdate( Entity::BNpc& bnpc, float deltaTime ) = 0; - virtual void onEnter( Entity::BNpc& bnpc ) { } - virtual void onExit( Entity::BNpc& bnpc ) { } - - void addTransition( FsmTransitionPtr transition ) - { - m_transitions.push_back( transition ); - } - - FsmTransitionPtr getTriggeredTransition( Entity::BNpc& bnpc ) - { - for( auto transition : m_transitions ) - { - if( transition->hasTriggered( bnpc ) ) - return transition; - } - return nullptr; - } - - private: - std::vector< FsmTransitionPtr > m_transitions; - }; -} \ No newline at end of file diff --git a/src/world/AI/FsmTransition.h b/src/world/AI/FsmTransition.h deleted file mode 100644 index 982dd8744..000000000 --- a/src/world/AI/FsmTransition.h +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include -#include -#include "FsmCondition.h" - -#pragma once - -namespace Sapphire::World::AI -{ - class FsmTransition - { - public: - FsmTransition( FsmStatePtr targetState, FsmConditionPtr condition ) : m_pTargetState( targetState ), m_pCondition( condition ) { } - virtual ~FsmTransition() = default; - - FsmStatePtr getTargetState() { return m_pTargetState; } - bool hasTriggered( Entity::BNpc& bnpc ) { return m_pCondition->isConditionMet( bnpc ); } - private: - FsmStatePtr m_pTargetState; - FsmConditionPtr m_pCondition; - }; -} \ No newline at end of file diff --git a/src/world/Actor/BNpc.cpp b/src/world/Actor/BNpc.cpp index dd38c7846..04107a5a0 100644 --- a/src/world/Actor/BNpc.cpp +++ b/src/world/Actor/BNpc.cpp @@ -47,6 +47,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include using namespace Sapphire; using namespace Sapphire::World; @@ -88,8 +95,7 @@ BNpc::BNpc( uint32_t id, std::shared_ptr< Common::BNPCInstanceObject > pInfo, co m_flags = 0; m_rank = pInfo->BNPCRankId; - if( pInfo->WanderingRange == 0 || pInfo->BoundInstanceID != 0 ) - setFlag( Immobile ); + // Striking Dummy if( pInfo->NameId == 541 ) @@ -107,6 +113,9 @@ BNpc::BNpc( uint32_t id, std::shared_ptr< Common::BNPCInstanceObject > pInfo, co m_modelChara = bNpcBaseData->data().Model; m_enemyType = bNpcBaseData->data().Battalion; + if( pInfo->WanderingRange == 0 || pInfo->BoundInstanceID != 0 || m_enemyType == 0 ) + setFlag( Immobile ); + m_class = ClassJob::Gladiator; m_territoryTypeId = zone.getTerritoryTypeId(); @@ -324,7 +333,7 @@ uint32_t BNpc::getBNpcNameId() const void BNpc::spawn( PlayerPtr pTarget ) { - m_lastRoamTargetReached = Common::Util::getTimeSeconds(); + m_lastRoamTargetReachedTime = Common::Util::getTimeSeconds(); auto& server = Common::Service< World::WorldServer >::ref(); server.queueForPlayer( pTarget->getCharacterId(), std::make_shared< NpcSpawnPacket >( *this, *pTarget ) ); @@ -638,165 +647,8 @@ void BNpc::onTick() void BNpc::update( uint64_t tickCount ) { - auto& teriMgr = Common::Service< World::Manager::TerritoryMgr >::ref(); - auto pZone = teriMgr.getTerritoryByGuId( getTerritoryId() ); - - const uint8_t maxDistanceToOrigin = 40; - const uint32_t roamTick = 20; - - auto pNaviProvider = pZone->getNaviProvider(); - - if( !pNaviProvider ) - return; - Chara::update( tickCount ); - - if( !checkAction() ) - processGambits( tickCount ); - - switch( m_state ) - { - case BNpcState::Dead: - case BNpcState::JustDied: - return; - - case BNpcState::Retreat: - { - setInvincibilityType( InvincibilityType::InvincibilityIgnoreDamage ); - - if( pNaviProvider ) - pNaviProvider->setMoveTarget( *this, m_spawnPos ); - - if( moveTo( m_spawnPos ) ) - { - setInvincibilityType( InvincibilityType::InvincibilityNone ); - - // retail doesn't seem to roam straight after retreating - // todo: perhaps requires more investigation? - m_lastRoamTargetReached = Common::Util::getTimeSeconds(); - - // resetHp - setHp( getMaxHp() ); - - m_state = BNpcState::Idle; - setOwner( nullptr ); - } - } - break; - - case BNpcState::Roaming: - { - - if( pNaviProvider ) - pNaviProvider->setMoveTarget( *this, m_roamPos ); - - if( moveTo( m_roamPos ) ) - { - m_lastRoamTargetReached = Common::Util::getTimeSeconds(); - m_state = BNpcState::Idle; - } - - checkAggro(); - } - break; - - case BNpcState::Idle: - { - auto pHatedActor = hateListGetHighest(); - if( pHatedActor ) - aggro( pHatedActor ); - - if( pNaviProvider->syncPosToChara( *this ) ) - sendPositionUpdate(); - - if( !hasFlag( Immobile ) && ( Common::Util::getTimeSeconds() - m_lastRoamTargetReached > roamTick ) ) - { - - if( !pNaviProvider ) - { - m_lastRoamTargetReached = Common::Util::getTimeSeconds(); - break; - } - if( m_pInfo->WanderingRange != 0 && getEnemyType() != 0 ) - { - m_roamPos = pNaviProvider->findRandomPositionInCircle( m_spawnPos, m_pInfo->WanderingRange ); - } - else - { - m_roamPos = m_spawnPos; - } - m_state = BNpcState::Roaming; - } - - checkAggro(); - break; - } - - case BNpcState::Combat: - { - auto pHatedActor = hateListGetHighest(); - if( !pHatedActor ) - return; - - pNaviProvider->updateAgentParameters( *this ); - - auto distanceOrig = Common::Util::distance( getPos(), m_spawnPos ); - - if( !pHatedActor->isAlive() || getTerritoryId() != pHatedActor->getTerritoryId() ) - { - hateListRemove( pHatedActor ); - pHatedActor = hateListGetHighest(); - } - - if( !pHatedActor ) - { - changeTarget( INVALID_GAME_OBJECT_ID64 ); - setStance( Stance::Passive ); - //setOwner( nullptr ); - m_state = BNpcState::Retreat; - pNaviProvider->updateAgentParameters( *this ); - break; - } - - auto distance = Common::Util::distance( getPos(), pHatedActor->getPos() ); - - if( !hasFlag( NoDeaggro ) && ( ( distanceOrig > maxDistanceToOrigin ) || distance > 30.0f ) ) - { - hateListClear(); - changeTarget( INVALID_GAME_OBJECT_ID64 ); - setStance( Stance::Passive ); - setOwner( nullptr ); - m_state = BNpcState::Retreat; - break; - } - - if( distance > ( getNaviTargetReachedDistance() + pHatedActor->getRadius() ) ) - { - if( hasFlag( Immobile ) ) - break; - - if( pNaviProvider ) - pNaviProvider->setMoveTarget( *this, pHatedActor->getPos() ); - - moveTo( *pHatedActor ); - } - - if( pNaviProvider->syncPosToChara( *this ) ) - sendPositionUpdate(); - - if( distance < ( getNaviTargetReachedDistance() + pHatedActor->getRadius() ) ) - { - if( !hasFlag( TurningDisabled ) && face( pHatedActor->getPos() ) ) - sendPositionUpdate(); - - // in combat range. ATTACK! - autoAttack( pHatedActor ); - } - - } - break; - } - + m_fsm->update( *this, tickCount ); } void BNpc::restHp() @@ -1054,12 +906,41 @@ void BNpc::init() m_maxHp = Math::CalcStats::calculateMaxHp( *getAsChara() ); m_hp = m_maxHp; + m_lastRoamTargetReachedTime = Common::Util::getTimeSeconds(); + //setup a test gambit auto testGambitRule = AI::make_GambitRule( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 88, 0 ), 5000 ); auto testGambitRule1 = AI::make_GambitRule( AI::make_HPSelfPctLessThanTargetCondition( 50 ), Action::make_Action( getAsChara(), 120, 0 ), 5000 ); m_gambits.push_back( testGambitRule ); m_gambits.push_back( testGambitRule1 ); + + using namespace AI::Fsm; + m_fsm = make_StateMachine(); + auto stateIdle = make_StateIdle(); + auto stateCombat = make_StateCombat(); + auto stateDead = make_StateDead(); + if( !hasFlag( Immobile ) ) + { + auto stateRoam = make_StateRoam(); + stateIdle->addTransition( stateRoam, make_RoamNextTimeReachedCondition() ); + stateRoam->addTransition( stateIdle, make_RoamTargetReachedCondition() ); + stateRoam->addTransition( stateCombat, make_HateListHasEntriesCondition() ); + stateRoam->addTransition( stateDead, make_IsDeadCondition() ); + m_fsm->addState( stateRoam ); + } + stateIdle->addTransition( stateCombat, make_HateListHasEntriesCondition() ); + stateCombat->addTransition( stateIdle, make_HateListEmptyCondition() ); + stateIdle->addTransition( stateDead, make_IsDeadCondition() ); + stateCombat->addTransition( stateDead, make_IsDeadCondition() ); + m_fsm->addState( stateIdle ); + if( !hasFlag( NoDeaggro ) ) + { + auto stateRetreat = make_StateRetreat(); + stateCombat->addTransition( stateRetreat, make_SpawnPointDistanceGtMaxDistanceCondition() ); + stateRetreat->addTransition( stateIdle, make_RoamTargetReachedCondition() ); + } + m_fsm->setCurrentState( stateIdle ); } void BNpc::processGambits( uint64_t tickCount ) @@ -1082,3 +963,43 @@ void BNpc::processGambits( uint64_t tickCount ) } } + +uint32_t BNpc::getLastRoamTargetReachedTime() const +{ + return m_lastRoamTargetReachedTime; +} + +void BNpc::setLastRoamTargetReachedTime( uint32_t time ) +{ + m_lastRoamTargetReachedTime = time; +} + +std::shared_ptr< Common::BNPCInstanceObject > BNpc::getInstanceObjectInfo() const +{ + return m_pInfo; +} + +void BNpc::setRoamTargetReached( bool reached ) +{ + m_roamTargetReached = reached; +} + +bool BNpc::isRoamTargetReached() const +{ + return m_roamTargetReached; +} + +void BNpc::setRoamTargetPos( const FFXIVARR_POSITION3& targetPos ) +{ + m_roamPos = targetPos; +} + +const Common::FFXIVARR_POSITION3& BNpc::getRoamTargetPos() const +{ + return m_roamPos; +} + +const Common::FFXIVARR_POSITION3& BNpc::getSpawnPos() const +{ + return m_spawnPos; +} \ No newline at end of file diff --git a/src/world/Actor/BNpc.h b/src/world/Actor/BNpc.h index 095a7ce41..a8804f720 100644 --- a/src/world/Actor/BNpc.h +++ b/src/world/Actor/BNpc.h @@ -151,6 +151,19 @@ namespace Sapphire::Entity void processGambits( uint64_t tickCount ); + uint32_t getLastRoamTargetReachedTime() const; + void setLastRoamTargetReachedTime( uint32_t time ); + + std::shared_ptr< Common::BNPCInstanceObject > getInstanceObjectInfo() const; + + void setRoamTargetReached( bool reached ); + bool isRoamTargetReached() const; + + void setRoamTargetPos( const Common::FFXIVARR_POSITION3& targetPos ); + + const Common::FFXIVARR_POSITION3& getRoamTargetPos() const; + const Common::FFXIVARR_POSITION3& getSpawnPos() const; + private: uint32_t m_bNpcBaseId; uint32_t m_bNpcNameId; @@ -178,7 +191,8 @@ namespace Sapphire::Entity std::shared_ptr< Common::BNPCInstanceObject > m_pInfo; uint32_t m_timeOfDeath; - uint32_t m_lastRoamTargetReached; + uint32_t m_lastRoamTargetReachedTime; + bool m_roamTargetReached{ false }; Common::FFXIVARR_POSITION3 m_spawnPos; Common::FFXIVARR_POSITION3 m_roamPos; @@ -194,6 +208,8 @@ namespace Sapphire::Entity CharaPtr m_pOwner; std::vector< World::AI::GambitRulePtr > m_gambits; + std::shared_ptr< World::AI::Fsm::StateMachine > m_fsm; + }; } \ No newline at end of file diff --git a/src/world/CMakeLists.txt b/src/world/CMakeLists.txt index 850069912..da82a2444 100644 --- a/src/world/CMakeLists.txt +++ b/src/world/CMakeLists.txt @@ -8,6 +8,7 @@ file( GLOB SERVER_SOURCE_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} Actor/*.cpp Action/*.cpp AI/*.cpp + AI/Fsm/*.cpp ContentFinder/*.cpp DebugCommand/*.cpp Event/*.cpp diff --git a/src/world/ForwardsZone.h b/src/world/ForwardsZone.h index e17eb9163..de26643f3 100644 --- a/src/world/ForwardsZone.h +++ b/src/world/ForwardsZone.h @@ -54,11 +54,31 @@ namespace World::AI TYPE_FORWARD( HPSelfPctLessThanTargetCondition ); TYPE_FORWARD( GambitRule ); +} + +namespace World::AI::Fsm +{ + + TYPE_FORWARD( Condition ); + TYPE_FORWARD( State ); + TYPE_FORWARD( Transition ); + TYPE_FORWARD( StateMachine ); + + TYPE_FORWARD( StateIdle ); + TYPE_FORWARD( StateRoam ); + TYPE_FORWARD( StateCombat ); + TYPE_FORWARD( StateRetreat ); + TYPE_FORWARD( StateDead ); + + TYPE_FORWARD( RoamNextTimeReachedCondition ); + TYPE_FORWARD( RoamTargetReachedCondition ); + TYPE_FORWARD( HateListEmptyCondition ); + TYPE_FORWARD( HateListHasEntriesCondition ); + TYPE_FORWARD( SpawnPointDistanceGtMaxDistanceCondition ); + TYPE_FORWARD( IsDeadCondition ); + + - TYPE_FORWARD( FsmCondition ); - TYPE_FORWARD( FsmState ); - TYPE_FORWARD( FsmTransition ); - TYPE_FORWARD( Fsm ); } namespace Inventory From 4f3f866531338ad4b9fe96cb5a6652ff37c3d481 Mon Sep 17 00:00:00 2001 From: Mordred Date: Mon, 20 Mar 2023 22:59:34 +0100 Subject: [PATCH 10/30] Fill Bnpc link info in spawn packet if available --- src/world/Network/PacketWrappers/NpcSpawnPacket.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/world/Network/PacketWrappers/NpcSpawnPacket.h b/src/world/Network/PacketWrappers/NpcSpawnPacket.h index 1cf379823..f3ff593c6 100644 --- a/src/world/Network/PacketWrappers/NpcSpawnPacket.h +++ b/src/world/Network/PacketWrappers/NpcSpawnPacket.h @@ -77,6 +77,16 @@ namespace Sapphire::Network::Packets::WorldPackets::Server m_data.NpcId = bnpc.getBNpcBaseId(); m_data.NameId = bnpc.getBNpcNameId(); + if( bnpc.getInstanceObjectInfo() ) + { + m_data.LinkCountLimit = bnpc.getInstanceObjectInfo()->LinkCountLimit; + m_data.LinkFamily = bnpc.getInstanceObjectInfo()->LinkFamily; + m_data.LinkGroup = bnpc.getInstanceObjectInfo()->LinkGroup; + m_data.LinkParent = bnpc.getInstanceObjectInfo()->LinkParent; + m_data.LinkRange = bnpc.getInstanceObjectInfo()->LinkRange; + m_data.LinkReply = bnpc.getInstanceObjectInfo()->LinkReply; + } + assert( target.getId() != bnpc.getId() ); m_data.Index = target.getSpawnIdForActorId( bnpc.getId() ); From d5c4739a772370c16f8b1c54e24082ed86d2c1be Mon Sep 17 00:00:00 2001 From: Alice Ogeda Date: Fri, 24 Mar 2023 13:31:50 -0300 Subject: [PATCH 11/30] use cache in getterritorydetail; remove unused bgpath; avoid throwing exceptions when possible; --- src/world/Manager/TerritoryMgr.cpp | 9 +- src/world/Territory/InstanceObjectCache.cpp | 102 +++++++++++--------- 2 files changed, 62 insertions(+), 49 deletions(-) diff --git a/src/world/Manager/TerritoryMgr.cpp b/src/world/Manager/TerritoryMgr.cpp index 540a06176..abce31346 100644 --- a/src/world/Manager/TerritoryMgr.cpp +++ b/src/world/Manager/TerritoryMgr.cpp @@ -77,12 +77,11 @@ uint32_t TerritoryMgr::getNextInstanceId() Excel::ExcelStructPtr< Excel::TerritoryType > TerritoryMgr::getTerritoryDetail( uint32_t territoryTypeId ) const { - auto& exdData = Common::Service< Data::ExdData >::ref(); - auto teri1 = exdData.getRow< Excel::TerritoryType >( territoryTypeId ); - if( !teri1 ) + auto it = m_territoryTypeDetailCacheMap.find( territoryTypeId ); + if( it == m_territoryTypeDetailCacheMap.end() ) return nullptr; - return teri1; + return it->second; } bool TerritoryMgr::isInstanceContentTerritory( uint32_t territoryTypeId ) const @@ -198,8 +197,6 @@ bool TerritoryMgr::createDefaultTerritories() pPlaceName->getString( pPlaceName->data().Text.SGL ) ); pZone->init(); - std::string bgPath = territoryInfo->getString( territoryData.LVB ); - bool hasNaviMesh = pZone->getNaviProvider() != nullptr; Logger::info( "{0}\t{1}\t{2}\t{3:<10}\t{4}\t{5}\t{6}", diff --git a/src/world/Territory/InstanceObjectCache.cpp b/src/world/Territory/InstanceObjectCache.cpp index 455975b2b..291f18e37 100644 --- a/src/world/Territory/InstanceObjectCache.cpp +++ b/src/world/Territory/InstanceObjectCache.cpp @@ -11,6 +11,9 @@ #include #include +#include +#include + #include #include #include @@ -22,7 +25,7 @@ Sapphire::InstanceObjectCache::InstanceObjectCache() auto idList = exdData.getIdList< Excel::TerritoryType >(); size_t count = 0; - for( const auto& id : idList ) + std::for_each( std::execution::seq, idList.begin(), idList.end() , [ & ]( int id ) { // show some loading indication... if( count++ % 10 == 0 ) @@ -30,12 +33,12 @@ Sapphire::InstanceObjectCache::InstanceObjectCache() auto territoryType = exdData.getRow< Excel::TerritoryType >( id ); if( !territoryType ) - continue; + return; auto path = territoryType->getString( territoryType->data().LVB ); if( path.empty() ) - continue; + return; path = std::string( "bg/" ) + path.substr( 0, path.find( "/level/" ) ); @@ -56,14 +59,18 @@ Sapphire::InstanceObjectCache::InstanceObjectCache() try { - bgFile = exdData.getGameData()->getFile( bgLgbPath ); + if( exdData.getGameData()->doesFileExist( bgLgbPath ) ) + bgFile = exdData.getGameData()->getFile( bgLgbPath ); + else + return; + planmap_file = exdData.getGameData()->getFile( planmapLgbPath ); planevent_file = exdData.getGameData()->getFile( planeventLgbPath ); } catch( std::runtime_error& ) { // ignore files that aren't found - continue; + return; } bgSection = bgFile->access_data_sections().at( 0 ); @@ -101,49 +108,58 @@ Sapphire::InstanceObjectCache::InstanceObjectCache() { for( const auto& pEntry : group.entries ) { - - if( pEntry->getType() == LgbEntryType::MapRange ) - { - auto pMapRange = std::reinterpret_pointer_cast< LGB_MAP_RANGE_ENTRY >( pEntry ); - m_mapRangeCache.insert( id, pMapRange ); - } - else if( pEntry->getType() == LgbEntryType::ExitRange ) - { - auto pExitRange = std::reinterpret_pointer_cast< LGB_EXIT_RANGE_ENTRY >( pEntry ); - m_exitRangeCache.insert( id, pExitRange ); - } - else if( pEntry->getType() == LgbEntryType::PopRange ) - { - - auto pPopRange = std::reinterpret_pointer_cast< LGB_POP_RANGE_ENTRY >( pEntry ); - m_popRangeCache.insert( id, pPopRange ); - } - else if( pEntry->getType() == LgbEntryType::CollisionBox ) - { - //auto pEObj = std::reinterpret_pointer_cast< LGB_ENPC_ENTRY >( pEntry ); - - //Logger::debug( "CollisionBox {}", pEntry->header.nameOffset ); - } - else if( pEntry->getType() == LgbEntryType::EventObject ) - { - auto pEObj = std::reinterpret_pointer_cast< LGB_EOBJ_ENTRY >( pEntry ); - m_eobjCache.insert( id, pEObj ); - } - else if( pEntry->getType() == LgbEntryType::EventNpc ) - { - auto pENpc = std::reinterpret_pointer_cast< LGB_ENPC_ENTRY >( pEntry ); - m_enpcCache.insert( id, pENpc ); - } - else if( pEntry->getType() == LgbEntryType::EventRange ) + switch( pEntry->getType() ) { - auto pEventRange = std::reinterpret_pointer_cast< LGB_EVENT_RANGE_ENTRY >( pEntry ); - m_eventRangeCache.insert( 0, pEventRange ); + case LgbEntryType::MapRange: + { + auto pMapRange = std::reinterpret_pointer_cast< LGB_MAP_RANGE_ENTRY >( pEntry ); + m_mapRangeCache.insert( id, pMapRange ); + + break; + } + case LgbEntryType::ExitRange: + { + auto pExitRange = std::reinterpret_pointer_cast< LGB_EXIT_RANGE_ENTRY >( pEntry ); + m_exitRangeCache.insert( id, pExitRange ); + + break; + } + case LgbEntryType::PopRange: + { + auto pPopRange = std::reinterpret_pointer_cast< LGB_POP_RANGE_ENTRY >( pEntry ); + m_popRangeCache.insert( id, pPopRange ); + break; + } + case LgbEntryType::CollisionBox: + { + //auto pEObj = std::reinterpret_pointer_cast< LGB_ENPC_ENTRY >( pEntry ); + + //Logger::debug( "CollisionBox {}", pEntry->header.nameOffset ); + break; + } + case LgbEntryType::EventObject: + { + auto pEObj = std::reinterpret_pointer_cast< LGB_EOBJ_ENTRY >( pEntry ); + m_eobjCache.insert( id, pEObj ); + break; + } + case LgbEntryType::EventNpc: + { + auto pENpc = std::reinterpret_pointer_cast< LGB_ENPC_ENTRY >( pEntry ); + m_enpcCache.insert( id, pENpc ); + break; + } + case LgbEntryType::EventRange: + { + auto pEventRange = std::reinterpret_pointer_cast< LGB_EVENT_RANGE_ENTRY >( pEntry ); + m_eventRangeCache.insert( 0, pEventRange ); + break; + } } } } } - } - std::cout << "\n"; + } ); Logger::debug( "InstanceObjectCache Cached: MapRange: {} ExitRange: {} PopRange: {} EventObj: {} EventNpc: {} EventRange: {}", From 09d0469c961dce2cfd4011c4bc5b3600345e5ba7 Mon Sep 17 00:00:00 2001 From: Alice Ogeda Date: Fri, 24 Mar 2023 13:32:36 -0300 Subject: [PATCH 12/30] emplace_back for in-place move const for shared ptr; --- deps/datReader/DatCategories/bg/lgb.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/deps/datReader/DatCategories/bg/lgb.h b/deps/datReader/DatCategories/bg/lgb.h index c5c99f11f..337d67312 100644 --- a/deps/datReader/DatCategories/bg/lgb.h +++ b/deps/datReader/DatCategories/bg/lgb.h @@ -237,39 +237,39 @@ struct LGB_GROUP const auto type = *reinterpret_cast< LgbEntryType* >( buf + entryOffset ); if( type == LgbEntryType::BgParts ) { - entries.push_back( std::make_shared< LGB_BGPARTS_ENTRY >( buf, entryOffset ) ); + entries.emplace_back( std::make_shared< LGB_BGPARTS_ENTRY >( buf, entryOffset ) ); } else if( type == LgbEntryType::Gimmick ) { - entries.push_back( std::make_shared< LGB_GIMMICK_ENTRY >( buf, entryOffset ) ); + entries.emplace_back( std::make_shared< LGB_GIMMICK_ENTRY >( buf, entryOffset ) ); } else if( type == LgbEntryType::EventNpc ) { - entries.push_back( std::make_shared< LGB_ENPC_ENTRY >( buf, entryOffset ) ); + entries.emplace_back( std::make_shared< LGB_ENPC_ENTRY >( buf, entryOffset ) ); } else if( type == LgbEntryType::EventObject ) { - entries.push_back( std::make_shared< LGB_EOBJ_ENTRY >( buf, entryOffset ) ); + entries.emplace_back( std::make_shared< LGB_EOBJ_ENTRY >( buf, entryOffset ) ); } else if( type == LgbEntryType::ExitRange ) { - entries.push_back( std::make_shared< LGB_EXIT_RANGE_ENTRY >( buf, entryOffset ) ); + entries.emplace_back( std::make_shared< LGB_EXIT_RANGE_ENTRY >( buf, entryOffset ) ); } else if( type == LgbEntryType::EventRange ) { - entries.push_back( std::make_shared< LGB_EVENT_RANGE_ENTRY >( buf, entryOffset ) ); + entries.emplace_back( std::make_shared< LGB_EVENT_RANGE_ENTRY >( buf, entryOffset ) ); } else if( type == LgbEntryType::PopRange ) { - entries.push_back( std::make_shared< LGB_POP_RANGE_ENTRY >( buf, entryOffset ) ); + entries.emplace_back( std::make_shared< LGB_POP_RANGE_ENTRY >( buf, entryOffset ) ); } else if( type == LgbEntryType::MapRange ) { - entries.push_back( std::make_shared< LGB_MAP_RANGE_ENTRY >( buf, entryOffset ) ); + entries.emplace_back( std::make_shared< LGB_MAP_RANGE_ENTRY >( buf, entryOffset ) ); } else { - entries.push_back( std::make_shared< LgbEntry >( buf, entryOffset ) ); + entries.emplace_back( std::make_shared< LgbEntry >( buf, entryOffset ) ); } } catch( std::exception& e ) From f6ce8207b2255c3f15a5580131f3f655edae794b Mon Sep 17 00:00:00 2001 From: Alice Ogeda Date: Fri, 24 Mar 2023 14:11:07 -0300 Subject: [PATCH 13/30] switchy; --- deps/datReader/DatCategories/bg/lgb.h | 82 ++++++++++++++++----------- 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/deps/datReader/DatCategories/bg/lgb.h b/deps/datReader/DatCategories/bg/lgb.h index 337d67312..d0c3f29bd 100644 --- a/deps/datReader/DatCategories/bg/lgb.h +++ b/deps/datReader/DatCategories/bg/lgb.h @@ -227,6 +227,8 @@ struct LGB_GROUP memcpy( (char*)&refs[0], buf + offset + header.LayerSetRef + layerSetReferencedList.LayerSets, layerSetReferencedList.LayerSetCount * sizeof( LayerSetReferenced ) ); } + entries.reserve( header.entryCount ); + const auto entriesOffset = offset + header.entriesOffset; for( auto i = 0; i < header.entryCount; ++i ) { @@ -235,41 +237,53 @@ struct LGB_GROUP try { const auto type = *reinterpret_cast< LgbEntryType* >( buf + entryOffset ); - if( type == LgbEntryType::BgParts ) - { - entries.emplace_back( std::make_shared< LGB_BGPARTS_ENTRY >( buf, entryOffset ) ); - } - else if( type == LgbEntryType::Gimmick ) - { - entries.emplace_back( std::make_shared< LGB_GIMMICK_ENTRY >( buf, entryOffset ) ); - } - else if( type == LgbEntryType::EventNpc ) - { - entries.emplace_back( std::make_shared< LGB_ENPC_ENTRY >( buf, entryOffset ) ); - } - else if( type == LgbEntryType::EventObject ) - { - entries.emplace_back( std::make_shared< LGB_EOBJ_ENTRY >( buf, entryOffset ) ); - } - else if( type == LgbEntryType::ExitRange ) - { - entries.emplace_back( std::make_shared< LGB_EXIT_RANGE_ENTRY >( buf, entryOffset ) ); - } - else if( type == LgbEntryType::EventRange ) - { - entries.emplace_back( std::make_shared< LGB_EVENT_RANGE_ENTRY >( buf, entryOffset ) ); - } - else if( type == LgbEntryType::PopRange ) - { - entries.emplace_back( std::make_shared< LGB_POP_RANGE_ENTRY >( buf, entryOffset ) ); - } - else if( type == LgbEntryType::MapRange ) - { - entries.emplace_back( std::make_shared< LGB_MAP_RANGE_ENTRY >( buf, entryOffset ) ); - } - else + switch( type ) { - entries.emplace_back( std::make_shared< LgbEntry >( buf, entryOffset ) ); + case LgbEntryType::BgParts: + { + entries.emplace_back( std::make_shared< LGB_BGPARTS_ENTRY >( buf, entryOffset ) ); + break; + } + case LgbEntryType::Gimmick: + { + entries.emplace_back( std::make_shared< LGB_GIMMICK_ENTRY >( buf, entryOffset ) ); + break; + } + case LgbEntryType::EventNpc: + { + entries.emplace_back( std::make_shared< LGB_ENPC_ENTRY >( buf, entryOffset ) ); + break; + } + case LgbEntryType::EventObject: + { + entries.emplace_back( std::make_shared< LGB_EOBJ_ENTRY >( buf, entryOffset ) ); + break; + } + case LgbEntryType::ExitRange: + { + entries.emplace_back( std::make_shared< LGB_EXIT_RANGE_ENTRY >( buf, entryOffset ) ); + break; + } + case LgbEntryType::EventRange: + { + entries.emplace_back( std::make_shared< LGB_EVENT_RANGE_ENTRY >( buf, entryOffset ) ); + break; + } + case LgbEntryType::PopRange: + { + entries.emplace_back( std::make_shared< LGB_POP_RANGE_ENTRY >( buf, entryOffset ) ); + break; + } + case LgbEntryType::MapRange: + { + entries.emplace_back( std::make_shared< LGB_MAP_RANGE_ENTRY >( buf, entryOffset ) ); + break; + } + default: + { + entries.emplace_back( std::make_shared< LgbEntry >( buf, entryOffset ) ); + break; + } } } catch( std::exception& e ) From dedf66f28da0e0652f73d6e3e3f5a0b71265ebc5 Mon Sep 17 00:00:00 2001 From: Alice Ogeda Date: Fri, 24 Mar 2023 17:38:58 -0300 Subject: [PATCH 14/30] add getRows to exd; optimize iterative exd calls further; split namespace for slim header structs; --- deps/datReader/Exd.cpp | 60 +----- deps/datReader/Exd.h | 191 +++++++++++++++++- src/common/Exd/ExdData.h | 21 ++ src/tools/action_parse/main.cpp | 8 +- src/tools/wiki_parse/main.cpp | 30 ++- src/world/ContentFinder/ContentFinder.cpp | 5 +- src/world/Manager/AchievementMgr.cpp | 6 +- src/world/Manager/MapMgr.cpp | 6 +- src/world/Manager/ShopMgr.cpp | 5 +- src/world/Manager/TerritoryMgr.cpp | 23 +-- src/world/Network/Handlers/CFHandlers.cpp | 8 +- .../Network/Handlers/GMCommandHandlers.cpp | 11 +- src/world/Network/Util/PacketUtil.cpp | 10 +- src/world/Territory/InstanceObjectCache.cpp | 20 +- 14 files changed, 268 insertions(+), 136 deletions(-) diff --git a/deps/datReader/Exd.cpp b/deps/datReader/Exd.cpp index 74aae36e0..b1a2a2b5f 100644 --- a/deps/datReader/Exd.cpp +++ b/deps/datReader/Exd.cpp @@ -7,50 +7,6 @@ using xiv::utils::bparse::extract; - -namespace xiv::exd -{ - struct ExdHeader - { - char magic[0x4]; - uint16_t unknown; - uint16_t unknown2; - uint32_t index_size; - }; - - struct ExdRecordIndex - { - uint32_t id; - uint32_t offset; - }; -} - -namespace xiv::utils::bparse { -template<> - inline void reorder< xiv::exd::ExdHeader >( xiv::exd::ExdHeader& i_struct ) - { - for( int32_t i = 0; i < 0x4; ++i ) - { - xiv::utils::bparse::reorder( i_struct.magic[ i ] ); - } - i_struct.unknown = xiv::utils::bparse::byteswap( i_struct.unknown ); - xiv::utils::bparse::reorder( i_struct.unknown ); - i_struct.unknown2 = xiv::utils::bparse::byteswap( i_struct.unknown2 ); - xiv::utils::bparse::reorder( i_struct.unknown2 ); - i_struct.index_size = xiv::utils::bparse::byteswap( i_struct.index_size ); - xiv::utils::bparse::reorder( i_struct.index_size ); - } - - template<> - inline void reorder< xiv::exd::ExdRecordIndex >( xiv::exd::ExdRecordIndex& i_struct ) - { - i_struct.id = xiv::utils::bparse::byteswap( i_struct.id ); - xiv::utils::bparse::reorder( i_struct.id ); - i_struct.offset = xiv::utils::bparse::byteswap( i_struct.offset ); - xiv::utils::bparse::reorder( i_struct.offset ); - } -}; - namespace xiv::exd { Exd::Exd( std::shared_ptr< Exh > i_exh, const std::vector< std::shared_ptr< dat::File>>& i_files ) @@ -68,16 +24,16 @@ namespace xiv::exd std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) ); // Extract the header and skip to the record indices - auto exd_header = extract< ExdHeader >( iss ); + auto exd_header = extract< ExdHeaderMinimal >( iss ); iss.seekg( 0x20 ); // Preallocate and extract the record_indices - const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndex ); - std::vector< ExdRecordIndex > record_indices; + const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndexData ); + std::vector< ExdRecordIndexData > record_indices; record_indices.reserve( record_count ); for( uint32_t i = 0; i < record_count; ++i ) { - auto recordIndex = extract< ExdRecordIndex >( iss ); + auto recordIndex = extract< ExdRecordIndexData >( iss ); _idCache[ recordIndex.id ] = ExdCacheEntry{ file_ptr, recordIndex.offset }; } } @@ -290,16 +246,16 @@ namespace xiv::exd std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) ); // Extract the header and skip to the record indices - auto exd_header = extract< ExdHeader >( iss ); + auto exd_header = extract< ExdHeaderMinimal >( iss ); iss.seekg( 0x20 ); // Preallocate and extract the record_indices - const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndex ); - std::vector< ExdRecordIndex > record_indices; + const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndexData ); + std::vector< ExdRecordIndexData > record_indices; record_indices.reserve( record_count ); for( uint32_t i = 0; i < record_count; ++i ) { - record_indices.emplace_back( extract< ExdRecordIndex >( iss ) ); + record_indices.emplace_back( extract< ExdRecordIndexData >( iss ) ); } for( auto& record_index : record_indices ) diff --git a/deps/datReader/Exd.h b/deps/datReader/Exd.h index 8cf406589..e08f6e54b 100644 --- a/deps/datReader/Exd.h +++ b/deps/datReader/Exd.h @@ -2,6 +2,7 @@ #include #include +#include #include @@ -12,6 +13,49 @@ #include #include "Exh.h" #include "bparse.h" + +namespace xiv::exd +{ + struct ExdHeaderMinimal { + char magic[ 0x4 ]; + uint16_t unknown; + uint16_t unknown2; + uint32_t index_size; + }; + + struct ExdRecordIndexData { + uint32_t id; + uint32_t offset; + }; +} + +namespace xiv::utils::bparse +{ + template<> + inline void reorder< xiv::exd::ExdHeaderMinimal >( xiv::exd::ExdHeaderMinimal& i_struct ) + { + for( int32_t i = 0; i < 0x4; ++i ) + { + xiv::utils::bparse::reorder( i_struct.magic[ i ] ); + } + i_struct.unknown = xiv::utils::bparse::byteswap( i_struct.unknown ); + xiv::utils::bparse::reorder( i_struct.unknown ); + i_struct.unknown2 = xiv::utils::bparse::byteswap( i_struct.unknown2 ); + xiv::utils::bparse::reorder( i_struct.unknown2 ); + i_struct.index_size = xiv::utils::bparse::byteswap( i_struct.index_size ); + xiv::utils::bparse::reorder( i_struct.index_size ); + } + + template<> + inline void reorder< xiv::exd::ExdRecordIndexData >( xiv::exd::ExdRecordIndexData& i_struct ) + { + i_struct.id = xiv::utils::bparse::byteswap( i_struct.id ); + xiv::utils::bparse::reorder( i_struct.id ); + i_struct.offset = xiv::utils::bparse::byteswap( i_struct.offset ); + xiv::utils::bparse::reorder( i_struct.offset ); + } +};// namespace xiv::utils::bparse + namespace xiv::exd { @@ -184,12 +228,153 @@ namespace xiv::exd const std::vector< Field > get_row( uint32_t id, uint32_t subRow ); // Get all rows - const std::map< uint32_t, std::vector< Field>>& get_rows(); + const std::map< uint32_t, std::vector< Field > >& get_rows(); + + // Get all rows + template< typename T > + const std::unordered_map< uint32_t, std::shared_ptr< Excel::ExcelStruct< T > > > get_sheet_rows() + { + std::unordered_map< uint32_t, std::shared_ptr< Excel::ExcelStruct< T > > > sheets; + + // Iterates over all the files + const uint32_t member_count = static_cast< uint32_t >( _exh->get_members().size() ); + for( auto& file_ptr : _files ) + { + // Get a stream + std::vector< char > dataCpy = file_ptr->get_data_sections().front(); + std::istringstream iss( std::string( dataCpy.begin(), dataCpy.end() ) ); + + // Extract the header and skip to the record indices + auto exd_header = xiv::utils::bparse::extract< ExdHeaderMinimal >( iss ); + iss.seekg( 0x20 ); + + // Preallocate and extract the record_indices + const uint32_t record_count = exd_header.index_size / sizeof( ExdRecordIndexData ); + std::vector< ExdRecordIndexData > record_indices; + record_indices.reserve( record_count ); + for( uint32_t i = 0; i < record_count; ++i ) + { + record_indices.emplace_back( xiv::utils::bparse::extract< ExdRecordIndexData >( iss ) ); + } + + for( auto& record_index : record_indices ) + { + auto cacheEntryIt = _idCache.find( record_index.id ); + if( cacheEntryIt == _idCache.end() ) + throw std::out_of_range( "Id not found: " + std::to_string( record_index.id ) ); + + auto pSheet = std::make_shared< Excel::ExcelStruct< T > >(); + + // Get the vector fields for the given record and preallocate it + auto fields = _data[ record_index.id ]; + fields.reserve( member_count ); + iss.seekg( cacheEntryIt->second.offset + 6 ); + + iss.read( reinterpret_cast( &pSheet.get()->_data ), sizeof( T ) ); + + int stringCount = 0; + for( auto& member_entry : _exh->get_exh_members() ) + { + + // Seek to the position of the member to extract. + // 6 is because we have uint32_t/uint16_t at the start of each record + iss.seekg( cacheEntryIt->second.offset + 6 + member_entry.offset ); + + // Switch depending on the type to extract + switch( member_entry.type ) + { + case DataType::string: + // Extract the offset to the actual string + // Seek to it then extract the actual string + { + auto string_offset = xiv::utils::bparse::extract< uint32_t >( iss, "string_offset", false ); + iss.seekg( cacheEntryIt->second.offset + 6 + _exh->get_header().data_offset + string_offset ); + std::string value = xiv::utils::bparse::extract_cstring( iss, "string" ); + auto it = pSheet->_strings.insert( pSheet->_strings.end(), value ); + *reinterpret_cast< uint32_t* >( pSheet->ptr() + member_entry.offset ) = + static_cast< uint32_t >( std::distance( pSheet->_strings.begin(), it ) ); + } + break; + + case DataType::boolean: + xiv::utils::bparse::extract< bool >( iss, "bool" ); + break; + + case DataType::int8: + xiv::utils::bparse::extract< int8_t >( iss, "int8_t" ); + break; + + case DataType::uint8: + xiv::utils::bparse::extract< uint8_t >( iss, "uint8_t" ); + break; + + + case DataType::int16: + { + int16_t value = xiv::utils::bparse::extract< int16_t >( iss, "int16_t", false ); + *reinterpret_cast< int16_t* >( pSheet->ptr() + member_entry.offset ) = value; + } + break; + + case DataType::uint16: + { + uint16_t value = xiv::utils::bparse::extract< uint16_t >( iss, "uint16_t", false ); + *reinterpret_cast< uint16_t* >( pSheet->ptr() + member_entry.offset ) = value; + } + break; + + case DataType::int32: + { + int32_t value = xiv::utils::bparse::extract< int32_t >( iss, "int32_t", false ); + *reinterpret_cast< int32_t* >( pSheet->ptr() + member_entry.offset ) = value; + } + break; + + case DataType::uint32: + { + uint32_t value = xiv::utils::bparse::extract< uint32_t >( iss, "uint32_t", false ); + *reinterpret_cast< uint32_t* >( pSheet->ptr() + member_entry.offset ) = value; + } + break; + + case DataType::float32: + { + float value = xiv::utils::bparse::extract< float >( iss, "float", false ); + *reinterpret_cast< float* >( pSheet->ptr() + member_entry.offset ) = value; + } + break; + + case DataType::uint64: + { + uint64_t value = xiv::utils::bparse::extract< uint64_t >( iss, "uint64_t", false ); + *reinterpret_cast< uint64_t* >( pSheet->ptr() + member_entry.offset ) = value; + } + break; + + default: + auto type = static_cast< uint16_t >( member_entry.type ); + if( type < 0x19 || type > 0x20 ) + throw std::runtime_error( "Unknown DataType: " + std::to_string( type ) ); + uint64_t val = xiv::utils::bparse::extract< uint64_t >( iss, "bool" ); + int32_t shift = type - 0x19; + int32_t i = 1 << shift; + val &= i; + fields.emplace_back( ( val & i ) == i ); + break; + } + } + + sheets[ record_index.id ] = pSheet; + } + } + + return sheets; + } protected: // Data indexed by the ID of the row, the vector is field with the same order as exh.members - std::map< uint32_t, std::vector< Field>> _data; - std::vector< std::shared_ptr< dat::File>> _files; + std::map< uint32_t, std::vector< Field > > _data; + std::vector< std::shared_ptr< dat::File > > _files; std::shared_ptr< Exh > _exh; std::map< uint32_t, ExdCacheEntry > _idCache; }; diff --git a/src/common/Exd/ExdData.h b/src/common/Exd/ExdData.h index 5ba553e5e..a4be91569 100644 --- a/src/common/Exd/ExdData.h +++ b/src/common/Exd/ExdData.h @@ -91,6 +91,27 @@ namespace Sapphire::Data return ids; } + template< typename T > + std::unordered_map< uint32_t, std::shared_ptr< Excel::ExcelStruct< T > > > getRows() + { + xiv::exd::Exd sheet; + auto needle = m_sheets.find( typeid( T ) ); + if( needle == m_sheets.end() ) + { + auto sheetName = getSheetName< T >(); + + // load sheet + auto& cat = m_exd_data->get_category( sheetName ); + m_sheets[ typeid( T ) ] = sheet = static_cast< xiv::exd::Exd >( cat.get_data( xiv::exd::Language::en ) ); + } + else + { + sheet = needle->second; + } + + return sheet.get_sheet_rows< T >(); + } + std::shared_ptr< xiv::dat::GameData > getGameData() { return m_data; diff --git a/src/tools/action_parse/main.cpp b/src/tools/action_parse/main.cpp index c542eae7f..4abed8267 100644 --- a/src/tools/action_parse/main.cpp +++ b/src/tools/action_parse/main.cpp @@ -157,22 +157,20 @@ int main( int argc, char* argv[] ) Logger::fatal( "Error setting up EXD data " ); return 0; } - auto idList = g_exdDataGen.getIdList< Excel::Action >(); + auto actionList = g_exdDataGen.getRows< Excel::Action >(); std::map< uint32_t, ActionEntry > actions; std::map< uint32_t, std::vector< uint32_t > > traversedCombos; - auto total = idList.size(); + auto total = actionList.size(); int cursor = 0; - for( auto id : idList ) + for( const auto& [ id, action ] : actionList ) { auto done = ( cursor++ / static_cast< float >( total ) ) * 100.f; if( cursor % 50 == 0 && cursor > 0 ) Logger::info( "Processing {} actions of {} ({:.2f}%)", cursor, total, done ); - auto action = g_exdDataGen.getRow< Excel::Action >( id ); - //auto actionTransient = g_exdData.get< Sapphire::Data::ActionTransient >( id ); if( action ) { diff --git a/src/tools/wiki_parse/main.cpp b/src/tools/wiki_parse/main.cpp index 914e79831..7469d5c1b 100644 --- a/src/tools/wiki_parse/main.cpp +++ b/src/tools/wiki_parse/main.cpp @@ -89,11 +89,11 @@ int main( int argc, char* argv[] ) // CFC list { - auto idList = g_exdDataGen.getIdList< Excel::ContentFinderCondition >(); + auto cfcList = g_exdDataGen.getRows< Excel::ContentFinderCondition >(); std::stringstream cfcOutputStream; - auto total = idList.size(); + auto total = cfcList.size(); int cursor = 0; std::map< uint8_t, std::string > instanceContentTypeMap; @@ -118,7 +118,7 @@ int main( int argc, char* argv[] ) cfcOutputStream << "| ID | Instance | Territory | Name | Type |" << std::endl << "| --- | --- | --- | --- | --- |" << std::endl; - for( auto id : idList ) + for( const auto& [ id, cfc ] : cfcList ) { auto done = ( cursor++ / static_cast< float >( total ) ) * 100.f; if( cursor % 50 == 0 && cursor > 0 ) @@ -127,8 +127,6 @@ int main( int argc, char* argv[] ) if( id == 0 ) continue; - auto cfc = g_exdDataGen.getRow< Excel::ContentFinderCondition >( id ); - if( cfc ) { auto& cfcData = cfc->data(); @@ -234,24 +232,22 @@ int main( int argc, char* argv[] ) teriTypeIntendedUseMap[ TheFeastArea ] = "TheFeastArea"; teriTypeIntendedUseMap[ PrivateEventArea ] = "PrivateEventArea"; - auto idList = g_exdDataGen.getIdList< Excel::TerritoryType >(); + auto teriList = g_exdDataGen.getRows< Excel::TerritoryType >(); std::stringstream teritypeOutputStream; teritypeOutputStream << "| ID | Place Name | Name | Intended Use |" << std::endl << "| --- | --- | --- | --- |" << std::endl; - auto total = idList.size(); + auto total = teriList.size(); int cursor = 0; - for( auto id : idList ) + for( const auto& [ id, teriType ] : teriList ) { auto done = ( cursor++ / static_cast< float >( total ) ) * 100.f; if( cursor % 50 == 0 && cursor > 0 ) Logger::info( "Processing {} teritypes of {} ({:.2f}%)", cursor, total, done ); - auto teriType = g_exdDataGen.getRow< Excel::TerritoryType >( id ); - if( teriType ) { auto& teriTypeData = teriType->data(); @@ -291,17 +287,17 @@ int main( int argc, char* argv[] ) // class/job list { - auto idList = g_exdDataGen.getIdList< Excel::ClassJob >(); + auto classJobList = g_exdDataGen.getRows< Excel::ClassJob >(); std::stringstream classjobOutputStream; classjobOutputStream << "| ID | Name | Short | Main Class |" << std::endl << "| --- | --- | --- | --- |" << std::endl; - auto total = idList.size(); + auto total = classJobList.size(); int cursor = 0; - for( auto id : idList ) + for( const auto& [ id, classJob ] : classJobList ) { auto done = ( cursor++ / static_cast< float >( total ) ) * 100.f; if( cursor % 50 == 0 && cursor > 0 ) @@ -338,7 +334,7 @@ int main( int argc, char* argv[] ) // achievement list { - auto idList = g_exdDataGen.getIdList< Excel::Achievement >(); + auto achvList = g_exdDataGen.getRows< Excel::Achievement >(); enum class Type : uint8_t { @@ -394,17 +390,15 @@ int main( int argc, char* argv[] ) achvOutputStream << "| ID | Name | Type (Subtype) | Description |" << std::endl << "| --- | --- | --- | --- |" << std::endl; - auto total = idList.size(); + auto total = achvList.size(); int cursor = 0; - for( auto id : idList ) + for( const auto& [ id, pAchv ] : achvList ) { auto done = ( cursor++ / static_cast< float >( total ) ) * 100.f; if( cursor % 50 == 0 && cursor > 0 ) Logger::info( "Processing {} achievements of {} ({:.2f}%)", cursor, total, done ); - auto pAchv = g_exdDataGen.getRow< Excel::Achievement >( id ); - if( pAchv ) { auto& achvData = pAchv->data(); diff --git a/src/world/ContentFinder/ContentFinder.cpp b/src/world/ContentFinder/ContentFinder.cpp index 78faebe3f..8d53c2ea5 100644 --- a/src/world/ContentFinder/ContentFinder.cpp +++ b/src/world/ContentFinder/ContentFinder.cpp @@ -131,12 +131,11 @@ void World::ContentFinder::registerContentRequest( Entity::Player &player, uint3 void World::ContentFinder::registerRandomContentRequest( Entity::Player &player, uint32_t randomContentTypeId ) { auto& exdData = Service< Data::ExdData >::ref(); - auto contentListIds = exdData.getIdList< Excel::ContentFinderCondition >(); + auto contentFinderList = exdData.getRows< Excel::ContentFinderCondition >(); std::vector< uint32_t > idList; - for( auto id : contentListIds ) + for( const auto& [ id, instanceContent ] : contentFinderList ) { - auto instanceContent = exdData.getRow< Excel::ContentFinderCondition >( id ); if( instanceContent->data().RandomContentType == randomContentTypeId ) { if( instanceContent->data().LevelMin <= player.getLevel() ) diff --git a/src/world/Manager/AchievementMgr.cpp b/src/world/Manager/AchievementMgr.cpp index 191c3f8e8..2c41e1239 100644 --- a/src/world/Manager/AchievementMgr.cpp +++ b/src/world/Manager/AchievementMgr.cpp @@ -14,12 +14,10 @@ using namespace Sapphire::World::Manager; bool AchievementMgr::cacheAchievements() { auto& exdData = Common::Service< Data::ExdData >::ref(); - auto idList = exdData.getIdList< Excel::Achievement >(); + auto achvDat = exdData.getRows< Excel::Achievement >(); - for( auto id : idList ) + for( const auto& [ id, achvExdData ] : achvDat ) { - auto achvExdData = exdData.getRow< Excel::Achievement >( id ); - uint32_t key = achvExdData->data().ConditionType; auto achvType = static_cast< Common::Achievement::Type >( key ); diff --git a/src/world/Manager/MapMgr.cpp b/src/world/Manager/MapMgr.cpp index 2824f4aed..f7a18a40e 100644 --- a/src/world/Manager/MapMgr.cpp +++ b/src/world/Manager/MapMgr.cpp @@ -35,12 +35,10 @@ using namespace Sapphire::World::Manager; bool MapMgr::loadQuests() { auto& exdData = Common::Service< Data::ExdData >::ref(); - auto idList = exdData.getIdList< Excel::Quest >(); + auto questList = exdData.getRows< Excel::Quest >(); - for( auto id : idList ) + for( auto& [ id, questExdData ] : questList ) { - auto questExdData = exdData.getRow< Excel::Quest >( id ); - m_quests.emplace( id, std::move( questExdData ) ); } diff --git a/src/world/Manager/ShopMgr.cpp b/src/world/Manager/ShopMgr.cpp index 2edeec1c4..7d9c9aa5f 100644 --- a/src/world/Manager/ShopMgr.cpp +++ b/src/world/Manager/ShopMgr.cpp @@ -12,13 +12,12 @@ using namespace Sapphire::World::Manager; void ShopMgr::cacheShop( uint32_t shopId ) { auto& exdData = Common::Service< Data::ExdData >::ref(); - auto itemShopList = exdData.getIdList< Excel::Shop >(); + auto itemShopList = exdData.getRows< Excel::Shop >(); uint8_t count = 0; - for( auto itemShop : itemShopList ) + for( const auto& [ itemShop, shop ] : itemShopList ) { if( shopId == itemShop ) { - auto shop = exdData.getRow< Excel::Shop >( itemShop ); for( auto shopItemId : shop->data().Item ) { auto shopItem = exdData.getRow< Excel::ShopItem >( shopItemId ); diff --git a/src/world/Manager/TerritoryMgr.cpp b/src/world/Manager/TerritoryMgr.cpp index abce31346..a7a27a7f5 100644 --- a/src/world/Manager/TerritoryMgr.cpp +++ b/src/world/Manager/TerritoryMgr.cpp @@ -35,14 +35,12 @@ TerritoryMgr::TerritoryMgr() : void TerritoryMgr::loadTerritoryTypeDetailCache() { auto& exdData = Common::Service< Data::ExdData >::ref(); - auto idList = exdData.getIdList< Excel::TerritoryType >(); + auto teriList = exdData.getRows< Excel::TerritoryType >(); - for( auto id : idList ) + for( const auto& [ id, teri ] : teriList ) { - auto teri1 = exdData.getRow< Excel::TerritoryType >( id ); - - if( !teri1->getString( teri1->data().Name ).empty() && id > 90 ) - m_territoryTypeDetailCacheMap[ id ] = teri1; + if( !teri->getString( teri->data().Name ).empty() && id > 90 ) + m_territoryTypeDetailCacheMap[ id ] = teri; } } @@ -158,11 +156,10 @@ bool TerritoryMgr::isHousingTerritory( uint32_t territoryTypeId ) const uint32_t TerritoryMgr::getInstanceContentId( uint32_t territoryTypeId ) const { auto& exdData = Common::Service< Data::ExdData >::ref(); - auto contentListIds = exdData.getIdList< Excel::InstanceContent >(); + auto contentFinderList = exdData.getRows< Excel::InstanceContent >(); - for( auto id : contentListIds ) + for( const auto& [ id, instanceContent ] : contentFinderList ) { - auto instanceContent = exdData.getRow< Excel::InstanceContent >( id ); if( instanceContent->data().TerritoryType == territoryTypeId ) { return id; @@ -306,10 +303,10 @@ TerritoryPtr TerritoryMgr::createQuestBattle( uint32_t questBattleId ) if( !pQuestInfo || pQuestInfo->getString( pQuestInfo->data().Text.Name ).empty() ) return nullptr; - for( auto& teriId : exdData.getIdList< Excel::TerritoryType >() ) - { + auto teriList = exdData.getRows< Excel::TerritoryType >(); - auto pTeri = exdData.getRow< Excel::TerritoryType >( teriId ); + for( const auto& [ teriId, pTeri ] : teriList ) + { if( !pTeri || pTeri->data().QuestBattle != questBattleId ) continue; @@ -329,8 +326,6 @@ TerritoryPtr TerritoryMgr::createQuestBattle( uint32_t questBattleId ) m_instanceZoneSet.insert( pZone ); return pZone; - - } return nullptr; diff --git a/src/world/Network/Handlers/CFHandlers.cpp b/src/world/Network/Handlers/CFHandlers.cpp index 6aef66e0a..61c0484c4 100644 --- a/src/world/Network/Handlers/CFHandlers.cpp +++ b/src/world/Network/Handlers/CFHandlers.cpp @@ -74,12 +74,12 @@ void Sapphire::Network::GameConnection::find5Contents( const Packets::FFXIVARR_P if( territoryType != 0 ) selectedContent.insert( territoryType ); - auto contentListIds = exdData.getIdList< Excel::InstanceContent >(); - std::vector< uint32_t > idList; - for( auto id : contentListIds ) + + auto contentFinderList = exdData.getRows< Excel::InstanceContent >(); + + for( const auto& [ id, instanceContent ] : contentFinderList ) { - auto instanceContent = exdData.getRow< Excel::InstanceContent >( id ); if( selectedContent.count( instanceContent->data().TerritoryType ) ) { idList.push_back( id ); diff --git a/src/world/Network/Handlers/GMCommandHandlers.cpp b/src/world/Network/Handlers/GMCommandHandlers.cpp index ace19b6d8..a0076141d 100644 --- a/src/world/Network/Handlers/GMCommandHandlers.cpp +++ b/src/world/Network/Handlers/GMCommandHandlers.cpp @@ -506,19 +506,14 @@ void Sapphire::Network::GameConnection::gmCommandHandler( const Packets::FFXIVAR bool doTeleport = false; uint16_t teleport; - auto idList = exdData.getIdList< Excel::Aetheryte >(); + auto aetheryteList = exdData.getRows< Excel::Aetheryte >(); - for( auto i : idList ) + for( const auto& [ id, data ] : aetheryteList ) { - auto data = exdData.getRow< Excel::Aetheryte >( i ); - - if( !data ) - continue; - if( data->data().TerritoryType == param1 && data->data().Telepo ) { doTeleport = true; - teleport = static_cast< uint16_t >( i ); + teleport = static_cast< uint16_t >( id ); break; } diff --git a/src/world/Network/Util/PacketUtil.cpp b/src/world/Network/Util/PacketUtil.cpp index 450bcfd67..584f5ee3c 100644 --- a/src/world/Network/Util/PacketUtil.cpp +++ b/src/world/Network/Util/PacketUtil.cpp @@ -52,15 +52,13 @@ void Util::Packet::sendBaseParams( Entity::Player& player ) std::fill( std::begin( statParams ), std::end( statParams ), 0 ); auto& exd = Common::Service< Data::ExdData >::ref(); - auto idList = exd.getIdList< Excel::BaseParam >(); + auto baseParamList = exd.getRows< Excel::BaseParam >(); - for( const auto id : idList ) + for( const auto& [ id, row ] : baseParamList ) { - auto row = exd.getRow< Excel::BaseParam >( id ); - if( !row ) - continue; - if( row->data().PacketIndex < 0 ) + if( !row || row->data().PacketIndex < 0 ) continue; + statParams[ row->data().PacketIndex ] = player.getStatValue( static_cast< Common::BaseParam >( id ) ); } diff --git a/src/world/Territory/InstanceObjectCache.cpp b/src/world/Territory/InstanceObjectCache.cpp index 291f18e37..91ff7a4c3 100644 --- a/src/world/Territory/InstanceObjectCache.cpp +++ b/src/world/Territory/InstanceObjectCache.cpp @@ -20,25 +20,19 @@ Sapphire::InstanceObjectCache::InstanceObjectCache() { - auto& exdData = Common::Service< Sapphire::Data::ExdData >::ref(); - auto idList = exdData.getIdList< Excel::TerritoryType >(); + auto teriList = exdData.getRows< Excel::TerritoryType >(); size_t count = 0; - std::for_each( std::execution::seq, idList.begin(), idList.end() , [ & ]( int id ) - { + for( const auto& [ id, territoryType ] : teriList ) { // show some loading indication... if( count++ % 10 == 0 ) std::cout << "."; - auto territoryType = exdData.getRow< Excel::TerritoryType >( id ); - if( !territoryType ) - return; - auto path = territoryType->getString( territoryType->data().LVB ); if( path.empty() ) - return; + continue; path = std::string( "bg/" ) + path.substr( 0, path.find( "/level/" ) ); @@ -62,7 +56,7 @@ Sapphire::InstanceObjectCache::InstanceObjectCache() if( exdData.getGameData()->doesFileExist( bgLgbPath ) ) bgFile = exdData.getGameData()->getFile( bgLgbPath ); else - return; + continue; planmap_file = exdData.getGameData()->getFile( planmapLgbPath ); planevent_file = exdData.getGameData()->getFile( planeventLgbPath ); @@ -70,7 +64,7 @@ Sapphire::InstanceObjectCache::InstanceObjectCache() catch( std::runtime_error& ) { // ignore files that aren't found - return; + continue; } bgSection = bgFile->access_data_sections().at( 0 ); @@ -159,7 +153,9 @@ Sapphire::InstanceObjectCache::InstanceObjectCache() } } } - } ); + } + + std::cout << std::endl; Logger::debug( "InstanceObjectCache Cached: MapRange: {} ExitRange: {} PopRange: {} EventObj: {} EventNpc: {} EventRange: {}", From 631abf48aae1b64eb9c118d545be4942b28d85fc Mon Sep 17 00:00:00 2001 From: Alice Ogeda Date: Fri, 24 Mar 2023 18:09:12 -0300 Subject: [PATCH 15/30] remove extra call; --- src/tools/wiki_parse/main.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tools/wiki_parse/main.cpp b/src/tools/wiki_parse/main.cpp index 7469d5c1b..ca12c46d7 100644 --- a/src/tools/wiki_parse/main.cpp +++ b/src/tools/wiki_parse/main.cpp @@ -303,8 +303,6 @@ int main( int argc, char* argv[] ) if( cursor % 50 == 0 && cursor > 0 ) Logger::info( "Processing {} classjobs of {} ({:.2f}%)", cursor, total, done ); - auto classJob = g_exdDataGen.getRow< Excel::ClassJob >( id ); - if( classJob ) { auto& classJobData = classJob->data(); From 928729326c707e0a208df4e86ee941d160d1abcf Mon Sep 17 00:00:00 2001 From: Mordred Date: Fri, 24 Mar 2023 22:52:38 +0100 Subject: [PATCH 16/30] Gambit packs added. Basic timelines for bnpc actions can be defined. --- src/world/AI/GambitPack.cpp | 135 ++++++++++++++++++++++++++++++++ src/world/AI/GambitPack.h | 60 ++++++++++++++ src/world/Actor/BNpc.cpp | 44 ++++++----- src/world/Actor/BNpc.h | 2 +- src/world/ForwardsZone.h | 3 + src/world/Manager/PlayerMgr.cpp | 2 +- 6 files changed, 224 insertions(+), 22 deletions(-) create mode 100644 src/world/AI/GambitPack.cpp create mode 100644 src/world/AI/GambitPack.h diff --git a/src/world/AI/GambitPack.cpp b/src/world/AI/GambitPack.cpp new file mode 100644 index 000000000..03a8e0de5 --- /dev/null +++ b/src/world/AI/GambitPack.cpp @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include +#include "GambitTargetCondition.h" +#include "GambitRule.h" +#include "GambitPack.h" + +using namespace Sapphire; +using namespace Sapphire::World; + +AI::GambitTimeLinePack::GambitTimeLinePack( int8_t loopCount ) : + GambitPack( GambitPackType::TimeLine ), + m_loopCount( loopCount ), + m_currentIndex( 0 ), + m_currentLoop( 0 ), + m_startTimeMs( 0 ) +{ + +} + +void AI::GambitTimeLinePack::start() +{ + m_startTimeMs = Common::Util::getTimeMs(); +} + +void AI::GambitTimeLinePack::addTimeLine( const GambitRulePtr& pRule, uint32_t offsetInSeconds ) +{ + auto timeLine = std::make_pair( pRule, offsetInSeconds ); + m_gambits.push_back( timeLine ); +} + +void AI::GambitTimeLinePack::addTimeLine( const GambitTargetConditionPtr& targetCondition, const Action::ActionPtr& action, uint32_t offsetInSeconds ) +{ + auto pRule = make_GambitRule( targetCondition, action, 0 ); + auto timeLine = std::make_pair( pRule, offsetInSeconds ); + m_gambits.push_back( timeLine ); +} + +uint8_t AI::GambitTimeLinePack::getLoopCount() const +{ + return m_loopCount; +} + +uint8_t AI::GambitTimeLinePack::getCurrentIndex() const +{ + return m_currentIndex; +} + +void AI::GambitTimeLinePack::update( Entity::BNpc& bnpc, uint64_t tickCount ) +{ + if( m_startTimeMs == 0 || m_gambits.empty() ) + return; + + auto& actionMgr = Common::Service< World::Manager::ActionMgr >::ref(); + + if( m_gambits.size() <= m_currentIndex ) + { + if( m_currentLoop < m_loopCount || m_loopCount == -1 ) + { + m_currentIndex = 0; + m_currentLoop++; + m_startTimeMs = Common::Util::getTimeMs(); + } + else + { + m_startTimeMs = 0; + m_currentLoop = 0; + return; + } + } + + auto currentTimeLine = m_gambits.at( m_currentIndex ); + auto& pRule = currentTimeLine.first; + auto offset = currentTimeLine.second * 1000; + + if( tickCount - m_startTimeMs >= offset ) + { + if( pRule->getGambitTargetCondition()->isConditionMet( bnpc ) ) + { + pRule->setLastExecutionMs( tickCount ); + actionMgr.handleTargetedAction( bnpc, pRule->getActionPtr()->getId(), pRule->getGambitTargetCondition()->getTarget()->getId(), 0 ); + } + m_currentIndex++; + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +AI::GambitRuleSetPack::GambitRuleSetPack() : GambitPack( GambitPackType::RuleSetList ) +{ + +} + +void AI::GambitRuleSetPack::addRule( const GambitRulePtr& pRule ) +{ + m_gambits.push_back( pRule ); +} + +void AI::GambitRuleSetPack::addRule( const GambitTargetConditionPtr& targetCondition, const Action::ActionPtr& action, uint32_t coolDown ) +{ + auto pRule = make_GambitRule( targetCondition, action, coolDown ); + m_gambits.push_back( pRule ); +} + +void AI::GambitRuleSetPack::update( Entity::BNpc& bnpc, uint64_t tickCount ) +{ + auto& actionMgr = Common::Service< World::Manager::ActionMgr >::ref(); + for( auto& gambitRule : m_gambits ) + { + if( !gambitRule->isEnabled() ) + continue; + + if( ( tickCount - gambitRule->getLastExecutionMs() ) > gambitRule->getCoolDown() ) + { + if( !gambitRule->getGambitTargetCondition()->isConditionMet( bnpc ) ) + continue; + + gambitRule->setLastExecutionMs( tickCount ); + actionMgr.handleTargetedAction( bnpc, gambitRule->getActionPtr()->getId(), gambitRule->getGambitTargetCondition()->getTarget()->getId(), 0 ); + break; + } + } +} + +AI::GambitTimeLinePackPtr AI::GambitPack::getAsTimeLine() +{ + return std::dynamic_pointer_cast< GambitTimeLinePack, GambitPack >( shared_from_this() ); +} + +AI::GambitRuleSetPackPtr AI::GambitPack::getAsRuleSet() +{ + return std::dynamic_pointer_cast< GambitRuleSetPack, GambitPack >( shared_from_this() ); +} diff --git a/src/world/AI/GambitPack.h b/src/world/AI/GambitPack.h new file mode 100644 index 000000000..caf62f9c1 --- /dev/null +++ b/src/world/AI/GambitPack.h @@ -0,0 +1,60 @@ +#include +#include +#include "GambitTargetCondition.h" +#include "GambitRule.h" + +#pragma once + +namespace Sapphire::World::AI +{ + enum class GambitPackType : uint8_t + { + None, + RuleSetList, + TimeLine + }; + + class GambitPack : public std::enable_shared_from_this< GambitPack > + { + public: + GambitPack( GambitPackType type ) : m_type( type ) { }; + virtual ~GambitPack() = default; + GambitPackType getType() const { return m_type; } + virtual void update( Entity::BNpc& bnpc, uint64_t tickCount ) = 0; + GambitTimeLinePackPtr getAsTimeLine(); + GambitRuleSetPackPtr getAsRuleSet(); + private: + GambitPackType m_type; + }; + + class GambitTimeLinePack : public GambitPack + { + public: + GambitTimeLinePack( int8_t loopCount ); + void update( Entity::BNpc& bnpc, uint64_t tickCount ); + void addTimeLine( const GambitRulePtr& pRule, uint32_t offsetInSeconds ); + void addTimeLine( const GambitTargetConditionPtr& targetCondition, const Action::ActionPtr& action, uint32_t offsetInSeconds ); + uint8_t getLoopCount() const; + uint8_t getCurrentIndex() const; + void start(); + + private: + std::vector< std::pair< GambitRulePtr, uint32_t > > m_gambits; + + uint64_t m_startTimeMs; + uint8_t m_currentIndex; + int8_t m_loopCount; + uint8_t m_currentLoop; + }; + + class GambitRuleSetPack : public GambitPack + { + public: + GambitRuleSetPack(); + void addRule( const GambitRulePtr& pRule ); + void addRule( const GambitTargetConditionPtr& targetCondition, const Action::ActionPtr& action, uint32_t coolDown ); + void update( Entity::BNpc& bnpc, uint64_t tickCount ); + private: + std::vector< GambitRulePtr > m_gambits; + }; +} \ No newline at end of file diff --git a/src/world/Actor/BNpc.cpp b/src/world/Actor/BNpc.cpp index 04107a5a0..9f9429b5b 100644 --- a/src/world/Actor/BNpc.cpp +++ b/src/world/Actor/BNpc.cpp @@ -46,6 +46,7 @@ #include #include +#include #include #include #include @@ -598,6 +599,11 @@ void BNpc::aggro( const Sapphire::Entity::CharaPtr& pChara ) auto& pRNGMgr = Common::Service< World::Manager::RNGMgr >::ref(); auto variation = static_cast< uint32_t >( pRNGMgr.getRandGenerator< float >( 500, 1000 ).next() ); + if( m_pGambitPack && m_pGambitPack->getAsTimeLine() ) + { + m_pGambitPack->getAsTimeLine()->start(); + } + m_lastAttack = Common::Util::getTimeMs() + variation; setStance( Stance::Active ); @@ -911,9 +917,22 @@ void BNpc::init() //setup a test gambit auto testGambitRule = AI::make_GambitRule( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 88, 0 ), 5000 ); auto testGambitRule1 = AI::make_GambitRule( AI::make_HPSelfPctLessThanTargetCondition( 50 ), Action::make_Action( getAsChara(), 120, 0 ), 5000 ); - - m_gambits.push_back( testGambitRule ); - m_gambits.push_back( testGambitRule1 ); +/* + auto gambitPack = AI::make_GambitRuleSetPack(); + gambitPack->addRule( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 88, 0 ), 5000 ); + gambitPack->addRule( AI::make_HPSelfPctLessThanTargetCondition( 50 ), Action::make_Action( getAsChara(), 120, 0 ), 10000 ); + m_pGambitPack = gambitPack; +*/ + + auto gambitPack = AI::make_GambitTimeLinePack( -1 ); + gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 88, 0 ), 2 ); + gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 89, 0 ), 4 ); + gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 90, 0 ), 6 ); + gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 91, 0 ), 8 ); + gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 92, 0 ), 10 ); + gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 81, 0 ), 12 ); + gambitPack->addTimeLine( AI::make_TopHateTargetCondition(), Action::make_Action( getAsChara(), 82, 0 ), 14 ); + m_pGambitPack = gambitPack; using namespace AI::Fsm; m_fsm = make_StateMachine(); @@ -945,23 +964,8 @@ void BNpc::init() void BNpc::processGambits( uint64_t tickCount ) { - auto& actionMgr = Common::Service< World::Manager::ActionMgr >::ref(); - for( auto& gambitRule : m_gambits ) - { - if( !gambitRule->isEnabled() ) - continue; - - if( ( tickCount - gambitRule->getLastExecutionMs() ) > gambitRule->getCoolDown() ) - { - if( !gambitRule->getGambitTargetCondition()->isConditionMet( *this ) ) - continue; - - gambitRule->setLastExecutionMs( tickCount ); - actionMgr.handleTargetedAction( *this, gambitRule->getActionPtr()->getId(), gambitRule->getGambitTargetCondition()->getTarget()->getId(), 0 ); - break; - } - - } + m_tp = 1000; + m_pGambitPack->update( *this, tickCount ); } uint32_t BNpc::getLastRoamTargetReachedTime() const diff --git a/src/world/Actor/BNpc.h b/src/world/Actor/BNpc.h index a8804f720..7076ae6ef 100644 --- a/src/world/Actor/BNpc.h +++ b/src/world/Actor/BNpc.h @@ -206,7 +206,7 @@ namespace Sapphire::Entity Common::FFXIVARR_POSITION3 m_naviTarget; CharaPtr m_pOwner; - std::vector< World::AI::GambitRulePtr > m_gambits; + World::AI::GambitPackPtr m_pGambitPack; std::shared_ptr< World::AI::Fsm::StateMachine > m_fsm; diff --git a/src/world/ForwardsZone.h b/src/world/ForwardsZone.h index de26643f3..398e98b84 100644 --- a/src/world/ForwardsZone.h +++ b/src/world/ForwardsZone.h @@ -54,6 +54,9 @@ namespace World::AI TYPE_FORWARD( HPSelfPctLessThanTargetCondition ); TYPE_FORWARD( GambitRule ); + TYPE_FORWARD( GambitPack ); + TYPE_FORWARD( GambitTimeLinePack ); + TYPE_FORWARD( GambitRuleSetPack ); } namespace World::AI::Fsm diff --git a/src/world/Manager/PlayerMgr.cpp b/src/world/Manager/PlayerMgr.cpp index 28636bbb8..15f7ad51a 100644 --- a/src/world/Manager/PlayerMgr.cpp +++ b/src/world/Manager/PlayerMgr.cpp @@ -313,7 +313,7 @@ void PlayerMgr::onUpdate( Entity::Player& player, uint64_t tickCount ) void PlayerMgr::checkAutoAttack( Entity::Player& player, uint64_t tickCount ) const { auto mainWeap = player.getItemAt( Common::GearSet0, Common::MainHand ); - if( !mainWeap || !player.isAutoattackOn() || player.checkAction() || !player.getTargetId() || player.getStance() != Common::Active ) + if( !mainWeap || player.checkAction() || !player.isAutoattackOn() || !player.getTargetId() || player.getStance() != Common::Active ) return; for( const auto& actor : player.getInRangeActors() ) From d4d8c3c1557702a89d3143c0d51218fd04077166 Mon Sep 17 00:00:00 2001 From: Toofy Date: Tue, 18 Apr 2023 16:42:25 +0100 Subject: [PATCH 17/30] Moving around level up logic to make gm level up command behave 'normally' --- src/world/Actor/Player.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/world/Actor/Player.cpp b/src/world/Actor/Player.cpp index c667fe390..5d0115cf6 100644 --- a/src/world/Actor/Player.cpp +++ b/src/world/Actor/Player.cpp @@ -642,11 +642,6 @@ void Player::levelUp() m_mp = getMaxMp(); setLevel( getLevel() + 1 ); - Network::Util::Packet::sendActorControl( getInRangePlayerIds( true ), getId(), LevelUpEffect, static_cast< uint8_t >( getClass() ), getLevel(), getLevel() - 1 ); - - auto& achvMgr = Common::Service< World::Manager::AchievementMgr >::ref(); - achvMgr.progressAchievementByType< Common::Achievement::Type::Classjob >( *this, static_cast< uint32_t >( getClass() ) ); - Service< World::Manager::MapMgr >::ref().updateQuests( *this ); } uint8_t Player::getLevel() const @@ -733,6 +728,11 @@ void Player::setLevel( uint8_t level ) Network::Util::Packet::sendBaseParams( *this ); Network::Util::Packet::sendHudParam( *this ); Network::Util::Packet::sendStatusUpdate( *this ); + Network::Util::Packet::sendActorControl( getInRangePlayerIds( true ), getId(), LevelUpEffect, static_cast< uint8_t >( getClass() ), getLevel(), getLevel() - 1 ); + + auto& achvMgr = Common::Service< World::Manager::AchievementMgr >::ref(); + achvMgr.progressAchievementByType< Common::Achievement::Type::Classjob >( *this, static_cast< uint32_t >( getClass() ) ); + Service< World::Manager::MapMgr >::ref().updateQuests( *this ); } void Player::setLevelForClass( uint8_t level, Common::ClassJob classjob ) From f0e1990cbd0cf700959de52a707b1270e5dbd79c Mon Sep 17 00:00:00 2001 From: Toofy Date: Tue, 18 Apr 2023 17:33:29 +0100 Subject: [PATCH 18/30] Some bug fixes --- src/world/Territory/Territory.cpp | 1 + src/world/WorldServer.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/world/Territory/Territory.cpp b/src/world/Territory/Territory.cpp index de4a5c4f5..1948a207e 100644 --- a/src/world/Territory/Territory.cpp +++ b/src/world/Territory/Territory.cpp @@ -836,6 +836,7 @@ Entity::BNpcPtr Territory::createBNpcFromLayoutId( uint32_t layoutId, uint32_t h return nullptr; auto pBNpc = std::make_shared< Entity::BNpc >( getNextActorId(), infoPtr->second, *this, hp, bnpcType ); + pBNpc->init(); pBNpc->setTriggerOwnerId( triggerOwnerId ); pushActor( pBNpc ); return pBNpc; diff --git a/src/world/WorldServer.cpp b/src/world/WorldServer.cpp index 4748e1e94..8c888209c 100644 --- a/src/world/WorldServer.cpp +++ b/src/world/WorldServer.cpp @@ -144,6 +144,11 @@ std::string readFileToString( const std::string& filename ) // Close the file file.close(); + // Remove all newlines from the file contents + fileContents.erase(std::remove(fileContents.begin(), fileContents.end(), '\n'), fileContents.end()); + fileContents.erase(std::remove(fileContents.begin(), fileContents.end(), '\r'), fileContents.end()); + + // Return the file contents as a string return fileContents; } From b3e86d38775d70f89b746dc9cc369d1cd614296b Mon Sep 17 00:00:00 2001 From: Toofy Date: Sun, 23 Apr 2023 16:42:24 +0100 Subject: [PATCH 19/30] Formatting --- src/world/WorldServer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/world/WorldServer.cpp b/src/world/WorldServer.cpp index 8c888209c..c89cf5508 100644 --- a/src/world/WorldServer.cpp +++ b/src/world/WorldServer.cpp @@ -145,8 +145,8 @@ std::string readFileToString( const std::string& filename ) file.close(); // Remove all newlines from the file contents - fileContents.erase(std::remove(fileContents.begin(), fileContents.end(), '\n'), fileContents.end()); - fileContents.erase(std::remove(fileContents.begin(), fileContents.end(), '\r'), fileContents.end()); + fileContents.erase( std::remove( fileContents.begin(), fileContents.end(), '\n' ), fileContents.end() ); + fileContents.erase( std::remove( fileContents.begin(), fileContents.end(), '\r' ), fileContents.end() ); // Return the file contents as a string From 78b860d9f8438502fa8f0a8e6b9503433564cf65 Mon Sep 17 00:00:00 2001 From: collett Date: Sun, 30 Apr 2023 19:36:24 +0900 Subject: [PATCH 20/30] fix some PlayerCondition flags --- src/common/Common.h | 7 ++++--- src/world/Actor/Player.cpp | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/common/Common.h b/src/common/Common.h index 18e529d17..8aa5836c5 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -1373,9 +1373,10 @@ namespace Sapphire::Common { None1 = 0, HideUILockChar = 1, // as the name suggests, hides the ui and logs the char... - InCombat = 2, // in Combat, locks gearchange/return/teleport - Casting = 3, - InNpcEvent = 6, // when talking to an npc, locks ui giving "occupied" message + InCombat = 18, // in Combat, locks gearchange/return/teleport + Casting = 19, + EventAction = 22, + InNpcEvent = 24, // when talking to an npc, locks ui giving "occupied" message // InNpcEvent1 = 10, // Sent together with InNpcEvent, when waiting for input? just a guess... diff --git a/src/world/Actor/Player.cpp b/src/world/Actor/Player.cpp index 5d0115cf6..3bbb74ef7 100644 --- a/src/world/Actor/Player.cpp +++ b/src/world/Actor/Player.cpp @@ -1134,6 +1134,7 @@ const std::map< uint32_t, uint8_t >& Player::getActorIdToHateSlotMap() void Player::onMobAggro( const BNpc& bnpc ) { hateListAdd( bnpc ); + setCondition( PlayerCondition::InCombat ); Network::Util::Packet::sendActorControl( *this, getId(), SetBattle, 1 ); } @@ -1141,7 +1142,10 @@ void Player::onMobDeaggro( const BNpc& bnpc ) { hateListRemove( bnpc ); if( m_actorIdTohateSlotMap.empty() ) + { + removeCondition( PlayerCondition::InCombat ); Network::Util::Packet::sendActorControl( *this, getId(), SetBattle, 0 ); + } } bool Player::isLogin() const From 0a70db86860b5bff412bb6ec95c51f53e654ae14 Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Sun, 7 May 2023 01:43:22 -0700 Subject: [PATCH 21/30] Underneath the Sultantree quest + questbattle implementation ManWil005 MSQ. HP values are likely to be wrong --- .../questbattles/UnderneaththeSultantree.cpp | 114 +++++++ src/scripts/quest/ManWil005.cpp | 318 ++++++++++++++++++ 2 files changed, 432 insertions(+) create mode 100644 src/scripts/quest/ManWil005.cpp diff --git a/src/scripts/instances/questbattles/UnderneaththeSultantree.cpp b/src/scripts/instances/questbattles/UnderneaththeSultantree.cpp index f5dc332f4..7d4d61a89 100644 --- a/src/scripts/instances/questbattles/UnderneaththeSultantree.cpp +++ b/src/scripts/instances/questbattles/UnderneaththeSultantree.cpp @@ -1,5 +1,8 @@ #include #include +#include +#include +#include using namespace Sapphire; @@ -100,15 +103,126 @@ class UnderneaththeSultantree : public Sapphire::ScriptAPI::QuestBattleScript instance.addEObj( "Millioncornseedling", 2001255, 0, 3927161, 4, { -320.576813f, 25.833500f, -527.550171f }, 0.961304f, -0.384837f, 0); } + enum vars + { + SET_1_SPAWNED, + SET_2_SPAWNED, + SUCCESS_CALLED, + }; + + void onPlayerSetup( Sapphire::QuestBattle& instance, Entity::Player& player ) override + { + player.setRot( -71.03f ); + player.setPos( { 198.303f, 14.244f, 538.248f } ); + } void onUpdate( QuestBattle& instance, uint64_t tickCount ) override { + auto pair1Spawnd = instance.getDirectorVar( SET_1_SPAWNED ); + auto pair2Spawnd = instance.getDirectorVar( SET_2_SPAWNED ); + auto successCalled = instance.getDirectorVar( SUCCESS_CALLED ); + + auto boss = instance.getActiveBNpcByLayoutId( INIT_POP_BOSS ); + auto thancred = instance.getActiveBNpcByLayoutId( INIT_P_POP_01 ); + auto pPlayer = instance.getPlayerPtr(); + + uint32_t bossHpPercent = 0; + if( boss ) + bossHpPercent = boss->getHpPercent(); + + if( pPlayer && !pPlayer->isAlive() ) + { + instance.fail(); + return; + } + + if (!thancred) + return; + + if( pair1Spawnd == 0 && bossHpPercent <= 70 ) + { + instance.setDirectorVar( SET_1_SPAWNED, 1 ); + auto a2 = instance.createBNpcFromLayoutId(INIT_POP_01_01, 1440, Common::BNpcType::Enemy); + auto a3 = instance.createBNpcFromLayoutId( INIT_POP_01_02, 1440, Common::BNpcType::Enemy ); + a2->setFlag( Entity::NoDeaggro ); + a3->setFlag( Entity::NoDeaggro ); + + auto pPlayer = instance.getPlayerPtr(); + a2->hateListAdd( pPlayer, 1 ); + a3->hateListAdd( pPlayer, 1 ); + + thancred->hateListAdd( a2, 9999 ); + thancred->hateListAdd( a3, 9999 ); + } + + if( pair2Spawnd == 0 && bossHpPercent <= 40 ) + { + instance.setDirectorVar( SET_2_SPAWNED, 1 ); + auto a2 = instance.createBNpcFromLayoutId( INIT_POP_02_01, 1440, Common::BNpcType::Enemy ); + auto a3 = instance.createBNpcFromLayoutId( INIT_POP_02_02, 1440, Common::BNpcType::Enemy ); + auto a4 = instance.createBNpcFromLayoutId( INIT_POP_02_03, 1440, Common::BNpcType::Enemy ); + auto a5 = instance.createBNpcFromLayoutId( INIT_POP_02_04, 1440, Common::BNpcType::Enemy ); + a2->setFlag( Entity::NoDeaggro ); + a3->setFlag( Entity::NoDeaggro ); + a4->setFlag( Entity::NoDeaggro ); + a5->setFlag( Entity::NoDeaggro ); + + auto pPlayer = instance.getPlayerPtr(); + a2->hateListAdd( pPlayer, 1 ); + a3->hateListAdd( pPlayer, 1 ); + a4->hateListAdd( pPlayer, 1 ); + a5->hateListAdd( pPlayer, 1 ); + + thancred->hateListAdd( a2, 9999 ); + thancred->hateListAdd( a3, 9999 ); + thancred->hateListAdd( a4, 9999 ); + thancred->hateListAdd( a5, 9999 ); + } + + if( instance.getCountEnemyBNpc() == 0 && successCalled == 0 ) + { + instance.setDirectorVar( SUCCESS_CALLED, 1 ); + instance.success(); + return; + } } void onEnterTerritory( QuestBattle& instance, Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 ) override { + eventMgr().playScene( player, instance.getDirectorId(), 1, + NO_DEFAULT_CAMERA | CONDITION_CUTSCENE | SILENT_ENTER_TERRI_ENV | + HIDE_HOTBAR | SILENT_ENTER_TERRI_BGM | SILENT_ENTER_TERRI_SE | + DISABLE_STEALTH | 0x00100000 | LOCK_HUD | LOCK_HOTBAR | + // todo: wtf is 0x00100000 + DISABLE_CANCEL_EMOTE, [ & ]( Entity::Player& player, const Event::SceneResult& result ) { + player.setOnEnterEventDone( true ); + } ); + } + + void onDutyComplete( QuestBattle& instance, Entity::Player& player ) override + { + auto idx = player.getQuestIndex( instance.getQuestId() ); + if( idx == -1 ) + return; + auto& quest = player.getQuestByIndex( idx ); + quest.setSeq( 2 ); + } + + void onDutyCommence( QuestBattle& instance, Entity::Player& player ) override + { + // TODO: Change to correct HP values + auto boss = instance.createBNpcFromLayoutId( INIT_POP_BOSS, 10571, Common::BNpcType::Enemy ); + auto thancred = instance.createBNpcFromLayoutId( INIT_P_POP_01, 27780, Common::BNpcType::Friendly ); + + boss->setFlag( Entity::NoDeaggro ); + thancred->setFlag( Entity::NoDeaggro ); + + boss->hateListAdd( thancred, 10000 ); + boss->hateListAdd( player.getAsPlayer(), 1 ); + + thancred->hateListAdd( boss, 10000 ); } diff --git a/src/scripts/quest/ManWil005.cpp b/src/scripts/quest/ManWil005.cpp new file mode 100644 index 000000000..75ab8a97a --- /dev/null +++ b/src/scripts/quest/ManWil005.cpp @@ -0,0 +1,318 @@ +// This is an automatically generated C++ script template +// Content needs to be added by hand to make it function +// In order for this script to be loaded, move it to the correct folder in /scripts/ + +#include +#include "Manager/EventMgr.h" +#include +#include + +// Quest Script: ManWil005_00550 +// Quest Name: Underneath the Sultantree +// Quest ID: 66086 +// Start NPC: 1003995 (Papashan) +// End NPC: 1003995 (Papashan) + +using namespace Sapphire; + +class ManWil005 : public Sapphire::ScriptAPI::QuestScript +{ + private: + // Basic quest information + // Quest vars / flags used + // BitFlag8 + // UI8AL + + /// Countable Num: 1 Seq: 1 Event: 1 Listener: 1003996 + /// Countable Num: 1 Seq: 2 Event: 1 Listener: 2001853 + /// Countable Num: 0 Seq: 255 Event: 15 Listener: 5020000 + // Steps in this quest ( 0 is before accepting, + // 1 is first, 255 means ready for turning it in + enum Sequence : uint8_t + { + Seq0 = 0, + Seq1 = 1, + Seq2 = 2, + SeqFinish = 255, + }; + + // Entities found in the script data of the quest + static constexpr auto Actor0 = 1003995; // Papashan ( Pos: 75.338402 2.138110 316.362000 Teri: 141 ) + static constexpr auto Actor1 = 1003996; // Hooded Lalafell ( Pos: 202.662994 14.104900 536.909973 Teri: 141 ) + static constexpr auto Actor2 = 1003997; // ×次女a ( Pos: 76.674599 2.137120 317.433014 Teri: 141 ) + static constexpr auto Actor3 = 1003998; // ×近衛a ( Pos: 77.176598 2.137340 315.631989 Teri: 141 ) + static constexpr auto Actor4 = 1003999; // ×近衛b ( Pos: 77.310501 2.136910 316.973999 Teri: 141 ) + static constexpr auto Actor5 = 1004000; // ×近衛c ( Pos: 78.402603 2.136520 316.269012 Teri: 141 ) + static constexpr auto Actor6 = 1004001; // Lilira ( Pos: 76.643402 2.136930 318.191010 Teri: 141 ) + static constexpr auto Actor20 = 1006171; // Lilira + static constexpr auto Actor30 = 1006167; // 侍女a + static constexpr auto Actor40 = 1006168; // 近衛a + static constexpr auto Actor50 = 1006169; // 近衛b + static constexpr auto Actor60 = 1006170; // 近衛c + static constexpr auto CutScene02 = 141; + static constexpr auto CutScene03 = 56; + static constexpr auto CutScene04 = 142; + static constexpr auto Eobject0 = 2001853; // ( Pos: 202.638000 14.137900 536.905029 Teri: 141 ) + static constexpr auto EventActionSearch = 1; // Interaction + static constexpr auto Questbattle0 = 37; + static constexpr auto Seq0Actor0Lq = 50; // Goblin Thug + static constexpr auto Territorytype0 = 270; + static constexpr auto Territorytype1 = 141; + + public: + ManWil005() : Sapphire::ScriptAPI::QuestScript( 66086 ){}; + ~ManWil005() = default; + + ////////////////////////////////////////////////////////////////////// + // Event Handlers + void onTalk( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override + { + switch( actorId ) + { + case Actor0: + { + if (quest.getSeq() == Seq0) + { + Scene00000( quest, player ); + } + else if (quest.getSeq() == SeqFinish) + { + Scene00006( quest, player ); + } + + break; + } + case Actor1: + { + if( quest.getSeq() == Seq1 ) + Scene00002( quest, player ); + break; + } + case Actor2: + { + break; + } + case Actor3: + { + break; + } + case Actor4: + { + break; + } + case Actor5: + { + break; + } + case Actor6: + { + break; + } + case Actor20: + { + break; + } + case Actor30: + { + break; + } + case Actor40: + { + break; + } + case Actor50: + { + break; + } + case Actor60: + { + break; + } + } + } + + void onEnterTerritory( World::Quest& quest, Entity::Player& player, uint16_t param1, uint16_t param2 ) override + { + if( quest.getSeq() == Seq2 ) + { + Scene00005( quest, player ); + } + } + + + private: + ////////////////////////////////////////////////////////////////////// + // Available Scenes in this quest, not necessarly all are used + ////////////////////////////////////////////////////////////////////// + + void Scene00000( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 0, HIDE_HOTBAR, bindSceneReturn( &ManWil005::Scene00000Return ) ); + } + + void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + if( result.getResult( 0 ) == 1 ) // accept quest + { + Scene00001( quest, player ); + } + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00001( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 1, FADE_OUT | CONDITION_CUTSCENE | HIDE_UI, bindSceneReturn( &ManWil005::Scene00001Return ) ); + } + + void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + quest.setSeq( Seq1 ); + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00002( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 2, NONE, bindSceneReturn( &ManWil005::Scene00002Return ) ); + } + + void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + if( result.getResult( 0 ) == 1 ) + { + auto& pTeriMgr = Common::Service< Sapphire::World::Manager::TerritoryMgr >::ref(); + + eventMgr().eventFinish( player, result.eventId, 0 ); + pTeriMgr.createAndJoinQuestBattle( player, Questbattle0 ); + } + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00003( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 3, NONE, bindSceneReturn( &ManWil005::Scene00003Return ) ); + } + + void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00004( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 4, NONE, bindSceneReturn( &ManWil005::Scene00004Return ) ); + } + + void Scene00004Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00005( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 5, NO_DEFAULT_CAMERA | CONDITION_CUTSCENE | SILENT_ENTER_TERRI_ENV | HIDE_HOTBAR | SILENT_ENTER_TERRI_BGM | SILENT_ENTER_TERRI_SE | DISABLE_STEALTH | 0x00100000 | LOCK_HUD | LOCK_HOTBAR | + // todo: wtf is 0x00100000 + DISABLE_CANCEL_EMOTE, + bindSceneReturn( &ManWil005::Scene00005Return ) ); + } + + void Scene00005Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + quest.setSeq( SeqFinish ); + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00006( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 6, FADE_OUT | HIDE_HOTBAR | CONDITION_CUTSCENE | HIDE_UI, bindSceneReturn( &ManWil005::Scene00006Return ) ); + } + + void Scene00006Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + if( result.getResult( 0 ) == 1 ) + { + player.finishQuest( getId(), result.getResult( 1 ) ); + } + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00007( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 7, NONE, bindSceneReturn( &ManWil005::Scene00007Return ) ); + } + + void Scene00007Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00008( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 8, NONE, bindSceneReturn( &ManWil005::Scene00008Return ) ); + } + + void Scene00008Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00009( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 9, NONE, bindSceneReturn( &ManWil005::Scene00009Return ) ); + } + + void Scene00009Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00010( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 10, NONE, bindSceneReturn( &ManWil005::Scene00010Return ) ); + } + + void Scene00010Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00011( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 11, NONE, bindSceneReturn( &ManWil005::Scene00011Return ) ); + } + + void Scene00011Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + +}; + +EXPOSE_SCRIPT( ManWil005 ); \ No newline at end of file From 6fb07971c7c7021ab8ef79eb7aa54ddcf37f2759 Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Tue, 9 May 2023 00:09:48 -0700 Subject: [PATCH 22/30] Added ItemIcons to quest notice, logic fixes, set Bitflag8 for SubsSea quests --- src/scripts/quest/subquest/limsa/SubSea002.cpp | 2 +- src/scripts/quest/subquest/limsa/SubSea004.cpp | 3 +++ src/scripts/quest/subquest/limsa/SubSea007.cpp | 3 ++- src/scripts/quest/subquest/limsa/SubSea008.cpp | 14 ++++++++++---- src/scripts/quest/subquest/limsa/SubSea016.cpp | 4 +++- 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/scripts/quest/subquest/limsa/SubSea002.cpp b/src/scripts/quest/subquest/limsa/SubSea002.cpp index 406c22d5b..9ec722922 100644 --- a/src/scripts/quest/subquest/limsa/SubSea002.cpp +++ b/src/scripts/quest/subquest/limsa/SubSea002.cpp @@ -8,7 +8,7 @@ #include // Quest Script: SubSea002_00112 -// Quest Name: Suspiciously SoberF +// Quest Name: Suspiciously Sober // Quest ID: 65648 // Start NPC: 1003604 (Ahldskyf) // End NPC: 1003275 (Frydwyb) diff --git a/src/scripts/quest/subquest/limsa/SubSea004.cpp b/src/scripts/quest/subquest/limsa/SubSea004.cpp index 6b08ea21d..b3e3ccf6b 100644 --- a/src/scripts/quest/subquest/limsa/SubSea004.cpp +++ b/src/scripts/quest/subquest/limsa/SubSea004.cpp @@ -145,6 +145,7 @@ class SubSea004 : public Sapphire::ScriptAPI::QuestScript { eventMgr().sendEventNotice( player, getId(), 0, 0 ); quest.setUI8AL( 1 ); + quest.setBitFlag8( 1, true ); checkQuestCompletion( quest, player, 1 ); } @@ -159,6 +160,7 @@ class SubSea004 : public Sapphire::ScriptAPI::QuestScript { eventMgr().sendEventNotice( player, getId(), 1, 0 ); quest.setUI8BH( 1 ); + quest.setBitFlag8( 2, true ); checkQuestCompletion( quest, player, 1 ); } @@ -173,6 +175,7 @@ class SubSea004 : public Sapphire::ScriptAPI::QuestScript { eventMgr().sendEventNotice( player, getId(), 2, 0 ); quest.setUI8BL( 1 ); + quest.setBitFlag8( 3, true ); checkQuestCompletion( quest, player, 1 ); } diff --git a/src/scripts/quest/subquest/limsa/SubSea007.cpp b/src/scripts/quest/subquest/limsa/SubSea007.cpp index 26feaf983..4475010a8 100644 --- a/src/scripts/quest/subquest/limsa/SubSea007.cpp +++ b/src/scripts/quest/subquest/limsa/SubSea007.cpp @@ -41,6 +41,7 @@ class SubSea007 : public Sapphire::ScriptAPI::QuestScript static constexpr auto Actor1 = 1000957; // R'sushmo ( Pos: -49.240898 43.991699 -146.380005 Teri: 128 ) static constexpr auto Actor2 = 1000937; // Godebert ( Pos: -12.222500 44.998798 -251.850006 Teri: 128 ) static constexpr auto Item0 = 2000455; + static constexpr auto Item0Icon = 25906; public: SubSea007() : Sapphire::ScriptAPI::QuestScript( 65653 ){}; @@ -117,7 +118,7 @@ class SubSea007 : public Sapphire::ScriptAPI::QuestScript void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) { - eventMgr().sendEventNotice( player, getId(), 0, 0 ); // TODO: Show item icon + eventMgr().sendNotice( player, getId(), 0, { Item0Icon } ); quest.setUI8BH( 1 ); quest.setSeq( Seq2 ); } diff --git a/src/scripts/quest/subquest/limsa/SubSea008.cpp b/src/scripts/quest/subquest/limsa/SubSea008.cpp index 6e7c013ea..6a220f83c 100644 --- a/src/scripts/quest/subquest/limsa/SubSea008.cpp +++ b/src/scripts/quest/subquest/limsa/SubSea008.cpp @@ -45,6 +45,7 @@ class SubSea008 : public Sapphire::ScriptAPI::QuestScript static constexpr auto Actor2 = 1000938; // Ginnade ( Pos: -4.651690 45.018398 -241.815002 Teri: 128 ) static constexpr auto Actor3 = 1000947; // Lyngsath ( Pos: -54.642601 43.991699 -151.201996 Teri: 128 ) static constexpr auto Item0 = 2000451; + static constexpr auto Item0Icon = 25919; public: SubSea008() : Sapphire::ScriptAPI::QuestScript( 65654 ){}; @@ -58,7 +59,8 @@ class SubSea008 : public Sapphire::ScriptAPI::QuestScript { case Actor0: { - Scene00000( quest, player ); + if( quest.getSeq() == Seq0 ) + Scene00000( quest, player ); break; } case Actor1: @@ -71,12 +73,14 @@ class SubSea008 : public Sapphire::ScriptAPI::QuestScript } case Actor2: { - Scene00003( quest, player ); + if( quest.getSeq() == Seq2 ) + Scene00003( quest, player ); break; } case Actor3: { - Scene00005( quest, player ); + if( quest.getSeq() == Seq2 ) + Scene00005( quest, player ); break; } } @@ -137,7 +141,7 @@ class SubSea008 : public Sapphire::ScriptAPI::QuestScript void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) { quest.setUI8BL( 1 ); - eventMgr().sendEventNotice( player, getId(), 0, 0 ); //TODO: add item icon + eventMgr().sendNotice( player, getId(), 0, { Item0Icon } ); quest.setSeq( Seq2 ); } @@ -167,6 +171,7 @@ class SubSea008 : public Sapphire::ScriptAPI::QuestScript { eventMgr().sendEventNotice( player, getId(), 1, 0 ); quest.setUI8AL( 1 ); + quest.setBitFlag8( 1, true ); checkQuestCompletion( quest, player, 1 ); } @@ -197,6 +202,7 @@ class SubSea008 : public Sapphire::ScriptAPI::QuestScript { eventMgr().sendEventNotice( player, getId(), 2, 0 ); quest.setUI8BH( 1 ); + quest.setBitFlag8( 2, true ); checkQuestCompletion( quest, player, 1 ); } diff --git a/src/scripts/quest/subquest/limsa/SubSea016.cpp b/src/scripts/quest/subquest/limsa/SubSea016.cpp index bd263eea7..48d8d5c34 100644 --- a/src/scripts/quest/subquest/limsa/SubSea016.cpp +++ b/src/scripts/quest/subquest/limsa/SubSea016.cpp @@ -64,7 +64,8 @@ class SubSea016 : public Sapphire::ScriptAPI::QuestScript } case Actor1: { - Scene00002( quest, player ); + if( quest.getSeq() == Seq1 ) + Scene00002( quest, player ); break; } } @@ -131,6 +132,7 @@ class SubSea016 : public Sapphire::ScriptAPI::QuestScript void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) { eventMgr().sendEventNotice( player, getId(), 0, 0 ); + quest.setBitFlag8( 1, true ); quest.setSeq( SeqFinish ); } From fe140ab2d67711d34da98abf1881286411efd69f Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Tue, 9 May 2023 17:06:50 -0700 Subject: [PATCH 23/30] Added Item Icons to notices in some existing quests - Miner Job Quest - White Mage Quest - MSQ --- src/scripts/quest/classquest/MIN/ClsMin502.cpp | 3 ++- src/scripts/quest/classquest/MIN/ClsMin600.cpp | 3 ++- src/scripts/quest/classquest/WHM/JobWhm001.cpp | 11 +++++++---- src/scripts/quest/classquest/WHM/JobWhm450.cpp | 12 ++++++++---- .../quest/subquest/blackshroud_central/SubFst069.cpp | 3 ++- .../quest/subquest/coerthas_central/GaiUsb808.cpp | 3 ++- src/scripts/quest/subquest/gridania/GaiUsc609.cpp | 6 ++++-- 7 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/scripts/quest/classquest/MIN/ClsMin502.cpp b/src/scripts/quest/classquest/MIN/ClsMin502.cpp index ee1238597..05505cdf3 100644 --- a/src/scripts/quest/classquest/MIN/ClsMin502.cpp +++ b/src/scripts/quest/classquest/MIN/ClsMin502.cpp @@ -45,6 +45,7 @@ class ClsMin502 : public Sapphire::ScriptAPI::QuestScript static constexpr auto Actor4 = 1013231;//Hatchling static constexpr auto BindActor1 = 5896086; static constexpr auto Item0 = 2001726; + static constexpr auto Item0Icon = 26177; static constexpr auto LocBgm1 = 313; public: @@ -137,7 +138,7 @@ class ClsMin502 : public Sapphire::ScriptAPI::QuestScript void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) { quest.setUI8BH( 1 ); - eventMgr().sendEventNotice( player, getId(), 0, 0 );//TODO: Item Icon, probably + eventMgr().sendNotice( player, getId(), 0, { Item0Icon } ); quest.setSeq( Seq2 ); } diff --git a/src/scripts/quest/classquest/MIN/ClsMin600.cpp b/src/scripts/quest/classquest/MIN/ClsMin600.cpp index 7e733494a..df5fd18f0 100644 --- a/src/scripts/quest/classquest/MIN/ClsMin600.cpp +++ b/src/scripts/quest/classquest/MIN/ClsMin600.cpp @@ -56,6 +56,7 @@ class ClsMin600 : public Sapphire::ScriptAPI::QuestScript static constexpr auto Actor7 = 1013961;//Goblin Trader (Seq5) static constexpr auto BindActor1 = 5896328; static constexpr auto Item0 = 2001729; + static constexpr auto Item0Icon = 25919; static constexpr auto LocActor1 = 1013954; static constexpr auto LocActor2 = 1013955; static constexpr auto LocBgm1 = 313; @@ -390,7 +391,7 @@ class ClsMin600 : public Sapphire::ScriptAPI::QuestScript void Scene00019Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) { - eventMgr().sendEventNotice( player, getId(), 5, 0 );//TODO: Item Icon? + eventMgr().sendNotice( player, getId(), 5, { Item0Icon } ); quest.setSeq( SeqFinish ); quest.setUI8BH( 0 ); } diff --git a/src/scripts/quest/classquest/WHM/JobWhm001.cpp b/src/scripts/quest/classquest/WHM/JobWhm001.cpp index 4a809993e..82d987281 100644 --- a/src/scripts/quest/classquest/WHM/JobWhm001.cpp +++ b/src/scripts/quest/classquest/WHM/JobWhm001.cpp @@ -13,7 +13,7 @@ // Quest Script: JobWhm001_01124 // Quest Name: A Relic Reborn (Thyrus) // Quest ID: 66660 -// Start NPC: 1003075 +// Start NPC: 1003075a // End NPC: 1003075 using namespace Sapphire; @@ -101,6 +101,8 @@ class JobWhm001 : public Sapphire::ScriptAPI::QuestScript static constexpr auto Item4 = 2001029; static constexpr auto Item5 = 2001038; static constexpr auto Item6 = 2001047; + static constexpr auto Item0Icon = 21003; + static constexpr auto Item3Icon = 26002; static constexpr auto LocAction0 = 858; static constexpr auto LocAction1 = 995; static constexpr auto LocAction2 = 936; @@ -109,6 +111,7 @@ class JobWhm001 : public Sapphire::ScriptAPI::QuestScript static constexpr auto Ritem0 = 2049;//Madman's Whispering Rod static constexpr auto Ritem1 = 2046;//Unfinished Thyrus static constexpr auto Ritem2 = 6267;//Radz-at-Han Quenching Oil + static constexpr auto Ritem1Icon = 32627; public: JobWhm001() : Sapphire::ScriptAPI::QuestScript( 66660 ){}; @@ -327,7 +330,7 @@ class JobWhm001 : public Sapphire::ScriptAPI::QuestScript void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) { quest.setUI8BH( 1 ); - eventMgr().sendEventNotice( player, getId(), 0, 0 );//TODO:Item Icon + eventMgr().sendNotice( player, getId(), 0, { Item0Icon } ); quest.setSeq( Seq2 ); } @@ -469,7 +472,7 @@ class JobWhm001 : public Sapphire::ScriptAPI::QuestScript void Scene00013Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) { - eventMgr().sendEventNotice( player, getId(), 7, 0 );//TODO: Item Icon + eventMgr().sendNotice( player, getId(), 7, { Item3Icon } ); quest.setSeq( Seq9 ); quest.setUI8BH( 1 ); } @@ -497,7 +500,7 @@ class JobWhm001 : public Sapphire::ScriptAPI::QuestScript void Scene00015Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) { quest.setUI8BH( 0 ); - eventMgr().sendEventNotice( player, getId(), 8, 0 );//TODO: Item Icon? + eventMgr().sendNotice( player, getId(), 8, { Ritem1Icon } ); player.addItem( Ritem1 ); quest.setSeq( Seq10 ); } diff --git a/src/scripts/quest/classquest/WHM/JobWhm450.cpp b/src/scripts/quest/classquest/WHM/JobWhm450.cpp index 4953a2142..fae06547b 100644 --- a/src/scripts/quest/classquest/WHM/JobWhm450.cpp +++ b/src/scripts/quest/classquest/WHM/JobWhm450.cpp @@ -80,6 +80,10 @@ class JobWhm450 : public Sapphire::ScriptAPI::QuestScript static constexpr auto Ritem1 = 3894; static constexpr auto Ritem2 = 3463; static constexpr auto Ritem3 = 2902; + static constexpr auto Ritem0Icon = 48242; + static constexpr auto Ritem1Icon = 48219; + static constexpr auto Ritem2Icon = 45189; + static constexpr auto Ritem3Icon = 40616; static constexpr auto VfxReaction = 177; public: @@ -214,7 +218,7 @@ class JobWhm450 : public Sapphire::ScriptAPI::QuestScript void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) { - eventMgr().sendEventNotice( player, getId(), 0, 0 );//TODO:Item Icon, Cleric's Gloves + eventMgr().sendNotice( player, getId(), 0, { Ritem0Icon } ); playerMgr().sendLogMessage( player, Logmessage0 ); quest.setUI8AL( 1 ); quest.setUI8CH( 0 ); @@ -241,7 +245,7 @@ class JobWhm450 : public Sapphire::ScriptAPI::QuestScript void Scene00005Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) { - eventMgr().sendEventNotice( player, getId(), 1, 0 );//TODO:Item Icon, Cleric's Culottes + eventMgr().sendNotice( player, getId(), 1, { Ritem2Icon } ); playerMgr().sendLogMessage( player, Logmessage0 ); quest.setUI8BH( 1 ); quest.setUI8CL( 0 ); @@ -268,7 +272,7 @@ class JobWhm450 : public Sapphire::ScriptAPI::QuestScript void Scene00007Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) { - eventMgr().sendEventNotice( player, getId(), 2, 0 );//TODO:Item Icon, Cleric's Boots + eventMgr().sendNotice( player, getId(), 2, {Ritem1Icon} ); playerMgr().sendLogMessage( player, Logmessage0 ); quest.setUI8BL( 1 ); quest.setUI8DH( 0 ); @@ -436,7 +440,7 @@ class JobWhm450 : public Sapphire::ScriptAPI::QuestScript void Scene00021Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) { - eventMgr().sendEventNotice( player, getId(), 6, 0 );//TODO:Item Icon, Cleric's Circlet + eventMgr().sendNotice( player, getId(), 6, { Ritem3Icon } ); playerMgr().sendLogMessage( player, Logmessage0 ); quest.setSeq( SeqFinish ); quest.setUI8BH( 0 ); diff --git a/src/scripts/quest/subquest/blackshroud_central/SubFst069.cpp b/src/scripts/quest/subquest/blackshroud_central/SubFst069.cpp index 855624f10..14a68e7b4 100644 --- a/src/scripts/quest/subquest/blackshroud_central/SubFst069.cpp +++ b/src/scripts/quest/subquest/blackshroud_central/SubFst069.cpp @@ -39,6 +39,7 @@ class SubFst069 : public Sapphire::ScriptAPI::QuestScript static constexpr auto Eobject0 = 2000685;//Well-worn Fishing Rod static constexpr auto EventActionSearch = 1; static constexpr auto Item0 = 2000185; + static constexpr auto Item0Icon = 38201; static constexpr auto Seq0Actor0 = 0; static constexpr auto Seq1Eobject0 = 1; static constexpr auto Seq1Eobject0Eventactionno = 99; @@ -169,7 +170,7 @@ class SubFst069 : public Sapphire::ScriptAPI::QuestScript void Scene00100Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) { - eventMgr().sendEventNotice( player, getId(), 0, 0 );//TODO: Probably Item Icon + eventMgr().sendNotice( player, getId(), 0, { Item0Icon } ); quest.setUI8BH( 1 ); quest.setSeq( SeqFinish ); } diff --git a/src/scripts/quest/subquest/coerthas_central/GaiUsb808.cpp b/src/scripts/quest/subquest/coerthas_central/GaiUsb808.cpp index 5ef10f234..3630fb8f4 100644 --- a/src/scripts/quest/subquest/coerthas_central/GaiUsb808.cpp +++ b/src/scripts/quest/subquest/coerthas_central/GaiUsb808.cpp @@ -55,6 +55,7 @@ class GaiUsb808 : public Sapphire::ScriptAPI::QuestScript static constexpr auto Item0 = 2000720; static constexpr auto Item1 = 2000721; static constexpr auto Item2 = 2000722; + static constexpr auto Item0Icon = 26002; public: GaiUsb808() : Sapphire::ScriptAPI::QuestScript( 66453 ){}; @@ -162,7 +163,7 @@ class GaiUsb808 : public Sapphire::ScriptAPI::QuestScript void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) { - eventMgr().sendEventNotice( player, getId(), 1, 0 );//TODO:Show Item Icon (Needs func update) + eventMgr().sendNotice( player, getId(), 1, { Item0Icon } ); quest.setUI8BH( 1 ); quest.setSeq( Seq3 ); } diff --git a/src/scripts/quest/subquest/gridania/GaiUsc609.cpp b/src/scripts/quest/subquest/gridania/GaiUsc609.cpp index 7b1b10471..a5cff6f2d 100644 --- a/src/scripts/quest/subquest/gridania/GaiUsc609.cpp +++ b/src/scripts/quest/subquest/gridania/GaiUsc609.cpp @@ -61,6 +61,8 @@ class GaiUsc609 : public Sapphire::ScriptAPI::QuestScript static constexpr auto EventActionSearch = 1; static constexpr auto Item0 = 2000963; static constexpr auto Item1 = 2000965; + static constexpr auto Item0Icon = 22614; + static constexpr auto Item1Icon = 21452; static constexpr auto Poprange0 = 3884000; static constexpr auto Territorytype0 = 204; @@ -263,7 +265,7 @@ class GaiUsc609 : public Sapphire::ScriptAPI::QuestScript void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) { - eventMgr().sendEventNotice( player, getId(), 0, 0 ); + eventMgr().sendNotice( player, getId(), 0, { Item0Icon } ); quest.setUI8BH( 1 ); quest.setSeq( Seq2 ); } @@ -393,7 +395,7 @@ class GaiUsc609 : public Sapphire::ScriptAPI::QuestScript { quest.setSeq( Seq4 ); quest.setUI8BH( 1 ); - eventMgr().sendEventNotice( player, getId(), 2, 0 /*1, Item1*/ );//TODO:Item Icon Event Notice + eventMgr().sendNotice( player, getId(), 2, { Item1Icon } ); } ////////////////////////////////////////////////////////////////////// From 8581a96a4024baf8e85e3dc08001f5d74a3c4e46 Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Wed, 10 May 2023 02:30:56 -0700 Subject: [PATCH 24/30] Central Thanalan SubWil MSQ pt.1 --- .../subquest/thanalan_central/SubWil025.cpp | 324 ++++++++++++++++++ .../subquest/thanalan_central/SubWil060.cpp | 194 +++++++++++ .../subquest/thanalan_central/SubWil062.cpp | 171 +++++++++ .../subquest/thanalan_central/SubWil063.cpp | 103 ++++++ .../subquest/thanalan_central/SubWil064.cpp | 315 +++++++++++++++++ .../subquest/thanalan_central/SubWil070.cpp | 233 +++++++++++++ 6 files changed, 1340 insertions(+) create mode 100644 src/scripts/quest/subquest/thanalan_central/SubWil025.cpp create mode 100644 src/scripts/quest/subquest/thanalan_central/SubWil060.cpp create mode 100644 src/scripts/quest/subquest/thanalan_central/SubWil062.cpp create mode 100644 src/scripts/quest/subquest/thanalan_central/SubWil063.cpp create mode 100644 src/scripts/quest/subquest/thanalan_central/SubWil064.cpp create mode 100644 src/scripts/quest/subquest/thanalan_central/SubWil070.cpp diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil025.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil025.cpp new file mode 100644 index 000000000..aba1d54dd --- /dev/null +++ b/src/scripts/quest/subquest/thanalan_central/SubWil025.cpp @@ -0,0 +1,324 @@ +// This is an automatically generated C++ script template +// Content needs to be added by hand to make it function +// In order for this script to be loaded, move it to the correct folder in /scripts/ + +#include "Manager/EventMgr.h" +#include +#include +#include + +// Quest Script: SubWil025_00671 +// Quest Name: Nothing to See Here +// Quest ID: 66207 +// Start NPC: 1003995 (Papashan) +// End NPC: 1003995 (Papashan) + +using namespace Sapphire; + +class SubWil025 : public Sapphire::ScriptAPI::QuestScript +{ +private: + // Basic quest information + // Quest vars / flags used + // BitFlag8 + // UI8AH + // UI8AL + // UI8BH + // UI8BL + // UI8CH + // UI8CL + + /// Countable Num: 0 Seq: 1 Event: 1 Listener: 1004599 + /// Countable Num: 0 Seq: 255 Event: 1 Listener: 1004600 + // Steps in this quest ( 0 is before accepting, + // 1 is first, 255 means ready for turning it in + enum Sequence : uint8_t + { + Seq0 = 0, + Seq1 = 1, + SeqFinish = 255, + }; + + // Entities found in the script data of the quest + static constexpr auto Actor0 = 1003995;// Papashan ( Pos: 75.338402 2.138110 316.362000 Teri: 141 ) + static constexpr auto Actor1 = 1004599;// Stern Sultansworn ( Pos: 89.876198 4.633540 425.415009 Teri: 141 ) + static constexpr auto Actor2 = 1004600;// Serious Sultansworn ( Pos: 126.024002 14.465300 278.462006 Teri: 141 ) + static constexpr auto Actor3 = 1004601;// Servile Sultansworn ( Pos: -62.415001 4.641350 261.281006 Teri: 141 ) + static constexpr auto Item0 = 2000463; + +public: + SubWil025() : Sapphire::ScriptAPI::QuestScript( 66207 ){}; + ~SubWil025() = default; + + ////////////////////////////////////////////////////////////////////// + // Event Handlers + void onTalk( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override + { + switch( actorId ) + { + case Actor0: + { + if( quest.getSeq() == Seq0 ) + Scene00000( quest, player ); + else if( quest.getSeq() == SeqFinish ) + Scene00010( quest, player ); + break; + } + + case Actor1: + { + if( quest.getSeq() == Seq1 ) + { + if( quest.getUI8AL() == 0 ) + Scene00001( quest, player ); + else + Scene00003( quest, player ); + } + else if( quest.getSeq() == SeqFinish ) + { + Scene00011( quest, player ); + } + break; + } + + case Actor2: + { + if( quest.getSeq() == Seq1 ) + { + if( quest.getUI8BH() == 0 ) + Scene00004( quest, player ); + else + Scene00006( quest, player ); + } + else if( quest.getSeq() == SeqFinish ) + { + Scene00012( quest, player ); + } + break; + } + + case Actor3: + { + if( quest.getSeq() == Seq1 ) + { + if( quest.getUI8BL() == 0 ) + Scene00007( quest, player ); + else + Scene00009( quest, player ); + } + break; + } + } + } + + void onEventItem( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override + { + } + + +private: + void checkQuestCompletion( World::Quest& quest, Entity::Player& player, uint32_t varIdx ) + { + if( varIdx == 1 ) + { + quest.setUI8AH( quest.getUI8AH() + 1 ); + quest.setUI8CH( quest.getUI8CH() - 1 ); + auto actor1Talked = quest.getUI8AL(); + auto actor2Talked = quest.getUI8BH(); + auto actor3Talked = quest.getUI8BL(); + if( actor1Talked && actor2Talked && actor3Talked ) + { + quest.setSeq( SeqFinish ); + } + eventMgr().sendEventNotice( player, getId(), 0, 2, quest.getUI8AH(), 3 ); + } + } + ////////////////////////////////////////////////////////////////////// + // Available Scenes in this quest, not necessarly all are used + ////////////////////////////////////////////////////////////////////// + + void Scene00000( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 0, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00000Return ) ); + } + + void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + if( result.getResult( 0 ) == 1 )// accept quest + { + quest.setSeq( Seq1 ); + quest.setUI8CH( 3 ); + } + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00001( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 1, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00001Return ) ); + } + + void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + if( result.getResult( 0 ) == 1 ) + { + Scene00002( quest, player ); + } + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00002( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 2, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00002Return ) ); + } + + void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + quest.setUI8AL( 1 ); + quest.setBitFlag8( 1, true ); + checkQuestCompletion( quest, player, 1 ); + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00003( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 3, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00003Return ) ); + } + + void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00004( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 4, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00004Return ) ); + } + + void Scene00004Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + if( result.getResult( 0 ) == 1 ) + { + Scene00005( quest, player ); + } + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00005( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 5, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00005Return ) ); + } + + void Scene00005Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + quest.setUI8BH( 1 ); + quest.setBitFlag8( 2, true ); + checkQuestCompletion( quest, player, 1 ); + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00006( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 6, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00006Return ) ); + } + + void Scene00006Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00007( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 7, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00007Return ) ); + } + + void Scene00007Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + if( result.getResult( 0 ) == 1 ) + { + Scene00008( quest, player ); + } + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00008( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 8, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00008Return ) ); + } + + void Scene00008Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + quest.setUI8BL( 1 ); + quest.setBitFlag8( 3, true ); + checkQuestCompletion( quest, player, 1 ); + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00009( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 9, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00009Return ) ); + } + + void Scene00009Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00010( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 10, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00010Return ) ); + } + + void Scene00010Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + if( result.getResult( 0 ) == 1 ) + { + player.finishQuest( getId(), result.getResult( 1 ) ); + } + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00011( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 11, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00011Return ) ); + } + + void Scene00011Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00012( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 12, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00012Return ) ); + } + + void Scene00012Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00013( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 13, HIDE_HOTBAR, bindSceneReturn( &SubWil025::Scene00013Return ) ); + } + + void Scene00013Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + } +}; + +EXPOSE_SCRIPT( SubWil025 ); \ No newline at end of file diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil060.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil060.cpp new file mode 100644 index 000000000..7d04b507a --- /dev/null +++ b/src/scripts/quest/subquest/thanalan_central/SubWil060.cpp @@ -0,0 +1,194 @@ +// This is an automatically generated C++ script template +// Content needs to be added by hand to make it function +// In order for this script to be loaded, move it to the correct folder in /scripts/ + +#include +#include "Manager/EventMgr.h" +#include +#include + +// Quest Script: SubWil060_00303 +// Quest Name: Step Nine +// Quest ID: 65839 +// Start NPC: 1001500 (Cicidoa) +// End NPC: 1001541 (Roger) + +using namespace Sapphire; + +class SubWil060 : public Sapphire::ScriptAPI::QuestScript +{ + private: + // Basic quest information + // Quest vars / flags used + // UI8AL + // UI8BH + // UI8BL + + /// Countable Num: 1 Seq: 1 Event: 1 Listener: 1001455 + /// Countable Num: 1 Seq: 255 Event: 1 Listener: 1001541 + // Steps in this quest ( 0 is before accepting, + // 1 is first, 255 means ready for turning it in + enum Sequence : uint8_t + { + Seq0 = 0, + Seq1 = 1, + SeqFinish = 255, + }; + + // Entities found in the script data of the quest + static constexpr auto Actor0 = 1001500; // Cicidoa ( Pos: 81.792099 1.050750 311.240997 Teri: 141 ) + static constexpr auto Actor1 = 1001455; // Gagari ( Pos: 59.952599 0.999894 255.863998 Teri: 141 ) + static constexpr auto Actor2 = 1001541; // Roger ( Pos: -99.395401 -11.380900 -41.723999 Teri: 141 ) + static constexpr auto Item0 = 2000199; + static constexpr auto Item1 = 2000238; + static constexpr auto Item1Icon = 25210; + + public: + SubWil060() : Sapphire::ScriptAPI::QuestScript( 65839 ){}; + ~SubWil060() = default; + + ////////////////////////////////////////////////////////////////////// + // Event Handlers + void onTalk( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override + { + switch( actorId ) + { + case Actor0: + { + if( quest.getSeq() == Seq0 ) + Scene00000( quest, player ); + break; + } + case Actor1: + { + if( quest.getSeq() == Seq1 ) + Scene00001( quest, player ); + break; + } + case Actor2: + { + if( quest.getSeq() == SeqFinish ) + Scene00004( quest, player ); + break; + } + } + } + + void onEventItem( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override + { + } + + + private: + ////////////////////////////////////////////////////////////////////// + // Available Scenes in this quest, not necessarly all are used + ////////////////////////////////////////////////////////////////////// + + void Scene00000( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 0, HIDE_HOTBAR, bindSceneReturn( &SubWil060::Scene00000Return ) ); + } + + void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + if( result.getResult( 0 ) == 1 ) // accept quest + { + quest.setUI8BH( 1 ); + quest.setSeq( Seq1 ); + } + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00001( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 1, HIDE_HOTBAR, bindSceneReturn( &SubWil060::Scene00001Return ) ); + } + + void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + if( result.getResult( 0 ) == 1 ) + { + Scene00002( quest, player ); + } + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00002( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 2, HIDE_HOTBAR, bindSceneReturn( &SubWil060::Scene00002Return ) ); + } + + void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + quest.setUI8BH( 0 ); + quest.setUI8BL( 1 ); + eventMgr().sendNotice( player, getId(), 0, { Item1Icon } ); + quest.setSeq( SeqFinish ); + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00003( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 3, NONE, bindSceneReturn( &SubWil060::Scene00003Return ) ); + } + + void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00004( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 4, HIDE_HOTBAR, bindSceneReturn( &SubWil060::Scene00004Return ) ); + } + + void Scene00004Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + if( result.getResult( 0 ) == 1 ) + { + Scene00005( quest, player ); + } + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00005( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 5, HIDE_HOTBAR, bindSceneReturn( &SubWil060::Scene00005Return ) ); + } + + void Scene00005Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + if( result.getResult( 0 ) == 1 ) + { + player.finishQuest( getId(), result.getResult( 1 ) ); + } + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00006( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 6, NONE, bindSceneReturn( &SubWil060::Scene00006Return ) ); + } + + void Scene00006Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + +}; + +EXPOSE_SCRIPT( SubWil060 ); \ No newline at end of file diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil062.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil062.cpp new file mode 100644 index 000000000..e393a57e5 --- /dev/null +++ b/src/scripts/quest/subquest/thanalan_central/SubWil062.cpp @@ -0,0 +1,171 @@ +// This is an automatically generated C++ script template +// Content needs to be added by hand to make it function +// In order for this script to be loaded, move it to the correct folder in /scripts/ + +#include "Manager/EventMgr.h" +#include +#include +#include +#include + +// Quest Script: SubWil062_00305 +// Quest Name: Until a Quieter Time +// Quest ID: 65841 +// Start NPC: 1001541 (Roger) +// End NPC: 1001447 (Warin) + +using namespace Sapphire; + +class SubWil062 : public Sapphire::ScriptAPI::QuestScript +{ + private: + // Basic quest information + // Quest vars / flags used + // UI8AL + // UI8BH + + /// Countable Num: 8 Seq: 1 Event: 9 Listener: 432 + /// Countable Num: 1 Seq: 255 Event: 1 Listener: 1001447 + // Steps in this quest ( 0 is before accepting, + // 1 is first, 255 means ready for turning it in + enum Sequence : uint8_t + { + Seq0 = 0, + Seq1 = 1, + SeqFinish = 255, + }; + + // Entities found in the script data of the quest + static constexpr auto Actor0 = 1001541; // Roger ( Pos: -99.395401 -11.380900 -41.723999 Teri: 141 ) + static constexpr auto Actor1 = 1001447; // Warin ( Pos: -32.639099 -1.033260 -148.485992 Teri: 141 ) + static constexpr auto Enemy0 = 294; // Antling Worker + static constexpr auto Item0 = 2000168; + static constexpr auto Item0Icon = 22205; + + public: + SubWil062() : Sapphire::ScriptAPI::QuestScript( 65841 ){}; + ~SubWil062() = default; + + ////////////////////////////////////////////////////////////////////// + // Event Handlers + void onTalk( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override + { + switch( actorId ) + { + case Actor0: + { + if( quest.getSeq() == Seq0 ) + Scene00000( quest, player ); + break; + } + case Actor1: + { + if( quest.getSeq() == SeqFinish ) + Scene00002( quest, player ); + break; + } + } + } + + void onEventItem( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override + { + } + + void onBNpcKill( World::Quest& quest, Entity::BNpc& bnpc, Entity::Player& player ) override + { + if( bnpc.getBNpcNameId() != Enemy0 ) + return; + + unsigned currentKC = quest.getUI8AL() + 1; + quest.setUI8BH( currentKC ); + quest.setUI8AL( currentKC ); + + if( currentKC >= 5 ) + quest.setSeq( SeqFinish ); + + eventMgr().sendNotice( player, getId(), 0, { currentKC, 5, Item0Icon } ); + } + + private: + ////////////////////////////////////////////////////////////////////// + // Available Scenes in this quest, not necessarly all are used + ////////////////////////////////////////////////////////////////////// + + void Scene00000( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 0, NONE, bindSceneReturn( &SubWil062::Scene00000Return ) ); + } + + void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + if( result.getResult( 0 ) == 1 ) // accept quest + { + quest.setUI8AL( 0 ); + quest.setSeq( Seq1 ); + } + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00001( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 1, NONE, bindSceneReturn( &SubWil062::Scene00001Return ) ); + } + + void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00002( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 2, NONE, bindSceneReturn( &SubWil062::Scene00002Return ) ); + } + + void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + if( result.getResult( 0 ) == 1 ) + { + quest.setUI8BH( 0 ); + Scene00003( quest, player ); + } + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00003( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 3, NONE, bindSceneReturn( &SubWil062::Scene00003Return ) ); + } + + void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + if( result.getResult( 0 ) == 1 ) + { + player.finishQuest( getId(), result.getResult( 1 ) ); + } + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00004( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 4, NONE, bindSceneReturn( &SubWil062::Scene00004Return ) ); + } + + void Scene00004Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + +}; + +EXPOSE_SCRIPT( SubWil062 ); \ No newline at end of file diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil063.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil063.cpp new file mode 100644 index 000000000..404393e1f --- /dev/null +++ b/src/scripts/quest/subquest/thanalan_central/SubWil063.cpp @@ -0,0 +1,103 @@ +// This is an automatically generated C++ script template +// Content needs to be added by hand to make it function +// In order for this script to be loaded, move it to the correct folder in /scripts/ + +#include +#include "Manager/EventMgr.h" +#include +#include + +// Quest Script: SubWil063_00306 +// Quest Name: Prudence at This Junction +// Quest ID: 65842 +// Start NPC: 1001447 (Warin) +// End NPC: 1001447 (Warin) + +using namespace Sapphire; + +class SubWil063 : public Sapphire::ScriptAPI::QuestScript +{ + private: + // Basic quest information + // Quest vars / flags used + // UI8AL + + /// Countable Num: 1 Seq: 255 Event: 1 Listener: 1001447 + // Steps in this quest ( 0 is before accepting, + // 1 is first, 255 means ready for turning it in + enum Sequence : uint8_t + { + Seq0 = 0, + SeqFinish = 255, + }; + + // Entities found in the script data of the quest + static constexpr auto Actor0 = 1001447; // Warin ( Pos: -32.639099 -1.033260 -148.485992 Teri: 141 ) + static constexpr auto Seq0Actor0 = 0; // + static constexpr auto Seq1Actor0 = 1; // + + public: + SubWil063() : Sapphire::ScriptAPI::QuestScript( 65842 ){}; + ~SubWil063() = default; + + ////////////////////////////////////////////////////////////////////// + // Event Handlers + void onTalk( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override + { + switch( actorId ) + { + case Actor0: + { + if( quest.getSeq() == Seq0 ) + Scene00000( quest, player ); + else if( quest.getSeq() == SeqFinish ) + Scene00001( quest, player ); + break; + } + } + } + + void onEventItem( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override + { + } + + + private: + ////////////////////////////////////////////////////////////////////// + // Available Scenes in this quest, not necessarly all are used + ////////////////////////////////////////////////////////////////////// + + void Scene00000( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 0, NONE, bindSceneReturn( &SubWil063::Scene00000Return ) ); + } + + void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + if( result.getResult( 0 ) == 1 ) // accept quest + { + quest.setSeq( SeqFinish ); + eventMgr().sendNotice( player, getId(), 0, {} ); + } + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00001( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 1, NONE, bindSceneReturn( &SubWil063::Scene00001Return ) ); + } + + void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + if( result.getResult( 0 ) == 1 ) + { + player.finishQuest( getId(), result.getResult( 1 ) ); + } + + } + +}; + +EXPOSE_SCRIPT( SubWil063 ); \ No newline at end of file diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil064.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil064.cpp new file mode 100644 index 000000000..c614aa306 --- /dev/null +++ b/src/scripts/quest/subquest/thanalan_central/SubWil064.cpp @@ -0,0 +1,315 @@ +// This is an automatically generated C++ script template +// Content needs to be added by hand to make it function +// In order for this script to be loaded, move it to the correct folder in /scripts/ + +#include "Manager/EventMgr.h" +#include +#include +#include +#include + +#include "Actor/BNpc.h" +#include "Manager/TerritoryMgr.h" +#include "Territory/Territory.h" + +// Quest Script: SubWil064_00307 +// Quest Name: Out of House and Home +// Quest ID: 65843 +// Start NPC: 1001447 (Warin) +// End NPC: 1001447 (Warin) + +using namespace Sapphire; + +class SubWil064 : public Sapphire::ScriptAPI::QuestScript +{ +private: + // Basic quest information + // Quest vars / flags used + // BitFlag8 + // UI8AL + // UI8BH + + /// Countable Num: 0 Seq: 1 Event: 1 Listener: 2000268 + /// Countable Num: 1 Seq: 255 Event: 8 Listener: 2000268 + // Steps in this quest ( 0 is before accepting, + // 1 is first, 255 means ready for turning it in + enum Sequence : uint8_t + { + Seq0 = 0, + Seq1 = 1, + SeqFinish = 255, + }; + + // Entities found in the script data of the quest + static constexpr auto Actor0 = 1001447; // Warin ( Pos: -32.639099 -1.033260 -148.485992 Teri: 141 ) + static constexpr auto Enemy0 = 3785130; // + static constexpr auto Enemy1 = 3785131; // + static constexpr auto Enemy2 = 3785134; // + static constexpr auto Eobject0 = 2000268; // Narrow Fissure ( Pos: 25.690800 13.106300 47.828999 Teri: 141 ) + static constexpr auto Item0 = 2000212; + + public: + SubWil064() : Sapphire::ScriptAPI::QuestScript( 65843 ){}; + ~SubWil064() = default; + + ////////////////////////////////////////////////////////////////////// + // Event Handlers + void onTalk( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override + { + switch( actorId ) + { + case Actor0: + { + if( quest.getSeq() == Seq0 ) + { + Scene00000( quest, player ); + } + else if( quest.getSeq() == SeqFinish ) + { + Scene00013( quest,player ); + } + break; + } + } + } + + void onEventItem( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override + { + if (actorId == Eobject0) + { + Scene00002( quest, player ); + } + } + + void onBNpcKill( World::Quest& quest, Entity::BNpc& bnpc, Entity::Player& player ) override + { + switch( bnpc.getLayoutId() ) + { + case Enemy0: + { + auto instance = teriMgr().getTerritoryByGuId( player.getTerritoryId() ); + auto enemy1 = instance->createBNpcFromLayoutId( Enemy1, 1220 /*Find the right value*/, Common::BNpcType::Enemy ); + auto enemy2 = instance->createBNpcFromLayoutId( Enemy2, 1220 /*Find the right value*/, Common::BNpcType::Enemy ); + + enemy1->setTriggerOwnerId( player.getId() ); + enemy2->setTriggerOwnerId( player.getId() ); + enemy1->hateListAddDelayed( player.getAsPlayer(), 1 ); + enemy2->hateListAddDelayed( player.getAsPlayer(), 1 ); + quest.setUI8AL( 1 ); + break; + } + case Enemy1: + case Enemy2: + { + quest.setUI8AL( quest.getUI8AL() + 1 ); + if( quest.getUI8AL() >= 4 ) + { + quest.setUI8BH( 0 ); + quest.setUI8AL( 0 ); + quest.setSeq( SeqFinish ); + eventMgr().sendNotice( player, getId(), 0, {} ); + } + break; + } + } + } + + private: + ////////////////////////////////////////////////////////////////////// + // Available Scenes in this quest, not necessarly all are used + ////////////////////////////////////////////////////////////////////// + + void Scene00000( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 0, NONE, bindSceneReturn( &SubWil064::Scene00000Return ) ); + } + + void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + if( result.getResult( 0 ) == 1 ) // accept quest + { + Scene00001( quest, player ); + } + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00001( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 1, NONE, bindSceneReturn( &SubWil064::Scene00001Return ) ); + } + + void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + quest.setUI8BH( 1 ); + quest.setSeq( Seq1 ); + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00002( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 2, NONE, bindSceneReturn( &SubWil064::Scene00002Return ) ); + } + + void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + quest.setBitFlag8( 1, true ); + auto instance = teriMgr().getTerritoryByGuId( player.getTerritoryId() ); + auto enemy0 = instance->createBNpcFromLayoutId( Enemy0, 1220 /*Find the right value*/, Common::BNpcType::Enemy ); + enemy0->setTriggerOwnerId( player.getId() ); + enemy0->hateListAddDelayed( player.getAsPlayer(), 1 ); + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00003( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 3, NONE, bindSceneReturn( &SubWil064::Scene00003Return ) ); + } + + void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00004( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 4, NONE, bindSceneReturn( &SubWil064::Scene00004Return ) ); + } + + void Scene00004Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00005( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 5, NONE, bindSceneReturn( &SubWil064::Scene00005Return ) ); + } + + void Scene00005Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00006( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 6, NONE, bindSceneReturn( &SubWil064::Scene00006Return ) ); + } + + void Scene00006Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00007( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 7, NONE, bindSceneReturn( &SubWil064::Scene00007Return ) ); + } + + void Scene00007Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00008( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 8, NONE, bindSceneReturn( &SubWil064::Scene00008Return ) ); + } + + void Scene00008Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00009( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 9, NONE, bindSceneReturn( &SubWil064::Scene00009Return ) ); + } + + void Scene00009Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00010( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 10, NONE, bindSceneReturn( &SubWil064::Scene00010Return ) ); + } + + void Scene00010Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00011( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 11, NONE, bindSceneReturn( &SubWil064::Scene00011Return ) ); + } + + void Scene00011Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00012( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 12, NONE, bindSceneReturn( &SubWil064::Scene00012Return ) ); + } + + void Scene00012Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00013( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 13, NONE, bindSceneReturn( &SubWil064::Scene00013Return ) ); + } + + void Scene00013Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + if( result.getResult( 0 ) == 1 ) + { + player.finishQuest( getId(), result.getResult( 1 ) ); + } + + } + +}; + +EXPOSE_SCRIPT( SubWil064 ); \ No newline at end of file diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil070.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil070.cpp new file mode 100644 index 000000000..eb43c4107 --- /dev/null +++ b/src/scripts/quest/subquest/thanalan_central/SubWil070.cpp @@ -0,0 +1,233 @@ +// This is an automatically generated C++ script template +// Content needs to be added by hand to make it function +// In order for this script to be loaded, move it to the correct folder in /scripts/ + +#include +#include "Manager/EventMgr.h" +#include +#include + +// Quest Script: SubWil070_00324 +// Quest Name: Disorderly Conduct +// Quest ID: 65860 +// Start NPC: 1001541 (Roger) +// End NPC: 1001541 (Roger) + +using namespace Sapphire; + +class SubWil070 : public Sapphire::ScriptAPI::QuestScript +{ + private: + // Basic quest information + // Quest vars / flags used + // BitFlag8 + // UI8AL + // UI8BH + + /// Countable Num: 4 Seq: 1 Event: 1 Listener: 1001462 + /// Countable Num: 1 Seq: 255 Event: 1 Listener: 1001463 + // Steps in this quest ( 0 is before accepting, + // 1 is first, 255 means ready for turning it in + enum Sequence : uint8_t + { + Seq0 = 0, + Seq1 = 1, + SeqFinish = 255, + }; + + // Entities found in the script data of the quest + static constexpr auto Actor0 = 1001541; // Roger ( Pos: -99.395401 -11.380900 -41.723999 Teri: 141 ) + static constexpr auto Actor1 = 1001462; // Roundelph ( Pos: -93.339500 -11.350300 -41.367199 Teri: 141 ) + static constexpr auto Actor2 = 1001463; // Adalfuns ( Pos: -72.826401 -12.667800 -54.076199 Teri: 141 ) + static constexpr auto Actor3 = 1001465; // Solid Trunk ( Pos: -90.043503 -11.398500 -53.666000 Teri: 141 ) + static constexpr auto Actor4 = 1001466; // Ricard ( Pos: -89.735001 -11.350000 -51.539902 Teri: 141 ) + static constexpr auto Item0 = 2000234; + static constexpr auto Seq0Actor0 = 0; + static constexpr auto Seq1Actor1 = 1; + static constexpr auto Seq1Actor2 = 2; + static constexpr auto Seq1Actor3 = 3; + static constexpr auto Seq1Actor4 = 4; + static constexpr auto Seq2Actor0 = 5; + static constexpr auto Seq2Actor0Npctradeno = 99; + static constexpr auto Seq2Actor0Npctradeok = 100; + + public: + SubWil070() : Sapphire::ScriptAPI::QuestScript( 65860 ){}; + ~SubWil070() = default; + + ////////////////////////////////////////////////////////////////////// + // Event Handlers + void onTalk( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override + { + switch( actorId ) + { + case Actor0: + { + if( quest.getSeq() == 0 ) + Scene00000( quest, player ); + else if( quest.getSeq() == SeqFinish ) + Scene00005( quest, player ); + break; + } + case Actor1: + { + if( quest.getSeq() == 1 ) + Scene00001( quest, player ); + break; + } + case Actor2: + { + if( quest.getSeq() == 1 ) + Scene00002( quest, player ); + break; + } + case Actor3: + { + if( quest.getSeq() == 1 ) + Scene00003( quest, player ); + break; + } + case Actor4: + { + if( quest.getSeq() == 1 ) + Scene00004( quest, player ); + break; + } + } + } + + void onEventItem( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override + { + } + + + private: + void checkQuestCompletion( World::Quest& quest, Entity::Player& player, uint32_t varIdx ) + { + if( varIdx == 1 ) + { + quest.setUI8AL( quest.getUI8AL() + 1 ); + if (quest.getUI8AL() == 4) + quest.setSeq( SeqFinish ); + } + eventMgr().sendEventNotice( player, getId(), 0, 2, quest.getUI8AL(), 4 ); // TODO: Add item icon (Oily Order Slip) + } + ////////////////////////////////////////////////////////////////////// + // Available Scenes in this quest, not necessarly all are used + ////////////////////////////////////////////////////////////////////// + + void Scene00000( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 0, HIDE_HOTBAR, bindSceneReturn( &SubWil070::Scene00000Return ) ); + } + + void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + if( result.getResult( 0 ) == 1 ) // accept quest + { + quest.setUI8BH( 1 ); + quest.setSeq( Seq1 ); + } + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00001( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 1, HIDE_HOTBAR, bindSceneReturn( &SubWil070::Scene00001Return ) ); + } + + void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + checkQuestCompletion( quest, player, 1 ); + quest.setBitFlag8( 1, true ); + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00002( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 2, HIDE_HOTBAR, bindSceneReturn( &SubWil070::Scene00002Return ) ); + } + + void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + checkQuestCompletion( quest, player, 1 ); + quest.setBitFlag8( 2, true ); + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00003( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 3, HIDE_HOTBAR, bindSceneReturn( &SubWil070::Scene00003Return ) ); + } + + void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + checkQuestCompletion( quest, player, 1 ); + quest.setBitFlag8( 3, true ); + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00004( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 4, HIDE_HOTBAR, bindSceneReturn( &SubWil070::Scene00004Return ) ); + } + + void Scene00004Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + checkQuestCompletion( quest, player, 1 ); + quest.setBitFlag8( 4, true ); + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00005( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 5, NONE, bindSceneReturn( &SubWil070::Scene00005Return ) ); + } + + void Scene00005Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + if( result.getResult( 0 ) == 1 ) + { + Scene00100( quest, player ); + } + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00099( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 99, NONE, bindSceneReturn( &SubWil070::Scene00099Return ) ); + } + + void Scene00099Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00100( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 100, HIDE_HOTBAR, bindSceneReturn( &SubWil070::Scene00100Return ) ); + } + + void Scene00100Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + if( result.getResult( 0 ) == 1 ) + { + player.finishQuest( getId(), result.getResult( 1 ) ); + } + + } + +}; + +EXPOSE_SCRIPT( SubWil070 ); \ No newline at end of file From bce9df158f64cf2fefe684d5f5eab0c1c461b3d5 Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Wed, 10 May 2023 13:27:51 -0700 Subject: [PATCH 25/30] Added ItemIcons to quest notices with multiple vars --- .../questbattles/UnderneaththeSultantree.cpp | 16 ++++++++-------- src/scripts/quest/classquest/MIN/ClsMin580.cpp | 3 ++- .../subquest/blackshroud_central/SubFst033.cpp | 3 ++- .../subquest/blackshroud_central/SubFst052.cpp | 4 +++- .../subquest/blackshroud_central/SubFst067.cpp | 3 ++- .../subquest/blackshroud_north/GaiUsa803.cpp | 3 ++- .../quest/subquest/lanoscea_outer/GaiUsb406.cpp | 8 +++++++- .../subquest/thanalan_central/SubWil070.cpp | 3 ++- 8 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/scripts/instances/questbattles/UnderneaththeSultantree.cpp b/src/scripts/instances/questbattles/UnderneaththeSultantree.cpp index 7d4d61a89..135be4b5a 100644 --- a/src/scripts/instances/questbattles/UnderneaththeSultantree.cpp +++ b/src/scripts/instances/questbattles/UnderneaththeSultantree.cpp @@ -142,8 +142,8 @@ class UnderneaththeSultantree : public Sapphire::ScriptAPI::QuestBattleScript if( pair1Spawnd == 0 && bossHpPercent <= 70 ) { instance.setDirectorVar( SET_1_SPAWNED, 1 ); - auto a2 = instance.createBNpcFromLayoutId(INIT_POP_01_01, 1440, Common::BNpcType::Enemy); - auto a3 = instance.createBNpcFromLayoutId( INIT_POP_01_02, 1440, Common::BNpcType::Enemy ); + auto a2 = instance.createBNpcFromLayoutId( INIT_POP_01_01, 1440 /*TODO: Find the right value*/, Common::BNpcType::Enemy ); + auto a3 = instance.createBNpcFromLayoutId( INIT_POP_01_02, 1440 /*TODO: Find the right value*/, Common::BNpcType::Enemy ); a2->setFlag( Entity::NoDeaggro ); a3->setFlag( Entity::NoDeaggro ); @@ -158,10 +158,10 @@ class UnderneaththeSultantree : public Sapphire::ScriptAPI::QuestBattleScript if( pair2Spawnd == 0 && bossHpPercent <= 40 ) { instance.setDirectorVar( SET_2_SPAWNED, 1 ); - auto a2 = instance.createBNpcFromLayoutId( INIT_POP_02_01, 1440, Common::BNpcType::Enemy ); - auto a3 = instance.createBNpcFromLayoutId( INIT_POP_02_02, 1440, Common::BNpcType::Enemy ); - auto a4 = instance.createBNpcFromLayoutId( INIT_POP_02_03, 1440, Common::BNpcType::Enemy ); - auto a5 = instance.createBNpcFromLayoutId( INIT_POP_02_04, 1440, Common::BNpcType::Enemy ); + auto a2 = instance.createBNpcFromLayoutId( INIT_POP_02_01, 1440 /*TODO: Find the right value*/, Common::BNpcType::Enemy ); + auto a3 = instance.createBNpcFromLayoutId( INIT_POP_02_02, 1440 /*TODO: Find the right value*/, Common::BNpcType::Enemy ); + auto a4 = instance.createBNpcFromLayoutId( INIT_POP_02_03, 1440 /*TODO: Find the right value*/, Common::BNpcType::Enemy ); + auto a5 = instance.createBNpcFromLayoutId( INIT_POP_02_04, 1440 /*TODO: Find the right value*/, Common::BNpcType::Enemy ); a2->setFlag( Entity::NoDeaggro ); a3->setFlag( Entity::NoDeaggro ); a4->setFlag( Entity::NoDeaggro ); @@ -213,8 +213,8 @@ class UnderneaththeSultantree : public Sapphire::ScriptAPI::QuestBattleScript void onDutyCommence( QuestBattle& instance, Entity::Player& player ) override { // TODO: Change to correct HP values - auto boss = instance.createBNpcFromLayoutId( INIT_POP_BOSS, 10571, Common::BNpcType::Enemy ); - auto thancred = instance.createBNpcFromLayoutId( INIT_P_POP_01, 27780, Common::BNpcType::Friendly ); + auto boss = instance.createBNpcFromLayoutId( INIT_POP_BOSS, 10571 /*TODO: Find the right value*/, Common::BNpcType::Enemy ); + auto thancred = instance.createBNpcFromLayoutId( INIT_P_POP_01, 27780 /*TODO: Find the right value*/, Common::BNpcType::Friendly ); boss->setFlag( Entity::NoDeaggro ); thancred->setFlag( Entity::NoDeaggro ); diff --git a/src/scripts/quest/classquest/MIN/ClsMin580.cpp b/src/scripts/quest/classquest/MIN/ClsMin580.cpp index 9505ca2f9..716fc9515 100644 --- a/src/scripts/quest/classquest/MIN/ClsMin580.cpp +++ b/src/scripts/quest/classquest/MIN/ClsMin580.cpp @@ -64,6 +64,7 @@ class ClsMin580 : public Sapphire::ScriptAPI::QuestScript static constexpr auto Eobject2 = 2005950; static constexpr auto EventActionGatherMiddle = 7; static constexpr auto Item0 = 2001728; + static constexpr auto Item0Icon = 21223; static constexpr auto LocActor1 = 1013860; static constexpr auto LocActor2 = 1013870; static constexpr auto LocActor3 = 1013871; @@ -207,7 +208,7 @@ class ClsMin580 : public Sapphire::ScriptAPI::QuestScript private: void checkQuestCompletion( World::Quest& quest, Entity::Player& player ) { - eventMgr().sendEventNotice( player, getId(), 1, 2, quest.getUI8AL(), 3 );//TODO: Item Icon, probably + eventMgr().sendNotice( player, getId(), 1, { quest.getUI8AL(), 3, Item0Icon } ); if( quest.getUI8AL() >= 3 ) { diff --git a/src/scripts/quest/subquest/blackshroud_central/SubFst033.cpp b/src/scripts/quest/subquest/blackshroud_central/SubFst033.cpp index 05dafa7b2..eb6b8abb6 100644 --- a/src/scripts/quest/subquest/blackshroud_central/SubFst033.cpp +++ b/src/scripts/quest/subquest/blackshroud_central/SubFst033.cpp @@ -54,6 +54,7 @@ class SubFst033 : public Sapphire::ScriptAPI::QuestScript static constexpr auto Eobject1 = 2000017;//Decaying Tree (South) static constexpr auto Eobject2 = 2000018;//Decaying Tree (East) static constexpr auto Item0 = 2000061; + static constexpr auto Item0Icon = 20661; static constexpr auto Seq0Actor0 = 0; static constexpr auto Seq1Eobject0 = 1; static constexpr auto Seq1Eobject0Useitemno = 99; @@ -184,7 +185,7 @@ class SubFst033 : public Sapphire::ScriptAPI::QuestScript private: void checkQuestCompletion( World::Quest& quest, Entity::Player& player ) { - eventMgr().sendEventNotice( player, getId(), 0, 2, quest.getUI8AH(), 3 );//TODO: Probably needs item icon + eventMgr().sendNotice( player, getId(), 0, { quest.getUI8AH(), 3, Item0Icon } ); if( quest.getUI8AH() >= 3 ) { diff --git a/src/scripts/quest/subquest/blackshroud_central/SubFst052.cpp b/src/scripts/quest/subquest/blackshroud_central/SubFst052.cpp index ed0a3e022..f91b170a9 100644 --- a/src/scripts/quest/subquest/blackshroud_central/SubFst052.cpp +++ b/src/scripts/quest/subquest/blackshroud_central/SubFst052.cpp @@ -45,6 +45,8 @@ class SubFst052 : public Sapphire::ScriptAPI::QuestScript static constexpr auto Enemy0 = 54;//Hornet Swarm (INCORRECT: 57) static constexpr auto Item0 = 2000099; static constexpr auto Item1 = 2000094; + static constexpr auto Item0Icon = 22623; + static constexpr auto Item1Icon = 24403; static constexpr auto Seq0Actor0 = 0; static constexpr auto Seq2Actor0 = 1; static constexpr auto Seq2Actor0Npctradeno = 99; @@ -88,7 +90,7 @@ class SubFst052 : public Sapphire::ScriptAPI::QuestScript { quest.setUI8BH( quest.getUI8BH() + 1 ); quest.setUI8AL( quest.getUI8AL() + 1 ); - eventMgr().sendEventNotice( player, getId(), 0, 2, quest.getUI8AL(), 4 );//TODO: Probably needs item icon + eventMgr().sendNotice( player, getId(), 0, { quest.getUI8AL(), 4, Item0Icon } ); // item Icon 2 missing if( quest.getUI8AL() >= 4 ) { diff --git a/src/scripts/quest/subquest/blackshroud_central/SubFst067.cpp b/src/scripts/quest/subquest/blackshroud_central/SubFst067.cpp index 6433ed1d3..a8c3da0fe 100644 --- a/src/scripts/quest/subquest/blackshroud_central/SubFst067.cpp +++ b/src/scripts/quest/subquest/blackshroud_central/SubFst067.cpp @@ -53,6 +53,7 @@ class SubFst067 : public Sapphire::ScriptAPI::QuestScript static constexpr auto Eventrange0 = 3841476; static constexpr auto EventActionSearch = 1; static constexpr auto Item0 = 2000192; + static constexpr auto Item0Icon = 22627; public: SubFst067() : Sapphire::ScriptAPI::QuestScript( 65919 ){}; @@ -182,7 +183,7 @@ class SubFst067 : public Sapphire::ScriptAPI::QuestScript private: void checkQuestCompletion( World::Quest& quest, Entity::Player& player ) { - eventMgr().sendEventNotice( player, getId(), 1, 2, quest.getUI8AL(), 3 );//TODO: Item Icon + eventMgr().sendNotice( player, getId(), 1, { quest.getUI8AL(), 3, Item0Icon } ); if( quest.getUI8AL() >= 3 ) { quest.setUI8AL( 0 ); diff --git a/src/scripts/quest/subquest/blackshroud_north/GaiUsa803.cpp b/src/scripts/quest/subquest/blackshroud_north/GaiUsa803.cpp index 15fcf1da9..341a8e8b5 100644 --- a/src/scripts/quest/subquest/blackshroud_north/GaiUsa803.cpp +++ b/src/scripts/quest/subquest/blackshroud_north/GaiUsa803.cpp @@ -55,6 +55,7 @@ class GaiUsa803 : public Sapphire::ScriptAPI::QuestScript static constexpr auto EventActionSearchMiddle = 3; static constexpr auto Item0 = 2000616; static constexpr auto Item1 = 2000617; + static constexpr auto Item1Icon = 20005; public: GaiUsa803() : Sapphire::ScriptAPI::QuestScript( 66323 ){}; @@ -140,7 +141,7 @@ class GaiUsa803 : public Sapphire::ScriptAPI::QuestScript private: void checkQuestCompletion( World::Quest& quest, Entity::Player& player ) { - eventMgr().sendEventNotice( player, getId(), 1, 2, quest.getUI8AH(), 5 );//TODO:Show Item Icon + eventMgr().sendNotice( player, getId(), 1, { quest.getUI8AH(), 5, Item1Icon } ); if( quest.getUI8AH() >= 5 ) { quest.setUI8BH( quest.getUI8DH() ); diff --git a/src/scripts/quest/subquest/lanoscea_outer/GaiUsb406.cpp b/src/scripts/quest/subquest/lanoscea_outer/GaiUsb406.cpp index 176978e3f..179139672 100644 --- a/src/scripts/quest/subquest/lanoscea_outer/GaiUsb406.cpp +++ b/src/scripts/quest/subquest/lanoscea_outer/GaiUsb406.cpp @@ -55,6 +55,8 @@ class GaiUsb406 : public Sapphire::ScriptAPI::QuestScript static constexpr auto EventActionSearch = 1; static constexpr auto Item0 = 2000669; static constexpr auto Item1 = 2000929; + static constexpr auto Item0Icon = 27241; + static constexpr auto Item1Icon = 22301; public: GaiUsb406() : Sapphire::ScriptAPI::QuestScript( 66398 ){}; @@ -143,7 +145,11 @@ class GaiUsb406 : public Sapphire::ScriptAPI::QuestScript { if( quest.getSeq() == Seq1 ) { - eventMgr().sendEventNotice( player, getId(), type, 2, ( type == 0 ) ? quest.getUI8AL() : quest.getUI8BH(), 3 ); //TODO: Item Icons + if( type == 0 ) + eventMgr().sendNotice( player, getId(), type, { quest.getUI8AL(), 3, Item1Icon } ); + else + eventMgr().sendNotice( player, getId(), type, { quest.getUI8BH(), 3, Item0Icon } ); + if( quest.getUI8BL() >= 3 && quest.getUI8CH() >= 3 ) { quest.setUI8BH( quest.getUI8BL() ); diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil070.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil070.cpp index eb43c4107..92b693132 100644 --- a/src/scripts/quest/subquest/thanalan_central/SubWil070.cpp +++ b/src/scripts/quest/subquest/thanalan_central/SubWil070.cpp @@ -42,6 +42,7 @@ class SubWil070 : public Sapphire::ScriptAPI::QuestScript static constexpr auto Actor3 = 1001465; // Solid Trunk ( Pos: -90.043503 -11.398500 -53.666000 Teri: 141 ) static constexpr auto Actor4 = 1001466; // Ricard ( Pos: -89.735001 -11.350000 -51.539902 Teri: 141 ) static constexpr auto Item0 = 2000234; + static constexpr auto Item0Icon = 26153; static constexpr auto Seq0Actor0 = 0; static constexpr auto Seq1Actor1 = 1; static constexpr auto Seq1Actor2 = 2; @@ -110,7 +111,7 @@ class SubWil070 : public Sapphire::ScriptAPI::QuestScript if (quest.getUI8AL() == 4) quest.setSeq( SeqFinish ); } - eventMgr().sendEventNotice( player, getId(), 0, 2, quest.getUI8AL(), 4 ); // TODO: Add item icon (Oily Order Slip) + eventMgr().sendNotice( player, getId(), 0, { quest.getUI8AL(), 4, Item0Icon } ); } ////////////////////////////////////////////////////////////////////// // Available Scenes in this quest, not necessarly all are used From 99b802c7c28d64ecf13d65f5f2c7e78e5ac81b26 Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Wed, 10 May 2023 16:46:31 -0700 Subject: [PATCH 26/30] Added missing HIDE_HOTBAR --- src/scripts/quest/subquest/thanalan_central/SubWil062.cpp | 8 +++----- src/scripts/quest/subquest/thanalan_central/SubWil063.cpp | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil062.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil062.cpp index e393a57e5..ce041da38 100644 --- a/src/scripts/quest/subquest/thanalan_central/SubWil062.cpp +++ b/src/scripts/quest/subquest/thanalan_central/SubWil062.cpp @@ -93,7 +93,7 @@ class SubWil062 : public Sapphire::ScriptAPI::QuestScript void Scene00000( World::Quest& quest, Entity::Player& player ) { - eventMgr().playQuestScene( player, getId(), 0, NONE, bindSceneReturn( &SubWil062::Scene00000Return ) ); + eventMgr().playQuestScene( player, getId(), 0, HIDE_HOTBAR, bindSceneReturn( &SubWil062::Scene00000Return ) ); } void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) @@ -103,8 +103,6 @@ class SubWil062 : public Sapphire::ScriptAPI::QuestScript quest.setUI8AL( 0 ); quest.setSeq( Seq1 ); } - - } ////////////////////////////////////////////////////////////////////// @@ -124,7 +122,7 @@ class SubWil062 : public Sapphire::ScriptAPI::QuestScript void Scene00002( World::Quest& quest, Entity::Player& player ) { - eventMgr().playQuestScene( player, getId(), 2, NONE, bindSceneReturn( &SubWil062::Scene00002Return ) ); + eventMgr().playQuestScene( player, getId(), 2, HIDE_HOTBAR, bindSceneReturn( &SubWil062::Scene00002Return ) ); } void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) @@ -140,7 +138,7 @@ class SubWil062 : public Sapphire::ScriptAPI::QuestScript void Scene00003( World::Quest& quest, Entity::Player& player ) { - eventMgr().playQuestScene( player, getId(), 3, NONE, bindSceneReturn( &SubWil062::Scene00003Return ) ); + eventMgr().playQuestScene( player, getId(), 3, HIDE_HOTBAR, bindSceneReturn( &SubWil062::Scene00003Return ) ); } void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil063.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil063.cpp index 404393e1f..e1fec0289 100644 --- a/src/scripts/quest/subquest/thanalan_central/SubWil063.cpp +++ b/src/scripts/quest/subquest/thanalan_central/SubWil063.cpp @@ -69,7 +69,7 @@ class SubWil063 : public Sapphire::ScriptAPI::QuestScript void Scene00000( World::Quest& quest, Entity::Player& player ) { - eventMgr().playQuestScene( player, getId(), 0, NONE, bindSceneReturn( &SubWil063::Scene00000Return ) ); + eventMgr().playQuestScene( player, getId(), 0, HIDE_HOTBAR, bindSceneReturn( &SubWil063::Scene00000Return ) ); } void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) @@ -85,7 +85,7 @@ class SubWil063 : public Sapphire::ScriptAPI::QuestScript void Scene00001( World::Quest& quest, Entity::Player& player ) { - eventMgr().playQuestScene( player, getId(), 1, NONE, bindSceneReturn( &SubWil063::Scene00001Return ) ); + eventMgr().playQuestScene( player, getId(), 1, HIDE_HOTBAR, bindSceneReturn( &SubWil063::Scene00001Return ) ); } void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) From 3b274cd9aecc33e282599053347a4c2b30befac6 Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Wed, 10 May 2023 16:47:24 -0700 Subject: [PATCH 27/30] Central Thanalan SubWil MSQ - SubWil026 - SubWil073 - SubWil080 --- .../subquest/thanalan_central/SubWil026.cpp | 117 +++++ .../subquest/thanalan_central/SubWil073.cpp | 415 ++++++++++++++++++ .../subquest/thanalan_central/SubWil080.cpp | 136 ++++++ 3 files changed, 668 insertions(+) create mode 100644 src/scripts/quest/subquest/thanalan_central/SubWil026.cpp create mode 100644 src/scripts/quest/subquest/thanalan_central/SubWil073.cpp create mode 100644 src/scripts/quest/subquest/thanalan_central/SubWil080.cpp diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil026.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil026.cpp new file mode 100644 index 000000000..5ae382c0b --- /dev/null +++ b/src/scripts/quest/subquest/thanalan_central/SubWil026.cpp @@ -0,0 +1,117 @@ +// This is an automatically generated C++ script template +// Content needs to be added by hand to make it function +// In order for this script to be loaded, move it to the correct folder in /scripts/ + +#include +#include "Manager/EventMgr.h" +#include +#include + +// Quest Script: SubWil026_00623 +// Quest Name: Takin' What They're Givin' +// Quest ID: 66159 +// Start NPC: 1001353 (Momodi) +// End NPC: 1002065 (Dadanen) + +using namespace Sapphire; + +class SubWil026 : public Sapphire::ScriptAPI::QuestScript +{ + private: + // Basic quest information + // Quest vars / flags used + // UI8AL + + /// Countable Num: 1 Seq: 255 Event: 1 Listener: 1002065 + // Steps in this quest ( 0 is before accepting, + // 1 is first, 255 means ready for turning it in + enum Sequence : uint8_t + { + Seq0 = 0, + SeqFinish = 255, + }; + + // Entities found in the script data of the quest + static constexpr auto Actor0 = 1001353; // Momodi ( Pos: 21.072599 7.450000 -78.782303 Teri: 130 ) + static constexpr auto Actor1 = 1002065; // Dadanen ( Pos: 60.946701 45.145302 -204.985992 Teri: 140 ) + + public: + SubWil026() : Sapphire::ScriptAPI::QuestScript( 66159 ){}; + ~SubWil026() = default; + + ////////////////////////////////////////////////////////////////////// + // Event Handlers + void onTalk( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override + { + switch( actorId ) + { + case Actor0: + { + if( quest.getSeq() == Seq0 ) + Scene00000( quest, player ); + break; + } + case Actor1: + { + if( quest.getSeq() == SeqFinish ) + Scene00001( quest, player ); + break; + } + } + } + + void onEventItem( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override + { + } + + + private: + ////////////////////////////////////////////////////////////////////// + // Available Scenes in this quest, not necessarly all are used + ////////////////////////////////////////////////////////////////////// + + void Scene00000( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 0, HIDE_HOTBAR, bindSceneReturn( &SubWil026::Scene00000Return ) ); + } + + void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + if( result.getResult( 0 ) == 1 ) // accept quest + { + quest.setUI8AL( 1 ); + quest.setSeq( SeqFinish ); + } + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00001( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 1, FADE_OUT | CONDITION_CUTSCENE | HIDE_UI, bindSceneReturn( &SubWil026::Scene00001Return ) ); + } + + void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + Scene00002( quest, player ); + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00002( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 2, HIDE_HOTBAR, bindSceneReturn( &SubWil026::Scene00002Return ) ); + } + + void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + if( result.getResult( 0 ) == 1 ) + { + player.finishQuest( getId(), result.getResult( 1 ) ); + } + } + +}; + +EXPOSE_SCRIPT( SubWil026 ); \ No newline at end of file diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil073.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil073.cpp new file mode 100644 index 000000000..857f5c213 --- /dev/null +++ b/src/scripts/quest/subquest/thanalan_central/SubWil073.cpp @@ -0,0 +1,415 @@ +// This is an automatically generated C++ script template +// Content needs to be added by hand to make it function +// In order for this script to be loaded, move it to the correct folder in /scripts/ + +#include "Manager/EventMgr.h" +#include +#include +#include +#include + +#include "Actor/BNpc.h" +#include "Manager/TerritoryMgr.h" +#include "Territory/Territory.h" + +// Quest Script: SubWil073_00327 +// Quest Name: Spriggan Cleaning +// Quest ID: 65863 +// Start NPC: 1001447 (Warin) +// End NPC: 1001447 (Warin) + +using namespace Sapphire; + +class SubWil073 : public Sapphire::ScriptAPI::QuestScript +{ + private: + // Basic quest information + // Quest vars / flags used + // BitFlag8 + // UI8AH + // UI8AL + // UI8BH + // UI8BL + // UI8CH + // UI8CL + // UI8DH + // UI8DL + // UI8EH + + /// Countable Num: 4 Seq: 1 Event: 1 Listener: 2000377 + /// Countable Num: 1 Seq: 255 Event: 5 Listener: 100 + // Steps in this quest ( 0 is before accepting, + // 1 is first, 255 means ready for turning it in + enum Sequence : uint8_t + { + Seq0 = 0, + Seq1 = 1, + SeqFinish = 255, + }; + + // Entities found in the script data of the quest + static constexpr auto Actor0 = 1001447; // Warin ( Pos: -32.639099 -1.033260 -148.485992 Teri: 141 ) + static constexpr auto Enemy0 = 3742257; // + static constexpr auto Enemy1 = 3742258; // + static constexpr auto Enemy2 = 3742259; // + static constexpr auto Enemy3 = 3742261; // + static constexpr auto Eobject0 = 2000377; // Pockmarked Silver Ore ( Pos: -134.695999 6.168210 -116.594002 Teri: 141 ) + static constexpr auto Eobject1 = 2000378; // Pockmarked Silver Ore ( Pos: -95.958298 -1.021940 -163.731003 Teri: 141 ) + static constexpr auto Eobject2 = 2000379; // Pockmarked Silver Ore ( Pos: -103.938004 0.491295 -213.695007 Teri: 141 ) + static constexpr auto Eobject3 = 2000380; // Pockmarked Silver Ore ( Pos: -1.174590 -1.322410 -111.265999 Teri: 141 ) + static constexpr auto EventActionSearch = 1; + static constexpr auto Seq0Actor0 = 0; // + static constexpr auto Seq1Eobject0 = 1; // + static constexpr auto Seq1Eobject0Eventactionno = 99; // Hecatoncheir Piledriver + static constexpr auto Seq1Eobject0Eventactionok = 100; // Hecatoncheir Blastmaster ( Pos: -135.210007 5.708900 -117.417999 Teri: 141 ) + static constexpr auto Seq1Eobject1 = 2; // Ruins Runner ( Pos: -5.462710 -1.142520 27.215000 Teri: 5 ) + static constexpr auto Seq1Eobject1Eventactionno = 97; // Hecatoncheir Stonehauler + static constexpr auto Seq1Eobject1Eventactionok = 98; // Hecatoncheir Shockblocker + static constexpr auto Seq1Eobject2 = 3; // Antelope Doe + static constexpr auto Seq1Eobject2Eventactionno = 95; // Flux Flan + static constexpr auto Seq1Eobject2Eventactionok = 96; // Hecatoncheir Overseer + static constexpr auto Seq1Eobject3 = 4; // Antelope Stag + static constexpr auto Seq1Eobject3Eventactionno = 93; // Sargas + static constexpr auto Seq1Eobject3Eventactionok = 94; // Shaula + static constexpr auto Seq2Actor0 = 5; // Opo-opo + + public: + SubWil073() : Sapphire::ScriptAPI::QuestScript( 65863 ){}; + ~SubWil073() = default; + + ////////////////////////////////////////////////////////////////////// + // Event Handlers + void onTalk( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override + { + switch( actorId ) + { + case Actor0: + { + if( quest.getSeq() == Seq0 ) + Scene00000( quest, player ); + else if( quest.getSeq() == SeqFinish ) + Scene00005( quest, player ); + break; + } + case Eobject0: + { + eventMgr().eventActionStart( + player, getId(), EventActionSearch, + [ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) { + Scene00094( quest, player ); + }, + nullptr, 0 ); + break; + + } + case Eobject1: + { + eventMgr().eventActionStart( + player, getId(), EventActionSearch, + [ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) { + Scene00095( quest, player ); + }, + nullptr, 0 ); + break; + } + case Eobject2: + { + eventMgr().eventActionStart( + player, getId(), EventActionSearch, + [ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) { + Scene00096( quest, player ); + }, + nullptr, 0 ); + break; + } + case Eobject3: + { + eventMgr().eventActionStart( + player, getId(), EventActionSearch, + [ & ]( Entity::Player& player, uint32_t eventId, uint64_t additional ) { + Scene00097( quest, player ); + }, + nullptr, 0 ); + break; + } + } + } + + void onEventItem( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override + { + } + + void onBNpcKill( World::Quest& quest, Entity::BNpc& bnpc, Entity::Player& player ) override + { + switch (bnpc.getLayoutId()) + { + case Enemy0: + { + quest.setUI8AL( 1 ); + quest.setUI8BH( 1 ); + checkQuestCompletion( quest, player ); + break; + } + case Enemy1: + { + quest.setUI8BL( 1 ); + quest.setUI8CH( 1 ); + checkQuestCompletion( quest, player ); + break; + } + case Enemy2: + { + quest.setUI8CL( 1 ); + quest.setUI8DH( 1 ); + checkQuestCompletion( quest, player ); + break; + } + case Enemy3: + { + quest.setUI8DL( 1 ); + quest.setUI8EH( 1 ); + checkQuestCompletion( quest, player ); + break; + } + } + } + + private: + void checkQuestCompletion( World::Quest& quest, Entity::Player& player ) + { + quest.setUI8AH( quest.getUI8AH() + 1 ); + eventMgr().sendEventNotice( player, getId(), 0, 2, quest.getUI8AH(), 4 ); + + if( quest.getUI8AH() >= 4 ) + { + quest.setUI8AL( 0 ); + quest.setUI8BH( 0 ); + quest.setUI8BL( 0 ); + quest.setUI8CH( 0 ); + quest.setUI8CL( 0 ); + quest.setUI8DH( 0 ); + quest.setUI8DL( 0 ); + quest.setUI8EH( 0 ); + quest.setUI8AH( 0 ); + quest.setBitFlag8( 1, false ); + quest.setBitFlag8( 2, false ); + quest.setBitFlag8( 3, false ); + quest.setBitFlag8( 4, false ); + quest.setSeq( SeqFinish ); + } + } + ////////////////////////////////////////////////////////////////////// + // Available Scenes in this quest, not necessarly all are used + ////////////////////////////////////////////////////////////////////// + + void Scene00000( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 0, HIDE_HOTBAR, bindSceneReturn( &SubWil073::Scene00000Return ) ); + } + + void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + if( result.getResult( 0 ) == 1 ) // accept quest + { + Scene00001( quest, player ); + } + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00001( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 1, HIDE_HOTBAR, bindSceneReturn( &SubWil073::Scene00001Return ) ); + } + + void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + quest.setSeq( Seq1 ); + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00002( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 2, NONE, bindSceneReturn( &SubWil073::Scene00002Return ) ); + } + + void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00003( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 3, NONE, bindSceneReturn( &SubWil073::Scene00003Return ) ); + } + + void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00004( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 4, NONE, bindSceneReturn( &SubWil073::Scene00004Return ) ); + } + + void Scene00004Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00005( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 5, HIDE_HOTBAR, bindSceneReturn( &SubWil073::Scene00005Return ) ); + } + + void Scene00005Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + if( result.getResult( 0 ) == 1 ) + { + player.finishQuest( getId(), result.getResult( 1 ) ); + } + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00093( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 93, NONE, bindSceneReturn( &SubWil073::Scene00093Return ) ); + } + + void Scene00093Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00094( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 94, NONE, bindSceneReturn( &SubWil073::Scene00094Return ) ); + } + + void Scene00094Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + auto instance = teriMgr().getTerritoryByGuId( player.getTerritoryId() ); + auto enemy = instance->createBNpcFromLayoutId( Enemy0, 1220 /*Find the right value*/, Common::BNpcType::Enemy ); + + enemy->setTriggerOwnerId( player.getId() ); + enemy->hateListAddDelayed( player.getAsPlayer(), 1 ); + quest.setBitFlag8( 1, true ); + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00095( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 95, NONE, bindSceneReturn( &SubWil073::Scene00095Return ) ); + } + + void Scene00095Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + auto instance = teriMgr().getTerritoryByGuId( player.getTerritoryId() ); + auto enemy = instance->createBNpcFromLayoutId( Enemy1, 1220 /*Find the right value*/, Common::BNpcType::Enemy ); + + enemy->setTriggerOwnerId( player.getId() ); + enemy->hateListAddDelayed( player.getAsPlayer(), 1 ); + quest.setBitFlag8( 2, true ); + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00096( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 96, NONE, bindSceneReturn( &SubWil073::Scene00096Return ) ); + } + + void Scene00096Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + auto instance = teriMgr().getTerritoryByGuId( player.getTerritoryId() ); + auto enemy = instance->createBNpcFromLayoutId( Enemy2, 1220 /*Find the right value*/, Common::BNpcType::Enemy ); + + enemy->setTriggerOwnerId( player.getId() ); + enemy->hateListAddDelayed( player.getAsPlayer(), 1 ); + quest.setBitFlag8( 3, true ); + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00097( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 97, NONE, bindSceneReturn( &SubWil073::Scene00097Return ) ); + } + + void Scene00097Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + auto instance = teriMgr().getTerritoryByGuId( player.getTerritoryId() ); + auto enemy = instance->createBNpcFromLayoutId( Enemy3, 1220 /*Find the right value*/, Common::BNpcType::Enemy ); + + enemy->setTriggerOwnerId( player.getId() ); + enemy->hateListAddDelayed( player.getAsPlayer(), 1 ); + quest.setBitFlag8( 4, true ); + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00098( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 98, NONE, bindSceneReturn( &SubWil073::Scene00098Return ) ); + } + + void Scene00098Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00099( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 99, NONE, bindSceneReturn( &SubWil073::Scene00099Return ) ); + } + + void Scene00099Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00100( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 100, NONE, bindSceneReturn( &SubWil073::Scene00100Return ) ); + } + + void Scene00100Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + + } + +}; + +EXPOSE_SCRIPT( SubWil073 ); \ No newline at end of file diff --git a/src/scripts/quest/subquest/thanalan_central/SubWil080.cpp b/src/scripts/quest/subquest/thanalan_central/SubWil080.cpp new file mode 100644 index 000000000..9619e8fe8 --- /dev/null +++ b/src/scripts/quest/subquest/thanalan_central/SubWil080.cpp @@ -0,0 +1,136 @@ +// This is an automatically generated C++ script template +// Content needs to be added by hand to make it function +// In order for this script to be loaded, move it to the correct folder in /scripts/ + +#include +#include "Manager/EventMgr.h" +#include +#include + +// Quest Script: SubWil080_00328 +// Quest Name: Supply and Demands +// Quest ID: 65864 +// Start NPC: 1002065 (Dadanen) +// End NPC: 1002061 (Drunken Stag) + +using namespace Sapphire; + +class SubWil080 : public Sapphire::ScriptAPI::QuestScript +{ + private: + // Basic quest information + // Quest vars / flags used + // UI8AL + // UI8BH + + /// Countable Num: 1 Seq: 255 Event: 1 Listener: 1002061 + // Steps in this quest ( 0 is before accepting, + // 1 is first, 255 means ready for turning it in + enum Sequence : uint8_t + { + Seq0 = 0, + SeqFinish = 255, + }; + + // Entities found in the script data of the quest + static constexpr auto Actor0 = 1002065; // Dadanen ( Pos: 60.946701 45.145302 -204.985992 Teri: 140 ) + static constexpr auto Actor1 = 1002061; // Drunken Stag ( Pos: 240.998993 58.318298 -160.998001 Teri: 140 ) + static constexpr auto Item0 = 2000368; + + public: + SubWil080() : Sapphire::ScriptAPI::QuestScript( 65864 ){}; + ~SubWil080() = default; + + ////////////////////////////////////////////////////////////////////// + // Event Handlers + void onTalk( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override + { + switch( actorId ) + { + case Actor0: + { + if( quest.getSeq() == Seq0 ) + Scene00000( quest, player ); + break; + } + case Actor1: + { + if( quest.getSeq() == SeqFinish ) + Scene00001( quest, player ); + break; + } + } + } + + void onEventItem( World::Quest& quest, Entity::Player& player, uint64_t actorId ) override + { + } + + + private: + ////////////////////////////////////////////////////////////////////// + // Available Scenes in this quest, not necessarly all are used + ////////////////////////////////////////////////////////////////////// + + void Scene00000( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 0, HIDE_HOTBAR, bindSceneReturn( &SubWil080::Scene00000Return ) ); + } + + void Scene00000Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + if( result.getResult( 0 ) == 1 ) // accept quest + { + quest.setUI8BH( 1 ); + quest.setSeq( SeqFinish ); + } + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00001( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 1, HIDE_HOTBAR, bindSceneReturn( &SubWil080::Scene00001Return ) ); + } + + void Scene00001Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + if (result.getResult(0) == 1) + { + Scene00002( quest, player ); + } + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00002( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 2, NONE, bindSceneReturn( &SubWil080::Scene00002Return ) ); + } + + void Scene00002Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + if( result.getResult( 0 ) == 1 ) + { + player.finishQuest( getId(), result.getResult( 1 ) ); + } + + } + + ////////////////////////////////////////////////////////////////////// + + void Scene00003( World::Quest& quest, Entity::Player& player ) + { + eventMgr().playQuestScene( player, getId(), 3, NONE, bindSceneReturn( &SubWil080::Scene00003Return ) ); + } + + void Scene00003Return( World::Quest& quest, Entity::Player& player, const Event::SceneResult& result ) + { + + } + +}; + +EXPOSE_SCRIPT( SubWil080 ); \ No newline at end of file From 511d22786274ce434347bc183351f657ce31aa1d Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Wed, 10 May 2023 18:11:03 -0700 Subject: [PATCH 28/30] Fixed typo --- src/scripts/quest/classquest/WHM/JobWhm001.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/quest/classquest/WHM/JobWhm001.cpp b/src/scripts/quest/classquest/WHM/JobWhm001.cpp index 82d987281..4fb8ad996 100644 --- a/src/scripts/quest/classquest/WHM/JobWhm001.cpp +++ b/src/scripts/quest/classquest/WHM/JobWhm001.cpp @@ -13,7 +13,7 @@ // Quest Script: JobWhm001_01124 // Quest Name: A Relic Reborn (Thyrus) // Quest ID: 66660 -// Start NPC: 1003075a +// Start NPC: 1003075 // End NPC: 1003075 using namespace Sapphire; @@ -722,4 +722,4 @@ class JobWhm001 : public Sapphire::ScriptAPI::QuestScript } }; -EXPOSE_SCRIPT( JobWhm001 ); \ No newline at end of file +EXPOSE_SCRIPT( JobWhm001 ); From 83590fc5cfcc8e7540f90d37d0b438a09b43475e Mon Sep 17 00:00:00 2001 From: Rushi <44952533+Skyliegirl33@users.noreply.github.com> Date: Sun, 23 Jul 2023 19:23:20 +0200 Subject: [PATCH 29/30] Some calculation work --- src/world/Math/CalcStats.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/world/Math/CalcStats.cpp b/src/world/Math/CalcStats.cpp index af58dad1b..a3236edc4 100644 --- a/src/world/Math/CalcStats.cpp +++ b/src/world/Math/CalcStats.cpp @@ -94,7 +94,7 @@ std::uniform_int_distribution< std::mt19937::result_type > CalcStats::range100( Big thanks to the Theoryjerks group! NOTE: - Formulas here shouldn't be considered final. It's possible that the formula it was based on is correct but + Formulas here shouldn't be considered final. It's possible that the formula it was based on is correct but wasn't implemented correctly here, or approximated things due to limited knowledge of how things work in retail. It's also possible that we're using formulas that were correct for previous patches, but not the current version. @@ -144,12 +144,15 @@ uint32_t CalcStats::calculateMaxHp( Player& player ) uint16_t hpMod = paramGrowthInfo->data().ParamBase; uint16_t jobModHp = classInfo->data().Hp; float approxBaseHp = 0.0f; // Read above + float hpModPercent = player.getModifier( Common::ParamModifier::HPPercent ); approxBaseHp = static_cast< float >( levelTable[ level ][ Common::LevelTableEntry::HP ] ); auto result = static_cast< uint32_t >( floor( jobModHp * ( approxBaseHp / 100.0f ) ) + floor( hpMod / 100.0f * ( vitStat - baseStat ) ) ); + result *= hpModPercent; + return result; } @@ -624,6 +627,7 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActio auto wd = weaponDamage( chara, wepDmg ); auto ap = getPrimaryAttackPower( chara ); auto det = determination( chara ); + auto damageDealtMod = chara.getModifier( Common::ParamModifier::DamageDealtPercent ); auto factor = Common::Util::trunc( pot * wd * ap * det, 0 ); Sapphire::Common::ActionHitSeverityType hitType = Sapphire::Common::ActionHitSeverityType::NormalDamage; @@ -646,11 +650,14 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActio // todo: buffs + factor *= damageDealtMod; + constexpr auto format = "dmg: pot: {} ({}) wd: {} ({}) ap: {} det: {} = {}"; if( auto player = const_cast< Entity::Chara& >( chara ).getAsPlayer() ) { PlayerMgr::sendDebug( *player, format, pot, ptc, wd, wepDmg, ap, det, factor ); + PlayerMgr::sendDebug( *player, "DamageDealtPercent: {}", damageDealtMod ); } else { @@ -683,4 +690,4 @@ std::pair< float, Sapphire::Common::ActionHitSeverityType > CalcStats::calcActio uint32_t CalcStats::primaryStatValue( const Sapphire::Entity::Chara& chara ) { return chara.getStatValue( chara.getPrimaryStat() ); -} \ No newline at end of file +} From 8a288f34f305695682926eb61c7c9829845def4c Mon Sep 17 00:00:00 2001 From: Kooper16 <56591765+Kooper16@users.noreply.github.com> Date: Sun, 23 Jul 2023 22:01:26 +0200 Subject: [PATCH 30/30] Fixed script skill processing --- src/world/Action/Action.cpp | 73 +++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/src/world/Action/Action.cpp b/src/world/Action/Action.cpp index 3bf585033..2b32970c4 100644 --- a/src/world/Action/Action.cpp +++ b/src/world/Action/Action.cpp @@ -520,7 +520,7 @@ void Action::Action::buildActionResults() Network::Util::Packet::sendHudParam( *m_pSource ); - if( !m_enableGenericHandler || !hasLutEntry || m_hitActors.empty() ) + if( m_hitActors.empty() ) { // send any effect packet added by script or an empty one just to play animation for other players m_actionResultBuilder->sendActionResults( {} ); @@ -539,56 +539,62 @@ void Action::Action::buildActionResults() bool shouldRestoreMP = true; bool shouldApplyComboSucceedEffect = true; - for( auto& actor : m_hitActors ) + if( m_enableGenericHandler && hasLutEntry ) { - if( m_lutEntry.potency > 0 ) + for( auto& actor : m_hitActors ) { - auto dmg = calcDamage( isCorrectCombo() ? m_lutEntry.comboPotency : m_lutEntry.potency ); - m_actionResultBuilder->damage( m_pSource, actor, dmg.first, dmg.second ); + if( m_lutEntry.potency > 0 ) + { + auto dmg = calcDamage( isCorrectCombo() ? m_lutEntry.comboPotency : m_lutEntry.potency ); + m_actionResultBuilder->damage( m_pSource, actor, dmg.first, dmg.second ); - if( dmg.first > 0 ) - actor->onActionHostile( m_pSource ); + if( dmg.first > 0 ) + actor->onActionHostile( m_pSource ); - if( isCorrectCombo() && shouldApplyComboSucceedEffect ) - { - m_actionResultBuilder->comboSucceed( m_pSource ); - shouldApplyComboSucceedEffect = false; - } + if( isCorrectCombo() && shouldApplyComboSucceedEffect ) + { + m_actionResultBuilder->comboSucceed( m_pSource ); + shouldApplyComboSucceedEffect = false; + } - if( !isComboAction() || isCorrectCombo() ) - { - if( m_lutEntry.curePotency > 0 ) // actions with self heal + if( !isComboAction() || isCorrectCombo() ) { - auto heal = calcHealing( m_lutEntry.curePotency ); - m_actionResultBuilder->heal( actor, m_pSource, heal.first, heal.second, Common::ActionResultFlag::EffectOnSource ); + if( m_lutEntry.curePotency > 0 )// actions with self heal + { + auto heal = calcHealing( m_lutEntry.curePotency ); + m_actionResultBuilder->heal( actor, m_pSource, heal.first, heal.second, Common::ActionResultFlag::EffectOnSource ); + } + + if( m_lutEntry.restoreMPPercentage > 0 && shouldRestoreMP ) + { + m_actionResultBuilder->restoreMP( actor, m_pSource, m_pSource->getMaxMp() * m_lutEntry.restoreMPPercentage / 100, Common::ActionResultFlag::EffectOnSource ); + shouldRestoreMP = false; + } + + if( !m_lutEntry.nextCombo.empty() ) // if we have a combo action followup + m_actionResultBuilder->startCombo( m_pSource, getId() );// this is on all targets hit } + } + else if( m_lutEntry.curePotency > 0 ) + { + auto heal = calcHealing( m_lutEntry.curePotency ); + m_actionResultBuilder->heal( actor, actor, heal.first, heal.second ); if( m_lutEntry.restoreMPPercentage > 0 && shouldRestoreMP ) { m_actionResultBuilder->restoreMP( actor, m_pSource, m_pSource->getMaxMp() * m_lutEntry.restoreMPPercentage / 100, Common::ActionResultFlag::EffectOnSource ); shouldRestoreMP = false; } - - if( !m_lutEntry.nextCombo.empty() ) // if we have a combo action followup - m_actionResultBuilder->startCombo( m_pSource, getId() ); // this is on all targets hit } - } - else if( m_lutEntry.curePotency > 0 ) - { - auto heal = calcHealing( m_lutEntry.curePotency ); - m_actionResultBuilder->heal( actor, actor, heal.first, heal.second ); - - if( m_lutEntry.restoreMPPercentage > 0 && shouldRestoreMP ) + else if( m_lutEntry.restoreMPPercentage > 0 && shouldRestoreMP ) { m_actionResultBuilder->restoreMP( actor, m_pSource, m_pSource->getMaxMp() * m_lutEntry.restoreMPPercentage / 100, Common::ActionResultFlag::EffectOnSource ); shouldRestoreMP = false; } } - else if( m_lutEntry.restoreMPPercentage > 0 && shouldRestoreMP ) - { - m_actionResultBuilder->restoreMP( actor, m_pSource, m_pSource->getMaxMp() * m_lutEntry.restoreMPPercentage / 100, Common::ActionResultFlag::EffectOnSource ); - shouldRestoreMP = false; - } + + if( m_lutEntry.statuses.caster.size() > 0 || m_lutEntry.statuses.target.size() > 0 ) + handleStatusEffects(); } // If we hit an enemy @@ -599,9 +605,6 @@ void Action::Action::buildActionResults() handleJobAction(); - if( m_lutEntry.statuses.caster.size() > 0 || m_lutEntry.statuses.target.size() > 0 ) - handleStatusEffects(); - m_actionResultBuilder->sendActionResults( m_hitActors ); // TODO: disabled, reset kills our queued actions