2024-04-29 16:51:28 +01:00
|
|
|
#include <fstream>
|
|
|
|
#include <memory>
|
|
|
|
#include <map>
|
|
|
|
#include <optional>
|
|
|
|
#include <stack>
|
|
|
|
#include <stdexcept>
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
2024-05-06 01:45:42 +01:00
|
|
|
#include <queue>
|
2024-04-29 16:51:28 +01:00
|
|
|
|
|
|
|
#include <nlohmann/json.hpp>
|
|
|
|
|
|
|
|
namespace Sapphire
|
|
|
|
{
|
2024-05-05 16:15:05 +01:00
|
|
|
class EncounterTimeline
|
2024-04-29 16:51:28 +01:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
// EncounterFight::OnTick() { switch EncounterTimepointConditionId }
|
2024-05-06 01:45:42 +01:00
|
|
|
enum class ConditionId : uint32_t
|
2024-04-29 16:51:28 +01:00
|
|
|
{
|
|
|
|
HpPctLessThan,
|
|
|
|
HpPctBetween,
|
|
|
|
DirectorVarEquals,
|
2024-05-06 01:45:42 +01:00
|
|
|
DirectorVarGreaterThan,
|
|
|
|
PhaseTimeElapsed,
|
|
|
|
EncounterTimeElapsed
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class DirectorOpId
|
|
|
|
{
|
|
|
|
SetDirectorVar,
|
|
|
|
SetDirectorVarLR,
|
|
|
|
SetDirectorSeq,
|
|
|
|
SetDirectorFlag,
|
|
|
|
ClearDirectorFlag
|
2024-04-29 16:51:28 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
// TODO: what should this do?
|
2024-05-06 01:45:42 +01:00
|
|
|
enum class TimepointOverrideFlags : uint32_t
|
2024-04-29 16:51:28 +01:00
|
|
|
{
|
|
|
|
None,
|
|
|
|
Invulnerable
|
|
|
|
};
|
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
enum class TimepointDataType : uint32_t
|
2024-04-29 16:51:28 +01:00
|
|
|
{
|
|
|
|
Idle,
|
|
|
|
CastAction,
|
|
|
|
MoveTo,
|
|
|
|
LogMessage,
|
|
|
|
BattleTalk,
|
|
|
|
SetDirectorVar,
|
2024-05-06 01:45:42 +01:00
|
|
|
SetDirectorSeq,
|
|
|
|
SetDirectorFlag,
|
2024-04-29 16:51:28 +01:00
|
|
|
AddStatusEffect,
|
|
|
|
RemoveStatusEffect
|
|
|
|
};
|
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
enum class TimepointCallbackType : uint32_t
|
2024-04-29 16:51:28 +01:00
|
|
|
{
|
|
|
|
OnActionInit,
|
|
|
|
OnActionStart,
|
|
|
|
OnActionInterrupt,
|
|
|
|
OnActionExecute
|
|
|
|
};
|
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
enum class TargetSelectFilterIds : uint32_t
|
2024-04-29 16:51:28 +01:00
|
|
|
{
|
|
|
|
Self,
|
|
|
|
Tank,
|
|
|
|
Healer,
|
|
|
|
Dps,
|
|
|
|
DpsMelee,
|
|
|
|
DpsRanged,
|
|
|
|
Furthest,
|
|
|
|
|
|
|
|
Aggro1,
|
|
|
|
Aggro2
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class MoveType
|
|
|
|
{
|
|
|
|
WalkPath,
|
|
|
|
Teleport
|
|
|
|
};
|
|
|
|
|
|
|
|
struct TargetSelectFilter
|
|
|
|
{
|
|
|
|
TargetSelectFilterIds m_flags;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
using TimepointCallbackFunc = std::function< void( EncounterFightPtr, uint64_t ) >;
|
|
|
|
// Timepoint Data Objects
|
|
|
|
struct TimepointCallbackData :
|
|
|
|
public std::enable_shared_from_this< TimepointCallbackData >
|
2024-04-29 16:51:28 +01:00
|
|
|
{
|
2024-05-06 01:45:42 +01:00
|
|
|
TimepointCallbackType m_type;
|
|
|
|
std::vector < TimepointCallbackFunc > m_callbacks;
|
2024-04-29 16:51:28 +01:00
|
|
|
};
|
2024-05-06 01:45:42 +01:00
|
|
|
using TimebackCallbackDataPtr = std::shared_ptr< TimepointCallbackData >;
|
|
|
|
using TimepointCallbacks = std::map< TimepointCallbackType, TimebackCallbackDataPtr >;
|
2024-04-29 16:51:28 +01:00
|
|
|
|
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
struct TimepointData :
|
|
|
|
public std::enable_shared_from_this< TimepointData >
|
2024-04-29 16:51:28 +01:00
|
|
|
{
|
2024-05-06 01:45:42 +01:00
|
|
|
TimepointData( TimepointDataType) {}
|
|
|
|
virtual ~TimepointData() = 0;
|
|
|
|
TimepointDataType m_type;
|
2024-04-29 16:51:28 +01:00
|
|
|
};
|
2024-05-06 01:45:42 +01:00
|
|
|
using TimepointDataPtr = std::shared_ptr< TimepointData >;
|
2024-04-29 16:51:28 +01:00
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
struct TimepointDataIdle : public TimepointData
|
|
|
|
{
|
|
|
|
uint32_t m_actorId;
|
|
|
|
uint64_t m_durationMs;
|
|
|
|
};
|
2024-04-29 16:51:28 +01:00
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
struct TimepointDataStatusEffect : public TimepointData
|
2024-04-29 16:51:28 +01:00
|
|
|
{
|
|
|
|
uint32_t m_statusEffectId;
|
|
|
|
TargetSelectFilter m_targetFilter;
|
|
|
|
uint32_t m_durationMs;
|
|
|
|
};
|
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
struct TimepointDataAction : public TimepointData
|
2024-04-29 16:51:28 +01:00
|
|
|
{
|
2024-05-06 01:45:42 +01:00
|
|
|
uint32_t m_actorId;
|
2024-04-29 16:51:28 +01:00
|
|
|
uint32_t m_actionId;
|
2024-05-06 01:45:42 +01:00
|
|
|
TimepointCallbacks m_callbacks;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct TimepointDataMoveTo : public TimepointData
|
|
|
|
{
|
|
|
|
uint32_t m_actorId;
|
|
|
|
MoveType m_moveType;
|
|
|
|
float m_x, m_y, m_z, m_rot;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
struct TimepointDataLogMessage : public TimepointData
|
|
|
|
{
|
|
|
|
uint32_t m_logMessageType;
|
|
|
|
uint32_t m_logMessageId;
|
|
|
|
std::string m_message;
|
2024-04-29 16:51:28 +01:00
|
|
|
};
|
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
struct TimepointDataDirector : public TimepointData
|
2024-04-29 16:51:28 +01:00
|
|
|
{
|
2024-05-06 01:45:42 +01:00
|
|
|
DirectorOpId m_directorOp;
|
|
|
|
union
|
|
|
|
{
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
uint8_t index;
|
|
|
|
union
|
|
|
|
{
|
|
|
|
uint8_t val;
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
uint8_t left, right;
|
|
|
|
};
|
|
|
|
} value;
|
|
|
|
};
|
|
|
|
uint8_t seq;
|
|
|
|
uint8_t flags;
|
|
|
|
} m_data;
|
2024-04-29 16:51:28 +01:00
|
|
|
};
|
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
class Timepoint :
|
|
|
|
public std::enable_shared_from_this< Timepoint >
|
2024-04-29 16:51:28 +01:00
|
|
|
{
|
|
|
|
public:
|
2024-05-06 01:45:42 +01:00
|
|
|
TimepointDataType m_type;
|
|
|
|
uint64_t m_duration{ 0 };
|
|
|
|
uint64_t m_executeTime{ 0 };
|
|
|
|
TimepointOverrideFlags m_overrideFlags;
|
|
|
|
TimepointDataPtr m_pData;
|
2024-04-29 16:51:28 +01:00
|
|
|
std::string m_description;
|
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
// todo: repeatable?
|
|
|
|
|
|
|
|
bool canExecute()
|
|
|
|
{
|
|
|
|
return m_executeTime == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool finished( uint64_t time )
|
|
|
|
{
|
|
|
|
return m_executeTime + m_duration <= time;
|
|
|
|
}
|
|
|
|
|
|
|
|
void execute( EncounterFightPtr pFight, uint64_t time );
|
2024-04-29 16:51:28 +01:00
|
|
|
};
|
2024-05-06 01:45:42 +01:00
|
|
|
using TimepointPtr = std::shared_ptr< Timepoint >;
|
2024-04-29 16:51:28 +01:00
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
class Phase :
|
|
|
|
public std::enable_shared_from_this< Phase >
|
2024-04-29 16:51:28 +01:00
|
|
|
{
|
|
|
|
public:
|
2024-05-06 01:45:42 +01:00
|
|
|
|
|
|
|
// todo: respect looping phases, allow callbacks to push timepoints
|
|
|
|
|
2024-04-29 16:51:28 +01:00
|
|
|
std::string m_name;
|
2024-05-06 01:45:42 +01:00
|
|
|
std::queue< TimepointPtr > m_timepoints;
|
2024-04-29 16:51:28 +01:00
|
|
|
uint64_t m_startTime{ 0 };
|
2024-05-06 01:45:42 +01:00
|
|
|
uint64_t m_lastTimepoint{ 0 };
|
|
|
|
|
|
|
|
std::queue< TimepointPtr > m_executed;
|
|
|
|
|
|
|
|
// todo: i wrote this very sleep deprived, ensure it is actually sane
|
2024-04-29 16:51:28 +01:00
|
|
|
void execute( EncounterFightPtr pFight, uint64_t time )
|
|
|
|
{
|
|
|
|
if( m_startTime == 0 )
|
|
|
|
m_startTime = time;
|
2024-05-06 01:45:42 +01:00
|
|
|
if( m_lastTimepoint == 0 )
|
|
|
|
m_lastTimepoint = time;
|
2024-04-29 16:51:28 +01:00
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
// todo: this is stupid
|
|
|
|
while( m_timepoints.size() > 0 )
|
|
|
|
{
|
|
|
|
uint64_t phaseElapsed = time - m_startTime;
|
|
|
|
uint64_t timepointElapsed = time - m_lastTimepoint;
|
|
|
|
|
|
|
|
auto& pTimepoint = m_timepoints.front();
|
|
|
|
if( pTimepoint->canExecute() )
|
|
|
|
{
|
|
|
|
pTimepoint->execute( pFight, time );
|
|
|
|
m_lastTimepoint = time;
|
|
|
|
m_executed.push( pTimepoint );
|
|
|
|
}
|
|
|
|
else if( pTimepoint->finished( timepointElapsed ) )
|
|
|
|
{
|
|
|
|
// todo: this is stupid, temp workaround for allowing phases to loop
|
|
|
|
pTimepoint->m_executeTime = 0;
|
|
|
|
m_timepoints.pop();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2024-04-29 16:51:28 +01:00
|
|
|
}
|
|
|
|
};
|
2024-05-06 01:45:42 +01:00
|
|
|
using PhasePtr = std::shared_ptr< Phase >;
|
2024-04-29 16:51:28 +01:00
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
class TimepointCondition :
|
|
|
|
public std::enable_shared_from_this< TimepointCondition >
|
2024-04-29 16:51:28 +01:00
|
|
|
{
|
|
|
|
public:
|
2024-05-06 01:45:42 +01:00
|
|
|
ConditionId m_conditionId{ 0 };
|
|
|
|
PhasePtr m_pPhase{ nullptr };
|
2024-04-29 16:51:28 +01:00
|
|
|
bool m_loop{ false };
|
|
|
|
uint64_t m_startTime{ 0 };
|
|
|
|
uint32_t m_cooldown{ 0 };
|
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
TimepointCondition() {}
|
|
|
|
~TimepointCondition() {}
|
2024-04-29 16:51:28 +01:00
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
virtual void from_json( nlohmann::json& json, PhasePtr pPhase, ConditionId conditionId )
|
2024-04-29 16:51:28 +01:00
|
|
|
{
|
|
|
|
this->m_conditionId = conditionId;
|
|
|
|
this->m_loop = json.at( "loop" ).get< bool >();
|
|
|
|
this->m_cooldown = json.at( "cooldown" ).get< uint32_t >();
|
|
|
|
this->m_pPhase = pPhase;
|
|
|
|
}
|
|
|
|
|
|
|
|
void execute( EncounterFightPtr pFight, uint64_t time )
|
|
|
|
{
|
|
|
|
m_startTime = time;
|
|
|
|
m_pPhase->execute( pFight, time );
|
|
|
|
};
|
|
|
|
|
|
|
|
virtual bool canExecute( EncounterFightPtr pFight, uint64_t time )
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
|
|
|
};
|
2024-05-06 01:45:42 +01:00
|
|
|
using TimepointConditionPtr = std::shared_ptr< TimepointCondition >;
|
2024-04-29 16:51:28 +01:00
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
class ConditionHp : TimepointCondition
|
2024-04-29 16:51:28 +01:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
uint32_t actorId;
|
|
|
|
union
|
|
|
|
{
|
|
|
|
uint8_t val;
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
uint8_t min, max;
|
|
|
|
};
|
|
|
|
} hp;
|
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
void from_json( nlohmann::json& json, PhasePtr pPhase, ConditionId conditionId );
|
2024-04-29 16:51:28 +01:00
|
|
|
bool canExecute( EncounterFightPtr pFight, uint64_t time ) override;
|
|
|
|
};
|
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
class ConditionDirectorVar : TimepointCondition
|
2024-04-29 16:51:28 +01:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
uint32_t directorVar;
|
|
|
|
uint32_t value;
|
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
void from_json( nlohmann::json& json, PhasePtr pPhase, ConditionId conditionId );
|
2024-04-29 16:51:28 +01:00
|
|
|
bool canExecute( EncounterFightPtr pFight, uint64_t time ) override;
|
|
|
|
};
|
|
|
|
|
2024-05-06 01:45:42 +01:00
|
|
|
using EncounterTimelineInfo = std::queue< TimepointConditionPtr >;
|
2024-04-29 16:51:28 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
EncounterTimelineInfo buildEncounterTimeline( uint32_t encounterId, bool reload = false );
|
|
|
|
};
|
|
|
|
}// namespace Sapphire
|