diff --git a/src/world/Encounter/EncounterFight.h b/src/world/Encounter/EncounterFight.h index d8bd421c..7a17cae0 100644 --- a/src/world/Encounter/EncounterFight.h +++ b/src/world/Encounter/EncounterFight.h @@ -7,6 +7,8 @@ namespace Sapphire { + using EncounterCallback = std::function< void( EncounterFightPtr, EncounterState ) >; + class EncounterState { public: @@ -19,6 +21,11 @@ namespace Sapphire StateStackPtr m_stateStack; std::shared_ptr< EncounterFight > m_pEncounter; uint64_t m_startTime{ 0 }; + uint64_t m_currTime{ 0 }; + + EncounterCallback m_onInitCb; + EncounterCallback m_onUpdateCb; + EncounterCallback m_onFinishCb; public: EncounterState( std::shared_ptr< EncounterFight > pEncounter ) : @@ -26,13 +33,51 @@ namespace Sapphire { }; - virtual ~EncounterState() = default; - bool shouldFinish() { return m_bShouldFinish; }; + bool shouldFinish() const { return m_bShouldFinish; }; - virtual void init() = 0; - virtual void update( uint64_t deltaTime ) = 0; + void setFinishFlag() { m_bShouldFinish = true; }; - virtual void finish() = 0; + uint64_t getStartTime() const { return m_startTime; }; + uint64_t getCurrTime() const { return m_currTime; }; + uint64_t getElapsedTime() const { return m_currTime - m_startTime; }; + + void init() + { + if( m_onInitCb ) + m_onInitCb( m_pEncounter, *this ); + } + + void update( uint64_t currTime ) + { + if( m_startTime == 0 ) + m_startTime = currTime; + + m_currTime = currTime; + + if( m_onUpdateCb ) + m_onUpdateCb( m_pEncounter, *this ); + } + + void finish() + { + if( m_onFinishCb ) + m_onFinishCb( m_pEncounter, *this ); + } + + void setOnInitCallback( EncounterCallback cb ) + { + m_onInitCb = cb; + } + + void setOnUpdateCallback( EncounterCallback cb ) + { + m_onUpdateCb = cb; + } + + void setOnFinishCallback( EncounterCallback cb ) + { + m_onFinishCb = cb; + } }; enum class EncounterFightStatus @@ -50,19 +95,44 @@ namespace Sapphire m_pInstance( pInstance ) { }; + virtual ~EncounterFight() = default; virtual void init() = 0; virtual void start() = 0; - virtual void update( uint64_t deltaTime ) = 0; + virtual void update( uint64_t currTime ) = 0; virtual void reset() = 0; - virtual void addState( EncounterState::EncounterStatePtr pState, bool initState = true ) = 0; - virtual void addBNpc( Entity::BNpcPtr pBNpc ) = 0; - virtual void removeBNpc( uint32_t layoutId ) = 0; - virtual Entity::BNpcPtr getBNpc( uint32_t layoutId ) = 0; + void addState( EncounterState::EncounterStatePtr pState, bool initState = true ) + { + m_stateStack->push( pState ); + if( initState ) + pState->init(); + } - virtual EncounterFightStatus getEncounterFightStatus() const = 0; + EncounterFightStatus getEncounterFightStatus() const + { + return m_status; + } + + void addBNpc( Entity::BNpcPtr pBNpc ) + { + m_bnpcs[ pBNpc->getLayoutId() ] = pBNpc; + } + + Entity::BNpcPtr getBNpc( uint32_t layoutId ) const + { + auto bnpc = m_bnpcs.find( layoutId ); + if( bnpc != std::end( m_bnpcs ) ) + return bnpc->second; + + return nullptr; + } + + void removeBNpc( uint32_t layoutId ) + { + m_bnpcs.erase( layoutId ); + } protected: uint64_t m_startTime{ 0 }; diff --git a/src/world/Encounter/InstanceContent/IfritNormal.h b/src/world/Encounter/InstanceContent/IfritNormal.h index d19e01cb..274b2020 100644 --- a/src/world/Encounter/InstanceContent/IfritNormal.h +++ b/src/world/Encounter/InstanceContent/IfritNormal.h @@ -2,98 +2,13 @@ namespace Sapphire { - class IfritNormalData - { - public: - static constexpr int IFRIT = 4126276; - static constexpr int HELLFIRE = 0; - }; - - class IfritStateTwo : public EncounterState - { - public: - IfritStateTwo( EncounterFightPtr pEncounter ) : EncounterState( pEncounter ) - { - } - - void init() override - { - Logger::info( "stage 2 init" ); - } - - void update( uint64_t deltaTime ) override - { - if( m_startTime == 0 ) - m_startTime = deltaTime; - - auto timeElapsedMs = deltaTime - m_startTime; - - auto pIfrit = m_pEncounter->getBNpc( IfritNormalData::IFRIT ); - - pIfrit->setRot( pIfrit->getRot() - .2f ); - pIfrit->sendPositionUpdate(); - - if( timeElapsedMs > 5000 ) - { - m_bShouldFinish = true; - } - } - - void finish() override - { - Logger::info( "stage 2 done, going back to stage 1" ); - } - }; - - - class IfritStateOne : public EncounterState - { - public: - IfritStateOne( EncounterFightPtr pEncounter ) : EncounterState( pEncounter ) - { - } - - void init() override - { - Logger::info( "stage 1 init" ); - } - - void update( uint64_t deltaTime ) override - { - if( m_startTime == 0 ) - m_startTime = deltaTime; - - auto timeElapsedMs = deltaTime - m_startTime; - - auto pIfrit = m_pEncounter->getBNpc( IfritNormalData::IFRIT ); - - pIfrit->setRot( pIfrit->getRot() + .2f ); - pIfrit->sendPositionUpdate(); - - if( timeElapsedMs > 10000 ) - { - m_bShouldFinish = true; - return; - } - - if( timeElapsedMs > 5000 ) - { - auto ifritTwoState = std::make_shared< IfritStateTwo >( m_pEncounter ); - m_pEncounter->addState( ifritTwoState ); - } - } - - void finish() override - { - Logger::info( "stage 1 finish - enrage" ); - - auto pIfrit = m_pEncounter->getBNpc( IfritNormalData::IFRIT ); - pIfrit->hateListGetHighest()->die(); - } - }; - class IfritEncounterFight : public EncounterFight { + private: + static constexpr int NPC_IFRIT = 4126276; + static constexpr int VAL_IFRIT_HP = 13884; + static constexpr int ACT_HELLFIRE = 0; + public: IfritEncounterFight( InstanceContentPtr pInstance ) : EncounterFight( pInstance ) { @@ -108,35 +23,97 @@ namespace Sapphire m_stateStack = std::make_shared< EncounterState::StateStack >(); // todo: i don't like this - auto boss = m_pInstance->createBNpcFromLayoutId( IfritNormalData::IFRIT, 13884, Common::BNpcType::Enemy ); + auto boss = m_pInstance->createBNpcFromLayoutId( NPC_IFRIT, VAL_IFRIT_HP, Common::BNpcType::Enemy ); addBNpc( boss ); - - //instance.sendForward(); - /* - auto ifritStateTwo = std::make_shared< IfritStateTwo >( m_stateStack ); - m_stateStack->push( ifritStateTwo );*/ - } - - void addState( EncounterState::EncounterStatePtr pState, bool initState = true ) override - { - m_stateStack->push( pState ); - if( initState ) - pState->init(); } void start() override { - auto ifritInitState = std::make_shared< IfritStateOne >( shared_from_this() ); + auto ifritInitState = makeIfritPhaseOneState(); + addState( ifritInitState ); m_status = EncounterFightStatus::ACTIVE; } + + void reset() override + { + if( auto boss = m_pInstance->getActiveBNpcByLayoutId( NPC_IFRIT ); boss ) + { + removeBNpc( NPC_IFRIT ); + m_pInstance->removeActor( boss ); + } + + init(); + } + + EncounterStatePtr makeIfritPhaseOneState() + { + auto ifritInitState = std::make_shared< EncounterState >( shared_from_this() ); + ifritInitState->setOnUpdateCallback( [ & ]( EncounterFightPtr pEncounter, EncounterState state ) + { + auto timeElapsedMs = state.getElapsedTime(); + + auto pIfrit = pEncounter->getBNpc( NPC_IFRIT ); + + pIfrit->setRot( pIfrit->getRot() + .2f ); + pIfrit->sendPositionUpdate(); + + // todo: use gambits+timelines for this + if( timeElapsedMs > 10000 ) + { + state.setFinishFlag(); + return; + } + + // todo: use gambits+timelines for this + if( timeElapsedMs > 5000 ) + { + auto ifritTwoState = makeIfritPhaseTwoState(); + pEncounter->addState( ifritTwoState ); + } + } + ); + + ifritInitState->setOnFinishCallback( [ & ]( EncounterFightPtr pEncounter, EncounterState state ) + { + Logger::info( "stage 1 finish - enrage" ); + + auto pIfrit = pEncounter->getBNpc( NPC_IFRIT ); + pIfrit->hateListGetHighest()->die(); + } + ); + + return ifritInitState; + } + + EncounterStatePtr makeIfritPhaseTwoState() + { + auto ifritTwoState = std::make_shared< EncounterState >( shared_from_this() ); + ifritTwoState->setOnUpdateCallback( [ & ]( EncounterFightPtr pEncounter, EncounterState state ) { + auto timeElapsedMs = state.getElapsedTime(); + + auto pIfrit = pEncounter->getBNpc( NPC_IFRIT ); + + pIfrit->setRot( pIfrit->getRot() - .2f ); + pIfrit->sendPositionUpdate(); + + // todo: use gambits+timelines for this + if( timeElapsedMs > 5000 ) + { + state.setFinishFlag(); + } + } ); + + return ifritTwoState; + } void update( uint64_t deltaTime ) override { // todo: better way to start fights here.. + // this probably doesn't need to be overriden either - auto ifrit = getBNpc( IfritNormalData::IFRIT ); + auto ifrit = getBNpc( NPC_IFRIT ); if( ifrit; ifrit->hateListGetHighestValue() != 0 && m_status == EncounterFightStatus::IDLE ) { @@ -161,42 +138,5 @@ namespace Sapphire m_stateStack->top()->update( deltaTime ); } } - - void reset() override - { - auto boss = m_pInstance->getActiveBNpcByLayoutId( IfritNormalData::IFRIT ); - if( boss ) - { - removeBNpc( IfritNormalData::IFRIT ); - m_pInstance->removeActor( boss ); - - } - - init(); - } - - EncounterFightStatus getEncounterFightStatus() const override - { - return m_status; - } - - void addBNpc( Entity::BNpcPtr pBNpc ) override - { - m_bnpcs[ pBNpc->getLayoutId() ] = pBNpc; - } - - Entity::BNpcPtr getBNpc( uint32_t layoutId ) override - { - auto bnpc = m_bnpcs.find( layoutId ); - if( bnpc != std::end( m_bnpcs ) ) - return bnpc->second; - - return nullptr; - } - - void removeBNpc( uint32_t layoutId ) override - { - m_bnpcs.erase( layoutId ); - } }; } diff --git a/src/world/ForwardsZone.h b/src/world/ForwardsZone.h index 7c30c238..f021b52e 100644 --- a/src/world/ForwardsZone.h +++ b/src/world/ForwardsZone.h @@ -30,6 +30,7 @@ TYPE_FORWARD( Land ); TYPE_FORWARD( Linkshell ); TYPE_FORWARD( FreeCompany ); TYPE_FORWARD( EncounterFight ); +TYPE_FORWARD( EncounterState ); namespace World {