mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-27 22:57:45 +00:00
Initial work on QuestBattle instances
This commit is contained in:
parent
5d865cef31
commit
1b86b87503
7 changed files with 596 additions and 4 deletions
|
@ -4835,9 +4835,9 @@ Sapphire::Data::Quest::Quest( uint32_t row_id, Sapphire::Data::ExdDataGenerated*
|
||||||
Sapphire::Data::QuestBattle::QuestBattle( uint32_t row_id, Sapphire::Data::ExdDataGenerated* exdData )
|
Sapphire::Data::QuestBattle::QuestBattle( uint32_t row_id, Sapphire::Data::ExdDataGenerated* exdData )
|
||||||
{
|
{
|
||||||
auto row = exdData->m_QuestBattleDat.get_row( row_id );
|
auto row = exdData->m_QuestBattleDat.get_row( row_id );
|
||||||
quest = exdData->getField< int32_t >( row, 0 );
|
|
||||||
timeLimit = exdData->getField< uint16_t >( row, 2 );
|
timeLimit = exdData->getField< uint16_t >( row, 2 );
|
||||||
levelSync = exdData->getField< uint16_t >( row, 3 );
|
quest = exdData->getField< int32_t >( row, 0 );
|
||||||
|
levelSync = exdData->getField< uint16_t >( row, 3 );
|
||||||
scriptInstruction.push_back( exdData->getField< std::string >( row, 4 ) );
|
scriptInstruction.push_back( exdData->getField< std::string >( row, 4 ) );
|
||||||
scriptInstruction.push_back( exdData->getField< std::string >( row, 5 ) );
|
scriptInstruction.push_back( exdData->getField< std::string >( row, 5 ) );
|
||||||
scriptInstruction.push_back( exdData->getField< std::string >( row, 6 ) );
|
scriptInstruction.push_back( exdData->getField< std::string >( row, 6 ) );
|
||||||
|
|
|
@ -290,11 +290,15 @@ void writeEobjEntry( std::ofstream& out, LGB_ENTRY* pObj )
|
||||||
void loadAllInstanceContentEntries()
|
void loadAllInstanceContentEntries()
|
||||||
{
|
{
|
||||||
auto& catInstance = eData->get_category( "ContentFinderCondition" );
|
auto& catInstance = eData->get_category( "ContentFinderCondition" );
|
||||||
|
auto& catQuest = eData->get_category( "Quest" );
|
||||||
|
auto& catQuestBattle = eData->get_category( "QuestBattle" );
|
||||||
auto& territoryTypeSheet = eData->get_category( "TerritoryType" );
|
auto& territoryTypeSheet = eData->get_category( "TerritoryType" );
|
||||||
auto& instanceContentSheet = eData->get_category( "InstanceContent" );
|
auto& instanceContentSheet = eData->get_category( "InstanceContent" );
|
||||||
|
|
||||||
auto exdInstance = static_cast< xiv::exd::Exd >( catInstance.get_data_ln( xiv::exd::Language::en ) );
|
auto exdInstance = static_cast< xiv::exd::Exd >( catInstance.get_data_ln( xiv::exd::Language::en ) );
|
||||||
auto instanceContentData = static_cast< xiv::exd::Exd >( instanceContentSheet.get_data_ln( xiv::exd::Language::en ) );
|
auto instanceContentData = static_cast< xiv::exd::Exd >( instanceContentSheet.get_data_ln( xiv::exd::Language::en ) );
|
||||||
|
auto questBattleData = static_cast< xiv::exd::Exd >( catQuestBattle.get_data_ln( xiv::exd::Language::none ) );
|
||||||
|
auto questDataData = static_cast< xiv::exd::Exd >( catQuest.get_data_ln( xiv::exd::Language::en ) );
|
||||||
|
|
||||||
if( zoneNameMap.size() == 0 )
|
if( zoneNameMap.size() == 0 )
|
||||||
{
|
{
|
||||||
|
@ -318,11 +322,14 @@ void loadAllInstanceContentEntries()
|
||||||
auto id = row.first;
|
auto id = row.first;
|
||||||
auto& fields = row.second;
|
auto& fields = row.second;
|
||||||
|
|
||||||
|
uint16_t teriId;
|
||||||
|
|
||||||
auto contentLinkType = std::get< uint8_t >( fields.at( 2 ) );
|
auto contentLinkType = std::get< uint8_t >( fields.at( 2 ) );
|
||||||
auto contentLink = std::get< uint16_t >( fields.at( 3 ) );
|
auto contentLink = std::get< uint16_t >( fields.at( 3 ) );
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
uint8_t type = 0;
|
uint8_t type = 0;
|
||||||
|
teriId = std::get< uint16_t >( fields.at( 1 ) );
|
||||||
|
|
||||||
if( contentLinkType == 1 )
|
if( contentLinkType == 1 )
|
||||||
{
|
{
|
||||||
|
@ -332,6 +339,23 @@ void loadAllInstanceContentEntries()
|
||||||
name = std::get< std::string >( row.at( 3 ) );
|
name = std::get< std::string >( row.at( 3 ) );
|
||||||
type = std::get< uint8_t >( row.at( 0 ) );
|
type = std::get< uint8_t >( row.at( 0 ) );
|
||||||
id = contentLink;
|
id = contentLink;
|
||||||
|
//std::cout << name << "\n";
|
||||||
|
}
|
||||||
|
else if( contentLinkType == 5 )
|
||||||
|
{
|
||||||
|
std::cout << contentLinkType << "\n";
|
||||||
|
// instancecontent
|
||||||
|
auto row = questBattleData.get_row( contentLink );
|
||||||
|
int32_t questId1 = std::get< int32_t >( row.at( 0 ) );
|
||||||
|
if( questId1 > 99999 )
|
||||||
|
continue;
|
||||||
|
auto row1 = questDataData.get_row( questId1 );
|
||||||
|
|
||||||
|
name = std::get< std::string >( row1.at( 0 ) );
|
||||||
|
std::cout << name << "\n";
|
||||||
|
|
||||||
|
type = 7;
|
||||||
|
id = contentLink;
|
||||||
}
|
}
|
||||||
// else if( contentLinkType == 2 )
|
// else if( contentLinkType == 2 )
|
||||||
// {
|
// {
|
||||||
|
@ -360,7 +384,7 @@ void loadAllInstanceContentEntries()
|
||||||
if( name.empty() )
|
if( name.empty() )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto teri = std::get< uint16_t >( fields.at( 1 ) );
|
auto teri = teriId;
|
||||||
auto i = 0;
|
auto i = 0;
|
||||||
while( ( i = name.find( ' ' ) ) != std::string::npos )
|
while( ( i = name.find( ' ' ) ) != std::string::npos )
|
||||||
name = name.replace( name.begin() + i, name.begin() + i + 1, { '_' } );
|
name = name.replace( name.begin() + i, name.begin() + i + 1, { '_' } );
|
||||||
|
@ -441,7 +465,14 @@ int main( int argc, char* argv[] )
|
||||||
if( !fs::exists( "instance.tmpl" ) )
|
if( !fs::exists( "instance.tmpl" ) )
|
||||||
throw std::runtime_error( "instance.tmpl is missing in working directory" );
|
throw std::runtime_error( "instance.tmpl is missing in working directory" );
|
||||||
|
|
||||||
initExd( gamePath );
|
try
|
||||||
|
{
|
||||||
|
initExd( gamePath );
|
||||||
|
}
|
||||||
|
catch( std::runtime_error error )
|
||||||
|
{
|
||||||
|
std::cout << error.what();
|
||||||
|
}
|
||||||
if( dumpInstances )
|
if( dumpInstances )
|
||||||
{
|
{
|
||||||
loadAllInstanceContentEntries();
|
loadAllInstanceContentEntries();
|
||||||
|
|
|
@ -29,7 +29,14 @@ namespace Sapphire::Event
|
||||||
GoldSaucer = 0x800A,
|
GoldSaucer = 0x800A,
|
||||||
DpsChallange = 0x800D,
|
DpsChallange = 0x800D,
|
||||||
Fate = 0x801A
|
Fate = 0x801A
|
||||||
|
};
|
||||||
|
|
||||||
|
enum DirectorState
|
||||||
|
{
|
||||||
|
Created,
|
||||||
|
DutyReset,
|
||||||
|
DutyInProgress,
|
||||||
|
DutyFinished
|
||||||
};
|
};
|
||||||
|
|
||||||
Director( DirectorType type, uint16_t contentId );
|
Director( DirectorType type, uint16_t contentId );
|
||||||
|
|
|
@ -23,6 +23,7 @@ TYPE_FORWARD( Zone );
|
||||||
TYPE_FORWARD( HousingZone );
|
TYPE_FORWARD( HousingZone );
|
||||||
TYPE_FORWARD( House );
|
TYPE_FORWARD( House );
|
||||||
TYPE_FORWARD( InstanceContent );
|
TYPE_FORWARD( InstanceContent );
|
||||||
|
TYPE_FORWARD( QuestBattle );
|
||||||
TYPE_FORWARD( Item );
|
TYPE_FORWARD( Item );
|
||||||
TYPE_FORWARD( ItemContainer );
|
TYPE_FORWARD( ItemContainer );
|
||||||
TYPE_FORWARD( ZonePosition );
|
TYPE_FORWARD( ZonePosition );
|
||||||
|
|
|
@ -231,6 +231,22 @@ namespace Sapphire::ScriptAPI
|
||||||
uint16_t param1, uint16_t param2 );
|
uint16_t param1, uint16_t param2 );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief The base class for any scripts that implement behaviour related to instance content zones
|
||||||
|
*/
|
||||||
|
class QuestBattleScript : public ScriptObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit QuestBattleScript( uint32_t questBattleId );
|
||||||
|
|
||||||
|
virtual void onInit( Sapphire::QuestBattle& instance );
|
||||||
|
|
||||||
|
virtual void onUpdate( Sapphire::QuestBattle& instance, uint32_t currTime );
|
||||||
|
|
||||||
|
virtual void onEnterTerritory( Sapphire::QuestBattle& instance, Sapphire::Entity::Player& player, uint32_t eventId,
|
||||||
|
uint16_t param1, uint16_t param2 );
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
429
src/world/Territory/QuestBattle.cpp
Normal file
429
src/world/Territory/QuestBattle.cpp
Normal file
|
@ -0,0 +1,429 @@
|
||||||
|
|
||||||
|
#include <Common.h>
|
||||||
|
#include <Logging/Logger.h>
|
||||||
|
#include <Util/Util.h>
|
||||||
|
#include <Util/UtilMath.h>
|
||||||
|
#include <Exd/ExdDataGenerated.h>
|
||||||
|
#include <Network/CommonActorControl.h>
|
||||||
|
|
||||||
|
#include "Event/Director.h"
|
||||||
|
#include "Event/EventDefs.h"
|
||||||
|
#include "Script/ScriptMgr.h"
|
||||||
|
|
||||||
|
#include "Actor/Player.h"
|
||||||
|
#include "Actor/EventObject.h"
|
||||||
|
|
||||||
|
#include "Network/PacketWrappers/ActorControlPacket142.h"
|
||||||
|
#include "Network/PacketWrappers/ActorControlPacket143.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "Event/EventHandler.h"
|
||||||
|
|
||||||
|
#include "QuestBattle.h"
|
||||||
|
#include "Framework.h"
|
||||||
|
|
||||||
|
using namespace Sapphire::Common;
|
||||||
|
using namespace Sapphire::Network::Packets;
|
||||||
|
using namespace Sapphire::Network::Packets::Server;
|
||||||
|
using namespace Sapphire::Network::ActorControl;
|
||||||
|
|
||||||
|
Sapphire::QuestBattle::QuestBattle( std::shared_ptr< Sapphire::Data::QuestBattle > pBattleDetails,
|
||||||
|
uint16_t territoryType,
|
||||||
|
uint32_t guId,
|
||||||
|
const std::string& internalName,
|
||||||
|
const std::string& contentName,
|
||||||
|
uint32_t questBattleId,
|
||||||
|
FrameworkPtr pFw ) :
|
||||||
|
Zone( static_cast< uint16_t >( territoryType ), guId, internalName, contentName, pFw ),
|
||||||
|
Director( Event::Director::QuestBattle, questBattleId ),
|
||||||
|
m_pBattleDetails( pBattleDetails ),
|
||||||
|
m_questBattleId( questBattleId ),
|
||||||
|
m_state( Created ),
|
||||||
|
m_instanceCommenceTime( 0 )
|
||||||
|
// m_currentBgm( pInstanceConfiguration->bGM )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sapphire::QuestBattle::init()
|
||||||
|
{
|
||||||
|
auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >();
|
||||||
|
pScriptMgr->onInstanceInit( getAsInstanceContent() );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Sapphire::QuestBattle::~QuestBattle()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Sapphire::QuestBattle::getQuestBattleId() const
|
||||||
|
{
|
||||||
|
return m_questBattleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sapphire::Data::ExdDataGenerated::QuestBattlePtr Sapphire::QuestBattle::getQuestBattleDetails() const
|
||||||
|
{
|
||||||
|
return m_pBattleDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::QuestBattle::onPlayerZoneIn( Entity::Player& player )
|
||||||
|
{
|
||||||
|
Logger::debug( "QuestBattle::onPlayerZoneIn: Zone#{0}|{1}, Entity#{2}",
|
||||||
|
getGuId(), getTerritoryTypeId(), player.getId() );
|
||||||
|
|
||||||
|
// mark player as "bound by duty"
|
||||||
|
player.setStateFlag( PlayerStateFlag::BoundByDuty );
|
||||||
|
|
||||||
|
// if the instance was not started yet, director init is sent on enter event.
|
||||||
|
// else it will be sent on finish loading.
|
||||||
|
if( m_state == Created )
|
||||||
|
sendDirectorInit( player );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::QuestBattle::onLeaveTerritory( Entity::Player& player )
|
||||||
|
{
|
||||||
|
Logger::debug( "QuestBattle::onLeaveTerritory: Zone#{0}|{1}, Entity#{2}",
|
||||||
|
getGuId(), getTerritoryTypeId(), player.getId() );
|
||||||
|
|
||||||
|
clearDirector( player );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::QuestBattle::onUpdate( uint32_t currTime )
|
||||||
|
{
|
||||||
|
switch( m_state )
|
||||||
|
{
|
||||||
|
case Created:
|
||||||
|
{
|
||||||
|
if( m_boundPlayerIds.size() == 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
for( auto playerId : m_boundPlayerIds )
|
||||||
|
{
|
||||||
|
auto it = m_playerMap.find( playerId );
|
||||||
|
if( it == m_playerMap.end() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto player = it->second;
|
||||||
|
if( !player->isLoadingComplete() ||
|
||||||
|
!player->isDirectorInitialized() ||
|
||||||
|
!player->isOnEnterEventDone() ||
|
||||||
|
player->hasStateFlag( PlayerStateFlag::WatchingCutscene ) )
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_instanceCommenceTime == 0 )
|
||||||
|
{
|
||||||
|
m_instanceCommenceTime = Util::getTimeMs() + instanceStartDelay;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if( Util::getTimeMs() < m_instanceCommenceTime )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// TODO: we do not have a list of players for questbattles... just one
|
||||||
|
for( const auto& playerIt : m_playerMap )
|
||||||
|
{
|
||||||
|
auto pPlayer = playerIt.second;
|
||||||
|
pPlayer->queuePacket( makeActorControl143( pPlayer->getId(), DirectorUpdate,
|
||||||
|
getDirectorId(), 0x40000001,
|
||||||
|
m_pBattleDetails->timeLimit * 60u ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_state = DutyInProgress;
|
||||||
|
m_instanceExpireTime = Util::getTimeSeconds() + ( m_pBattleDetails->timeLimit * 60u );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
case DutyReset:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DutyInProgress:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
case DutyFinished:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >();
|
||||||
|
pScriptMgr->onInstanceUpdate( getAsInstanceContent(), currTime );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::QuestBattle::onFinishLoading( Entity::Player& player )
|
||||||
|
{
|
||||||
|
sendDirectorInit( player );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::QuestBattle::onInitDirector( Entity::Player& player )
|
||||||
|
{
|
||||||
|
sendDirectorVars( player );
|
||||||
|
player.setDirectorInitialized( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::QuestBattle::onDirectorSync( Entity::Player& player )
|
||||||
|
{
|
||||||
|
player.queuePacket( makeActorControl143( player.getId(), DirectorUpdate, 0x00110001, 0x80000000, 1 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::QuestBattle::setVar( uint8_t index, uint8_t value )
|
||||||
|
{
|
||||||
|
if( index > 19 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch( index )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
setDirectorUI8AL( value );
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
setDirectorUI8AH( value );
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
setDirectorUI8BL( value );
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
setDirectorUI8BH( value );
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
setDirectorUI8CL( value );
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
setDirectorUI8CH( value );
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
setDirectorUI8DL( value );
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
setDirectorUI8DH( value );
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
setDirectorUI8EL( value );
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
setDirectorUI8EH( value );
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
setDirectorUI8FL( value );
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
setDirectorUI8FH( value );
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
setDirectorUI8GL( value );
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
setDirectorUI8GH( value );
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
setDirectorUI8HL( value );
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
setDirectorUI8HH( value );
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
setDirectorUI8IL( value );
|
||||||
|
break;
|
||||||
|
case 17:
|
||||||
|
setDirectorUI8IH( value );
|
||||||
|
break;
|
||||||
|
case 18:
|
||||||
|
setDirectorUI8JL( value );
|
||||||
|
break;
|
||||||
|
case 19:
|
||||||
|
setDirectorUI8JH( value );
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: genericise this?
|
||||||
|
for( const auto& playerIt : m_playerMap )
|
||||||
|
{
|
||||||
|
sendDirectorVars( *playerIt.second );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::QuestBattle::setSequence( uint8_t value )
|
||||||
|
{
|
||||||
|
setDirectorSequence( value );
|
||||||
|
|
||||||
|
for( const auto& playerIt : m_playerMap )
|
||||||
|
{
|
||||||
|
sendDirectorVars( *playerIt.second );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::QuestBattle::setBranch( uint8_t value )
|
||||||
|
{
|
||||||
|
setDirectorBranch( value );
|
||||||
|
|
||||||
|
for( const auto& playerIt : m_playerMap )
|
||||||
|
{
|
||||||
|
sendDirectorVars( *playerIt.second );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::QuestBattle::startQte()
|
||||||
|
{
|
||||||
|
for( const auto& playerIt : m_playerMap )
|
||||||
|
{
|
||||||
|
auto player = playerIt.second;
|
||||||
|
player->queuePacket( makeActorControl143( player->getId(), DirectorUpdate, getDirectorId(), 0x8000000A ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::QuestBattle::startEventCutscene()
|
||||||
|
{
|
||||||
|
// TODO: lock player movement
|
||||||
|
for( const auto& playerIt : m_playerMap )
|
||||||
|
{
|
||||||
|
auto player = playerIt.second;
|
||||||
|
player->queuePacket( makeActorControl143( player->getId(), DirectorUpdate, getDirectorId(), 0x80000008 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::QuestBattle::endEventCutscene()
|
||||||
|
{
|
||||||
|
for( const auto& playerIt : m_playerMap )
|
||||||
|
{
|
||||||
|
auto player = playerIt.second;
|
||||||
|
player->queuePacket( makeActorControl143( player->getId(), DirectorUpdate, getDirectorId(), 0x80000009 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::QuestBattle::onRegisterEObj( Entity::EventObjectPtr object )
|
||||||
|
{
|
||||||
|
if( object->getName() != "none" )
|
||||||
|
m_eventObjectMap[ object->getName() ] = object;
|
||||||
|
|
||||||
|
auto pExdData = m_pFw->get< Data::ExdDataGenerated >();
|
||||||
|
auto objData = pExdData->get< Sapphire::Data::EObj >( object->getObjectId() );
|
||||||
|
if( objData )
|
||||||
|
// todo: data should be renamed to eventId
|
||||||
|
m_eventIdToObjectMap[ objData->data ] = object;
|
||||||
|
else
|
||||||
|
Logger::error( "InstanceContent::onRegisterEObj Zone " +
|
||||||
|
m_internalName + ": No EObj data found for EObj with ID: " +
|
||||||
|
std::to_string( object->getObjectId() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
Sapphire::Event::Director::DirectorState Sapphire::QuestBattle::getState() const
|
||||||
|
{
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::QuestBattle::onBeforePlayerZoneIn( Sapphire::Entity::Player& player )
|
||||||
|
{
|
||||||
|
// remove any players from the instance who aren't bound on zone in
|
||||||
|
if( !isPlayerBound( player.getId() ) )
|
||||||
|
player.exitInstance();
|
||||||
|
|
||||||
|
// TODO: let script set start position??
|
||||||
|
player.setRot( PI );
|
||||||
|
player.setPos( { 0.f, 0.f, 0.f } );
|
||||||
|
|
||||||
|
|
||||||
|
player.resetObjSpawnIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
Sapphire::Entity::EventObjectPtr Sapphire::QuestBattle::getEObjByName( const std::string& name )
|
||||||
|
{
|
||||||
|
auto it = m_eventObjectMap.find( name );
|
||||||
|
if( it == m_eventObjectMap.end() )
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::QuestBattle::onTalk( Sapphire::Entity::Player& player, uint32_t eventId, uint64_t actorId )
|
||||||
|
{
|
||||||
|
// todo: handle exit (and maybe shortcut?) behaviour here
|
||||||
|
|
||||||
|
auto it = m_eventIdToObjectMap.find( eventId );
|
||||||
|
if( it == m_eventIdToObjectMap.end() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( auto onTalk = it->second->getOnTalkHandler() )
|
||||||
|
onTalk( player, it->second, getAsInstanceContent(), actorId );
|
||||||
|
else
|
||||||
|
player.sendDebug( "No onTalk handler found for interactable eobj with EObjID#{0}, eventId#{1} ",
|
||||||
|
it->second->getObjectId(), eventId );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Sapphire::QuestBattle::onEnterTerritory( Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 )
|
||||||
|
{
|
||||||
|
auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >();
|
||||||
|
pScriptMgr->onInstanceEnterTerritory( getAsInstanceContent(), player, eventId, param1, param2 );
|
||||||
|
|
||||||
|
// TODO: this may or may not be correct for questbattles
|
||||||
|
player.directorPlayScene( getDirectorId(), 1, NO_DEFAULT_CAMERA | CONDITION_CUTSCENE | SILENT_ENTER_TERRI_ENV |
|
||||||
|
HIDE_HOTBAR | SILENT_ENTER_TERRI_BGM | SILENT_ENTER_TERRI_SE |
|
||||||
|
DISABLE_STEALTH | 0x00100000 | LOCK_HUD | LOCK_HOTBAR |
|
||||||
|
// todo: wtf is 0x00100000
|
||||||
|
DISABLE_CANCEL_EMOTE, 0, 0x9, getCurrentBGM() );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::QuestBattle::setCurrentBGM( uint16_t bgmIndex )
|
||||||
|
{
|
||||||
|
m_currentBgm = bgmIndex;
|
||||||
|
|
||||||
|
for( const auto& playerIt : m_playerMap )
|
||||||
|
{
|
||||||
|
auto player = playerIt.second;
|
||||||
|
// note: retail do send a BGM_MUTE(1) first before any BGM transition, but YOLO in this case.
|
||||||
|
// also do note that this code can't control the bgm granularly. (i.e. per player for WoD submap.) oops.
|
||||||
|
// player->queuePacket( ActorControlPacket143( player->getId(), DirectorUpdate, getDirectorId(), 0x80000001, 1 ) );
|
||||||
|
player->queuePacket(
|
||||||
|
makeActorControl143( player->getId(), DirectorUpdate, getDirectorId(), 0x80000001, bgmIndex ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::QuestBattle::setPlayerBGM( Sapphire::Entity::Player& player, uint16_t bgmId )
|
||||||
|
{
|
||||||
|
player.queuePacket( makeActorControl143( player.getId(), DirectorUpdate, getDirectorId(), 0x80000001, bgmId ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Sapphire::QuestBattle::getCurrentBGM() const
|
||||||
|
{
|
||||||
|
return m_currentBgm;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sapphire::QuestBattle::bindPlayer( uint32_t playerId )
|
||||||
|
{
|
||||||
|
// if player already bound, return false
|
||||||
|
if( m_boundPlayerIds.count( playerId ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_boundPlayerIds.insert( playerId );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sapphire::QuestBattle::isPlayerBound( uint32_t playerId ) const
|
||||||
|
{
|
||||||
|
return m_boundPlayerIds.count( playerId ) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::QuestBattle::unbindPlayer( uint32_t playerId )
|
||||||
|
{
|
||||||
|
m_boundPlayerIds.erase( playerId );
|
||||||
|
|
||||||
|
auto it = m_playerMap.find( playerId );
|
||||||
|
if( it != m_playerMap.end() )
|
||||||
|
it->second->exitInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sapphire::QuestBattle::clearDirector( Entity::Player& player )
|
||||||
|
{
|
||||||
|
sendDirectorClear( player );
|
||||||
|
|
||||||
|
player.setDirectorInitialized( false );
|
||||||
|
// remove "bound by duty" state
|
||||||
|
player.unsetStateFlag( PlayerStateFlag::BoundByDuty );
|
||||||
|
}
|
108
src/world/Territory/QuestBattle.h
Normal file
108
src/world/Territory/QuestBattle.h
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
#ifndef SAPPHIRE_QUESTBATTLE_H
|
||||||
|
#define SAPPHIRE_QUESTBATTLE_H
|
||||||
|
|
||||||
|
#include "Zone.h"
|
||||||
|
#include "Event/Director.h"
|
||||||
|
#include "Forwards.h"
|
||||||
|
|
||||||
|
namespace Sapphire {
|
||||||
|
namespace Data {
|
||||||
|
struct QuestBattle;
|
||||||
|
}
|
||||||
|
class QuestBattle : public Event::Director, public Zone
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QuestBattle( std::shared_ptr< Sapphire::Data::QuestBattle > pBattleDetails,
|
||||||
|
uint16_t territoryType,
|
||||||
|
uint32_t guId,
|
||||||
|
const std::string& internalName,
|
||||||
|
const std::string& contentName,
|
||||||
|
uint32_t questBattleId,
|
||||||
|
FrameworkPtr pFw );
|
||||||
|
|
||||||
|
virtual ~QuestBattle();
|
||||||
|
|
||||||
|
bool init() override;
|
||||||
|
|
||||||
|
void onBeforePlayerZoneIn( Entity::Player& player ) override;
|
||||||
|
|
||||||
|
void onPlayerZoneIn( Entity::Player& player ) override;
|
||||||
|
|
||||||
|
void onLeaveTerritory( Entity::Player& player ) override;
|
||||||
|
|
||||||
|
void onFinishLoading( Entity::Player& player ) override;
|
||||||
|
|
||||||
|
void onInitDirector( Entity::Player& player ) override;
|
||||||
|
|
||||||
|
void onDirectorSync( Entity::Player& player ) override;
|
||||||
|
|
||||||
|
void onUpdate( uint32_t currTime ) override;
|
||||||
|
|
||||||
|
void onTalk( Entity::Player& player, uint32_t eventId, uint64_t actorId );
|
||||||
|
|
||||||
|
void onEnterTerritory( Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 ) override;
|
||||||
|
|
||||||
|
void onRegisterEObj( Entity::EventObjectPtr object ) override;
|
||||||
|
|
||||||
|
void setVar( uint8_t index, uint8_t value );
|
||||||
|
|
||||||
|
void setSequence( uint8_t value );
|
||||||
|
|
||||||
|
void setBranch( uint8_t value );
|
||||||
|
|
||||||
|
void startQte();
|
||||||
|
|
||||||
|
void startEventCutscene();
|
||||||
|
|
||||||
|
void endEventCutscene();
|
||||||
|
|
||||||
|
void clearDirector( Entity::Player& player );
|
||||||
|
|
||||||
|
/*! set the current bgm index (inside bgm.exd) */
|
||||||
|
void setCurrentBGM( uint16_t bgmId );
|
||||||
|
|
||||||
|
/*! set the current bgm for a specific player */
|
||||||
|
void setPlayerBGM( Entity::Player& player, uint16_t bgmId );
|
||||||
|
|
||||||
|
/*! get the currently playing bgm index */
|
||||||
|
uint16_t getCurrentBGM() const;
|
||||||
|
|
||||||
|
Event::Director::DirectorState getState() const;
|
||||||
|
|
||||||
|
std::shared_ptr< Sapphire::Data::QuestBattle > getQuestBattleDetails() const;
|
||||||
|
|
||||||
|
uint32_t getQuestBattleId() const;
|
||||||
|
|
||||||
|
Entity::EventObjectPtr getEObjByName( const std::string& name );
|
||||||
|
|
||||||
|
/*! binds a player to the instance */
|
||||||
|
bool bindPlayer( uint32_t playerId );
|
||||||
|
|
||||||
|
/*! removes bind of player from the instance */
|
||||||
|
void unbindPlayer( uint32_t playerId );
|
||||||
|
|
||||||
|
/*! return true if the player is bound to the instance */
|
||||||
|
bool isPlayerBound( uint32_t playerId ) const;
|
||||||
|
|
||||||
|
/*! number of milliseconds after all players are ready for the instance to commence (spawn circle removed) */
|
||||||
|
const uint32_t instanceStartDelay = 1250;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr< Sapphire::Data::QuestBattle > m_pBattleDetails;
|
||||||
|
uint32_t m_questBattleId;
|
||||||
|
Event::Director::DirectorState m_state;
|
||||||
|
uint16_t m_currentBgm;
|
||||||
|
|
||||||
|
int64_t m_instanceExpireTime;
|
||||||
|
uint64_t m_instanceCommenceTime;
|
||||||
|
|
||||||
|
std::map< std::string, Entity::EventObjectPtr > m_eventObjectMap;
|
||||||
|
std::unordered_map< uint32_t, Entity::EventObjectPtr > m_eventIdToObjectMap;
|
||||||
|
std::set< uint32_t > m_spawnedPlayers;
|
||||||
|
|
||||||
|
// the players which are bound to the instance, regardless of inside or offline
|
||||||
|
std::set< uint32_t > m_boundPlayerIds;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
Loading…
Add table
Reference in a new issue