1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-05-02 16:57:47 +00:00
sapphire/src/world/Encounter/EncounterTimeline.h

401 lines
9.5 KiB
C
Raw Normal View History

#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>
#include <nlohmann/json.hpp>
namespace Sapphire
{
2024-05-05 16:15:05 +01:00
class EncounterTimeline
{
public:
// EncounterFight::OnTick() { switch EncounterTimepointConditionId }
2024-05-06 01:45:42 +01:00
enum class ConditionId : uint32_t
{
HpPctLessThan,
HpPctBetween,
DirectorVarEquals,
2024-05-06 01:45:42 +01:00
DirectorVarGreaterThan,
2024-05-06 20:13:53 +01:00
DirectorSeqEquals,
DirectorSeqGreaterThan,
DirectorFlagsEquals,
DirectorFlagsGreaterThan,
2024-05-06 01:45:42 +01:00
PhaseTimeElapsed,
EncounterTimeElapsed
};
enum class DirectorOpId
{
SetDirectorVar,
SetDirectorVarLR,
SetDirectorSeq,
SetDirectorFlag,
ClearDirectorFlag
};
// TODO: what should this do?
2024-05-06 01:45:42 +01:00
enum class TimepointOverrideFlags : uint32_t
{
None,
Invulnerable
};
2024-05-06 01:45:42 +01:00
enum class TimepointDataType : uint32_t
{
Idle,
CastAction,
MoveTo,
LogMessage,
BattleTalk,
SetDirectorVar,
2024-05-06 01:45:42 +01:00
SetDirectorSeq,
SetDirectorFlag,
AddStatusEffect,
RemoveStatusEffect
};
2024-05-06 01:45:42 +01:00
enum class TimepointCallbackType : uint32_t
{
OnActionInit,
OnActionStart,
OnActionInterrupt,
OnActionExecute
};
2024-05-06 20:13:53 +01:00
enum class TargetSelectFilterId : uint32_t
{
Self,
Tank,
Healer,
Dps,
DpsMelee,
DpsRanged,
Furthest,
Aggro1,
Aggro2
};
enum class MoveType
{
WalkPath,
Teleport
};
struct TargetSelectFilter
{
2024-05-06 20:13:53 +01:00
TargetSelectFilterId 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-05-06 01:45:42 +01:00
TimepointCallbackType m_type;
std::vector < TimepointCallbackFunc > m_callbacks;
};
2024-05-06 01:45:42 +01:00
using TimebackCallbackDataPtr = std::shared_ptr< TimepointCallbackData >;
using TimepointCallbacks = std::map< TimepointCallbackType, TimebackCallbackDataPtr >;
2024-05-06 01:45:42 +01:00
struct TimepointData :
public std::enable_shared_from_this< TimepointData >
{
2024-05-06 20:13:53 +01:00
TimepointData( TimepointDataType type ) : m_type( type ) {}
virtual ~TimepointData(){};
TimepointDataType m_type{ 0 };
};
2024-05-06 01:45:42 +01:00
using TimepointDataPtr = std::shared_ptr< TimepointData >;
2024-05-06 01:45:42 +01:00
struct TimepointDataIdle : public TimepointData
{
uint32_t m_actorId;
uint64_t m_durationMs;
2024-05-06 20:13:53 +01:00
TimepointDataIdle( uint32_t actorId, uint64_t durationMs ) :
TimepointData( TimepointDataType::Idle ),
m_actorId( actorId ),
m_durationMs( durationMs )
{
}
2024-05-06 01:45:42 +01:00
};
2024-05-06 20:13:53 +01:00
struct TimepointDataAddStatusEffect : public TimepointData
{
uint32_t m_statusEffectId;
TargetSelectFilter m_targetFilter;
uint32_t m_durationMs;
2024-05-06 20:13:53 +01:00
TimepointDataAddStatusEffect( uint32_t statusId, TargetSelectFilter targFilter, uint32_t durationMs ) :
TimepointData( TimepointDataType::AddStatusEffect ),
m_statusEffectId( statusId ),
m_targetFilter( targFilter ),
m_durationMs( durationMs )
{
}
};
struct TimepointDataRemoveStatusEffect : public TimepointData
{
uint32_t m_statusEffectId;
TargetSelectFilter m_targetFilter;
TimepointDataRemoveStatusEffect( uint32_t statusId, TargetSelectFilter targFilter ) :
TimepointData( TimepointDataType::RemoveStatusEffect ),
m_statusEffectId( statusId ),
m_targetFilter( targFilter )
{
}
};
2024-05-06 01:45:42 +01:00
struct TimepointDataAction : public TimepointData
{
2024-05-06 01:45:42 +01:00
uint32_t m_actorId;
uint32_t m_actionId;
2024-05-06 01:45:42 +01:00
TimepointCallbacks m_callbacks;
2024-05-06 20:13:53 +01:00
TimepointDataAction( uint32_t actorId, uint32_t actionId, TimepointCallbacks callbacks ) :
TimepointData( TimepointDataType::CastAction ),
m_actorId( actorId ),
m_actionId( actionId ),
m_callbacks( callbacks )
{
}
2024-05-06 01:45:42 +01:00
};
struct TimepointDataMoveTo : public TimepointData
{
uint32_t m_actorId;
MoveType m_moveType;
float m_x, m_y, m_z, m_rot;
2024-05-06 20:13:53 +01:00
TimepointDataMoveTo( uint32_t actorId, MoveType moveType, float x, float y, float z, float rot ) :
TimepointData( TimepointDataType::MoveTo ),
m_actorId( actorId ),
m_moveType( moveType ),
m_x( x ), m_y( y ), m_z( z ), m_rot( rot )
{
}
2024-05-06 01:45:42 +01:00
};
struct TimepointDataLogMessage : public TimepointData
{
2024-05-06 20:13:53 +01:00
uint32_t m_messageId;
uint32_t m_params[ 6 ]{ 0 };
TimepointDataLogMessage( uint32_t messageId, std::vector< uint32_t > params ) :
TimepointData( TimepointDataType::LogMessage ),
m_messageId( messageId )
{
for( auto i = 0; i < params.size(); ++i )
m_params[i] = params[i];
}
};
2024-05-06 01:45:42 +01:00
struct TimepointDataDirector : public TimepointData
{
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-05-06 20:13:53 +01:00
};
2024-05-06 01:45:42 +01:00
class Timepoint :
public std::enable_shared_from_this< Timepoint >
{
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;
std::string m_description;
2024-05-06 01:45:42 +01:00
// todo: repeatable?
2024-05-06 20:13:53 +01:00
const TimepointDataPtr getData() const
{
return m_pData;
}
2024-05-06 01:45:42 +01:00
bool canExecute()
{
return m_executeTime == 0;
}
bool finished( uint64_t time )
{
return m_executeTime + m_duration <= time;
}
2024-05-06 20:13:53 +01:00
void from_json( const nlohmann::json& json );
2024-05-06 01:45:42 +01:00
void execute( EncounterFightPtr pFight, uint64_t time );
};
2024-05-06 01:45:42 +01:00
class Phase :
public std::enable_shared_from_this< Phase >
{
public:
2024-05-06 01:45:42 +01:00
// todo: respect looping phases, allow callbacks to push timepoints
std::string m_name;
2024-05-06 20:13:53 +01:00
std::queue< Timepoint > m_timepoints;
uint64_t m_startTime{ 0 };
2024-05-06 01:45:42 +01:00
uint64_t m_lastTimepoint{ 0 };
2024-05-06 20:13:53 +01:00
std::queue< Timepoint > m_executed;
2024-05-06 01:45:42 +01:00
// todo: i wrote this very sleep deprived, ensure it is actually sane
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-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;
2024-05-06 20:13:53 +01:00
auto& timepoint = m_timepoints.front();
if( timepoint.canExecute() )
2024-05-06 01:45:42 +01:00
{
2024-05-06 20:13:53 +01:00
timepoint.execute( pFight, time );
2024-05-06 01:45:42 +01:00
m_lastTimepoint = time;
2024-05-06 20:13:53 +01:00
m_executed.push( timepoint );
2024-05-06 01:45:42 +01:00
}
2024-05-06 20:13:53 +01:00
else if( timepoint.finished( timepointElapsed ) )
2024-05-06 01:45:42 +01:00
{
// todo: this is stupid, temp workaround for allowing phases to loop
2024-05-06 20:13:53 +01:00
timepoint.m_executeTime = 0;
2024-05-06 01:45:42 +01:00
m_timepoints.pop();
}
else
{
break;
}
}
}
2024-05-06 20:13:53 +01:00
bool completed()
{
return m_timepoints.size() == 0;
}
};
2024-05-06 01:45:42 +01:00
using PhasePtr = std::shared_ptr< Phase >;
2024-05-06 01:45:42 +01:00
class TimepointCondition :
public std::enable_shared_from_this< TimepointCondition >
{
public:
2024-05-06 01:45:42 +01:00
ConditionId m_conditionId{ 0 };
2024-05-06 20:13:53 +01:00
Phase m_phase;
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-05-06 20:13:53 +01:00
virtual void from_json( nlohmann::json& json, Phase phase, ConditionId conditionId )
{
this->m_conditionId = conditionId;
this->m_loop = json.at( "loop" ).get< bool >();
this->m_cooldown = json.at( "cooldown" ).get< uint32_t >();
2024-05-06 20:13:53 +01:00
this->m_phase = phase;
}
void execute( EncounterFightPtr pFight, uint64_t time )
{
m_startTime = time;
2024-05-06 20:13:53 +01:00
m_phase.execute( pFight, time );
};
2024-05-06 20:13:53 +01:00
bool completed()
{
return m_phase.completed();
}
bool canLoop()
{
return m_phase.completed() && m_loop;
}
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-05-06 01:45:42 +01:00
class ConditionHp : TimepointCondition
{
public:
uint32_t actorId;
union
{
uint8_t val;
struct
{
uint8_t min, max;
};
} hp;
2024-05-06 20:13:53 +01:00
void from_json( nlohmann::json& json, Phase phase, ConditionId conditionId );
bool canExecute( EncounterFightPtr pFight, uint64_t time ) override;
};
2024-05-06 01:45:42 +01:00
class ConditionDirectorVar : TimepointCondition
{
public:
2024-05-06 20:13:53 +01:00
union
{
struct
{
uint32_t var;
uint32_t value;
};
uint8_t seq;
uint8_t flag;
} param;
void from_json( nlohmann::json& json, Phase phase, ConditionId conditionId );
bool canExecute( EncounterFightPtr pFight, uint64_t time ) override;
};
2024-05-06 01:45:42 +01:00
using EncounterTimelineInfo = std::queue< TimepointConditionPtr >;
public:
EncounterTimelineInfo buildEncounterTimeline( uint32_t encounterId, bool reload = false );
};
}// namespace Sapphire