1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-28 15:17:46 +00:00

wip: timeline refactor to use Territory instead of just InstanceContent (should support overworld now)

This commit is contained in:
Tahir 2024-05-27 01:45:37 +01:00
parent 989e1eeff7
commit b29971b9a3
4 changed files with 220 additions and 119 deletions

View file

@ -8,18 +8,20 @@
#include <Actor/EventObject.h> #include <Actor/EventObject.h>
#include <Actor/Player.h> #include <Actor/Player.h>
#include <Event/Director.h>
#include <Manager/ActionMgr.h> #include <Manager/ActionMgr.h>
#include <Manager/PlayerMgr.h> #include <Manager/PlayerMgr.h>
#include <Service.h> #include <Service.h>
#include <Territory/QuestBattle.h>
#include <Util/UtilMath.h> #include <Util/UtilMath.h>
namespace Sapphire 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 ) if( !pBNpc )
return false; return false;
@ -38,33 +40,34 @@ namespace Sapphire
return false; 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 ) Event::DirectorPtr pDirector = pTeri->getAsInstanceContent();
return false; if( pDirector == nullptr )
pDirector = pTeri->getAsQuestBattle();
switch( m_conditionId ) switch( m_conditionId )
{ {
case ConditionId::DirectorVarEquals: case ConditionId::DirectorVarEquals:
return pInstance->getDirectorVar( param.index ) == param.value; return pDirector->getDirectorVar( param.index ) == param.value;
case ConditionId::DirectorVarGreaterThan: case ConditionId::DirectorVarGreaterThan:
return pInstance->getDirectorVar( param.index ) > param.value; return pDirector->getDirectorVar( param.index ) > param.value;
case ConditionId::DirectorFlagsEquals: case ConditionId::DirectorFlagsEquals:
return pInstance->getFlags() == param.flags; return pDirector->getFlags() == param.flags;
case ConditionId::DirectorFlagsGreaterThan: case ConditionId::DirectorFlagsGreaterThan:
return pInstance->getFlags() > param.flags; return pDirector->getFlags() > param.flags;
case ConditionId::DirectorSeqEquals: case ConditionId::DirectorSeqEquals:
return pInstance->getSequence() == param.seq; return pDirector->getSequence() == param.seq;
case ConditionId::DirectorSeqGreaterThan: case ConditionId::DirectorSeqGreaterThan:
return pInstance->getSequence() > param.seq; return pDirector->getSequence() > param.seq;
} }
return false; 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 ) switch( combatState )
{ {
@ -86,20 +89,20 @@ namespace Sapphire
return false; 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(); auto elapsed = time - pack.getStartTime();
// todo: check encounter time // todo: check encounter time
return elapsed >= this->duration; 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 ); 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; state.m_lastTick = time;
@ -112,7 +115,7 @@ namespace Sapphire
case TimepointDataType::Idle: case TimepointDataType::Idle:
{ {
auto pIdleData = std::dynamic_pointer_cast< TimepointDataIdle, TimepointData >( getData() ); 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 ) if( pBNpc )
{ {
@ -124,7 +127,7 @@ namespace Sapphire
case TimepointDataType::CastAction: case TimepointDataType::CastAction:
{ {
auto pActionData = std::dynamic_pointer_cast< TimepointDataAction, TimepointData >( getData() ); 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: filter the correct target
// todo: tie to mechanic script? // todo: tie to mechanic script?
// todo: mechanic should probably just be an Action::onTick, with instance/director passed to it // todo: mechanic should probably just be an Action::onTick, with instance/director passed to it
@ -141,7 +144,7 @@ namespace Sapphire
case TimepointDataType::MoveTo: case TimepointDataType::MoveTo:
{ {
auto pMoveToData = std::dynamic_pointer_cast< TimepointDataMoveTo, TimepointData >( getData() ); 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 ) if( pBNpc )
{ {
@ -171,12 +174,12 @@ namespace Sapphire
auto params = pLogMessage->m_params; auto params = pLogMessage->m_params;
// todo: probably should use ContentDirector // todo: probably should use ContentDirector
if( pInstance )
{ {
auto& playerMgr = Common::Service< Sapphire::World::Manager::PlayerMgr >::ref(); 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 ) if( pPlayer )
playerMgr.sendLogMessage( *pPlayer.get(), pLogMessage->m_messageId, playerMgr.sendLogMessage( *pPlayer.get(), pLogMessage->m_messageId,
params[ 0 ], params[ 1 ], params[ 2 ], params[ 3 ], params[ 4 ] ); 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 pBtData = std::dynamic_pointer_cast< TimepointDataBattleTalk, TimepointData >( getData() );
auto params = pBtData->m_params; 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(); auto pPlayer = player.second;
for( uint32_t id : pInstance->getSpawnedPlayerIds() ) if( pPlayer )
{ playerMgr.sendBattleTalk( *pPlayer.get(), pBtData->m_battleTalkId, pBtData->m_handlerId,
auto pPlayer = playerMgr.getPlayer( id ); pBtData->m_kind, pBtData->m_nameId, pBtData->m_talkerId,
if( pPlayer ) params[ 0 ], params[ 1 ], params[ 2 ], params[ 3 ],
playerMgr.sendBattleTalk( *pPlayer.get(), pBtData->m_battleTalkId, pBtData->m_handlerId, params[ 4 ], params[ 5 ], params[ 6 ], params[ 7 ] );
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; break;
@ -215,22 +216,28 @@ namespace Sapphire
uint32_t val = 0; uint32_t val = 0;
uint32_t param = 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: this should never not be set?
// todo: probably should use ContentDirector // todo: probably should use ContentDirector
if( pInstance ) // todo: this needs to resend packets too
if( pDirector )
{ {
switch( m_type ) switch( m_type )
{ {
case TimepointDataType::DirectorVar: case TimepointDataType::DirectorVar:
val = pInstance->getDirectorVar( pDirectorData->m_data.index ); val = pDirector->getDirectorVar( pDirectorData->m_data.index );
param = pDirectorData->m_data.value.val; param = pDirectorData->m_data.value.val;
break; break;
case TimepointDataType::DirectorFlags: case TimepointDataType::DirectorFlags:
val = pInstance->getFlags(); val = pDirector->getFlags();
param = pDirectorData->m_data.flags; param = pDirectorData->m_data.flags;
break; break;
case TimepointDataType::DirectorSeq: case TimepointDataType::DirectorSeq:
val = pInstance->getSequence(); val = pDirector->getSequence();
param = pDirectorData->m_data.seq; param = pDirectorData->m_data.seq;
break; break;
default: default:
@ -254,16 +261,17 @@ namespace Sapphire
default: break; default: break;
} }
// todo: resend packets
switch( m_type ) switch( m_type )
{ {
case TimepointDataType::DirectorVar: case TimepointDataType::DirectorVar:
pInstance->setVar( pDirectorData->m_data.index, val ); pDirector->setDirectorVar( pDirectorData->m_data.index, val );
break; break;
case TimepointDataType::DirectorFlags: case TimepointDataType::DirectorFlags:
pInstance->setFlags( val ); pDirector->setDirectorFlags( val );
break; break;
case TimepointDataType::DirectorSeq: case TimepointDataType::DirectorSeq:
pInstance->setSequence( val ); pDirector->setDirectorSequence( val );
break; break;
default: default:
break; break;
@ -284,21 +292,20 @@ namespace Sapphire
case TimepointDataType::SpawnBNpc: case TimepointDataType::SpawnBNpc:
{ {
auto pSpawnData = std::dynamic_pointer_cast< TimepointDataSpawnBNpc, TimepointData >( getData() ); 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 ) if( pBNpc )
{ {
pBNpc->clearFlags(); pBNpc->clearFlags();
pBNpc->setFlag( pSpawnData->m_flags ); pBNpc->setFlag( pSpawnData->m_flags );
// todo: pBNpc->hateListAdd(); pBNpc->init();
pInstance->pushActor( pBNpc );
} }
} }
break; break;
case TimepointDataType::SetBNpcFlags: case TimepointDataType::SetBNpcFlags:
{ {
auto pBNpcFlagData = std::dynamic_pointer_cast< TimepointDataBNpcFlags, TimepointData >( getData() ); 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 ) if( pBNpc )
{ {
@ -311,20 +318,35 @@ namespace Sapphire
case TimepointDataType::SetEObjState: case TimepointDataType::SetEObjState:
{ {
auto pEObjData = std::dynamic_pointer_cast< TimepointDataEObjState, TimepointData >( getData() ); 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? // todo: SetEObjAnimationFlag?
if( pEObj )
if( pInstance )
{ {
pEObj->setState( pEObjData->m_state ); auto pEObj = pInstance->getEObjById( pEObjData->m_eobjId );
// todo: resend the eobj spawn packet? if( pEObj )
{
pEObj->setState( pEObjData->m_state );
// todo: resend the eobj spawn packet?
}
} }
} }
break; break;
case TimepointDataType::SetBgm: case TimepointDataType::SetBgm:
{ {
auto pBgmData = std::dynamic_pointer_cast< TimepointDataBGM, TimepointData >( getData() ); 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; break;
case TimepointDataType::SetCondition: case TimepointDataType::SetCondition:
@ -390,7 +412,7 @@ namespace Sapphire
callback( this, action ); callback( this, action );
} }
void EncounterTimeline::Timepoint::execute( InstanceContentPtr pInstance, uint64_t time ) void EncounterTimeline::Timepoint::execute( TerritoryPtr pTeri, uint64_t time )
{ {
switch( m_type ) 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; 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 }, { "self", TargetSelectFilterFlags::Self },
{ "tank", TargetSelectFilterId::Tank }, { "tank", TargetSelectFilterFlags::Tank },
{ "healer", TargetSelectFilterId::Healer }, { "healer", TargetSelectFilterFlags::Healer },
{ "dps", TargetSelectFilterId::Dps }, { "dps", TargetSelectFilterFlags::Dps },
{ "dpsMelee", TargetSelectFilterId::DpsMelee }, { "melee", TargetSelectFilterFlags::Melee },
{ "dpsRanged", TargetSelectFilterId::DpsRanged }, { "ranged", TargetSelectFilterFlags::Ranged },
{ "furthest", TargetSelectFilterId::Furthest }, { "furthest", TargetSelectFilterFlags::Furthest },
{ "aggro1", TargetSelectFilterId::Aggro1 }, { "aggro1", TargetSelectFilterFlags::Aggro1 },
{ "aggro2", TargetSelectFilterId::Aggro2 } { "aggro2", TargetSelectFilterFlags::Aggro2 }
}; };
const static std::unordered_map< std::string, TimepointCallbackType > callbackTypeMap = const static std::unordered_map< std::string, TimepointCallbackType > callbackTypeMap =
@ -596,8 +618,7 @@ namespace Sapphire
{ {
case TimepointDataType::Idle: case TimepointDataType::Idle:
{ {
auto duration = json.at( "duration" ).get< uint32_t >(); m_pData = std::make_shared< TimepointDataIdle >( selfLayoutId, m_duration );
m_pData = std::make_shared< TimepointDataIdle >( selfLayoutId, duration );
} }
break; break;
case TimepointDataType::CastAction: case TimepointDataType::CastAction:
@ -777,7 +798,7 @@ namespace Sapphire
auto index = dataJ.at( "conditionId" ).get< uint32_t >(); auto index = dataJ.at( "conditionId" ).get< uint32_t >();
auto enabled = dataJ.at( "enabled" ).get< bool >(); 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; 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 = const static std::unordered_map< std::string, ConditionId > conditionIdMap =
{ {
{ "hpPctLessThan", ConditionId::HpPctLessThan }, { "hpPctLessThan", ConditionId::HpPctLessThan },
@ -810,10 +831,10 @@ namespace Sapphire
}; };
TimelinePack pack; TimelinePack pack;
if( cache.find( encounterId ) != cache.end() && !reload ) if( cache.find( name ) != cache.end() && !reload )
return cache.at( encounterId ); 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 ); std::fstream f( encounter_name );
@ -829,7 +850,7 @@ namespace Sapphire
for( const auto& actorJ : json.at( "actors" ).items() ) for( const auto& actorJ : json.at( "actors" ).items() )
{ {
TimelineActor actor; TimelineActor actor;
auto actorV = actorJ.value(); auto& actorV = actorJ.value();
actor.m_hp = actorV.at( "hp" ).get< uint32_t >(); actor.m_hp = actorV.at( "hp" ).get< uint32_t >();
actor.m_layoutId = actorV.at( "layoutId" ).get< uint32_t >(); actor.m_layoutId = actorV.at( "layoutId" ).get< uint32_t >();
actor.m_name = actorV.at( "name" ).get< std::string >(); 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 // todo: are phases linked by actor, or global in the json
for( const auto& phaseJ : json.at( "phases" ).items() ) 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 id = phaseV.at( "id" ).get< uint32_t >();
const auto& phaseName = phaseV.at( "name" ).get< std::string >(); const auto& phaseName = phaseV.at( "name" ).get< std::string >();
const auto& timepointsJ = phaseV.at( "timepoints" ); const auto& timepointsJ = phaseV.at( "timepoints" );
@ -880,7 +901,7 @@ namespace Sapphire
// build the condition list // build the condition list
for( const auto& pcJ : json.at( "conditions" ).items() ) 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 conditionName = pcV.at( "condition" ).get< std::string >();
auto description = pcV.at( "description" ).get< std::string >(); auto description = pcV.at( "description" ).get< std::string >();
auto loop = pcV.at( "loop" ).get< bool >(); auto loop = pcV.at( "loop" ).get< bool >();
@ -956,16 +977,57 @@ namespace Sapphire
for( const auto& actor : actorNameMap ) for( const auto& actor : actorNameMap )
pack.addTimelineActor( actor.second ); pack.addTimelineActor( actor.second );
std::string name( "Encounter" );
name += std::to_string( encounterId );
pack.setName( name ); pack.setName( name );
// todo: reload will probably kill the server when CastAction.callbacks are added // todo: reload will probably kill the server when CastAction.callbacks are added
if( reload ) if( reload )
cache[ encounterId ] = pack; cache[ name ] = pack;
else else
cache.emplace( std::make_pair( encounterId, pack ) ); cache.emplace( std::make_pair( name, pack ) );
return 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 }// namespace Sapphire

View file

@ -127,18 +127,25 @@ namespace Sapphire
OnActionExecute OnActionExecute
}; };
enum class TargetSelectFilterId : uint32_t enum class TargetSelectFilterFlags : uint32_t
{ {
Self, Self = 0x00000000,
Tank,
Healer,
Dps,
DpsMelee,
DpsRanged,
Furthest,
Aggro1, Player = 0x00000001,
Aggro2
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 enum class MoveType : uint32_t
@ -171,13 +178,13 @@ namespace Sapphire
struct TargetSelectFilter struct TargetSelectFilter
{ {
TargetSelectFilterId m_flags; TargetSelectFilterFlags m_flags;
}; };
// //
// Timepoint.m_pData objects // Timepoint.m_pData objects
// //
using TimepointCallbackFunc = std::function< void( InstanceContentPtr, uint64_t ) >; using TimepointCallbackFunc = std::function< void( TerritoryPtr, uint64_t ) >;
// Timepoint Data Objects // Timepoint Data Objects
struct TimepointCallbackData : struct TimepointCallbackData :
public std::enable_shared_from_this< 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 ); 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? // todo: separate execute/update into onStart and onTick?
void update( 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, InstanceContentPtr pInstance, uint64_t time ) const; void execute( TimepointState& state, TimelineActor& self, TerritoryPtr pTeri, uint64_t time ) const;
}; };
class Phase : class Phase :
@ -452,7 +459,7 @@ namespace Sapphire
std::vector< Timepoint > m_timepoints; std::vector< Timepoint > m_timepoints;
// todo: i wrote this very sleep deprived, ensure it is actually sane // 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 ) if( state.m_startTime == 0 )
state.m_startTime = time; state.m_startTime = time;
@ -476,12 +483,12 @@ namespace Sapphire
if( timepoint.canExecute( tpState, timepointElapsed ) ) if( timepoint.canExecute( tpState, timepointElapsed ) )
{ {
timepoint.execute( tpState, self, pInstance, time ); timepoint.execute( tpState, self, pTeri, time );
state.m_phaseInfo.m_lastTimepointTime = time; state.m_phaseInfo.m_lastTimepointTime = time;
} }
else if( !timepoint.finished( tpState, timepointElapsed ) ) 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 ) ) if( timepoint.durationElapsed( timepointElapsed ) && timepoint.finished( tpState, timepointElapsed ) )
@ -543,15 +550,15 @@ namespace Sapphire
this->m_enabled = json.at( "enabled" ).get< bool >(); 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; 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 ) 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 ); 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; return false;
}; };
@ -611,6 +618,8 @@ namespace Sapphire
std::vector< PhaseConditionPtr > m_phaseConditions; std::vector< PhaseConditionPtr > m_phaseConditions;
std::queue< PhaseConditionPtr > m_phaseHistory; std::queue< PhaseConditionPtr > m_phaseHistory;
std::vector< ConditionState > m_conditionStates; std::vector< ConditionState > m_conditionStates;
// PARENTNAME_SUBACTOR_1, ..., PARENTNAME_SUBACTOR_69
std::map< std::string, Entity::BNpcPtr > m_subActors;
public: public:
uint32_t m_layoutId{ 0 }; uint32_t m_layoutId{ 0 };
uint32_t m_hp{ 0 }; uint32_t m_hp{ 0 };
@ -634,10 +643,9 @@ namespace Sapphire
m_conditionStates[ m_conditionStates.size() - 1 ].m_enabled = pCondition->isDefaultEnabled(); m_conditionStates[ m_conditionStates.size() - 1 ].m_enabled = pCondition->isDefaultEnabled();
} }
// todo: make this sane and pass info down // todo: make this sane
void update( InstanceContentPtr pInstance, TimelinePack& pack, uint64_t time ) 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 // todo: handle interrupts
for( auto i = 0; i < m_phaseConditions.size(); ++i ) for( auto i = 0; i < m_phaseConditions.size(); ++i )
{ {
@ -645,7 +653,7 @@ namespace Sapphire
auto& state = m_conditionStates[ i ]; auto& state = m_conditionStates[ i ];
// ignore if not enabled, unless overriden to enable // ignore if not enabled, unless overriden to enable
if( !pCondition->isDefaultEnabled() && !pCondition->isStateEnabled( state ) ) if( !pCondition->isStateEnabled( state ) )
continue; continue;
if( pCondition->completed( state ) ) if( pCondition->completed( state ) )
@ -658,11 +666,11 @@ namespace Sapphire
} }
else if( pCondition->inProgress( state ) ) 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 ); m_phaseHistory.push( pCondition );
if( pack.getStartTime() == 0 ) if( pack.getStartTime() == 0 )
@ -688,12 +696,27 @@ namespace Sapphire
auto& state = m_conditionStates[ conditionIdx ]; auto& state = m_conditionStates[ conditionIdx ];
state.m_enabled = enabled; 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) // todo: actually handle solo stuff properly (or tie to zone director/content director at least)
class TimelinePack class TimelinePack
{ {
TimelinePackType m_type{TimelinePackType::Solo}; TimelinePackType m_type{TimelinePackType::EncounterFight};
std::vector< TimelineActor > m_actors; std::vector< TimelineActor > m_actors;
std::string m_name; std::string m_name;
@ -717,7 +740,7 @@ namespace Sapphire
void addTimelineActor( const TimelineActor& actor ) void addTimelineActor( const TimelineActor& actor )
{ {
m_actors.push_back( actor ); m_actors.emplace_back( actor );
} }
void setStartTime( uint64_t time ) void setStartTime( uint64_t time )
@ -730,10 +753,10 @@ namespace Sapphire
return m_startTime; return m_startTime;
} }
void update( InstanceContentPtr pInstance, uint64_t time ) void update( TerritoryPtr pTeri, uint64_t time )
{ {
for( auto& actor : m_actors ) 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, void from_json( nlohmann::json& json, Phase& phase, ConditionId conditionId,
const std::unordered_map< std::string, TimelineActor >& actors ); 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 class ConditionDirectorVar : PhaseCondition
@ -774,7 +797,7 @@ namespace Sapphire
} param; } param;
void from_json( nlohmann::json& json, Phase& phase, ConditionId conditionId ); 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 class ConditionEncounterTimeElapsed : PhaseCondition
@ -783,7 +806,7 @@ namespace Sapphire
uint64_t duration; uint64_t duration;
void from_json( nlohmann::json& json, Phase& phase, ConditionId conditionId ); 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 class ConditionCombatState : PhaseCondition
@ -793,7 +816,7 @@ namespace Sapphire
CombatStateType combatState; CombatStateType combatState;
void from_json( nlohmann::json& json, Phase& phase, ConditionId conditionId, const std::unordered_map< std::string, TimelineActor >& actors ); 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 class ConditionBNpcFlags : PhaseCondition
@ -803,11 +826,11 @@ namespace Sapphire
uint32_t flags; uint32_t flags;
void from_json( nlohmann::json& json, Phase& phase, ConditionId conditionId, const std::unordered_map< std::string, TimelineActor >& actors ); 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: public:
TimelinePack getEncounterPack( uint32_t encounterId, bool reload = false ); TimelinePack getEncounterPack( const std::string& name, bool reload = false );
}; };
}// namespace Sapphire }// namespace Sapphire

View file

@ -765,6 +765,18 @@ Entity::EventObjectPtr Territory::getEObj( uint32_t objId )
return obj->second; 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() InstanceContentPtr Territory::getAsInstanceContent()
{ {
return std::dynamic_pointer_cast< InstanceContent, Territory >( shared_from_this() ); return std::dynamic_pointer_cast< InstanceContent, Territory >( shared_from_this() );

View file

@ -186,6 +186,10 @@ namespace Sapphire
Entity::EventObjectPtr getEObj( uint32_t objId ); Entity::EventObjectPtr getEObj( uint32_t objId );
Entity::PlayerPtr getPlayer( uint32_t playerId );
std::unordered_map< uint32_t, Entity::PlayerPtr > getPlayers();
InstanceContentPtr getAsInstanceContent(); InstanceContentPtr getAsInstanceContent();
QuestBattlePtr getAsQuestBattle(); QuestBattlePtr getAsQuestBattle();