From 658d2fa7aad3f51a1cc8b8f635ce6e0f196fe0a8 Mon Sep 17 00:00:00 2001 From: Mordred Date: Mon, 13 Mar 2023 23:26:50 +0100 Subject: [PATCH 01/28] 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 898a7c18..d6bc36a4 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 82f73c1b..9e190a34 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 37393d37..b6752374 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/28] 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 aefdc2e3..999c05aa 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 af58dad1..7c7980e9 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 87625067..1e80ca81 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/28] 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 7c7980e9..b08bd833 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 1e80ca81..0d8f1cb4 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/28] 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 078d26fa..28ed82a5 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 cb93cd63..944ae4cf 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 90b49198..83b5dbe3 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 999c05aa..caedd31f 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 a2fbbf85..f951fbb0 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 d6bc36a4..23e82c16 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 19e00ae2..a70773e8 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 b08bd833..4dbaa36e 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 0d8f1cb4..a4c69ecc 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/28] More cleanup of actions --- src/common/Common.h | 124 +++++++++++------------ 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, 106 insertions(+), 116 deletions(-) diff --git a/src/common/Common.h b/src/common/Common.h index 4e07628f..18e529d1 100644 --- a/src/common/Common.h +++ b/src/common/Common.h @@ -948,74 +948,64 @@ namespace Sapphire::Common LimitBreak = 8, }; - enum ActionEffectType : uint8_t + enum CalcResultType : 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 + 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 944ae4cf..5ea83d07 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 83b5dbe3..3b0e5a9d 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 caedd31f..e07c308c 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 f951fbb0..b4ba479e 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 23e82c16..66ba8c6c 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 a70773e8..a5d1b936 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 fdb09aeb..ed096782 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 58fefc9e..cf237326 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 7dcbe84c..2442c679 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 4dbaa36e..e0b6fe28 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 a4c69ecc..ad1d5b94 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 7443a839..3f2d0749 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/28] 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 ec0cd7ae..931b579d 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 e07c308c..31d82aed 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 4a9c95e6..30a3235c 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 02bbc8a6..ef95ab0a 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/28] 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 | 82 ++++++++++++++++++------------------ src/world/ForwardsZone.h | 5 +++ 7 files changed, 189 insertions(+), 41 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 00000000..ce78c6d5 --- /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 00000000..4477f8de --- /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 00000000..41619ac0 --- /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 00000000..cb1b7466 --- /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 00000000..982dd874 --- /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 30a3235c..dd38c784 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 ) - { - 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 ); - } - } - else + 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; } - - Chara::update( tickCount ); } void BNpc::restHp() diff --git a/src/world/ForwardsZone.h b/src/world/ForwardsZone.h index ef95ab0a..e17eb916 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/28] 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 30194d9d..b7d9c061 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 2eebc7a7..42bda667 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 07c0cfc3..4aca5791 100644 --- a/src/world/Territory/Cell.h +++ b/src/world/Territory/Cell.h @@ -20,6 +20,7 @@ private: bool m_bActive; uint16_t m_playerCount; + uint32_t m_lastActiveTime; public: Cell(); @@ -82,6 +83,9 @@ public: { 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 375c7071..de4a5c4f 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/28] 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 ce78c6d5..00000000 --- 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 4477f8de..00000000 --- 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 00000000..11fb4804 --- /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 00000000..d5739e03 --- /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 00000000..5bcefd58 --- /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 00000000..9030331c --- /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 00000000..15b3a665 --- /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 00000000..9051288a --- /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 00000000..957e4c88 --- /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 00000000..fe145bfe --- /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 00000000..ac67ab86 --- /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 00000000..3156b846 --- /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 00000000..1f1e937d --- /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 00000000..00cfe427 --- /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 00000000..1b684817 --- /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 00000000..6f9ba3ca --- /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 00000000..f5bd3b2f --- /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 41619ac0..00000000 --- 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 cb1b7466..00000000 --- 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 982dd874..00000000 --- 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 dd38c784..04107a5a 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 095a7ce4..a8804f72 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 85006991..da82a244 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 e17eb916..de26643f 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/28] 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 1cf37982..f3ff593c 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/28] use cache in getterritorydetail; remove unused bgpath; avoid throwing exceptions when possible; --- src/world/Manager/TerritoryMgr.cpp | 9 +- src/world/Territory/InstanceObjectCache.cpp | 98 ++++++++++++--------- 2 files changed, 60 insertions(+), 47 deletions(-) diff --git a/src/world/Manager/TerritoryMgr.cpp b/src/world/Manager/TerritoryMgr.cpp index 540a0617..abce3134 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 455975b2..291f18e3 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 ) { + switch( pEntry->getType() ) + { + case LgbEntryType::MapRange: + { + auto pMapRange = std::reinterpret_pointer_cast< LGB_MAP_RANGE_ENTRY >( pEntry ); + m_mapRangeCache.insert( id, pMapRange ); - 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 ) - { + break; + } + case LgbEntryType::ExitRange: + { + auto pExitRange = std::reinterpret_pointer_cast< LGB_EXIT_RANGE_ENTRY >( pEntry ); + m_exitRangeCache.insert( id, pExitRange ); - 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 ); + 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 ); - } - 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 ) - { - auto pEventRange = std::reinterpret_pointer_cast< LGB_EVENT_RANGE_ENTRY >( pEntry ); - m_eventRangeCache.insert( 0, pEventRange ); + //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/28] 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 c5c99f11..337d6731 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/28] 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 337d6731..d0c3f29b 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 ) + switch( type ) { - 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 - { - 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/28] 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 74aae36e..b1a2a2b5 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 8cf40658..e08f6e54 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 5ba553e5..a4be9156 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 c542eae7..4abed826 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 914e7983..7469d5c1 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 78faebe3..8d53c2ea 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 191c3f8e..2c41e123 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 2824f4ae..f7a18a40 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 2edeec1c..7d9c9aa5 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 abce3134..a7a27a7f 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 6aef66e0..61c0484c 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 ace19b6d..a0076141 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 450bcfd6..584f5ee3 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 291f18e3..91ff7a4c 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/28] 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 7469d5c1..ca12c46d 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/28] 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 | 42 +++++----- src/world/Actor/BNpc.h | 2 +- src/world/ForwardsZone.h | 3 + src/world/Manager/PlayerMgr.cpp | 2 +- 6 files changed, 223 insertions(+), 21 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 00000000..03a8e0de --- /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 00000000..caf62f9c --- /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 04107a5a..9f9429b5 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 ); +/* + 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; +*/ - m_gambits.push_back( testGambitRule ); - m_gambits.push_back( testGambitRule1 ); + 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 a8804f72..7076ae6e 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 de26643f..398e98b8 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 28636bbb..15f7ad51 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/28] 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 c667fe39..5d0115cf 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/28] 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 de4a5c4f..1948a207 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 4748e1e9..8c888209 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/28] 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 8c888209..c89cf550 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/28] 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 18e529d1..8aa5836c 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 5d0115cf..3bbb74ef 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/28] 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 f5dc332f..7d4d61a8 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 @@ public: 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 00000000..75ab8a97 --- /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/28] 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 406c22d5..9ec72292 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 6b08ea21..b3e3ccf6 100644 --- a/src/scripts/quest/subquest/limsa/SubSea004.cpp +++ b/src/scripts/quest/subquest/limsa/SubSea004.cpp @@ -145,6 +145,7 @@ private: { eventMgr().sendEventNotice( player, getId(), 0, 0 ); quest.setUI8AL( 1 ); + quest.setBitFlag8( 1, true ); checkQuestCompletion( quest, player, 1 ); } @@ -159,6 +160,7 @@ private: { eventMgr().sendEventNotice( player, getId(), 1, 0 ); quest.setUI8BH( 1 ); + quest.setBitFlag8( 2, true ); checkQuestCompletion( quest, player, 1 ); } @@ -173,6 +175,7 @@ private: { 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 26feaf98..4475010a 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 6e7c013e..6a220f83 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 @@ private: 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 @@ private: { eventMgr().sendEventNotice( player, getId(), 1, 0 ); quest.setUI8AL( 1 ); + quest.setBitFlag8( 1, true ); checkQuestCompletion( quest, player, 1 ); } @@ -197,6 +202,7 @@ private: { 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 bd263eea..48d8d5c3 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/28] 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 ee123859..05505cdf 100644 --- a/src/scripts/quest/classquest/MIN/ClsMin502.cpp +++ b/src/scripts/quest/classquest/MIN/ClsMin502.cpp @@ -45,6 +45,7 @@ private: 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 @@ private: 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 7e733494..df5fd18f 100644 --- a/src/scripts/quest/classquest/MIN/ClsMin600.cpp +++ b/src/scripts/quest/classquest/MIN/ClsMin600.cpp @@ -56,6 +56,7 @@ private: 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 @@ private: 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 4a809993..82d98728 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 @@ private: 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 @@ private: 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 @@ private: 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 @@ private: 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 @@ private: 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 4953a214..fae06547 100644 --- a/src/scripts/quest/classquest/WHM/JobWhm450.cpp +++ b/src/scripts/quest/classquest/WHM/JobWhm450.cpp @@ -80,6 +80,10 @@ private: 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 @@ private: 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 @@ private: 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 @@ private: 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 @@ private: 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 855624f1..14a68e7b 100644 --- a/src/scripts/quest/subquest/blackshroud_central/SubFst069.cpp +++ b/src/scripts/quest/subquest/blackshroud_central/SubFst069.cpp @@ -39,6 +39,7 @@ private: 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 @@ private: 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 5ef10f23..3630fb8f 100644 --- a/src/scripts/quest/subquest/coerthas_central/GaiUsb808.cpp +++ b/src/scripts/quest/subquest/coerthas_central/GaiUsb808.cpp @@ -55,6 +55,7 @@ private: 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 @@ private: 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 7b1b1047..a5cff6f2 100644 --- a/src/scripts/quest/subquest/gridania/GaiUsc609.cpp +++ b/src/scripts/quest/subquest/gridania/GaiUsc609.cpp @@ -61,6 +61,8 @@ private: 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 @@ private: 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 @@ private: { 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/28] 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 00000000..aba1d54d --- /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 00000000..7d04b507 --- /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 00000000..e393a57e --- /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 00000000..404393e1 --- /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 00000000..c614aa30 --- /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 00000000..eb43c410 --- /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/28] 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 7d4d61a8..135be4b5 100644 --- a/src/scripts/instances/questbattles/UnderneaththeSultantree.cpp +++ b/src/scripts/instances/questbattles/UnderneaththeSultantree.cpp @@ -142,8 +142,8 @@ public: 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 @@ public: 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 @@ public: 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 9505ca2f..716fc951 100644 --- a/src/scripts/quest/classquest/MIN/ClsMin580.cpp +++ b/src/scripts/quest/classquest/MIN/ClsMin580.cpp @@ -64,6 +64,7 @@ private: 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 @@ public: 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 05dafa7b..eb6b8abb 100644 --- a/src/scripts/quest/subquest/blackshroud_central/SubFst033.cpp +++ b/src/scripts/quest/subquest/blackshroud_central/SubFst033.cpp @@ -54,6 +54,7 @@ private: 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 @@ public: 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 ed0a3e02..f91b170a 100644 --- a/src/scripts/quest/subquest/blackshroud_central/SubFst052.cpp +++ b/src/scripts/quest/subquest/blackshroud_central/SubFst052.cpp @@ -45,6 +45,8 @@ private: 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 @@ public: { 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 6433ed1d..a8c3da0f 100644 --- a/src/scripts/quest/subquest/blackshroud_central/SubFst067.cpp +++ b/src/scripts/quest/subquest/blackshroud_central/SubFst067.cpp @@ -53,6 +53,7 @@ private: 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 @@ public: 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 15fcf1da..341a8e8b 100644 --- a/src/scripts/quest/subquest/blackshroud_north/GaiUsa803.cpp +++ b/src/scripts/quest/subquest/blackshroud_north/GaiUsa803.cpp @@ -55,6 +55,7 @@ private: 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 @@ public: 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 176978e3..17913967 100644 --- a/src/scripts/quest/subquest/lanoscea_outer/GaiUsb406.cpp +++ b/src/scripts/quest/subquest/lanoscea_outer/GaiUsb406.cpp @@ -55,6 +55,8 @@ private: 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 @@ private: { 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 eb43c410..92b69313 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/28] 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 e393a57e..ce041da3 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 404393e1..e1fec028 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/28] 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 00000000..5ae382c0 --- /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 00000000..857f5c21 --- /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 00000000..9619e8fe --- /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/28] 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 82d98728..4fb8ad99 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 @@ private: } }; -EXPOSE_SCRIPT( JobWhm001 ); \ No newline at end of file +EXPOSE_SCRIPT( JobWhm001 );