mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-05-01 16:37:45 +00:00
wip: refactor some encounter timeline stuff
- todo: test if any of this actually works
This commit is contained in:
parent
05f9feb6ed
commit
342c30aa43
2 changed files with 328 additions and 153 deletions
|
@ -6,53 +6,7 @@
|
||||||
|
|
||||||
namespace Sapphire
|
namespace Sapphire
|
||||||
{
|
{
|
||||||
void EncounterTimeline::ConditionHp::from_json( nlohmann::json& json, Phase phase, ConditionId conditionId )
|
bool EncounterTimeline::ConditionHp::isConditionMet( EncounterFightPtr pFight, uint64_t time )
|
||||||
{
|
|
||||||
TimepointCondition::from_json( json, phase, conditionId );
|
|
||||||
|
|
||||||
auto params = json.at( "params" ).get< std::vector< uint32_t > >();
|
|
||||||
|
|
||||||
this->actorId = params[ 0 ];
|
|
||||||
|
|
||||||
if( conditionId == ConditionId::HpPctLessThan )
|
|
||||||
this->hp.val = params[ 1 ];
|
|
||||||
else
|
|
||||||
this->hp.min = params[ 1 ], this->hp.max = params[ 2 ];
|
|
||||||
}
|
|
||||||
|
|
||||||
void EncounterTimeline::ConditionDirectorVar::from_json( nlohmann::json& json, Phase phase, ConditionId conditionId )
|
|
||||||
{
|
|
||||||
TimepointCondition::from_json( json, phase, conditionId );
|
|
||||||
|
|
||||||
auto params = json.at( "params" ).get< std::vector< uint32_t > >();
|
|
||||||
|
|
||||||
switch( conditionId )
|
|
||||||
{
|
|
||||||
case ConditionId::DirectorVarEquals:
|
|
||||||
case ConditionId::DirectorVarGreaterThan:
|
|
||||||
{
|
|
||||||
param.var = params[ 0 ];
|
|
||||||
param.value = params[ 1 ];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ConditionId::DirectorFlagsEquals:
|
|
||||||
case ConditionId::DirectorFlagsGreaterThan:
|
|
||||||
{
|
|
||||||
param.flag = params[ 0 ];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ConditionId::DirectorSeqEquals:
|
|
||||||
case ConditionId::DirectorSeqGreaterThan:
|
|
||||||
{
|
|
||||||
param.seq = params[ 0 ];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool EncounterTimeline::ConditionHp::canExecute( EncounterFightPtr pFight, uint64_t time )
|
|
||||||
{
|
{
|
||||||
auto pBNpc = pFight->getBNpc( actorId );
|
auto pBNpc = pFight->getBNpc( actorId );
|
||||||
if( !pBNpc )
|
if( !pBNpc )
|
||||||
|
@ -73,7 +27,7 @@ namespace Sapphire
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool EncounterTimeline::ConditionDirectorVar::canExecute( EncounterFightPtr pFight, uint64_t time )
|
bool EncounterTimeline::ConditionDirectorVar::isConditionMet( EncounterFightPtr pFight, uint64_t time )
|
||||||
{
|
{
|
||||||
auto pInstance = pFight->getInstance();
|
auto pInstance = pFight->getInstance();
|
||||||
|
|
||||||
|
@ -178,7 +132,86 @@ namespace Sapphire
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EncounterTimeline::Timepoint::from_json( const nlohmann::json& json )
|
//
|
||||||
|
// parsing stuff below
|
||||||
|
//
|
||||||
|
|
||||||
|
void EncounterTimeline::ConditionHp::from_json( nlohmann::json& json, Phase phase, ConditionId conditionId,
|
||||||
|
const std::unordered_map< std::string, TimelineActor >& actors )
|
||||||
|
{
|
||||||
|
PhaseCondition::from_json( json, phase, conditionId );
|
||||||
|
|
||||||
|
auto paramData = json.at( "paramData" );
|
||||||
|
auto actorRef = paramData.at( "sourceActor" );
|
||||||
|
|
||||||
|
// resolve the actor whose hp we are checking
|
||||||
|
if( auto it = actors.find( actorRef ); it != actors.end() )
|
||||||
|
this->actorId = it->second.m_layoutId;
|
||||||
|
else
|
||||||
|
throw std::runtime_error( fmt::format( std::string( "EncounterTimeline::ConditionHp::from_json unable to find actor by name: %s" ), actorRef ) );
|
||||||
|
|
||||||
|
switch( conditionId )
|
||||||
|
{
|
||||||
|
case ConditionId::HpPctLessThan:
|
||||||
|
this->hp.val = paramData.at( "hp" ).get< uint32_t >();
|
||||||
|
break;
|
||||||
|
case ConditionId::HpPctBetween:
|
||||||
|
this->hp.val = paramData.at( "hpMin" ).get< uint32_t >(),
|
||||||
|
this->hp.val = paramData.at( "hpMax" ).get< uint32_t >();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EncounterTimeline::ConditionDirectorVar::from_json( nlohmann::json& json, Phase phase, ConditionId conditionId )
|
||||||
|
{
|
||||||
|
PhaseCondition::from_json( json, phase, conditionId );
|
||||||
|
|
||||||
|
auto params = json.at( "params" ).get< std::vector< uint32_t > >();
|
||||||
|
|
||||||
|
switch( conditionId )
|
||||||
|
{
|
||||||
|
case ConditionId::DirectorVarEquals:
|
||||||
|
case ConditionId::DirectorVarGreaterThan:
|
||||||
|
{
|
||||||
|
param.var = params[ 0 ];
|
||||||
|
param.value = params[ 1 ];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ConditionId::DirectorFlagsEquals:
|
||||||
|
case ConditionId::DirectorFlagsGreaterThan:
|
||||||
|
{
|
||||||
|
param.flag = params[ 0 ];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ConditionId::DirectorSeqEquals:
|
||||||
|
case ConditionId::DirectorSeqGreaterThan:
|
||||||
|
{
|
||||||
|
param.seq = params[ 0 ];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void EncounterTimeline::ConditionCombatState::from_json( nlohmann::json& json, Phase phase, ConditionId conditionId,
|
||||||
|
const std::unordered_map< std::string, TimelineActor >& actors )
|
||||||
|
{
|
||||||
|
PhaseCondition::from_json( json, phase, conditionId );
|
||||||
|
|
||||||
|
auto paramData = json.at( "paramData" );
|
||||||
|
auto actorRef = paramData.at( "sourceActor" ).get< std::string >();
|
||||||
|
|
||||||
|
// resolve the actor whose name we are checking
|
||||||
|
if( auto it = actors.find( actorRef ); it != actors.end() )
|
||||||
|
this->actorId = it->second.m_layoutId;
|
||||||
|
else
|
||||||
|
throw std::runtime_error( fmt::format( std::string( "EncounterTimeline::ConditionCombatState::from_json unable to find actor by name: %s" ), actorRef ) );
|
||||||
|
|
||||||
|
this->type = paramData.at( "combatState" ).get< CombatStateType >();
|
||||||
|
}
|
||||||
|
void EncounterTimeline::Timepoint::from_json( const nlohmann::json& json, const std::unordered_map< std::string, TimelineActor>& actors )
|
||||||
{
|
{
|
||||||
const static std::unordered_map< std::string, TimepointDataType > timepointTypeMap =
|
const static std::unordered_map< std::string, TimepointDataType > timepointTypeMap =
|
||||||
{
|
{
|
||||||
|
@ -251,9 +284,9 @@ namespace Sapphire
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EncounterTimeline::EncounterTimelineInfo EncounterTimeline::buildEncounterTimeline( uint32_t encounterId, bool reload )
|
EncounterTimeline::TimelinePack EncounterTimeline::buildEncounterTimeline( uint32_t encounterId, bool reload )
|
||||||
{
|
{
|
||||||
static std::map< uint32_t, EncounterTimelineInfo > cache = {};
|
static std::map< uint32_t, 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 },
|
||||||
|
@ -264,7 +297,7 @@ namespace Sapphire
|
||||||
{ "phaseTimeElapsed", ConditionId::PhaseTimeElapsed }
|
{ "phaseTimeElapsed", ConditionId::PhaseTimeElapsed }
|
||||||
};
|
};
|
||||||
|
|
||||||
EncounterTimelineInfo info;
|
TimelinePack pack;
|
||||||
if( cache.find( encounterId ) != cache.end() && !reload )
|
if( cache.find( encounterId ) != cache.end() && !reload )
|
||||||
return cache.at( encounterId );
|
return cache.at( encounterId );
|
||||||
/*
|
/*
|
||||||
|
@ -284,21 +317,6 @@ namespace Sapphire
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Main encounter script
|
|
||||||
EncounterFight::update()
|
|
||||||
{
|
|
||||||
auto pStateCondition = m_stateConditions.pop();
|
|
||||||
|
|
||||||
switch( pStateCondition->getType() )
|
|
||||||
{
|
|
||||||
case EncounterTimepointConditionId::HpBetweenPct:
|
|
||||||
if (((HpPercentCondition*)pStateCondition)->isConditionMet( bossHpPct ) )
|
|
||||||
pStateCondition->execute( someDutyInstanceInfoHere );
|
|
||||||
else if( !pStateCondition->hasExecuted() || pStateCondition->canLoop() )
|
|
||||||
m_stateConditions.push( pStateCondition );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
std::string encounter_name( fmt::format( std::string( "data/EncounterTimelines/EncounterTimeline%u.json" ), encounterId ) );
|
std::string encounter_name( fmt::format( std::string( "data/EncounterTimelines/EncounterTimeline%u.json" ), encounterId ) );
|
||||||
|
@ -306,42 +324,75 @@ namespace Sapphire
|
||||||
std::fstream f( encounter_name );
|
std::fstream f( encounter_name );
|
||||||
|
|
||||||
if( !f.is_open() )
|
if( !f.is_open() )
|
||||||
return {};
|
return pack;
|
||||||
|
|
||||||
auto json = nlohmann::json::parse( f );
|
auto json = nlohmann::json::parse( f );
|
||||||
|
|
||||||
std::map< std::string, Phase > phaseNameMap;
|
std::unordered_map< std::string, TimelineActor > actorNameMap;
|
||||||
|
std::unordered_map< std::string, std::map< std::string, Phase > > actorNamePhaseMap;
|
||||||
|
|
||||||
|
// first run through cache actor info
|
||||||
for( const auto& phaseJ : json.at( "phases" ).items() )
|
for( const auto& actorJ : json.at( "actors" ).items() )
|
||||||
{
|
{
|
||||||
auto phaseV = phaseJ.value();
|
TimelineActor actor;
|
||||||
const auto id = phaseV.at( "id" ).get< uint32_t >();
|
auto actorV = actorJ.value();
|
||||||
const auto& phaseName = phaseV.at( "name" ).get< std::string >();
|
actor.m_hp = actorV.at( "hp" ).get< uint32_t >();
|
||||||
const auto& timepointsJ = phaseV.at( "timepoints" );
|
actor.m_layoutId = actorV.at( "layoutId" ).get< uint32_t >();
|
||||||
|
actor.m_name = actorV.at( "name" ).get< std::string >();
|
||||||
|
|
||||||
Phase phase;
|
actorNameMap.emplace( std::make_pair( actor.m_name, actor ) );
|
||||||
for( const auto& timepointJ : timepointsJ.items() )
|
|
||||||
{
|
|
||||||
auto timepointV = timepointJ.value();
|
|
||||||
Timepoint timepoint;
|
|
||||||
timepoint.from_json( timepointV );
|
|
||||||
|
|
||||||
phase.m_timepoints.push( timepoint );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( phaseNameMap.find( phaseName ) != phaseNameMap.end() )
|
|
||||||
throw std::runtime_error( fmt::format( std::string( "EncounterTimeline::buildEncounterTimeline - duplicate phase by name: %s" ), phaseName ) );
|
|
||||||
|
|
||||||
phaseNameMap.emplace( std::make_pair( phaseName, phase ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// build timeline info per actor
|
||||||
|
for( const auto& actorJ : json.at( "actors" ).items() )
|
||||||
|
{
|
||||||
|
// < actorName, < phasename, phase > >
|
||||||
|
std::map< std::string, Phase > phaseNameMap;
|
||||||
|
|
||||||
|
auto actorV = actorJ.value();
|
||||||
|
uint32_t layoutId = actorV.at( "layoutId" );
|
||||||
|
std::string actorName = actorV.at( "name" );
|
||||||
|
|
||||||
|
TimelineActor actor;
|
||||||
|
// todo: are phases linked by actor, or global in the json
|
||||||
|
for( const auto& phaseJ : json.at( "phases" ).items() )
|
||||||
|
{
|
||||||
|
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" );
|
||||||
|
|
||||||
|
Phase phase;
|
||||||
|
for( const auto& timepointJ : timepointsJ.items() )
|
||||||
|
{
|
||||||
|
auto timepointV = timepointJ.value();
|
||||||
|
Timepoint timepoint;
|
||||||
|
timepoint.from_json( timepointV, actorNameMap );
|
||||||
|
|
||||||
|
phase.m_timepoints.push_back( timepoint );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( phaseNameMap.find( phaseName ) != phaseNameMap.end() )
|
||||||
|
throw std::runtime_error( fmt::format( std::string( "EncounterTimeline::buildEncounterTimeline - duplicate phase by name: %s" ), phaseName ) );
|
||||||
|
|
||||||
|
phaseNameMap.emplace( std::make_pair( phaseName, phase ) );
|
||||||
|
}
|
||||||
|
actorNamePhaseMap[ actorName ] = phaseNameMap;
|
||||||
|
if( actorNameMap.find( actorName ) != actorNameMap.end() )
|
||||||
|
throw std::runtime_error( fmt::format( std::string( "EncounterTimeline::buildEncounterTimeline - duplicate actor by name: %s" ), actorName ) );
|
||||||
|
|
||||||
|
actorNameMap.emplace( std::make_pair( actorName, actor ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// build the condition list
|
||||||
for( const auto& pcJ : json.at( "phaseConditions" ).items() )
|
for( const auto& pcJ : json.at( "phaseConditions" ).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 >();
|
||||||
auto phaseRef = pcV.at( "phase" ).get< std::string >();
|
auto phaseRef = pcV.at( "targetPhase" ).get< std::string >();
|
||||||
|
auto actorRef = pcV.at( "targetActor" ).get< std::string >();
|
||||||
|
|
||||||
ConditionId conditionId;
|
ConditionId conditionId;
|
||||||
|
|
||||||
|
@ -351,33 +402,42 @@ namespace Sapphire
|
||||||
else
|
else
|
||||||
throw std::runtime_error( fmt::format( std::string( "EncounterTimeline::buildEncounterTimeline - no condition id found by name: %s" ), conditionName ) );
|
throw std::runtime_error( fmt::format( std::string( "EncounterTimeline::buildEncounterTimeline - no condition id found by name: %s" ), conditionName ) );
|
||||||
|
|
||||||
// make sure phase we're referencing exists
|
// make sure the actor we're referencing exists
|
||||||
if( auto phaseIt = phaseNameMap.find( phaseRef ); phaseIt != phaseNameMap.end() )
|
if( auto actorIt = actorNameMap.find( actorRef ); actorIt != actorNameMap.end() )
|
||||||
{
|
{
|
||||||
Phase& phase = phaseIt->second;
|
auto phaseNameMap = actorNamePhaseMap[ actorRef ];
|
||||||
|
|
||||||
// build the condition
|
TimelineActor& actor = actorIt->second;
|
||||||
TimepointConditionPtr pCondition;
|
|
||||||
switch( conditionId )
|
// make sure phase we're referencing exists
|
||||||
|
if( auto phaseIt = phaseNameMap.find( phaseRef ); phaseIt != phaseNameMap.end() )
|
||||||
{
|
{
|
||||||
case ConditionId::HpPctLessThan:
|
Phase& phase = phaseIt->second;
|
||||||
case ConditionId::HpPctBetween:
|
|
||||||
|
// build the condition
|
||||||
|
PhaseConditionPtr pCondition;
|
||||||
|
pCondition->m_description = description;
|
||||||
|
switch( conditionId )
|
||||||
{
|
{
|
||||||
auto pHpCondition = std::make_shared< ConditionHp >();
|
case ConditionId::HpPctLessThan:
|
||||||
pHpCondition->from_json( pcV, phase, conditionId );
|
case ConditionId::HpPctBetween:
|
||||||
}
|
{
|
||||||
break;
|
auto pHpCondition = std::make_shared< ConditionHp >();
|
||||||
case ConditionId::DirectorVarEquals:
|
pHpCondition->from_json( pcV, phase, conditionId, actorNameMap );
|
||||||
case ConditionId::DirectorVarGreaterThan:
|
}
|
||||||
{
|
|
||||||
auto pDirectorCondition = std::make_shared< ConditionDirectorVar >();
|
|
||||||
pDirectorCondition->from_json( pcV, phase, conditionId );
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
break;
|
||||||
|
case ConditionId::DirectorVarEquals:
|
||||||
|
case ConditionId::DirectorVarGreaterThan:
|
||||||
|
{
|
||||||
|
auto pDirectorCondition = std::make_shared< ConditionDirectorVar >();
|
||||||
|
pDirectorCondition->from_json( pcV, phase, conditionId );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
actor.m_phaseConditions.push_back( pCondition );
|
||||||
}
|
}
|
||||||
info.push( pCondition );
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -385,9 +445,9 @@ namespace Sapphire
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( reload )
|
if( reload )
|
||||||
cache[ encounterId ] = info;
|
cache[ encounterId ] = pack;
|
||||||
else
|
else
|
||||||
cache.emplace( std::make_pair( encounterId, info ) );
|
cache.emplace( std::make_pair( encounterId, pack ) );
|
||||||
return info;
|
return pack;
|
||||||
}
|
}
|
||||||
}// namespace Sapphire
|
}// namespace Sapphire
|
|
@ -8,6 +8,8 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
|
#include <Common.h>
|
||||||
|
#include <Forwards.h>
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
namespace Sapphire
|
namespace Sapphire
|
||||||
|
@ -15,6 +17,9 @@ namespace Sapphire
|
||||||
class EncounterTimeline
|
class EncounterTimeline
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
// forwards
|
||||||
|
class TimelineActor;
|
||||||
|
|
||||||
// EncounterFight::OnTick() { switch EncounterTimepointConditionId }
|
// EncounterFight::OnTick() { switch EncounterTimepointConditionId }
|
||||||
enum class ConditionId : uint32_t
|
enum class ConditionId : uint32_t
|
||||||
{
|
{
|
||||||
|
@ -82,12 +87,34 @@ namespace Sapphire
|
||||||
Aggro2
|
Aggro2
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class MoveType
|
enum class MoveType : uint32_t
|
||||||
{
|
{
|
||||||
WalkPath,
|
WalkPath,
|
||||||
Teleport
|
Teleport
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class TimelineActorType : uint32_t
|
||||||
|
{
|
||||||
|
LayerSetObject,
|
||||||
|
BattleNpc
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class CombatStateType
|
||||||
|
{
|
||||||
|
Idle,
|
||||||
|
Combat,
|
||||||
|
Retreat,
|
||||||
|
Roaming,
|
||||||
|
JustDied,
|
||||||
|
Dead
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class TimelinePackType : uint32_t
|
||||||
|
{
|
||||||
|
Solo,
|
||||||
|
EncounterFight
|
||||||
|
};
|
||||||
|
|
||||||
struct TargetSelectFilter
|
struct TargetSelectFilter
|
||||||
{
|
{
|
||||||
TargetSelectFilterId m_flags;
|
TargetSelectFilterId m_flags;
|
||||||
|
@ -224,6 +251,7 @@ namespace Sapphire
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// todo: refactor all this to allow solo actor to use
|
||||||
class Timepoint :
|
class Timepoint :
|
||||||
public std::enable_shared_from_this< Timepoint >
|
public std::enable_shared_from_this< Timepoint >
|
||||||
{
|
{
|
||||||
|
@ -242,9 +270,9 @@ namespace Sapphire
|
||||||
return m_pData;
|
return m_pData;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool canExecute()
|
bool canExecute( uint64_t elapsed )
|
||||||
{
|
{
|
||||||
return m_executeTime == 0;
|
return m_executeTime == 0 && m_duration <= elapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool finished( uint64_t time )
|
bool finished( uint64_t time )
|
||||||
|
@ -252,7 +280,7 @@ namespace Sapphire
|
||||||
return m_executeTime + m_duration <= time;
|
return m_executeTime + m_duration <= time;
|
||||||
}
|
}
|
||||||
|
|
||||||
void from_json( const nlohmann::json& json );
|
void from_json( const nlohmann::json& json, const std::unordered_map< std::string, TimelineActor >& actors );
|
||||||
void execute( EncounterFightPtr pFight, uint64_t time );
|
void execute( EncounterFightPtr pFight, uint64_t time );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -264,9 +292,10 @@ namespace Sapphire
|
||||||
// todo: respect looping phases, allow callbacks to push timepoints
|
// todo: respect looping phases, allow callbacks to push timepoints
|
||||||
|
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
std::queue< Timepoint > m_timepoints;
|
std::vector< Timepoint > m_timepoints;
|
||||||
|
uint32_t m_lastTimepointIndex{ 0 };
|
||||||
uint64_t m_startTime{ 0 };
|
uint64_t m_startTime{ 0 };
|
||||||
uint64_t m_lastTimepoint{ 0 };
|
uint64_t m_lastTimepointTime{ 0 };
|
||||||
|
|
||||||
std::queue< Timepoint > m_executed;
|
std::queue< Timepoint > m_executed;
|
||||||
|
|
||||||
|
@ -275,32 +304,32 @@ namespace Sapphire
|
||||||
{
|
{
|
||||||
if( m_startTime == 0 )
|
if( m_startTime == 0 )
|
||||||
m_startTime = time;
|
m_startTime = time;
|
||||||
if( m_lastTimepoint == 0 )
|
if( m_lastTimepointTime == 0 )
|
||||||
m_lastTimepoint = time;
|
m_lastTimepointTime = time;
|
||||||
|
|
||||||
// todo: this is stupid
|
for( auto i = m_lastTimepointIndex; i < m_timepoints.size(); )
|
||||||
while( m_timepoints.size() > 0 )
|
|
||||||
{
|
{
|
||||||
uint64_t phaseElapsed = time - m_startTime;
|
uint64_t phaseElapsed = time - m_startTime;
|
||||||
uint64_t timepointElapsed = time - m_lastTimepoint;
|
uint64_t timepointElapsed = time - m_lastTimepointTime;
|
||||||
|
|
||||||
auto& timepoint = m_timepoints.front();
|
auto& timepoint = m_timepoints[ i ];
|
||||||
if( timepoint.canExecute() )
|
if( timepoint.canExecute( timepointElapsed ) )
|
||||||
{
|
{
|
||||||
timepoint.execute( pFight, time );
|
timepoint.execute( pFight, time );
|
||||||
m_lastTimepoint = time;
|
m_lastTimepointTime = time;
|
||||||
m_executed.push( timepoint );
|
m_executed.push( timepoint );
|
||||||
}
|
}
|
||||||
else if( timepoint.finished( timepointElapsed ) )
|
|
||||||
|
// fire off all timepoints
|
||||||
|
if( timepoint.finished( timepointElapsed ) )
|
||||||
{
|
{
|
||||||
// todo: this is stupid, temp workaround for allowing phases to loop
|
// todo: this is stupid, temp workaround for allowing phases to loop
|
||||||
timepoint.m_executeTime = 0;
|
timepoint.m_executeTime = 0;
|
||||||
m_timepoints.pop();
|
m_lastTimepointIndex = i;
|
||||||
}
|
++i;
|
||||||
else
|
continue;
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,8 +340,8 @@ namespace Sapphire
|
||||||
};
|
};
|
||||||
using PhasePtr = std::shared_ptr< Phase >;
|
using PhasePtr = std::shared_ptr< Phase >;
|
||||||
|
|
||||||
class TimepointCondition :
|
class PhaseCondition :
|
||||||
public std::enable_shared_from_this< TimepointCondition >
|
public std::enable_shared_from_this< PhaseCondition >
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConditionId m_conditionId{ 0 };
|
ConditionId m_conditionId{ 0 };
|
||||||
|
@ -320,15 +349,16 @@ namespace Sapphire
|
||||||
bool m_loop{ false };
|
bool m_loop{ false };
|
||||||
uint64_t m_startTime{ 0 };
|
uint64_t m_startTime{ 0 };
|
||||||
uint32_t m_cooldown{ 0 };
|
uint32_t m_cooldown{ 0 };
|
||||||
|
std::string m_description;
|
||||||
|
|
||||||
TimepointCondition() {}
|
PhaseCondition() {}
|
||||||
~TimepointCondition() {}
|
~PhaseCondition() {}
|
||||||
|
|
||||||
virtual void from_json( nlohmann::json& json, Phase phase, ConditionId conditionId )
|
virtual void from_json( nlohmann::json& json, Phase phase, ConditionId conditionId )
|
||||||
{
|
{
|
||||||
this->m_conditionId = conditionId;
|
this->m_conditionId = conditionId;
|
||||||
this->m_loop = json.at( "loop" ).get< bool >();
|
this->m_loop = json.at( "loop" ).get< bool >();
|
||||||
this->m_cooldown = json.at( "cooldown" ).get< uint32_t >();
|
//this->m_cooldown = json.at( "cooldown" ).get< uint32_t >();
|
||||||
this->m_phase = phase;
|
this->m_phase = phase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,25 +368,101 @@ namespace Sapphire
|
||||||
m_phase.execute( pFight, time );
|
m_phase.execute( pFight, time );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void update( EncounterFightPtr pFight, uint64_t time )
|
||||||
|
{
|
||||||
|
m_phase.execute( pFight, time );
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
m_startTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool inProgress()
|
||||||
|
{
|
||||||
|
return m_startTime != 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool completed()
|
bool completed()
|
||||||
{
|
{
|
||||||
return m_phase.completed();
|
return m_phase.completed();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool canLoop()
|
bool isLoopable()
|
||||||
{
|
{
|
||||||
return m_phase.completed() && m_loop;
|
return m_loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool canExecute( EncounterFightPtr pFight, uint64_t time )
|
bool loopReady( uint64_t time )
|
||||||
|
{
|
||||||
|
return m_phase.completed() && m_loop && ( m_startTime + m_cooldown <= time );
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isConditionMet( EncounterFightPtr pFight, uint64_t time )
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
using TimepointConditionPtr = std::shared_ptr< TimepointCondition >;
|
using PhaseConditionPtr = std::shared_ptr< PhaseCondition >;
|
||||||
|
|
||||||
class ConditionHp : TimepointCondition
|
class TimelineActor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint32_t m_layoutId;
|
||||||
|
uint32_t m_hp;
|
||||||
|
std::string m_name;
|
||||||
|
|
||||||
|
std::vector< PhaseConditionPtr > m_phaseConditions;
|
||||||
|
std::queue< PhaseConditionPtr > m_phaseHistory;
|
||||||
|
|
||||||
|
void update( EncounterFightPtr pFight, uint64_t time )
|
||||||
|
{
|
||||||
|
// todo: handle auto attacks and make it so they dont fire during boss intermission phases
|
||||||
|
// todo: handle interrupts
|
||||||
|
for( const auto& pCondition : m_phaseConditions )
|
||||||
|
{
|
||||||
|
if( pCondition->completed() )
|
||||||
|
{
|
||||||
|
if( pCondition->isLoopable() )
|
||||||
|
{
|
||||||
|
if( pCondition->loopReady( time ) )
|
||||||
|
pCondition->reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( pCondition->inProgress() )
|
||||||
|
{
|
||||||
|
pCondition->execute( pFight, time );
|
||||||
|
}
|
||||||
|
else if( pCondition->isConditionMet( pFight, time ) )
|
||||||
|
{
|
||||||
|
pCondition->execute( pFight, time );
|
||||||
|
m_phaseHistory.push( pCondition );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class TimelinePack
|
||||||
|
{
|
||||||
|
TimelinePackType m_type{TimelinePackType::Solo};
|
||||||
|
std::vector< TimelineActor > m_actors;
|
||||||
|
std::string m_name;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TimelinePack() { }
|
||||||
|
TimelinePack( TimelinePackType type ) : m_type( type ) {}
|
||||||
|
void update( EncounterFightPtr pFight, uint64_t time )
|
||||||
|
{
|
||||||
|
for( auto& actor : m_actors )
|
||||||
|
actor.update( pFight, time );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Conditions
|
||||||
|
//
|
||||||
|
class ConditionHp : PhaseCondition
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
uint32_t actorId;
|
uint32_t actorId;
|
||||||
|
@ -365,18 +471,19 @@ namespace Sapphire
|
||||||
uint8_t val;
|
uint8_t val;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
uint8_t min, max;
|
uint8_t min, max;
|
||||||
};
|
};
|
||||||
} hp;
|
} hp;
|
||||||
|
|
||||||
void from_json( nlohmann::json& json, Phase phase, ConditionId conditionId );
|
void from_json( nlohmann::json& json, Phase phase, ConditionId conditionId,
|
||||||
bool canExecute( EncounterFightPtr pFight, uint64_t time ) override;
|
const std::unordered_map< std::string, TimelineActor >& actors );
|
||||||
|
|
||||||
|
bool isConditionMet( EncounterFightPtr pFight, uint64_t time ) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConditionDirectorVar : TimepointCondition
|
class ConditionDirectorVar : PhaseCondition
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
|
@ -387,15 +494,23 @@ namespace Sapphire
|
||||||
uint8_t seq;
|
uint8_t seq;
|
||||||
uint8_t flag;
|
uint8_t flag;
|
||||||
} param;
|
} param;
|
||||||
|
|
||||||
void from_json( nlohmann::json& json, Phase phase, ConditionId conditionId );
|
void from_json( nlohmann::json& json, Phase phase, ConditionId conditionId );
|
||||||
bool canExecute( EncounterFightPtr pFight, uint64_t time ) override;
|
bool isConditionMet( EncounterFightPtr pFight, uint64_t time ) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
using EncounterTimelineInfo = std::queue< TimepointConditionPtr >;
|
class ConditionCombatState : PhaseCondition
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint32_t actorId;
|
||||||
|
CombatStateType type;
|
||||||
|
|
||||||
|
void from_json( nlohmann::json& json, Phase phase, ConditionId conditionId, const std::unordered_map< std::string, TimelineActor >& actors );
|
||||||
|
bool isConditionMet( EncounterFightPtr pFight, uint64_t time ) override;
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
EncounterTimelineInfo buildEncounterTimeline( uint32_t encounterId, bool reload = false );
|
TimelinePack buildEncounterTimeline( uint32_t encounterId, bool reload = false );
|
||||||
};
|
};
|
||||||
}// namespace Sapphire
|
}// namespace Sapphire
|
Loading…
Add table
Reference in a new issue