From b29971b9a3d8a720dcad56d6a5630e7d2028ad9a Mon Sep 17 00:00:00 2001 From: Tahir Date: Mon, 27 May 2024 01:45:37 +0100 Subject: [PATCH] wip: timeline refactor to use Territory instead of just InstanceContent (should support overworld now) --- src/world/Encounter/EncounterTimeline.cpp | 222 ++++++++++++++-------- src/world/Encounter/EncounterTimeline.h | 101 ++++++---- src/world/Territory/Territory.cpp | 12 ++ src/world/Territory/Territory.h | 4 + 4 files changed, 220 insertions(+), 119 deletions(-) diff --git a/src/world/Encounter/EncounterTimeline.cpp b/src/world/Encounter/EncounterTimeline.cpp index 2c3764f1..bc0d8f84 100644 --- a/src/world/Encounter/EncounterTimeline.cpp +++ b/src/world/Encounter/EncounterTimeline.cpp @@ -8,18 +8,20 @@ #include #include +#include #include #include #include +#include #include namespace Sapphire { - bool EncounterTimeline::ConditionHp::isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const + bool EncounterTimeline::ConditionHp::isConditionMet( ConditionState& state, TerritoryPtr pTeri, TimelinePack& pack, uint64_t time ) const { - auto pBNpc = pInstance->getActiveBNpcByLayoutId( layoutId ); + auto pBNpc = pTeri->getActiveBNpcByLayoutId( layoutId ); if( !pBNpc ) return false; @@ -38,33 +40,34 @@ namespace Sapphire return false; }; - bool EncounterTimeline::ConditionDirectorVar::isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const + bool EncounterTimeline::ConditionDirectorVar::isConditionMet( ConditionState& state, TerritoryPtr pTeri, TimelinePack& pack, uint64_t time ) const { - // todo: use something other than InstanceContentPtr - if( !pInstance ) - return false; + + Event::DirectorPtr pDirector = pTeri->getAsInstanceContent(); + if( pDirector == nullptr ) + pDirector = pTeri->getAsQuestBattle(); switch( m_conditionId ) { case ConditionId::DirectorVarEquals: - return pInstance->getDirectorVar( param.index ) == param.value; + return pDirector->getDirectorVar( param.index ) == param.value; case ConditionId::DirectorVarGreaterThan: - return pInstance->getDirectorVar( param.index ) > param.value; + return pDirector->getDirectorVar( param.index ) > param.value; case ConditionId::DirectorFlagsEquals: - return pInstance->getFlags() == param.flags; + return pDirector->getFlags() == param.flags; case ConditionId::DirectorFlagsGreaterThan: - return pInstance->getFlags() > param.flags; + return pDirector->getFlags() > param.flags; case ConditionId::DirectorSeqEquals: - return pInstance->getSequence() == param.seq; + return pDirector->getSequence() == param.seq; case ConditionId::DirectorSeqGreaterThan: - return pInstance->getSequence() > param.seq; + return pDirector->getSequence() > param.seq; } return false; } - bool EncounterTimeline::ConditionCombatState::isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const + bool EncounterTimeline::ConditionCombatState::isConditionMet( ConditionState& state, TerritoryPtr pTeri, TimelinePack& pack, uint64_t time ) const { - auto pBattleNpc = pInstance->getActiveBNpcByLayoutId( this->layoutId ); + auto pBattleNpc = pTeri->getActiveBNpcByLayoutId( this->layoutId ); switch( combatState ) { @@ -86,20 +89,20 @@ namespace Sapphire return false; } - bool EncounterTimeline::ConditionEncounterTimeElapsed::isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const + bool EncounterTimeline::ConditionEncounterTimeElapsed::isConditionMet( ConditionState& state, TerritoryPtr pTeri, TimelinePack& pack, uint64_t time ) const { auto elapsed = time - pack.getStartTime(); // todo: check encounter time return elapsed >= this->duration; } - bool EncounterTimeline::ConditionBNpcFlags::isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const + bool EncounterTimeline::ConditionBNpcFlags::isConditionMet( ConditionState& state, TerritoryPtr pTeri, TimelinePack& pack, uint64_t time ) const { - auto pBNpc = pInstance->getActiveBNpcByLayoutId( this->layoutId ); + auto pBNpc = pTeri->getActiveBNpcByLayoutId( this->layoutId ); return pBNpc && pBNpc->hasFlag( this->flags ); } - void EncounterTimeline::Timepoint::update( TimepointState& state, TimelineActor& self, InstanceContentPtr pInstance, uint64_t time ) const + void EncounterTimeline::Timepoint::update( TimepointState& state, TimelineActor& self, TerritoryPtr pTeri, uint64_t time ) const { state.m_lastTick = time; @@ -112,7 +115,7 @@ namespace Sapphire case TimepointDataType::Idle: { auto pIdleData = std::dynamic_pointer_cast< TimepointDataIdle, TimepointData >( getData() ); - auto pBNpc = pInstance->getActiveBNpcByLayoutId( pIdleData->m_layoutId ); + auto pBNpc = pTeri->getActiveBNpcByLayoutId( pIdleData->m_layoutId ); if( pBNpc ) { @@ -124,7 +127,7 @@ namespace Sapphire case TimepointDataType::CastAction: { auto pActionData = std::dynamic_pointer_cast< TimepointDataAction, TimepointData >( getData() ); - auto pBNpc = pInstance->getActiveBNpcByLayoutId( pActionData->m_layoutId ); + auto pBNpc = pTeri->getActiveBNpcByLayoutId( pActionData->m_layoutId ); // todo: filter the correct target // todo: tie to mechanic script? // todo: mechanic should probably just be an Action::onTick, with instance/director passed to it @@ -141,7 +144,7 @@ namespace Sapphire case TimepointDataType::MoveTo: { auto pMoveToData = std::dynamic_pointer_cast< TimepointDataMoveTo, TimepointData >( getData() ); - auto pBNpc = pInstance->getActiveBNpcByLayoutId( pMoveToData->m_layoutId ); + auto pBNpc = pTeri->getActiveBNpcByLayoutId( pMoveToData->m_layoutId ); if( pBNpc ) { @@ -171,12 +174,12 @@ namespace Sapphire auto params = pLogMessage->m_params; // todo: probably should use ContentDirector - if( pInstance ) + { auto& playerMgr = Common::Service< Sapphire::World::Manager::PlayerMgr >::ref(); - for( uint32_t id : pInstance->getSpawnedPlayerIds() ) + for( auto player : pTeri->getPlayers() ) { - auto pPlayer = playerMgr.getPlayer( id ); + auto pPlayer = player.second; if( pPlayer ) playerMgr.sendLogMessage( *pPlayer.get(), pLogMessage->m_messageId, params[ 0 ], params[ 1 ], params[ 2 ], params[ 3 ], params[ 4 ] ); @@ -190,18 +193,16 @@ namespace Sapphire auto pBtData = std::dynamic_pointer_cast< TimepointDataBattleTalk, TimepointData >( getData() ); auto params = pBtData->m_params; - if( pInstance ) + + auto& playerMgr = Common::Service< Sapphire::World::Manager::PlayerMgr >::ref(); + for( auto player : pTeri->getPlayers() ) { - auto& playerMgr = Common::Service< Sapphire::World::Manager::PlayerMgr >::ref(); - for( uint32_t id : pInstance->getSpawnedPlayerIds() ) - { - auto pPlayer = playerMgr.getPlayer( id ); - if( pPlayer ) - playerMgr.sendBattleTalk( *pPlayer.get(), pBtData->m_battleTalkId, pBtData->m_handlerId, - pBtData->m_kind, pBtData->m_nameId, pBtData->m_talkerId, - params[ 0 ], params[ 1 ], params[ 2 ], params[ 3 ], - params[ 4 ], params[ 5 ], params[ 6 ], params[ 7 ] ); - } + auto pPlayer = player.second; + if( pPlayer ) + playerMgr.sendBattleTalk( *pPlayer.get(), pBtData->m_battleTalkId, pBtData->m_handlerId, + pBtData->m_kind, pBtData->m_nameId, pBtData->m_talkerId, + params[ 0 ], params[ 1 ], params[ 2 ], params[ 3 ], + params[ 4 ], params[ 5 ], params[ 6 ], params[ 7 ] ); } } break; @@ -215,22 +216,28 @@ namespace Sapphire uint32_t val = 0; uint32_t param = 0; + // todo: expand for fates + Event::DirectorPtr pDirector = pTeri->getAsInstanceContent(); + if( pDirector == nullptr ) + pDirector = pTeri->getAsQuestBattle(); + // todo: this should never not be set? // todo: probably should use ContentDirector - if( pInstance ) + // todo: this needs to resend packets too + if( pDirector ) { switch( m_type ) { case TimepointDataType::DirectorVar: - val = pInstance->getDirectorVar( pDirectorData->m_data.index ); + val = pDirector->getDirectorVar( pDirectorData->m_data.index ); param = pDirectorData->m_data.value.val; break; case TimepointDataType::DirectorFlags: - val = pInstance->getFlags(); + val = pDirector->getFlags(); param = pDirectorData->m_data.flags; break; case TimepointDataType::DirectorSeq: - val = pInstance->getSequence(); + val = pDirector->getSequence(); param = pDirectorData->m_data.seq; break; default: @@ -254,16 +261,17 @@ namespace Sapphire default: break; } + // todo: resend packets switch( m_type ) { case TimepointDataType::DirectorVar: - pInstance->setVar( pDirectorData->m_data.index, val ); + pDirector->setDirectorVar( pDirectorData->m_data.index, val ); break; case TimepointDataType::DirectorFlags: - pInstance->setFlags( val ); + pDirector->setDirectorFlags( val ); break; case TimepointDataType::DirectorSeq: - pInstance->setSequence( val ); + pDirector->setDirectorSequence( val ); break; default: break; @@ -284,21 +292,20 @@ namespace Sapphire case TimepointDataType::SpawnBNpc: { auto pSpawnData = std::dynamic_pointer_cast< TimepointDataSpawnBNpc, TimepointData >( getData() ); - auto pBNpc = pInstance->getActiveBNpcByLayoutId( pSpawnData->m_layoutId ); + auto pBNpc = pTeri->getActiveBNpcByLayoutId( pSpawnData->m_layoutId ); if( pBNpc ) { pBNpc->clearFlags(); pBNpc->setFlag( pSpawnData->m_flags ); - // todo: pBNpc->hateListAdd(); - pInstance->pushActor( pBNpc ); + pBNpc->init(); } } break; case TimepointDataType::SetBNpcFlags: { auto pBNpcFlagData = std::dynamic_pointer_cast< TimepointDataBNpcFlags, TimepointData >( getData() ); - auto pBNpc = pInstance->getActiveBNpcByLayoutId( pBNpcFlagData->m_layoutId ); + auto pBNpc = pTeri->getActiveBNpcByLayoutId( pBNpcFlagData->m_layoutId ); if( pBNpc ) { @@ -311,20 +318,35 @@ namespace Sapphire case TimepointDataType::SetEObjState: { auto pEObjData = std::dynamic_pointer_cast< TimepointDataEObjState, TimepointData >( getData() ); - auto pEObj = pInstance->getEObjById( pEObjData->m_eobjId ); + auto pInstance = pTeri->getAsInstanceContent(); + auto pQBattle = pTeri->getAsQuestBattle(); + + // todo: event objects on quest battles // todo: SetEObjAnimationFlag? - if( pEObj ) + + if( pInstance ) { - pEObj->setState( pEObjData->m_state ); - // todo: resend the eobj spawn packet? + auto pEObj = pInstance->getEObjById( pEObjData->m_eobjId ); + if( pEObj ) + { + pEObj->setState( pEObjData->m_state ); + // todo: resend the eobj spawn packet? + } } } break; case TimepointDataType::SetBgm: { auto pBgmData = std::dynamic_pointer_cast< TimepointDataBGM, TimepointData >( getData() ); - pInstance->setCurrentBGM( pBgmData->m_bgmId ); + auto pInstance = pTeri->getAsInstanceContent(); + auto pQBattle = pTeri->getAsQuestBattle(); + + // todo: quest battles refactor to inherit InstanceContent + if( pInstance ) + { + pInstance->setCurrentBGM( pBgmData->m_bgmId ); + } } break; case TimepointDataType::SetCondition: @@ -390,7 +412,7 @@ namespace Sapphire callback( this, action ); } - void EncounterTimeline::Timepoint::execute( InstanceContentPtr pInstance, uint64_t time ) + void EncounterTimeline::Timepoint::execute( TerritoryPtr pTeri, uint64_t time ) { switch( m_type ) { @@ -405,10 +427,10 @@ namespace Sapphire } */ - void EncounterTimeline::Timepoint::execute( TimepointState& state, TimelineActor& self, InstanceContentPtr pInstance, uint64_t time ) const + void EncounterTimeline::Timepoint::execute( TimepointState& state, TimelineActor& self, TerritoryPtr pTeri, uint64_t time ) const { state.m_startTime = time; - update( state, self, pInstance, time ); + update( state, self, pTeri, time ); } // @@ -543,17 +565,17 @@ namespace Sapphire {} }; - const static std::unordered_map< std::string, TargetSelectFilterId > targetFilterMap = + const static std::unordered_map< std::string, TargetSelectFilterFlags > targetFilterMap = { - { "self", TargetSelectFilterId::Self }, - { "tank", TargetSelectFilterId::Tank }, - { "healer", TargetSelectFilterId::Healer }, - { "dps", TargetSelectFilterId::Dps }, - { "dpsMelee", TargetSelectFilterId::DpsMelee }, - { "dpsRanged", TargetSelectFilterId::DpsRanged }, - { "furthest", TargetSelectFilterId::Furthest }, - { "aggro1", TargetSelectFilterId::Aggro1 }, - { "aggro2", TargetSelectFilterId::Aggro2 } + { "self", TargetSelectFilterFlags::Self }, + { "tank", TargetSelectFilterFlags::Tank }, + { "healer", TargetSelectFilterFlags::Healer }, + { "dps", TargetSelectFilterFlags::Dps }, + { "melee", TargetSelectFilterFlags::Melee }, + { "ranged", TargetSelectFilterFlags::Ranged }, + { "furthest", TargetSelectFilterFlags::Furthest }, + { "aggro1", TargetSelectFilterFlags::Aggro1 }, + { "aggro2", TargetSelectFilterFlags::Aggro2 } }; const static std::unordered_map< std::string, TimepointCallbackType > callbackTypeMap = @@ -596,8 +618,7 @@ namespace Sapphire { case TimepointDataType::Idle: { - auto duration = json.at( "duration" ).get< uint32_t >(); - m_pData = std::make_shared< TimepointDataIdle >( selfLayoutId, duration ); + m_pData = std::make_shared< TimepointDataIdle >( selfLayoutId, m_duration ); } break; case TimepointDataType::CastAction: @@ -777,7 +798,7 @@ namespace Sapphire auto index = dataJ.at( "conditionId" ).get< uint32_t >(); auto enabled = dataJ.at( "enabled" ).get< bool >(); - m_pData = std::make_shared< TimepointDataCondition >( index, enabled ); + m_pData = std::make_shared< TimepointDataCondition >( index - 1, enabled ); } break; @@ -786,9 +807,9 @@ namespace Sapphire } } - EncounterTimeline::TimelinePack EncounterTimeline::getEncounterPack( uint32_t encounterId, bool reload ) + EncounterTimeline::TimelinePack EncounterTimeline::getEncounterPack( const std::string& name, bool reload ) { - static std::map< uint32_t, TimelinePack > cache = {}; + static std::map< std::string, TimelinePack > cache = {}; const static std::unordered_map< std::string, ConditionId > conditionIdMap = { { "hpPctLessThan", ConditionId::HpPctLessThan }, @@ -810,10 +831,10 @@ namespace Sapphire }; TimelinePack pack; - if( cache.find( encounterId ) != cache.end() && !reload ) - return cache.at( encounterId ); + if( cache.find( name ) != cache.end() && !reload ) + return cache.at( name ); - std::string encounter_name( fmt::format( std::string( "data/EncounterTimelines/EncounterTimeline%u.json" ), encounterId ) ); + std::string encounter_name( fmt::format( std::string( "data/EncounterTimelines/%s.json" ), name ) ); std::fstream f( encounter_name ); @@ -829,7 +850,7 @@ namespace Sapphire for( const auto& actorJ : json.at( "actors" ).items() ) { TimelineActor actor; - auto actorV = actorJ.value(); + auto& actorV = actorJ.value(); actor.m_hp = actorV.at( "hp" ).get< uint32_t >(); actor.m_layoutId = actorV.at( "layoutId" ).get< uint32_t >(); actor.m_name = actorV.at( "name" ).get< std::string >(); @@ -850,7 +871,7 @@ namespace Sapphire // todo: are phases linked by actor, or global in the json for( const auto& phaseJ : json.at( "phases" ).items() ) { - auto phaseV = phaseJ.value(); + auto& phaseV = phaseJ.value(); const auto id = phaseV.at( "id" ).get< uint32_t >(); const auto& phaseName = phaseV.at( "name" ).get< std::string >(); const auto& timepointsJ = phaseV.at( "timepoints" ); @@ -880,7 +901,7 @@ namespace Sapphire // build the condition list for( const auto& pcJ : json.at( "conditions" ).items() ) { - auto pcV = pcJ.value(); + auto& pcV = pcJ.value(); auto conditionName = pcV.at( "condition" ).get< std::string >(); auto description = pcV.at( "description" ).get< std::string >(); auto loop = pcV.at( "loop" ).get< bool >(); @@ -956,16 +977,57 @@ namespace Sapphire for( const auto& actor : actorNameMap ) pack.addTimelineActor( actor.second ); - std::string name( "Encounter" ); - name += std::to_string( encounterId ); - pack.setName( name ); // todo: reload will probably kill the server when CastAction.callbacks are added if( reload ) - cache[ encounterId ] = pack; + cache[ name ] = pack; else - cache.emplace( std::make_pair( encounterId, pack ) ); + cache.emplace( std::make_pair( name, pack ) ); return pack; } + + Entity::BNpcPtr EncounterTimeline::TimelineActor::spawnSubActor( TerritoryPtr pTeri, const std::string& name ) + { + // todo: retail straight up respawns sub actors, even bnpc parts (qarn adjudicator body parts respawn each time with new ids) + auto flags = Entity::BNpcFlag::Invincible | Entity::BNpcFlag::Untargetable | + Entity::BNpcFlag::Immobile | Entity::BNpcFlag::AutoAttackDisabled | + Entity::BNpcFlag::TurningDisabled; + + auto pActor = getSubActor( name ); + if( pActor == nullptr ) + { + auto pParent = pTeri->getActiveBNpcByLayoutId( m_layoutId ); + pActor = pTeri->createBNpcFromLayoutId( m_layoutId, 1000, pParent->getBNpcType() ); + m_subActors[ name ] = pActor; + } + pActor->setInvincibilityType( Common::InvincibilityIgnoreDamage ); + pActor->setFlag( flags ); + pActor->init(); + + pTeri->pushActor( pActor ); + return pActor; + } + + Entity::BNpcPtr EncounterTimeline::TimelineActor::getSubActor( const std::string& name ) + { + if( auto it = m_subActors.find( name ); it != m_subActors.end() ) + return it->second; + return nullptr; + } + + void EncounterTimeline::TimelineActor::resetSubActors( TerritoryPtr pTeri ) + { + for( auto& subActor : m_subActors ) + { + if( subActor.second ) + { + auto pBNpc = subActor.second; + pTeri->removeActor( pBNpc ); + // todo: despawn? + subActor.second = nullptr; + } + } + } + }// namespace Sapphire \ No newline at end of file diff --git a/src/world/Encounter/EncounterTimeline.h b/src/world/Encounter/EncounterTimeline.h index 0a05185f..7f18cc4a 100644 --- a/src/world/Encounter/EncounterTimeline.h +++ b/src/world/Encounter/EncounterTimeline.h @@ -127,18 +127,25 @@ namespace Sapphire OnActionExecute }; - enum class TargetSelectFilterId : uint32_t + enum class TargetSelectFilterFlags : uint32_t { - Self, - Tank, - Healer, - Dps, - DpsMelee, - DpsRanged, - Furthest, + Self = 0x00000000, - Aggro1, - Aggro2 + Player = 0x00000001, + + EnemyBattalion = 0x00000002, + OwnBattalion = 0x00000004, + + Tank = 0x00000010, + Healer = 0x00000020, + Dps = 0x00000040, + Melee = 0x00000080, + Ranged = 0x00000100, + Closest = 0x00000200, + Furthest = 0x00000400, + + Aggro1 = 0x10000000, + Aggro2 = 0x20000000, }; enum class MoveType : uint32_t @@ -171,13 +178,13 @@ namespace Sapphire struct TargetSelectFilter { - TargetSelectFilterId m_flags; + TargetSelectFilterFlags m_flags; }; // // Timepoint.m_pData objects // - using TimepointCallbackFunc = std::function< void( InstanceContentPtr, uint64_t ) >; + using TimepointCallbackFunc = std::function< void( TerritoryPtr, uint64_t ) >; // Timepoint Data Objects struct TimepointCallbackData : public std::enable_shared_from_this< TimepointCallbackData > @@ -437,8 +444,8 @@ namespace Sapphire void from_json( const nlohmann::json& json, const std::unordered_map< std::string, TimelineActor >& actors, uint32_t selfLayoutId ); // todo: separate execute/update into onStart and onTick? - void update( TimepointState& state, TimelineActor& self, InstanceContentPtr pInstance, uint64_t time ) const; - void execute( TimepointState& state, TimelineActor& self, InstanceContentPtr pInstance, uint64_t time ) const; + void update( TimepointState& state, TimelineActor& self, TerritoryPtr pTeri, uint64_t time ) const; + void execute( TimepointState& state, TimelineActor& self, TerritoryPtr pTeri, uint64_t time ) const; }; class Phase : @@ -452,7 +459,7 @@ namespace Sapphire std::vector< Timepoint > m_timepoints; // todo: i wrote this very sleep deprived, ensure it is actually sane - void execute( ConditionState& state, TimelineActor& self, InstanceContentPtr pInstance, uint64_t time ) const + void execute( ConditionState& state, TimelineActor& self, TerritoryPtr pTeri, uint64_t time ) const { if( state.m_startTime == 0 ) state.m_startTime = time; @@ -476,12 +483,12 @@ namespace Sapphire if( timepoint.canExecute( tpState, timepointElapsed ) ) { - timepoint.execute( tpState, self, pInstance, time ); + timepoint.execute( tpState, self, pTeri, time ); state.m_phaseInfo.m_lastTimepointTime = time; } else if( !timepoint.finished( tpState, timepointElapsed ) ) { - timepoint.update( tpState, self, pInstance, time ); + timepoint.update( tpState, self, pTeri, time ); } if( timepoint.durationElapsed( timepointElapsed ) && timepoint.finished( tpState, timepointElapsed ) ) @@ -543,15 +550,15 @@ namespace Sapphire this->m_enabled = json.at( "enabled" ).get< bool >(); } - void execute( ConditionState& state, TimelineActor& self, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const + void execute( ConditionState& state, TimelineActor& self, TerritoryPtr pTeri, TimelinePack& pack, uint64_t time ) const { state.m_startTime = time; - m_phase.execute( state, self, pInstance, time ); + m_phase.execute( state, self, pTeri, time ); }; - void update( ConditionState& state, TimelineActor& self, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const + void update( ConditionState& state, TimelineActor& self, TerritoryPtr pTeri, TimelinePack& pack, uint64_t time ) const { - m_phase.execute( state, self, pInstance, time ); + m_phase.execute( state, self, pTeri, time ); } void setEnabled( ConditionState& state, bool enabled ) @@ -597,7 +604,7 @@ namespace Sapphire return m_phase.completed( state ) && m_loop && ( state.m_startTime + m_cooldown <= time ); } - virtual bool isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const + virtual bool isConditionMet( ConditionState& state, TerritoryPtr pTeri, TimelinePack& pack, uint64_t time ) const { return false; }; @@ -611,6 +618,8 @@ namespace Sapphire std::vector< PhaseConditionPtr > m_phaseConditions; std::queue< PhaseConditionPtr > m_phaseHistory; std::vector< ConditionState > m_conditionStates; + // PARENTNAME_SUBACTOR_1, ..., PARENTNAME_SUBACTOR_69 + std::map< std::string, Entity::BNpcPtr > m_subActors; public: uint32_t m_layoutId{ 0 }; uint32_t m_hp{ 0 }; @@ -634,10 +643,9 @@ namespace Sapphire m_conditionStates[ m_conditionStates.size() - 1 ].m_enabled = pCondition->isDefaultEnabled(); } - // todo: make this sane and pass info down - void update( InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) + // todo: make this sane + void update( TerritoryPtr pTeri, TimelinePack& pack, uint64_t time ) { - // todo: handle auto attacks and make it so they dont fire during boss intermission phases // todo: handle interrupts for( auto i = 0; i < m_phaseConditions.size(); ++i ) { @@ -645,7 +653,7 @@ namespace Sapphire auto& state = m_conditionStates[ i ]; // ignore if not enabled, unless overriden to enable - if( !pCondition->isDefaultEnabled() && !pCondition->isStateEnabled( state ) ) + if( !pCondition->isStateEnabled( state ) ) continue; if( pCondition->completed( state ) ) @@ -658,11 +666,11 @@ namespace Sapphire } else if( pCondition->inProgress( state ) ) { - pCondition->update( state, *this, pInstance, pack, time ); + pCondition->update( state, *this, pTeri, pack, time ); } - else if( pCondition->isConditionMet( state, pInstance, pack, time ) ) + else if( pCondition->isConditionMet( state, pTeri, pack, time ) ) { - pCondition->execute( state, *this, pInstance, pack, time ); + pCondition->execute( state, *this, pTeri, pack, time ); m_phaseHistory.push( pCondition ); if( pack.getStartTime() == 0 ) @@ -688,12 +696,27 @@ namespace Sapphire auto& state = m_conditionStates[ conditionIdx ]; state.m_enabled = enabled; } + + void resetAllConditionStates() + { + for( auto i = 0; i < m_phaseConditions.size(); ++i ) + { + const auto& pCondition = m_phaseConditions[ i ]; + auto& state = m_conditionStates[ i ]; + + pCondition->reset( state ); + } + } + + Entity::BNpcPtr spawnSubActor( TerritoryPtr pTeri, const std::string& name ); + Entity::BNpcPtr getSubActor( const std::string& name ); + void resetSubActors( TerritoryPtr pTeri ); }; // todo: actually handle solo stuff properly (or tie to zone director/content director at least) class TimelinePack { - TimelinePackType m_type{TimelinePackType::Solo}; + TimelinePackType m_type{TimelinePackType::EncounterFight}; std::vector< TimelineActor > m_actors; std::string m_name; @@ -717,7 +740,7 @@ namespace Sapphire void addTimelineActor( const TimelineActor& actor ) { - m_actors.push_back( actor ); + m_actors.emplace_back( actor ); } void setStartTime( uint64_t time ) @@ -730,10 +753,10 @@ namespace Sapphire return m_startTime; } - void update( InstanceContentPtr pInstance, uint64_t time ) + void update( TerritoryPtr pTeri, uint64_t time ) { for( auto& actor : m_actors ) - actor.update( pInstance, *this, time ); + actor.update( pTeri, *this, time ); } }; @@ -756,7 +779,7 @@ namespace Sapphire void from_json( nlohmann::json& json, Phase& phase, ConditionId conditionId, const std::unordered_map< std::string, TimelineActor >& actors ); - bool isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const override; + bool isConditionMet( ConditionState& state, TerritoryPtr pTeri, TimelinePack& pack, uint64_t time ) const override; }; class ConditionDirectorVar : PhaseCondition @@ -774,7 +797,7 @@ namespace Sapphire } param; void from_json( nlohmann::json& json, Phase& phase, ConditionId conditionId ); - bool isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const override; + bool isConditionMet( ConditionState& state, TerritoryPtr pTeri, TimelinePack& pack, uint64_t time ) const override; }; class ConditionEncounterTimeElapsed : PhaseCondition @@ -783,7 +806,7 @@ namespace Sapphire uint64_t duration; void from_json( nlohmann::json& json, Phase& phase, ConditionId conditionId ); - bool isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const override; + bool isConditionMet( ConditionState& state, TerritoryPtr pTeri, TimelinePack& pack, uint64_t time ) const override; }; class ConditionCombatState : PhaseCondition @@ -793,7 +816,7 @@ namespace Sapphire CombatStateType combatState; void from_json( nlohmann::json& json, Phase& phase, ConditionId conditionId, const std::unordered_map< std::string, TimelineActor >& actors ); - bool isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const override; + bool isConditionMet( ConditionState& state, TerritoryPtr pTeri, TimelinePack& pack, uint64_t time ) const override; }; class ConditionBNpcFlags : PhaseCondition @@ -803,11 +826,11 @@ namespace Sapphire uint32_t flags; void from_json( nlohmann::json& json, Phase& phase, ConditionId conditionId, const std::unordered_map< std::string, TimelineActor >& actors ); - bool isConditionMet( ConditionState& state, InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) const override; + bool isConditionMet( ConditionState& state, TerritoryPtr pTeri, TimelinePack& pack, uint64_t time ) const override; }; public: - TimelinePack getEncounterPack( uint32_t encounterId, bool reload = false ); + TimelinePack getEncounterPack( const std::string& name, bool reload = false ); }; }// namespace Sapphire \ No newline at end of file diff --git a/src/world/Territory/Territory.cpp b/src/world/Territory/Territory.cpp index 1948a207..c965a5ad 100644 --- a/src/world/Territory/Territory.cpp +++ b/src/world/Territory/Territory.cpp @@ -765,6 +765,18 @@ Entity::EventObjectPtr Territory::getEObj( uint32_t objId ) return obj->second; } +Entity::PlayerPtr Territory::getPlayer( uint32_t playerId ) +{ + if( auto it = m_playerMap.find( playerId ); it != m_playerMap.end() ) + return it->second; + return nullptr; +} + +std::unordered_map< uint32_t, Entity::PlayerPtr > Territory::getPlayers() +{ + return m_playerMap; +} + InstanceContentPtr Territory::getAsInstanceContent() { return std::dynamic_pointer_cast< InstanceContent, Territory >( shared_from_this() ); diff --git a/src/world/Territory/Territory.h b/src/world/Territory/Territory.h index d6b4f89c..a00df76c 100644 --- a/src/world/Territory/Territory.h +++ b/src/world/Territory/Territory.h @@ -186,6 +186,10 @@ namespace Sapphire Entity::EventObjectPtr getEObj( uint32_t objId ); + Entity::PlayerPtr getPlayer( uint32_t playerId ); + + std::unordered_map< uint32_t, Entity::PlayerPtr > getPlayers(); + InstanceContentPtr getAsInstanceContent(); QuestBattlePtr getAsQuestBattle();