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

reference conditions globally in timeline

- add PhaseActive and GetAction conditions
- refactor ifrit to use controller
This commit is contained in:
Tahir 2024-06-24 22:45:06 +01:00
parent 9445bc0260
commit 75a2fcbb63
9 changed files with 693 additions and 343 deletions

View file

@ -132,29 +132,6 @@
"duration": 8000,
"type": "castAction"
},
{
"data": {
"selectorName": "Eruption",
"sourceActor": "Ifrit"
},
"description": "",
"duration": 0,
"type": "snapshot"
},
{
"data": {
"actionId": 733,
"selectorIndex": 0,
"selectorName": "Eruption",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit <subactor 1>",
"targetType": "selector"
},
"description": "Eruption",
"duration": 8000,
"type": "castAction"
},
{
"data": {
"actionId": 454,
@ -217,11 +194,21 @@
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit",
"targetType": "selector"
"targetType": "self"
},
"description": "Eruption",
"duration": 8000,
"duration": 0,
"type": "castAction"
},
{
"data": {
"conditionId": 11,
"conditionStr": "If Ifrit casts Action#455, loop Ifrit Control->Eruption",
"enabled": true
},
"description": "",
"duration": 8000,
"type": "setCondition"
}
]
},
@ -291,6 +278,14 @@
"id": 7,
"name": "Hellfire",
"timepoints": [
{
"data": {
"despawnActor": "Ifrit Nail 1"
},
"description": "Despawn nail if up",
"duration": 0,
"type": "bNpcDespawn"
},
{
"data": {
"conditionId": 7,
@ -388,6 +383,20 @@
"id": 6,
"name": "Final Phase",
"timepoints": [
{
"data": {
"actionId": 455,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit",
"targetType": "self"
},
"description": "Eruption telegraph",
"duration": 8000,
"type": "castAction"
},
{
"data": {
"actionId": 453,
@ -404,306 +413,27 @@
},
{
"data": {
"selectorName": "Eruption",
"sourceActor": "Ifrit"
},
"description": "Eruption snapshot",
"duration": 0,
"type": "snapshot"
},
{
"data": {
"actionId": 733,
"selectorIndex": 0,
"selectorName": "Eruption",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit <subactor 1>",
"targetType": "selector"
},
"description": "Subactor 1 Eruption",
"duration": 8000,
"type": "castAction"
},
{
"data": {
"actorName": "Ifrit <subactor 1>",
"pos": [
-5,
0,
5
],
"rot": 0
},
"description": "Move plumes",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit <subactor 2>",
"pos": [
-5,
0,
-5
],
"rot": 0
},
"description": "",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit <subactor 3>",
"pos": [
5,
0,
5
],
"rot": 0
},
"description": "",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit <subactor 4>",
"pos": [
5,
0,
-5
],
"rot": 0
},
"description": "",
"duration": 8000,
"type": "setPos"
},
{
"data": {
"actionId": 734,
"actionId": 456,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit <subactor 1>",
"sourceActor": "Ifrit",
"targetType": "self"
},
"description": "Cast plumes",
"description": "Plumes telegraph",
"duration": 0,
"type": "castAction"
},
{
"data": {
"actionId": 734,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit <subactor 2>",
"targetType": "self"
"conditionId": 12,
"conditionStr": "If Ifrit->Final Phase is active, push Ifrit Control->Plumes Loop",
"enabled": true
},
"description": "",
"duration": 0,
"type": "castAction"
},
{
"data": {
"actionId": 734,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit <subactor 3>",
"targetType": "self"
},
"description": "",
"duration": 0,
"type": "castAction"
},
{
"data": {
"actionId": 734,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit <subactor 4>",
"targetType": "self"
},
"description": "",
"duration": 5000,
"type": "castAction"
},
{
"data": {
"actorName": "Ifrit <subactor 1>",
"pos": [
0,
0,
-20
],
"rot": 0
},
"description": "Move plumes out",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit <subactor 2>",
"pos": [
0,
0,
20
],
"rot": 0
},
"description": "",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit <subactor 3>",
"pos": [
-20,
0,
0
],
"rot": 0
},
"description": "",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit <subactor 4>",
"pos": [
-20,
0,
20
],
"rot": 0
},
"description": "",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit <subactor 5>",
"pos": [
-15,
0,
15
],
"rot": 0
},
"description": "",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit <subactor 6>",
"pos": [
-15,
0,
-15
],
"rot": 0
},
"description": "",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit <subactor 7>",
"pos": [
15,
0,
-15
],
"rot": 0
},
"description": "",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit <subactor 8>",
"pos": [
15,
0,
15
],
"rot": 0
},
"description": "",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actionId": 734,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit <subactor 1>",
"targetType": "self"
},
"description": "Cast plumes out",
"duration": 0,
"type": "castAction"
},
{
"data": {
"actionId": 734,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit <subactor 2>",
"targetType": "self"
},
"description": "",
"duration": 0,
"type": "castAction"
},
{
"data": {
"actionId": 734,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit <subactor 3>",
"targetType": "self"
},
"description": "",
"duration": 0,
"type": "castAction"
},
{
"data": {
"actionId": 734,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit <subactor 4>",
"targetType": "self"
},
"description": "",
"duration": 5000,
"type": "castAction"
"duration": 16000,
"type": "setCondition"
}
]
},
@ -730,16 +460,7 @@
]
}
],
"subactors": [
"Ifrit <subactor 1>",
"Ifrit <subactor 2>",
"Ifrit <subactor 3>",
"Ifrit <subactor 4>",
"Ifrit <subactor 5>",
"Ifrit <subactor 6>",
"Ifrit <subactor 7>",
"Ifrit <subactor 8>"
],
"subactors": [],
"type": "bnpc"
},
{
@ -747,8 +468,404 @@
"id": 2,
"layoutId": 4126284,
"name": "Ifrit Control",
"phases": [],
"subactors": [],
"phases": [
{
"description": "",
"id": 1,
"name": "Eruption",
"timepoints": [
{
"data": {
"selectorName": "Eruption",
"sourceActor": "Ifrit Control <subactor 1>"
},
"description": "",
"duration": 0,
"type": "snapshot"
},
{
"data": {
"actionId": 733,
"selectorIndex": 0,
"selectorName": "Eruption",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit Control <subactor 1>",
"targetType": "selector"
},
"description": "Subactor 1 Eruption",
"duration": 8000,
"type": "castAction"
}
]
},
{
"description": "",
"id": 2,
"name": "Plumes Loop",
"timepoints": [
{
"data": {
"actorName": "Ifrit Control <subactor 1>",
"pos": [
-10,
0,
10
],
"rot": 0
},
"description": "Move plumes",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit Control <subactor 2>",
"pos": [
-10,
0,
-10
],
"rot": 0
},
"description": "",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit Control <subactor 3>",
"pos": [
10,
0,
10
],
"rot": 0
},
"description": "",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit Control <subactor 4>",
"pos": [
10,
0,
-10
],
"rot": 0
},
"description": "",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actionId": 734,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit Control <subactor 1>",
"targetType": "self"
},
"description": "Cast plumes",
"duration": 0,
"type": "castAction"
},
{
"data": {
"actionId": 734,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit Control <subactor 2>",
"targetType": "self"
},
"description": "",
"duration": 0,
"type": "castAction"
},
{
"data": {
"actionId": 734,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit Control <subactor 3>",
"targetType": "self"
},
"description": "",
"duration": 0,
"type": "castAction"
},
{
"data": {
"actionId": 734,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit Control <subactor 4>",
"targetType": "self"
},
"description": "",
"duration": 4000,
"type": "castAction"
},
{
"data": {
"actorName": "Ifrit Control <subactor 1>",
"pos": [
0,
0,
-20
],
"rot": 0
},
"description": "Move plumes out",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit Control <subactor 2>",
"pos": [
0,
0,
20
],
"rot": 0
},
"description": "",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit Control <subactor 3>",
"pos": [
-20,
0,
0
],
"rot": 0
},
"description": "",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit Control <subactor 4>",
"pos": [
-20,
0,
20
],
"rot": 0
},
"description": "",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit Control <subactor 5>",
"pos": [
-15,
0,
15
],
"rot": 0
},
"description": "",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit Control <subactor 6>",
"pos": [
-15,
0,
-15
],
"rot": 0
},
"description": "",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit Control <subactor 7>",
"pos": [
15,
0,
-15
],
"rot": 0
},
"description": "",
"duration": 0,
"type": "setPos"
},
{
"data": {
"actorName": "Ifrit Control <subactor 8>",
"pos": [
15,
0,
15
],
"rot": 0
},
"description": "",
"duration": 200,
"type": "setPos"
},
{
"data": {
"actionId": 734,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit Control <subactor 1>",
"targetType": "self"
},
"description": "Cast plumes out",
"duration": 0,
"type": "castAction"
},
{
"data": {
"actionId": 734,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit Control <subactor 2>",
"targetType": "self"
},
"description": "",
"duration": 0,
"type": "castAction"
},
{
"data": {
"actionId": 734,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit Control <subactor 3>",
"targetType": "self"
},
"description": "",
"duration": 0,
"type": "castAction"
},
{
"data": {
"actionId": 734,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit Control <subactor 4>",
"targetType": "self"
},
"description": "",
"duration": 0,
"type": "castAction"
},
{
"data": {
"actionId": 734,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit Control <subactor 5>",
"targetType": "self"
},
"description": "",
"duration": 0,
"type": "castAction"
},
{
"data": {
"actionId": 734,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit Control <subactor 6>",
"targetType": "self"
},
"description": "",
"duration": 0,
"type": "castAction"
},
{
"data": {
"actionId": 734,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit Control <subactor 7>",
"targetType": "self"
},
"description": "",
"duration": 0,
"type": "castAction"
},
{
"data": {
"actionId": 734,
"selectorIndex": 0,
"selectorName": "<unset>",
"snapshot": false,
"snapshotTime": 0,
"sourceActor": "Ifrit Control <subactor 8>",
"targetType": "self"
},
"description": "",
"duration": 0,
"type": "castAction"
}
]
},
{
"description": "",
"id": 3,
"name": "Setup",
"timepoints": [
{
"data": {},
"description": "",
"duration": 5000,
"type": "idle"
}
]
}
],
"subactors": [
"Ifrit Control <subactor 1>",
"Ifrit Control <subactor 2>",
"Ifrit Control <subactor 3>",
"Ifrit Control <subactor 4>",
"Ifrit Control <subactor 5>",
"Ifrit Control <subactor 6>",
"Ifrit Control <subactor 7>",
"Ifrit Control <subactor 8>"
],
"type": "bnpc"
},
{
@ -902,6 +1019,45 @@
},
"targetActor": "Ifrit",
"targetPhase": "Final Phase"
},
{
"condition": "getAction",
"description": "",
"enabled": true,
"id": 11,
"loop": true,
"paramData": {
"actionId": 455,
"sourceActor": "Ifrit"
},
"targetActor": "Ifrit Control",
"targetPhase": "Eruption"
},
{
"condition": "phaseActive",
"description": "",
"enabled": false,
"id": 12,
"loop": false,
"paramData": {
"phaseName": "Final Phase",
"sourceActor": "Ifrit"
},
"targetActor": "Ifrit Control",
"targetPhase": "Plumes Loop"
},
{
"condition": "combatState",
"description": "",
"enabled": true,
"id": 13,
"loop": false,
"paramData": {
"combatState": 1,
"sourceActor": "Ifrit"
},
"targetActor": "Ifrit Control",
"targetPhase": "Setup"
}
],
"name": "Brand new timeline",

View file

@ -115,7 +115,10 @@ namespace Sapphire::Encounter
{ "encounterTimeElapsed", ConditionType::EncounterTimeElapsed },
{ "combatState", ConditionType::CombatState },
{ "bnpcHasFlags", ConditionType::BNpcHasFlags }
{ "bnpcHasFlags", ConditionType::BNpcHasFlags },
{ "getAction", ConditionType::GetAction },
{ "phaseActive", ConditionType::PhaseActive }
};
TimelinePack pack;
@ -263,6 +266,18 @@ namespace Sapphire::Encounter
pCondition->from_json( pcV, phase, condition, actorNameMap );
}
break;
case ConditionType::GetAction:
{
pCondition = std::make_shared< ConditionGetAction >();
pCondition->from_json( pcV, phase, condition, actorNameMap );
}
break;
case ConditionType::PhaseActive:
{
pCondition = std::make_shared< ConditionPhaseActive >();
pCondition->from_json( pcV, phase, condition, actorNameMap );
}
break;
default:
break;
}
@ -368,6 +383,32 @@ namespace Sapphire::Encounter
actor.spawnAllSubActors( pTeri );
}
bool TimelinePack::isPhaseActive( const std::string& actorName, const std::string& phaseName )
{
for( const auto& actor : m_actors )
if( actor.getName() == actorName )
return actor.isPhaseActive( phaseName );
return false;
}
void TimelinePack::resetConditionState( uint32_t id, bool toDefault )
{
for( auto& actor : m_actors )
{
if( actor.resetConditionState( id, toDefault ) )
return;
}
}
void TimelinePack::setConditionStateEnabled( uint32_t id, bool enabled )
{
for( auto& actor : m_actors )
{
if( actor.setConditionStateEnabled( id, enabled ) )
return;
}
}
bool TimelinePack::valid()
{
return !m_actors.empty();

View file

@ -82,6 +82,12 @@ namespace Sapphire::Encounter
// todo: probably just make this a Timepoint in an InitPhase
void spawnSubActors( TerritoryPtr pTeri );
bool isPhaseActive( const std::string& actorRef, const std::string& phaseName );
void resetConditionState( uint32_t id, bool toDefault = false );
void setConditionStateEnabled( uint32_t id, bool enabled );
bool valid();
};

View file

@ -4,6 +4,8 @@
#include "TimelineActor.h"
#include "TimelineActorState.h"
#include <Action/Action.h>
#include <Actor/Chara.h>
#include <Actor/BNpc.h>
#include <Actor/Player.h>
@ -101,6 +103,17 @@ namespace Sapphire::Encounter
return pBNpc && pBNpc->hasFlag( this->flags );
}
bool ConditionGetAction::isConditionMet( ConditionState& state, TimelinePack& pack, TerritoryPtr pTeri, uint64_t time ) const
{
auto pBNpc = pTeri->getActiveBNpcByLayoutId( this->layoutId );
return pBNpc && pBNpc->getCurrentAction() && pBNpc->getCurrentAction()->getId() == this->actionId;
}
bool ConditionPhaseActive::isConditionMet( ConditionState& state, TimelinePack& pack, TerritoryPtr pTeri, uint64_t time ) const
{
return pack.isPhaseActive( this->actorName, this->phaseName );
}
void ConditionHp::from_json( nlohmann::json& json, Phase& phase, ConditionType condition,
const std::unordered_map< std::string, TimelineActor >& actors )
{
@ -113,7 +126,7 @@ namespace Sapphire::Encounter
if( auto it = actors.find( actorRef ); it != actors.end() )
this->layoutId = 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 ) );
throw std::runtime_error( fmt::format( std::string( "ConditionHp::from_json unable to find actor by name: %s" ), actorRef ) );
switch( condition )
{
@ -174,7 +187,7 @@ namespace Sapphire::Encounter
if( auto it = actors.find( actorRef ); it != actors.end() )
this->layoutId = 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 ) );
throw std::runtime_error( fmt::format( std::string( "ConditionCombatState::from_json unable to find actor by name: %s" ), actorRef ) );
this->combatState = paramData.at( "combatState" ).get< CombatStateType >();
}
@ -201,12 +214,43 @@ namespace Sapphire::Encounter
if( auto it = actors.find( actorRef ); it != actors.end() )
this->layoutId = it->second.m_layoutId;
else
throw std::runtime_error( fmt::format( std::string( "EncounterTimeline::ConditionBNpcFlags::from_json unable to find actor by name: %s" ), actorRef ) );
throw std::runtime_error( fmt::format( std::string( "ConditionBNpcFlags::from_json unable to find actor by name: %s" ), actorRef ) );
this->flags = json.at( "flags" ).get< uint32_t >();
// todo: BNpcHasFlags
}
void ConditionGetAction::from_json( nlohmann::json& json, Phase& phase, ConditionType condition,
const std::unordered_map< std::string, TimelineActor >& actors )
{
PhaseCondition::from_json( json, phase, condition, actors );
auto& paramData = json.at( "paramData" );
auto actorRef = paramData.at( "sourceActor" ).get< std::string >();
auto actionId = paramData.at( "actionId" ).get< uint32_t >();
// resolve the actor whose name we are checking
if( auto it = actors.find( actorRef ); it != actors.end() )
this->layoutId = it->second.m_layoutId;
else
throw std::runtime_error( fmt::format( std::string( "ConditionGetAction::from_json unable to find actor by name: %s" ), actorRef ) );
this->actionId = actionId;
}
void ConditionPhaseActive::from_json( nlohmann::json& json, Phase& phase, ConditionType condition,
const std::unordered_map< std::string, TimelineActor >& actors )
{
PhaseCondition::from_json( json, phase, condition, actors );
auto& paramData = json.at( "paramData" );
auto actorRef = paramData.at( "sourceActor" ).get< std::string >();
auto phaseName = paramData.at( "phaseName" ).get< std::string >();
this->actorName = actorRef;
this->phaseName = phaseName;
}
// todo: i wrote this very sleep deprived, ensure it is actually sane
void Phase::execute( ConditionState& state, TimelineActor& self, TimelinePack& pack, TerritoryPtr pTeri, uint64_t time ) const

View file

@ -32,7 +32,10 @@ namespace Sapphire::Encounter
EncounterTimeElapsed,
CombatState,
BNpcHasFlags
BNpcHasFlags,
GetAction,
PhaseActive
};
class Phase : public std::enable_shared_from_this< Phase >
@ -77,6 +80,11 @@ namespace Sapphire::Encounter
this->m_id = json.at( "id" ).get< uint32_t >();
}
const std::string& getPhaseName()
{
return m_phase.m_name;
}
void execute( ConditionState& state, TimelineActor& self, TimelinePack& pack, TerritoryPtr pTeri, uint64_t time ) const
{
m_phase.execute( state, self, pack, pTeri, time );
@ -213,4 +221,24 @@ namespace Sapphire::Encounter
bool isConditionMet( ConditionState& state, TimelinePack& pack, TerritoryPtr pTeri, uint64_t time ) const override;
};
class ConditionGetAction : public PhaseCondition
{
public:
uint32_t layoutId;
uint32_t actionId;
void from_json( nlohmann::json& json, Phase& phase, ConditionType condition, const std::unordered_map< std::string, TimelineActor >& actors ) override;
bool isConditionMet( ConditionState& state, TimelinePack& pack, TerritoryPtr pTeri, uint64_t time ) const override;
};
class ConditionPhaseActive : public PhaseCondition
{
public:
std::string actorName;
std::string phaseName;
void from_json( nlohmann::json& json, Phase& phase, ConditionType condition, const std::unordered_map< std::string, TimelineActor >& actors ) override;
bool isConditionMet( ConditionState& state, TimelinePack& pack, TerritoryPtr pTeri, uint64_t time ) const override;
};
}// namespace Sapphire::Encounter

View file

@ -12,6 +12,28 @@
namespace Sapphire::Encounter
{
const std::string& TimelineActor::getName() const
{
return m_name;
}
uint32_t TimelineActor::getLayoutId() const
{
return m_layoutId;
}
bool TimelineActor::isPhaseActive( const std::string& name ) const
{
for( const auto& condition : m_phaseConditions )
{
const auto& pCondition = condition.second;
const auto& state = m_conditionStates.at( condition.first );
if( pCondition->inProgress( state ) && pCondition->getPhaseName() == name )
return true;
}
return false;
}
void TimelineActor::addPhaseCondition( PhaseConditionPtr pCondition )
{
m_phaseConditions.emplace( std::make_pair( pCondition->getId(), pCondition ) );
@ -59,22 +81,26 @@ namespace Sapphire::Encounter
}
}
void TimelineActor::resetConditionState( uint32_t conditionId )
bool TimelineActor::resetConditionState( uint32_t conditionId, bool toDefault )
{
if( auto it = m_phaseConditions.find( conditionId ); it != m_phaseConditions.end() )
{
auto& state = m_conditionStates.at( it->first );
it->second->reset( state );
it->second->reset( state, toDefault );
return true;
}
return false;
}
void TimelineActor::setConditionStateEnabled( uint32_t conditionId, bool enabled )
bool TimelineActor::setConditionStateEnabled( uint32_t conditionId, bool enabled )
{
if( auto it = m_conditionStates.find( conditionId ); it != m_conditionStates.end() )
{
auto& state = m_conditionStates.at( it->first );
state.m_enabled = enabled;
return true;
}
return false;
}
void TimelineActor::resetAllConditionStates()
@ -149,7 +175,9 @@ namespace Sapphire::Encounter
if( pActor == nullptr )
{
auto pParent = pTeri->getActiveBNpcByLayoutId( m_layoutId );
pActor = pTeri->createBNpcFromLayoutId( m_layoutId, 1000, pParent->getBNpcType() );
Common::BNpcType type = pParent ? pParent->getBNpcType() : Common::BNpcType::Enemy;
pActor = pTeri->createBNpcFromLayoutId( m_layoutId, 1000, type );
m_subActors[ name ] = pActor;
pActor->setInvincibilityType( Common::InvincibilityIgnoreDamage );

View file

@ -40,17 +40,23 @@ namespace Sapphire::Encounter
m_conditionStates = rhs.m_conditionStates;
for( const auto& state : rhs.m_phaseConditions )
state.second->reset( m_conditionStates[ state.first ] );
state.second->reset( m_conditionStates[ state.first ], true );
}
const std::string& getName() const;
uint32_t getLayoutId() const;
bool isPhaseActive( const std::string& name ) const;
void addPhaseCondition( PhaseConditionPtr pCondition );
// todo: make this sane
void update( TerritoryPtr pTeri, TimelinePack& pack, uint64_t time );
void resetConditionState( uint32_t conditionId );
bool resetConditionState( uint32_t conditionId, bool toDefault = false );
void setConditionStateEnabled( uint32_t conditionId, bool enabled );
bool setConditionStateEnabled( uint32_t conditionId, bool enabled );
void resetAllConditionStates();

View file

@ -63,6 +63,7 @@ namespace Sapphire::Encounter
{ "directorSeq", TimepointDataType::DirectorSeq },
{ "directorFlags", TimepointDataType::DirectorFlags },
{ "bNpcDespawn", TimepointDataType::BNpcDespawn },
{ "bNpcSpawn", TimepointDataType::BNpcSpawn },
{ "bNpcFlags", TimepointDataType::BNpcFlags },
{ "setEObjState", TimepointDataType::SetEObjState },
@ -246,7 +247,20 @@ namespace Sapphire::Encounter
}
break;
case TimepointDataType::BNpcDespawn:
{
auto& dataJ = json.at( "data" );
auto actorRef = dataJ.at( "despawnActor" ).get< std::string >();
uint32_t layoutId = 0xE0000000;
if( auto it = actors.find( actorRef ); it != actors.end() )
layoutId = it->second.m_layoutId;
else
throw std::runtime_error( fmt::format( std::string( "Timepoint::from_json: SpawnBNpc invalid actor ref: {}" ), actorRef ) );
m_pData = std::make_shared< TimepointDataBNpcDespawn >( layoutId );
}
break;
case TimepointDataType::BNpcSpawn:
{
auto& dataJ = json.at( "data" );
@ -265,7 +279,7 @@ namespace Sapphire::Encounter
else
throw std::runtime_error( fmt::format( std::string( "Timepoint::from_json: SpawnBNpc invalid actor ref: {}" ), actorRef ) );
m_pData = std::make_shared< TimepointDataSpawnBNpc >( layoutId, flags, bnpcType );
m_pData = std::make_shared< TimepointDataBNpcSpawn >( layoutId, flags, bnpcType );
}
break;
case TimepointDataType::BNpcFlags:
@ -409,6 +423,7 @@ namespace Sapphire::Encounter
{
pAction->setInterrupted( Common::ActionInterruptType::RegularInterrupt );
pAction->interrupt();
return false;
}
else
{
@ -610,9 +625,23 @@ namespace Sapphire::Encounter
{
}
break;
case TimepointDataType::BNpcDespawn:
{
auto pDespawnData = std::dynamic_pointer_cast< TimepointDataBNpcDespawn, TimepointData >( m_pData );
auto pBNpc = pTeri->getActiveBNpcByLayoutId( pDespawnData->m_layoutId );
if( pBNpc )
{
for( const auto& player : pTeri->getPlayers() )
pBNpc->despawn( player.second );
pTeri->removeActor( pBNpc );
}
}
break;
case TimepointDataType::BNpcSpawn:
{
auto pSpawnData = std::dynamic_pointer_cast< TimepointDataSpawnBNpc, TimepointData >( m_pData );
auto pSpawnData = std::dynamic_pointer_cast< TimepointDataBNpcSpawn, TimepointData >( m_pData );
auto pBNpc = pTeri->getActiveBNpcByLayoutId( pSpawnData->m_layoutId );
// todo: probably have this info in the timepoint data
@ -682,8 +711,8 @@ namespace Sapphire::Encounter
auto pConditionData = std::dynamic_pointer_cast< TimepointDataCondition, TimepointData >( m_pData );
// todo: dont reset so things can resume? idk
self.resetConditionState( pConditionData->m_conditionId );
self.setConditionStateEnabled( pConditionData->m_conditionId, pConditionData->m_enabled );
pack.resetConditionState( pConditionData->m_conditionId );
pack.setConditionStateEnabled( pConditionData->m_conditionId, pConditionData->m_enabled );
}
break;
case TimepointDataType::Snapshot:

View file

@ -31,6 +31,7 @@ namespace Sapphire::Encounter
RemoveStatusEffect,
BNpcSpawn,
BNpcDespawn,
BNpcFlags,
SetEObjState,
SetBgm,
@ -186,7 +187,18 @@ namespace Sapphire::Encounter
}
};
struct TimepointDataSpawnBNpc : public TimepointData
struct TimepointDataBNpcDespawn : public TimepointData
{
uint32_t m_layoutId{ 0xE0000000 };
TimepointDataBNpcDespawn( uint32_t layoutId ) :
TimepointData( TimepointDataType::BNpcDespawn ),
m_layoutId( layoutId )
{
}
};
struct TimepointDataBNpcSpawn : public TimepointData
{
uint32_t m_layoutId{ 0xE0000000 };
uint32_t m_flags{ 0 };
@ -194,7 +206,7 @@ namespace Sapphire::Encounter
// todo: hate type, source
TimepointDataSpawnBNpc( uint32_t layoutId, uint32_t flags, uint32_t type ) :
TimepointDataBNpcSpawn( uint32_t layoutId, uint32_t flags, uint32_t type ) :
TimepointData( TimepointDataType::BNpcSpawn ),
m_layoutId( layoutId ),
m_flags( flags ),