2024-06-21 00:27:41 +01:00
|
|
|
#include "TimelineActor.h"
|
|
|
|
|
|
|
|
#include "EncounterTimeline.h"
|
|
|
|
|
|
|
|
#include <Actor/BNpc.h>
|
2024-06-22 06:12:41 +01:00
|
|
|
#include <Action/Action.h>
|
2024-06-21 00:27:41 +01:00
|
|
|
|
2024-06-24 18:41:18 +01:00
|
|
|
#include <Manager/PlayerMgr.h>
|
|
|
|
#include <Service.h>
|
|
|
|
|
2024-06-23 22:44:51 +01:00
|
|
|
#include <Territory/Territory.h>
|
|
|
|
|
2024-06-21 00:27:41 +01:00
|
|
|
namespace Sapphire::Encounter
|
|
|
|
{
|
2024-06-24 22:45:06 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-06-21 00:27:41 +01:00
|
|
|
void TimelineActor::addPhaseCondition( PhaseConditionPtr pCondition )
|
|
|
|
{
|
|
|
|
m_phaseConditions.emplace( std::make_pair( pCondition->getId(), pCondition ) );
|
|
|
|
m_conditionStates[ pCondition->getId() ] = {};
|
|
|
|
m_conditionStates[ pCondition->getId() ].m_enabled = pCondition->isDefaultEnabled();
|
|
|
|
}
|
|
|
|
|
|
|
|
// todo: make this sane
|
|
|
|
|
|
|
|
void TimelineActor::update( TerritoryPtr pTeri, TimelinePack& pack, uint64_t time )
|
|
|
|
{
|
|
|
|
// todo: handle interrupts
|
|
|
|
for( const auto& condition : m_phaseConditions )
|
|
|
|
{
|
|
|
|
const auto& pCondition = condition.second;
|
|
|
|
auto& state = m_conditionStates[ pCondition->getId() ];
|
|
|
|
|
|
|
|
// ignore if not enabled, unless overriden to enable
|
|
|
|
if( !pCondition->isStateEnabled( state ) )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if( pCondition->completed( state ) )
|
|
|
|
{
|
|
|
|
if( pCondition->isLoopable() )
|
|
|
|
{
|
|
|
|
if( pCondition->loopReady( state, time ) )
|
|
|
|
pCondition->reset( state );
|
|
|
|
}
|
|
|
|
}
|
2024-06-23 01:30:07 +01:00
|
|
|
// update or execute
|
2024-06-21 19:46:14 +01:00
|
|
|
else if( pCondition->isConditionMet( state, pack, pTeri, time ) )
|
2024-06-21 00:27:41 +01:00
|
|
|
{
|
2024-06-23 01:30:07 +01:00
|
|
|
if( pCondition->inProgress( state ) )
|
|
|
|
{
|
|
|
|
pCondition->update( state, *this, pack, pTeri, time );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pCondition->execute( state, *this, pack, pTeri, time );
|
2024-06-21 00:27:41 +01:00
|
|
|
|
2024-06-23 01:30:07 +01:00
|
|
|
if( pack.getStartTime() == 0 )
|
|
|
|
pack.setStartTime( state.m_startTime );
|
|
|
|
}
|
2024-06-21 00:27:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-24 22:45:06 +01:00
|
|
|
bool TimelineActor::resetConditionState( uint32_t conditionId, bool toDefault )
|
2024-06-21 00:27:41 +01:00
|
|
|
{
|
|
|
|
if( auto it = m_phaseConditions.find( conditionId ); it != m_phaseConditions.end() )
|
|
|
|
{
|
|
|
|
auto& state = m_conditionStates.at( it->first );
|
2024-06-24 22:45:06 +01:00
|
|
|
it->second->reset( state, toDefault );
|
|
|
|
return true;
|
2024-06-21 00:27:41 +01:00
|
|
|
}
|
2024-06-24 22:45:06 +01:00
|
|
|
return false;
|
2024-06-21 00:27:41 +01:00
|
|
|
}
|
|
|
|
|
2024-06-24 22:45:06 +01:00
|
|
|
bool TimelineActor::setConditionStateEnabled( uint32_t conditionId, bool enabled )
|
2024-06-21 00:27:41 +01:00
|
|
|
{
|
|
|
|
if( auto it = m_conditionStates.find( conditionId ); it != m_conditionStates.end() )
|
|
|
|
{
|
|
|
|
auto& state = m_conditionStates.at( it->first );
|
|
|
|
state.m_enabled = enabled;
|
2024-06-24 22:45:06 +01:00
|
|
|
return true;
|
2024-06-21 00:27:41 +01:00
|
|
|
}
|
2024-06-24 22:45:06 +01:00
|
|
|
return false;
|
2024-06-21 00:27:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TimelineActor::resetAllConditionStates()
|
|
|
|
{
|
|
|
|
for( const auto& condition : m_phaseConditions )
|
|
|
|
{
|
|
|
|
const auto& pCondition = condition.second;
|
|
|
|
auto& state = m_conditionStates.at( condition.first );
|
|
|
|
|
2024-06-23 22:44:51 +01:00
|
|
|
pCondition->reset( state, true );
|
2024-06-21 00:27:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TimelineActor::spawnAllSubActors( TerritoryPtr pTeri )
|
|
|
|
{
|
|
|
|
std::vector< std::string > toSpawn;
|
|
|
|
for( const auto& subActor : m_subActors )
|
|
|
|
if( getSubActor( subActor.first ) == nullptr )
|
|
|
|
toSpawn.push_back( subActor.first );
|
|
|
|
|
|
|
|
for( const auto& name : toSpawn )
|
|
|
|
spawnSubActor( name, pTeri );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TimelineActor::addPlaceholderSubactor( const std::string& name )
|
|
|
|
{
|
|
|
|
// populate m_subActors with nullptr BNpcs
|
|
|
|
// then spawn them all in first timepoint and ref them by name subsequently
|
|
|
|
if( getSubActor( name ) == nullptr )
|
|
|
|
m_subActors.emplace( std::make_pair( name, nullptr ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
Entity::BNpcPtr TimelineActor::getBNpcByRef( const std::string& name, TerritoryPtr pTeri ) const
|
|
|
|
{
|
|
|
|
if( name == m_name )
|
|
|
|
return pTeri->getActiveBNpcByLayoutId( m_layoutId );
|
|
|
|
return getSubActor( name );
|
|
|
|
}
|
|
|
|
|
|
|
|
void TimelineActor::resetAllSubActors( TerritoryPtr pTeri )
|
|
|
|
{
|
|
|
|
for( auto& subActor : m_subActors )
|
|
|
|
{
|
|
|
|
if( subActor.second )
|
|
|
|
{
|
|
|
|
auto inRange = subActor.second->getInRangeActors();
|
|
|
|
for( const auto& pActor : inRange )
|
|
|
|
{
|
|
|
|
if( auto pPlayer = pActor->getAsPlayer() )
|
|
|
|
subActor.second->despawn( pPlayer );
|
|
|
|
}
|
2024-06-22 06:12:41 +01:00
|
|
|
// todo: need to reset the ai on interrupt
|
|
|
|
auto pAction = subActor.second->getCurrentAction();
|
|
|
|
if( pAction )
|
|
|
|
pAction->interrupt();
|
|
|
|
|
2024-06-21 00:27:41 +01:00
|
|
|
pTeri->removeActor( subActor.second );
|
|
|
|
subActor.second = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Entity::BNpcPtr TimelineActor::spawnSubActor( const std::string& name, TerritoryPtr pTeri )
|
|
|
|
{
|
|
|
|
// 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 |
|
2024-06-24 18:41:18 +01:00
|
|
|
Entity::BNpcFlag::TurningDisabled | Entity::BNpcFlag::NoDeaggro;
|
2024-06-21 00:27:41 +01:00
|
|
|
|
|
|
|
auto pActor = getSubActor( name );
|
|
|
|
if( pActor == nullptr )
|
|
|
|
{
|
|
|
|
auto pParent = pTeri->getActiveBNpcByLayoutId( m_layoutId );
|
2024-06-24 22:45:06 +01:00
|
|
|
Common::BNpcType type = pParent ? pParent->getBNpcType() : Common::BNpcType::Enemy;
|
|
|
|
|
|
|
|
pActor = pTeri->createBNpcFromLayoutId( m_layoutId, 1000, type );
|
2024-06-21 00:27:41 +01:00
|
|
|
m_subActors[ name ] = pActor;
|
|
|
|
|
|
|
|
pActor->setInvincibilityType( Common::InvincibilityIgnoreDamage );
|
|
|
|
pActor->setFlag( flags );
|
|
|
|
pActor->init();
|
|
|
|
|
|
|
|
pTeri->pushActor( pActor );
|
2024-06-23 22:44:51 +01:00
|
|
|
|
2024-06-24 18:41:18 +01:00
|
|
|
auto& playerMgr = Common::Service< World::Manager::PlayerMgr >::ref();
|
2024-06-23 22:44:51 +01:00
|
|
|
for( const auto& player : pTeri->getPlayers() )
|
2024-06-24 18:41:18 +01:00
|
|
|
{
|
2024-06-23 22:44:51 +01:00
|
|
|
pActor->spawn( player.second );
|
2024-06-24 18:41:18 +01:00
|
|
|
playerMgr.sendDebug( *player.second, fmt::format( "Spawned subactor {}", name ) );
|
|
|
|
}
|
2024-06-21 00:27:41 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return pActor;
|
|
|
|
}
|
|
|
|
|
|
|
|
Entity::BNpcPtr TimelineActor::getSubActor( const std::string& name ) const
|
|
|
|
{
|
|
|
|
if( auto it = m_subActors.find( name ); it != m_subActors.end() )
|
|
|
|
return it->second;
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TimelineActor::resetSubActors( TerritoryPtr pTeri )
|
|
|
|
{
|
|
|
|
for( auto& subActor : m_subActors )
|
|
|
|
{
|
|
|
|
if( subActor.second )
|
|
|
|
{
|
2024-06-23 22:44:51 +01:00
|
|
|
auto& pBNpc = subActor.second;
|
2024-06-21 00:27:41 +01:00
|
|
|
pTeri->removeActor( pBNpc );
|
|
|
|
// todo: despawn?
|
|
|
|
subActor.second = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|