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

fix 0 duration timepoints

- fix BNpcSpawn timepoint
- temp workaround for actions
- fix selectors not working as intended
- todo: rewrite this shit to not abuse copy ctors
This commit is contained in:
Tahir 2024-06-24 18:41:18 +01:00
parent 8c952540d5
commit 9445bc0260
13 changed files with 182 additions and 60 deletions

View file

@ -107,7 +107,7 @@
"data": {
"battleTalkId": 2939,
"handlerActorName": "Ifrit",
"kind": 0,
"kind": 1,
"nameId": 2961,
"params": [
0
@ -211,7 +211,7 @@
},
{
"data": {
"actionId": 733,
"actionId": 455,
"selectorIndex": 0,
"selectorName": "Eruption",
"snapshot": false,
@ -234,7 +234,7 @@
"data": {
"battleTalkId": 2939,
"handlerActorName": "Ifrit",
"kind": 0,
"kind": 1,
"nameId": 2961,
"params": [
0
@ -256,7 +256,7 @@
},
"description": "",
"duration": 1500,
"type": "spawnBNpc"
"type": "bNpcSpawn"
},
{
"data": {
@ -291,6 +291,16 @@
"id": 7,
"name": "Hellfire",
"timepoints": [
{
"data": {
"conditionId": 7,
"conditionStr": "If Ifrit Nail 1 state is Dead, push Ifrit->Hellfire",
"enabled": false
},
"description": "",
"duration": 0,
"type": "setCondition"
},
{
"data": {
"conditionId": 6,
@ -354,7 +364,7 @@
},
{
"data": {
"flags": 1,
"flags": 16,
"targetActor": ""
},
"description": "",
@ -367,7 +377,7 @@
"conditionStr": "If Ifrit state is Combat, loop Ifrit->Final Phase",
"enabled": true
},
"description": "",
"description": "Enable final phase",
"duration": 0,
"type": "setCondition"
}
@ -388,7 +398,7 @@
"sourceActor": "Ifrit",
"targetType": "target"
},
"description": "Radiant plume begin",
"description": "Incinerate Final Phase",
"duration": 8000,
"type": "castAction"
},
@ -412,7 +422,7 @@
"targetType": "selector"
},
"description": "Subactor 1 Eruption",
"duration": 5000,
"duration": 8000,
"type": "castAction"
},
{
@ -524,16 +534,16 @@
"targetType": "self"
},
"description": "",
"duration": 0,
"duration": 5000,
"type": "castAction"
},
{
"data": {
"actorName": "Ifrit <subactor 1>",
"pos": [
-10,
0,
10
0,
-20
],
"rot": 0
},
@ -545,9 +555,9 @@
"data": {
"actorName": "Ifrit <subactor 2>",
"pos": [
-10,
0,
-10
0,
20
],
"rot": 0
},
@ -559,9 +569,9 @@
"data": {
"actorName": "Ifrit <subactor 3>",
"pos": [
10,
-20,
0,
10
0
],
"rot": 0
},
@ -573,9 +583,65 @@
"data": {
"actorName": "Ifrit <subactor 4>",
"pos": [
10,
-20,
0,
-10
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
},

View file

@ -260,4 +260,10 @@ namespace Sapphire::World::AI
return m_targetIds;
}
void Snapshot::clearResults()
{
m_results.clear();
m_targetIds.clear();
}
};// namespace Sapphire::World::AI

View file

@ -236,12 +236,14 @@ namespace Sapphire::World::AI
m_filters( filters )
{
}
void createSnapshot( Entity::CharaPtr pSrc, const std::set< Entity::GameObjectPtr >& inRange,
int count, bool fillWithRandom, const std::vector< uint32_t >& exclude = {} );
// returns actors sorted by distance
const std::vector< CharaEntry >& getResults() const;
const std::vector< uint32_t >& getTargetIds() const;
void clearResults();
};
using SnapshotPtr = std::shared_ptr< Snapshot >;
}// namespace Sapphire::World::AI

View file

@ -36,7 +36,7 @@ namespace Sapphire::Entity
Immobile = 0x01,
TurningDisabled = 0x02,
Invincible = 0x04,
InvincibleRefill = 0x08,
StayAlive = 0x08,
NoDeaggro = 0x10,
Untargetable = 0x20,
AutoAttackDisabled = 0x40,

View file

@ -399,7 +399,7 @@ void Chara::takeDamage( uint32_t damage )
resetHp();
break;
case InvincibilityStayAlive:
setHp( 0 );
setHp( 1 );
break;
case InvincibilityIgnoreDamage:
break;

View file

@ -24,6 +24,8 @@
#include <Util/UtilMath.h>
#include <Util/Util.h>
#include <filesystem>
namespace Sapphire::Encounter
{
@ -134,8 +136,8 @@ namespace Sapphire::Encounter
for( const auto& selectorJ : json.at( "selectors" ).items() )
{
auto selectorV = selectorJ.value();
auto name = selectorV.at( "name" );
auto& selectorV = selectorJ.value();
auto name = selectorV.at( "name" ).get< std::string >();
Selector selector;
selector.from_json( selectorV );
@ -151,6 +153,12 @@ namespace Sapphire::Encounter
actor.m_layoutId = actorV.at( "layoutId" ).get< uint32_t >();
actor.m_name = actorV.at( "name" ).get< std::string >();
auto& subActorsJ = actorV.at( "subactors" );
if( !subActorsJ.is_null() )
for( const auto& subActorV : subActorsJ.items() )
actor.addPlaceholderSubactor( subActorV.value().get< std::string >() );
actorNameMap.emplace( std::make_pair( actor.m_name, actor ) );
}
@ -317,14 +325,13 @@ namespace Sapphire::Encounter
m_actors.emplace_back( actor );
}
Entity::BNpcPtr TimelinePack::getBNpcByActorRef( const std::string& name, TerritoryPtr pTeri, const std::string& subActorName )
Entity::BNpcPtr TimelinePack::getBNpcByRef( const std::string& name, TerritoryPtr pTeri )
{
for( const auto& actor : m_actors )
{
if( actor.m_name == name )
{
return actor.getBNpcByRef( name, pTeri );
}
auto pBNpc = actor.getBNpcByRef( name, pTeri );
if( pBNpc )
return pBNpc;
}
return nullptr;
}
@ -355,6 +362,12 @@ namespace Sapphire::Encounter
actor.update( pTeri, *this, now );
}
void TimelinePack::spawnSubActors( TerritoryPtr pTeri )
{
for( auto& actor : m_actors )
actor.spawnAllSubActors( pTeri );
}
bool TimelinePack::valid()
{
return !m_actors.empty();

View file

@ -46,8 +46,11 @@ namespace Sapphire::Encounter
m_type( rhs.m_type ),
m_name( rhs.m_name ),
m_actors( rhs.m_actors ),
m_selectors( rhs.m_selectors ),
m_startTime( 0 )
{
for( auto& selector : m_selectors )
selector.second.clearResults();
}
TimelinePack( TimelinePackType type ) : m_type( type ) {}
@ -65,7 +68,8 @@ namespace Sapphire::Encounter
void addTimelineActor( const TimelineActor& actor );
Entity::BNpcPtr getBNpcByActorRef( const std::string& name, TerritoryPtr pTeri, const std::string& subActorName = {} );
// get bnpc by internal timeline name
Entity::BNpcPtr getBNpcByRef( const std::string& name, TerritoryPtr pTeri );
void reset( TerritoryPtr pTeri );
@ -75,6 +79,9 @@ namespace Sapphire::Encounter
void update( TerritoryPtr pTeri, uint64_t time );
// todo: probably just make this a Timepoint in an InitPhase
void spawnSubActors( TerritoryPtr pTeri );
bool valid();
};

View file

@ -45,8 +45,8 @@ namespace Sapphire
{
removeBNpc( NPC_IFRIT );
m_pInstance->removeActor( boss );
m_pInstance->getEncounterTimeline().reset( getInstance() );
}
m_pInstance->getEncounterTimeline().reset( getInstance() );
init();
}

View file

@ -134,4 +134,9 @@ namespace Sapphire::Encounter
{
return m_snapshot.getTargetIds();
}
void Selector::clearResults()
{
m_snapshot.clearResults();
}
}// namespace Sapphire::Encounter

View file

@ -12,7 +12,7 @@ namespace Sapphire::Encounter
private:
std::string m_name;
bool m_fillWithRandom{ true };
uint32_t m_count;
uint32_t m_count{ 0 };
World::AI::Snapshot m_snapshot;
public:
@ -20,6 +20,7 @@ namespace Sapphire::Encounter
void createSnapshot( Entity::CharaPtr pSrc, const std::vector< uint32_t >& exclude = {} );
const World::AI::Snapshot::Results& getResults();
const World::AI::Snapshot::TargetIds& getTargetIds();
void clearResults();
void from_json( const nlohmann::json& json );
};
};// namespace Sapphire::Encounter

View file

@ -5,6 +5,9 @@
#include <Actor/BNpc.h>
#include <Action/Action.h>
#include <Manager/PlayerMgr.h>
#include <Service.h>
#include <Territory/Territory.h>
namespace Sapphire::Encounter
@ -140,7 +143,7 @@ namespace Sapphire::Encounter
// 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;
Entity::BNpcFlag::TurningDisabled | Entity::BNpcFlag::NoDeaggro;
auto pActor = getSubActor( name );
if( pActor == nullptr )
@ -155,8 +158,12 @@ namespace Sapphire::Encounter
pTeri->pushActor( pActor );
auto& playerMgr = Common::Service< World::Manager::PlayerMgr >::ref();
for( const auto& player : pTeri->getPlayers() )
{
pActor->spawn( player.second );
playerMgr.sendDebug( *player.second, fmt::format( "Spawned subactor {}", name ) );
}
}
return pActor;

View file

@ -28,12 +28,12 @@ namespace Sapphire::Encounter
bool Timepoint::canExecute( const TimepointState& state, uint64_t elapsed ) const
{
return state.m_startTime == 0;// & &m_duration <= elapsed;
return state.m_startTime == 0;
}
bool Timepoint::durationElapsed( uint64_t elapsed ) const
{
return m_duration < elapsed;
return m_duration <= elapsed;
}
bool Timepoint::finished( const TimepointState& state, uint64_t elapsed ) const
@ -63,8 +63,8 @@ namespace Sapphire::Encounter
{ "directorSeq", TimepointDataType::DirectorSeq },
{ "directorFlags", TimepointDataType::DirectorFlags },
{ "spawnBNpc", TimepointDataType::SpawnBNpc },
{ "bNpcFlags", TimepointDataType::SetBNpcFlags },
{ "bNpcSpawn", TimepointDataType::BNpcSpawn },
{ "bNpcFlags", TimepointDataType::BNpcFlags },
{ "setEObjState", TimepointDataType::SetEObjState },
{ "setBGM", TimepointDataType::SetBgm },
@ -134,7 +134,7 @@ namespace Sapphire::Encounter
auto selectorIndex = dataJ.at( "selectorIndex" ).get< uint32_t >();
m_pData = std::make_shared< TimepointDataAction >( sourceRef, actionId, targetType,
selectorRef, selectorIndex );
selectorRef, selectorIndex - 1 );
}
break;
case TimepointDataType::SetPos:
@ -247,7 +247,7 @@ namespace Sapphire::Encounter
break;
case TimepointDataType::SpawnBNpc:
case TimepointDataType::BNpcSpawn:
{
auto& dataJ = json.at( "data" );
// auto hateSrcJ = dataJ.at( "hateSrc" );
@ -268,7 +268,7 @@ namespace Sapphire::Encounter
m_pData = std::make_shared< TimepointDataSpawnBNpc >( layoutId, flags, bnpcType );
}
break;
case TimepointDataType::SetBNpcFlags:
case TimepointDataType::BNpcFlags:
{
auto& dataJ = json.at( "data" );
auto actorRef = dataJ.at( "targetActor" ).get< std::string >();
@ -330,20 +330,21 @@ namespace Sapphire::Encounter
bool Timepoint::execute( TimepointState& state, TimelineActor& self, TimelinePack& pack, TerritoryPtr pTeri, uint64_t time ) const
{
const auto& players = pTeri->getPlayers();
// send debug msg
if( !m_description.empty() )
{
auto& playerMgr = Common::Service< Sapphire::World::Manager::PlayerMgr >::ref();
for( const auto& player : players )
playerMgr.sendDebug( *player.second, m_description );
}
if( update( state, self, pack, pTeri, time ) )
{
state.m_startTime = time;
state.m_finished = true;
const auto& players = pTeri->getPlayers();
// send debug msg
if( !m_description.empty() )
{
auto& playerMgr = Common::Service< Sapphire::World::Manager::PlayerMgr >::ref();
for( const auto& player : players )
playerMgr.sendDebug( *player.second, m_description );
}
return true;
}
return false;
@ -367,7 +368,7 @@ namespace Sapphire::Encounter
case TimepointDataType::CastAction:
{
auto pActionData = std::dynamic_pointer_cast< TimepointDataAction, TimepointData >( m_pData );
auto pBNpc = self.getBNpcByRef( pActionData->m_sourceRef, pTeri );
auto pBNpc = pack.getBNpcByRef( pActionData->m_sourceRef, pTeri );
// todo: filter the correct target
// todo: tie to mechanic script?
// todo: mechanic should probably just be an Action::onTick, with instance/director passed to it
@ -376,9 +377,15 @@ namespace Sapphire::Encounter
uint32_t targetId = pBNpc->getId();
switch( pActionData->m_targetType )
{
case ActionTargetType::None:
targetId = 0xE0000000;
break;
case ActionTargetType::Target:
targetId = static_cast< uint32_t >( pBNpc->getTargetId() );
break;
case ActionTargetType::Self:
targetId = pBNpc->getId();
break;
case ActionTargetType::Selector:
{
const auto& results = pack.getSnapshotTargetIds( pActionData->m_selectorRef );
@ -390,12 +397,19 @@ namespace Sapphire::Encounter
break;
}
auto& actionMgr = Common::Service< Sapphire::World::Manager::ActionMgr >::ref();
auto pAction = pBNpc->getCurrentAction();
// todo: this is probably wrong
if( !pBNpc->getCurrentAction() )
if( !pAction )
{
actionMgr.handleTargetedAction( *pBNpc, pActionData->m_actionId, targetId, 0 );
}
// todo: this really shouldnt exist, but need to figure out why actions interrupt
else if( pAction->getId() == pActionData->m_actionId )
{
pAction->setInterrupted( Common::ActionInterruptType::RegularInterrupt );
pAction->interrupt();
}
else
{
return false;
@ -406,12 +420,13 @@ namespace Sapphire::Encounter
case TimepointDataType::SetPos:
{
auto pSetPosData = std::dynamic_pointer_cast< TimepointDataSetPos, TimepointData >( m_pData );
auto pBNpc = self.getBNpcByRef( pSetPosData->m_actorRef, pTeri );
auto pBNpc = pack.getBNpcByRef( pSetPosData->m_actorRef, pTeri );
if( pBNpc )
{
pBNpc->setRot( pSetPosData->m_rot );
pBNpc->setPos( pSetPosData->m_x, pSetPosData->m_y, pSetPosData->m_z, true );
pBNpc->sendPositionUpdate();
}
}
break;
@ -419,7 +434,7 @@ namespace Sapphire::Encounter
case TimepointDataType::MoveTo:
{
auto pMoveToData = std::dynamic_pointer_cast< TimepointDataMoveTo, TimepointData >( m_pData );
auto pBNpc = self.getBNpcByRef( pMoveToData->m_actorRef, pTeri );
auto pBNpc = pack.getBNpcByRef( pMoveToData->m_actorRef, pTeri );
if( pBNpc )
{
@ -469,8 +484,8 @@ namespace Sapphire::Encounter
auto pBtData = std::dynamic_pointer_cast< TimepointDataBattleTalk, TimepointData >( m_pData );
auto params = pBtData->m_params;
auto pHandler = pack.getBNpcByActorRef( pBtData->m_handlerRef , pTeri );
auto pTalker = pack.getBNpcByActorRef( pBtData->m_talkerRef, pTeri );
auto pHandler = pack.getBNpcByRef( pBtData->m_handlerRef , pTeri );
auto pTalker = pack.getBNpcByRef( pBtData->m_talkerRef, pTeri );
auto handlerId = pHandler ? pHandler->getId() : 0xE0000000;
auto talkerId = pTalker ? pTalker->getId() : 0xE0000000;
@ -595,7 +610,7 @@ namespace Sapphire::Encounter
{
}
break;
case TimepointDataType::SpawnBNpc:
case TimepointDataType::BNpcSpawn:
{
auto pSpawnData = std::dynamic_pointer_cast< TimepointDataSpawnBNpc, TimepointData >( m_pData );
auto pBNpc = pTeri->getActiveBNpcByLayoutId( pSpawnData->m_layoutId );
@ -615,7 +630,7 @@ namespace Sapphire::Encounter
}
}
break;
case TimepointDataType::SetBNpcFlags:
case TimepointDataType::BNpcFlags:
{
auto pBNpcFlagData = std::dynamic_pointer_cast< TimepointDataBNpcFlags, TimepointData >( m_pData );
auto pBNpc = pTeri->getActiveBNpcByLayoutId( pBNpcFlagData->m_layoutId );
@ -674,7 +689,7 @@ namespace Sapphire::Encounter
case TimepointDataType::Snapshot:
{
auto pSnapshotData = std::dynamic_pointer_cast< TimepointDataSnapshot, TimepointData >( m_pData );
auto pBNpc = self.getBNpcByRef( pSnapshotData->m_actorRef, pTeri );
auto pBNpc = pack.getBNpcByRef( pSnapshotData->m_actorRef, pTeri );
if( pBNpc )
{

View file

@ -30,8 +30,8 @@ namespace Sapphire::Encounter
AddStatusEffect,
RemoveStatusEffect,
SpawnBNpc,
SetBNpcFlags,
BNpcSpawn,
BNpcFlags,
SetEObjState,
SetBgm,
@ -195,7 +195,7 @@ namespace Sapphire::Encounter
// todo: hate type, source
TimepointDataSpawnBNpc( uint32_t layoutId, uint32_t flags, uint32_t type ) :
TimepointData( TimepointDataType::SpawnBNpc ),
TimepointData( TimepointDataType::BNpcSpawn ),
m_layoutId( layoutId ),
m_flags( flags ),
m_type( type )
@ -209,7 +209,7 @@ namespace Sapphire::Encounter
uint32_t m_flags{ 0 };
TimepointDataBNpcFlags( uint32_t layoutId, uint32_t flags ) :
TimepointData( TimepointDataType::SetBNpcFlags ),
TimepointData( TimepointDataType::BNpcFlags ),
m_layoutId( layoutId ),
m_flags( flags )
{