1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-24 13:47:46 +00:00
sapphire/src/servers/sapphire_zone/Zone/InstanceContent.cpp

453 lines
13 KiB
C++
Raw Normal View History

2018-03-06 22:22:19 +01:00
#include <Common.h>
#include <Logging/Logger.h>
#include <Util/Util.h>
#include <Util/UtilMath.h>
#include <Exd/ExdDataGenerated.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 "InstanceContent.h"
#include "Framework.h"
extern Core::Framework g_fw;
using namespace Core::Common;
using namespace Core::Network::Packets;
using namespace Core::Network::Packets::Server;
2018-03-17 01:25:44 +11:00
Core::InstanceContent::InstanceContent( boost::shared_ptr< Core::Data::InstanceContent > pInstanceConfiguration,
uint32_t guId,
const std::string& internalName,
2018-01-29 19:41:41 +01:00
const std::string& contentName,
uint32_t instanceContentId )
2018-03-17 01:25:44 +11:00
: Zone( static_cast< uint16_t >( pInstanceConfiguration->territoryType ), guId, internalName, contentName ),
Director( Event::Director::InstanceContent, instanceContentId ),
2018-03-17 01:25:44 +11:00
m_instanceConfiguration( pInstanceConfiguration ),
2018-01-29 19:41:41 +01:00
m_instanceContentId( instanceContentId ),
m_state( Created ),
2018-03-06 13:33:10 +11:00
m_pEntranceEObj( nullptr ),
2018-03-15 20:48:35 +11:00
m_instanceCommenceTime( 0 ),
2018-03-17 01:25:44 +11:00
m_currentBgm( pInstanceConfiguration->bGM )
{
}
bool Core::InstanceContent::init()
{
auto pScriptMgr = g_fw.get< Scripting::ScriptMgr >();
pScriptMgr->onInstanceInit( getAsInstanceContent() );
return true;
}
Core::InstanceContent::~InstanceContent()
{
2018-01-29 19:41:41 +01:00
}
uint32_t Core::InstanceContent::getInstanceContentId() const
{
return m_instanceContentId;
}
Core::Data::ExdDataGenerated::InstanceContentPtr Core::InstanceContent::getInstanceConfiguration() const
2018-01-29 19:41:41 +01:00
{
return m_instanceConfiguration;
2018-01-29 19:41:41 +01:00
}
2018-03-05 14:34:34 +01:00
void Core::InstanceContent::onPlayerZoneIn( Entity::Player& player )
{
auto pLog = g_fw.get< Logger >();
pLog->debug( "InstanceContent::onPlayerZoneIn: Zone#" + std::to_string( getGuId() ) + "|"
+ std::to_string( getInstanceContentId() ) +
+ ", Entity#" + std::to_string( 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 Core::InstanceContent::onLeaveTerritory( Entity::Player& player )
{
auto pLog = g_fw.get< Logger >();
pLog->debug( "InstanceContent::onLeaveTerritory: Zone#" + std::to_string( getGuId() ) + "|"
+ std::to_string( getInstanceContentId() ) +
+ ", Entity#" + std::to_string( player.getId() ) );
sendDirectorClear( player );
player.setDirectorInitialized( false );
// remove "bound by duty" state
player.unsetStateFlag( PlayerStateFlag::BoundByDuty );
}
void Core::InstanceContent::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;
}
2018-03-06 13:33:10 +11:00
if( m_instanceCommenceTime == 0 )
{
2018-03-06 18:00:57 +11:00
m_instanceCommenceTime = Util::getTimeMs() + instanceStartDelay;
2018-03-06 13:33:10 +11:00
return;
}
else if( Util::getTimeMs() < m_instanceCommenceTime )
return;
2018-03-05 14:34:34 +01:00
for( const auto& playerIt : m_playerMap )
{
auto pPlayer = playerIt.second;
pPlayer->queuePacket(
ActorControlPacket143( pPlayer->getId(), DirectorUpdate,
getDirectorId(), 0x40000001, m_instanceConfiguration->timeLimitmin * 60u ) );
}
2018-03-06 18:00:57 +11:00
if( m_pEntranceEObj )
m_pEntranceEObj->setState( 7 );
m_state = DutyInProgress;
m_instanceExpireTime = Util::getTimeSeconds() + ( m_instanceConfiguration->timeLimitmin * 60u );
break;
}
case DutyReset:
break;
case DutyInProgress:
{
break;
}
case DutyFinished:
break;
}
auto pScriptMgr = g_fw.get< Scripting::ScriptMgr >();
pScriptMgr->onInstanceUpdate( getAsInstanceContent(), currTime );
}
void Core::InstanceContent::onFinishLoading( Entity::Player& player )
{
2018-02-24 23:53:32 +01:00
sendDirectorInit( player );
}
void Core::InstanceContent::onInitDirector( Entity::Player& player )
{
sendDirectorVars( player );
player.setDirectorInitialized( true );
}
void Core::InstanceContent::onSomeDirectorEvent( Entity::Player& player )
{
player.queuePacket( ActorControlPacket143( player.getId(), DirectorUpdate, 0x00110001, 0x80000000, 1 ) );
}
void Core::InstanceContent::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?
2018-03-05 14:34:34 +01:00
for( const auto& playerIt : m_playerMap )
{
sendDirectorVars( *playerIt.second );
}
}
void Core::InstanceContent::setSequence( uint8_t value )
{
setDirectorSequence( value );
2018-03-05 14:34:34 +01:00
for( const auto& playerIt : m_playerMap )
{
sendDirectorVars( *playerIt.second );
}
}
void Core::InstanceContent::setBranch( uint8_t value )
{
setDirectorBranch( value );
2018-03-05 14:34:34 +01:00
for( const auto& playerIt : m_playerMap )
{
sendDirectorVars( *playerIt.second );
}
}
2018-03-10 00:06:44 +09:00
void Core::InstanceContent::startQte()
{
2018-03-15 18:06:12 +11:00
for( const auto& playerIt : m_playerMap )
2018-03-10 00:06:44 +09:00
{
auto player = playerIt.second;
player->queuePacket( ActorControlPacket143( player->getId(), DirectorUpdate, getDirectorId(), 0x8000000A ) );
}
}
void Core::InstanceContent::startEventCutscene()
{
// TODO: lock player movement
2018-03-15 18:06:12 +11:00
for( const auto& playerIt : m_playerMap )
2018-03-10 00:06:44 +09:00
{
auto player = playerIt.second;
player->queuePacket( ActorControlPacket143( player->getId(), DirectorUpdate, getDirectorId(), 0x80000008 ) );
}
}
void Core::InstanceContent::endEventCutscene()
{
2018-03-15 18:06:12 +11:00
for( const auto& playerIt : m_playerMap )
2018-03-10 00:06:44 +09:00
{
auto player = playerIt.second;
player->queuePacket( ActorControlPacket143( player->getId(), DirectorUpdate, getDirectorId(), 0x80000009 ) );
}
}
void Core::InstanceContent::onRegisterEObj( Entity::EventObjectPtr object )
{
if( object->getName() != "none" )
m_eventObjectMap[object->getName()] = object;
if( object->getObjectId() == 2000182 ) // start
m_pEntranceEObj = object;
auto pLog = g_fw.get< Logger >();
auto pExdData = g_fw.get< Data::ExdDataGenerated >();
auto objData = pExdData->get< Core::Data::EObj >( object->getObjectId() );
if( objData )
// todo: data should be renamed to eventId
m_eventIdToObjectMap[objData->data] = object;
else
pLog->error( "InstanceContent::onRegisterEObj Zone " +
m_internalName + ": No EObj data found for EObj with ID: " +
std::to_string( object->getObjectId() ) );
}
bool Core::InstanceContent::hasPlayerPreviouslySpawned( Entity::Player &player ) const
{
auto it = m_spawnedPlayers.find( player.getId() );
return it != m_spawnedPlayers.end();
}
Core::InstanceContent::InstanceContentState Core::InstanceContent::getState() const
{
return m_state;
}
2018-03-05 14:34:34 +01:00
void Core::InstanceContent::onBeforePlayerZoneIn( Core::Entity::Player& player )
{
// remove any players from the instance who aren't bound on zone in
if( !isPlayerBound( player.getId() ) )
player.exitInstance();
// if a player has already spawned once inside this instance, don't move them if they happen to zone in again
if( !hasPlayerPreviouslySpawned( player ) )
2018-02-24 23:53:32 +01:00
{
if( m_pEntranceEObj != nullptr )
{
player.setRot( PI );
player.setPos( m_pEntranceEObj->getPos() );
}
else
{
player.setRot( PI );
player.setPos( { 0.f, 0.f, 0.f } );
}
2018-02-24 23:53:32 +01:00
}
player.resetObjSpawnIndex();
}
2018-03-05 14:34:34 +01:00
Core::Entity::EventObjectPtr Core::InstanceContent::getEObjByName( const std::string& name )
{
auto it = m_eventObjectMap.find( name );
if( it == m_eventObjectMap.end() )
return nullptr;
return it->second;
}
void Core::InstanceContent::onTalk( Core::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() )
2018-02-27 23:05:42 +11:00
onTalk( player, it->second, getAsInstanceContent(), actorId );
else
player.sendDebug( "No onTalk handler found for interactable eobj with EObjID: " +
std::to_string( it->second->getObjectId() ) + ", eventId: " + std::to_string( eventId ) );
}
2018-03-05 22:10:14 +11:00
void Core::InstanceContent::onEnterTerritory( Entity::Player& player, uint32_t eventId, uint16_t param1, uint16_t param2 )
{
auto pScriptMgr = g_fw.get< Scripting::ScriptMgr >();
pScriptMgr->onInstanceEnterTerritory( getAsInstanceContent(), player, eventId, param1, param2 );
if( !hasPlayerPreviouslySpawned( player ) )
{
m_spawnedPlayers.insert( player.getId() );
2018-03-15 02:49:35 +11:00
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
2018-03-15 20:48:35 +11:00
DISABLE_CANCEL_EMOTE, 0, 0x9, getCurrentBGM() );
}
else
2018-03-15 20:48:35 +11:00
player.directorPlayScene( getDirectorId(), 2, NO_DEFAULT_CAMERA | HIDE_HOTBAR, 0, 0x9, getCurrentBGM() );
2018-03-05 22:10:14 +11:00
}
2018-03-15 20:48:35 +11:00
void Core::InstanceContent::setCurrentBGM( uint16_t bgmIndex )
{
m_currentBgm = bgmIndex;
2018-03-15 12:24:34 +01:00
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.
2018-03-15 12:24:34 +01:00
// player->queuePacket( ActorControlPacket143( player->getId(), DirectorUpdate, getDirectorId(), 0x80000001, 1 ) );
player->queuePacket( ActorControlPacket143( player->getId(), DirectorUpdate, getDirectorId(), 0x80000001, bgmIndex ) );
}
2018-03-15 20:48:35 +11:00
}
void Core::InstanceContent::setPlayerBGM( Core::Entity::Player& player, uint16_t bgmId )
{
player.queuePacket( ActorControlPacket143( player.getId(), DirectorUpdate, getDirectorId(), 0x80000001, bgmId ) );
}
2018-03-15 20:48:35 +11:00
uint16_t Core::InstanceContent::getCurrentBGM() const
{
return m_currentBgm;
2018-03-15 12:24:34 +01:00
}
2018-03-15 23:37:21 +01:00
bool Core::InstanceContent::bindPlayer( uint32_t playerId )
{
// if player already bound, return false
if( m_boundPlayerIds.count( playerId ) )
return false;
// TODO: do not allow binding of players if instance already has all it can take
// if( m_boundPlayerIds.size() >= party resttrictions )
// return false;
m_boundPlayerIds.insert( playerId );
return true;
}
bool Core::InstanceContent::isPlayerBound( uint32_t playerId ) const
{
return m_boundPlayerIds.count( playerId ) > 0;
}
void Core::InstanceContent::unbindPlayer( uint32_t playerId )
{
m_boundPlayerIds.erase( playerId );
auto it = m_playerMap.find( playerId );
if( it != m_playerMap.end() )
it->second->exitInstance();
2018-03-15 23:37:21 +01:00
}