2019-03-31 01:39:49 +01:00
|
|
|
|
|
|
|
#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"
|
2019-04-15 23:41:43 +02:00
|
|
|
#include "Actor/BNpc.h"
|
|
|
|
#include "Actor/BNpcTemplate.h"
|
2019-03-31 01:39:49 +01:00
|
|
|
|
|
|
|
#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 )
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Sapphire::QuestBattle::init()
|
|
|
|
{
|
|
|
|
auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >();
|
2019-03-31 11:27:11 +02:00
|
|
|
pScriptMgr->onInstanceInit( getAsQuestBattle() );
|
2019-03-31 01:39:49 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
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() );
|
|
|
|
|
2019-04-02 00:00:58 +02:00
|
|
|
m_pPlayer = player.getAsPlayer();
|
|
|
|
|
2019-03-31 01:39:49 +01:00
|
|
|
// mark player as "bound by duty"
|
|
|
|
player.setStateFlag( PlayerStateFlag::BoundByDuty );
|
|
|
|
|
2019-04-04 23:29:52 +02:00
|
|
|
sendDirectorInit( player );
|
2019-03-31 01:39:49 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sapphire::QuestBattle::onLeaveTerritory( Entity::Player& player )
|
|
|
|
{
|
|
|
|
Logger::debug( "QuestBattle::onLeaveTerritory: Zone#{0}|{1}, Entity#{2}",
|
|
|
|
getGuId(), getTerritoryTypeId(), player.getId() );
|
|
|
|
|
|
|
|
clearDirector( player );
|
|
|
|
}
|
|
|
|
|
2019-04-02 00:00:58 +02:00
|
|
|
void Sapphire::QuestBattle::onEnterSceneFinish( Entity::Player& player )
|
|
|
|
{
|
|
|
|
player.eventStart( player.getId(), getDirectorId(), Event::EventHandler::GameProgress, 1, 0 );
|
|
|
|
player.playScene( getDirectorId(), 60000, 0x40000 /*unmapped*/ );
|
|
|
|
setSequence( 2 );
|
|
|
|
}
|
|
|
|
|
2019-04-04 23:29:52 +02:00
|
|
|
void Sapphire::QuestBattle::onUpdate( uint64_t tickCount )
|
2019-03-31 01:39:49 +01:00
|
|
|
{
|
2019-04-09 23:17:00 +02:00
|
|
|
if( !m_pPlayer )
|
|
|
|
return;
|
|
|
|
|
2019-03-31 01:39:49 +01:00
|
|
|
switch( m_state )
|
|
|
|
{
|
|
|
|
case Created:
|
|
|
|
{
|
2019-04-09 23:17:00 +02:00
|
|
|
|
2019-03-31 01:39:49 +01:00
|
|
|
|
2019-04-02 00:00:58 +02:00
|
|
|
if( !m_pPlayer->isLoadingComplete() ||
|
|
|
|
!m_pPlayer->isDirectorInitialized() ||
|
|
|
|
!m_pPlayer->isOnEnterEventDone() ||
|
|
|
|
m_pPlayer->hasStateFlag( PlayerStateFlag::WatchingCutscene ) )
|
2019-03-31 23:45:03 +02:00
|
|
|
return;
|
2019-03-31 01:39:49 +01:00
|
|
|
|
|
|
|
if( m_instanceCommenceTime == 0 )
|
|
|
|
{
|
|
|
|
m_instanceCommenceTime = Util::getTimeMs() + instanceStartDelay;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if( Util::getTimeMs() < m_instanceCommenceTime )
|
|
|
|
return;
|
|
|
|
|
2019-04-02 00:00:58 +02:00
|
|
|
onEnterSceneFinish( *m_pPlayer );
|
2019-03-31 01:39:49 +01:00
|
|
|
|
|
|
|
m_state = DutyInProgress;
|
|
|
|
m_instanceExpireTime = Util::getTimeSeconds() + ( m_pBattleDetails->timeLimit * 60u );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case DutyReset:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DutyInProgress:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DutyFinished:
|
|
|
|
break;
|
2019-04-04 23:29:52 +02:00
|
|
|
|
|
|
|
case DutyFailed:
|
2019-04-09 23:17:00 +02:00
|
|
|
{
|
|
|
|
if( getSequence() != 0xFE )
|
|
|
|
{
|
|
|
|
setSequence( 0xFE );
|
|
|
|
m_instanceFailTime = tickCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( ( static_cast< int64_t >( tickCount ) - static_cast< int64_t >( m_instanceFailTime ) ) > 6000 )
|
|
|
|
{
|
|
|
|
m_pPlayer->exitInstance();
|
|
|
|
m_pPlayer.reset();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2019-03-31 01:39:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >();
|
2019-04-04 23:29:52 +02:00
|
|
|
pScriptMgr->onInstanceUpdate( getAsQuestBattle(), tickCount );
|
2019-03-31 01:39:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Sapphire::QuestBattle::onFinishLoading( Entity::Player& player )
|
|
|
|
{
|
2019-03-31 23:45:03 +02:00
|
|
|
|
2019-03-31 01:39:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Sapphire::QuestBattle::onInitDirector( Entity::Player& player )
|
|
|
|
{
|
2019-03-31 23:45:03 +02:00
|
|
|
player.sendQuestMessage( getDirectorId(), 0, 2, Util::getTimeSeconds(), 0x0708 );
|
2019-03-31 01:39:49 +01:00
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-04-02 00:00:58 +02:00
|
|
|
sendDirectorVars( *m_pPlayer );
|
2019-03-31 01:39:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Sapphire::QuestBattle::setSequence( uint8_t value )
|
|
|
|
{
|
|
|
|
setDirectorSequence( value );
|
2019-04-02 00:00:58 +02:00
|
|
|
sendDirectorVars( *m_pPlayer );
|
2019-03-31 01:39:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Sapphire::QuestBattle::setBranch( uint8_t value )
|
|
|
|
{
|
|
|
|
setDirectorBranch( value );
|
2019-04-02 00:00:58 +02:00
|
|
|
sendDirectorVars( *m_pPlayer );
|
2019-03-31 01:39:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Sapphire::QuestBattle::startQte()
|
|
|
|
{
|
2019-04-02 00:00:58 +02:00
|
|
|
m_pPlayer->queuePacket( makeActorControl143( m_pPlayer->getId(), DirectorUpdate, getDirectorId(), 0x8000000A ) );
|
2019-03-31 01:39:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Sapphire::QuestBattle::startEventCutscene()
|
|
|
|
{
|
2019-04-02 00:00:58 +02:00
|
|
|
m_pPlayer->queuePacket( makeActorControl143( m_pPlayer->getId(), DirectorUpdate, getDirectorId(), 0x80000008 ) );
|
2019-03-31 01:39:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Sapphire::QuestBattle::endEventCutscene()
|
|
|
|
{
|
2019-04-02 00:00:58 +02:00
|
|
|
m_pPlayer->queuePacket( makeActorControl143( m_pPlayer->getId(), DirectorUpdate, getDirectorId(), 0x80000009 ) );
|
2019-03-31 01:39:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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 )
|
|
|
|
{
|
|
|
|
player.setRot( PI );
|
|
|
|
player.setPos( { 0.f, 0.f, 0.f } );
|
2019-04-02 00:00:58 +02:00
|
|
|
auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >();
|
|
|
|
pScriptMgr->onPlayerSetup( *this, player );
|
2019-03-31 01:39:49 +01:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2019-03-31 11:27:11 +02:00
|
|
|
if( auto onTalkHandler = it->second->getOnTalkHandler() )
|
|
|
|
onTalkHandler( player, it->second, getAsQuestBattle(), actorId );
|
2019-03-31 01:39:49 +01:00
|
|
|
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 >();
|
2019-03-31 11:27:11 +02:00
|
|
|
pScriptMgr->onInstanceEnterTerritory( getAsQuestBattle(), player, eventId, param1, param2 );
|
2019-03-31 01:39:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void Sapphire::QuestBattle::clearDirector( Entity::Player& player )
|
|
|
|
{
|
|
|
|
sendDirectorClear( player );
|
|
|
|
|
|
|
|
player.setDirectorInitialized( false );
|
|
|
|
// remove "bound by duty" state
|
|
|
|
player.unsetStateFlag( PlayerStateFlag::BoundByDuty );
|
|
|
|
}
|
2019-04-07 13:27:56 +02:00
|
|
|
|
|
|
|
void Sapphire::QuestBattle::success()
|
|
|
|
{
|
|
|
|
|
|
|
|
m_pPlayer->eventStart( m_pPlayer->getId(), getDirectorId(), Event::EventHandler::GameProgress, 1, 0 );
|
|
|
|
m_pPlayer->playScene( getDirectorId(), 60001, 0x40000,
|
|
|
|
[ & ]( Entity::Player& player, const Event::SceneResult& result )
|
|
|
|
{
|
|
|
|
player.eventFinish( getDirectorId(), 1 );
|
|
|
|
player.eventStart( player.getId(), getDirectorId(), Event::EventHandler::GameProgress, 1, 0 );
|
|
|
|
player.playScene( getDirectorId(), 6, HIDE_HOTBAR | NO_DEFAULT_CAMERA,
|
|
|
|
[ & ]( Entity::Player& player, const Event::SceneResult& result )
|
|
|
|
{
|
|
|
|
player.eventFinish( getDirectorId(), 1 );
|
|
|
|
auto pScriptMgr = m_pFw->get< Scripting::ScriptMgr >();
|
|
|
|
pScriptMgr->onDutyComplete( getAsQuestBattle(), *m_pPlayer );
|
2019-04-07 23:42:24 +02:00
|
|
|
player.exitInstance();
|
2019-04-07 13:27:56 +02:00
|
|
|
} );
|
|
|
|
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Sapphire::QuestBattle::fail()
|
|
|
|
{
|
2019-04-09 23:17:00 +02:00
|
|
|
m_state = DutyFailed;
|
2019-04-07 13:27:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t Sapphire::QuestBattle::getQuestId() const
|
|
|
|
{
|
|
|
|
return m_pBattleDetails->quest;
|
|
|
|
}
|
2019-04-15 23:41:43 +02:00
|
|
|
|
|
|
|
Sapphire::Entity::BNpcPtr
|
|
|
|
Sapphire::QuestBattle::createBNpcFromLevelEntry( uint32_t levelId, uint8_t level, uint8_t type,
|
|
|
|
uint32_t hp, uint16_t nameId, uint32_t directorId,
|
|
|
|
uint8_t bnpcType )
|
|
|
|
{
|
|
|
|
auto pExdData = m_pFw->get< Data::ExdDataGenerated >();
|
|
|
|
auto levelData = pExdData->get< Sapphire::Data::Level >( levelId );
|
|
|
|
if( !levelData )
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
if( levelData->type != 9 )
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
auto bnpcBaseId = levelData->object;
|
|
|
|
|
|
|
|
auto bnpcBaseData = pExdData->get< Sapphire::Data::BNpcBase >( bnpcBaseId );
|
|
|
|
if( !bnpcBaseData )
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
//BNpcTemplate( uint32_t id, uint32_t baseId, uint32_t nameId, uint64_t weaponMain, uint64_t weaponSub,
|
|
|
|
// uint8_t aggressionMode, uint8_t enemyType, uint8_t onlineStatus, uint8_t pose,
|
|
|
|
// uint16_t modelChara, uint32_t displayFlags, uint32_t* modelEquip,
|
|
|
|
// uint8_t* customize )
|
|
|
|
|
|
|
|
std::vector< uint8_t > customize( 26 );
|
|
|
|
if( bnpcBaseData->bNpcCustomize != 0 )
|
|
|
|
{
|
|
|
|
auto bnpcCustomizeData = pExdData->get< Sapphire::Data::BNpcCustomize >( bnpcBaseData->bNpcCustomize );
|
|
|
|
if( bnpcCustomizeData )
|
|
|
|
{
|
|
|
|
customize[0] = bnpcCustomizeData->race;
|
|
|
|
customize[1] = bnpcCustomizeData->gender;
|
|
|
|
customize[2] = bnpcCustomizeData->bodyType;
|
|
|
|
customize[3] = bnpcCustomizeData->height;
|
|
|
|
customize[4] = bnpcCustomizeData->tribe;
|
|
|
|
customize[5] = bnpcCustomizeData->face;
|
|
|
|
customize[6] = bnpcCustomizeData->hairStyle;
|
|
|
|
customize[7] = bnpcCustomizeData->hairHighlight;
|
|
|
|
customize[8] = bnpcCustomizeData->skinColor;
|
|
|
|
customize[9] = bnpcCustomizeData->eyeHeterochromia;
|
|
|
|
customize[10] = bnpcCustomizeData->hairColor;
|
|
|
|
customize[11] = bnpcCustomizeData->hairHighlightColor;
|
|
|
|
customize[12] = bnpcCustomizeData->facialFeature;
|
|
|
|
customize[13] = bnpcCustomizeData->facialFeatureColor;
|
|
|
|
customize[14] = bnpcCustomizeData->eyebrows;
|
|
|
|
customize[15] = bnpcCustomizeData->eyeColor;
|
|
|
|
customize[16] = bnpcCustomizeData->eyeShape;
|
|
|
|
customize[17] = bnpcCustomizeData->nose;
|
|
|
|
customize[18] = bnpcCustomizeData->jaw;
|
|
|
|
customize[19] = bnpcCustomizeData->mouth;
|
|
|
|
customize[20] = bnpcCustomizeData->lipColor;
|
|
|
|
customize[21] = bnpcCustomizeData->bustOrTone1;
|
|
|
|
customize[22] = bnpcCustomizeData->extraFeature1;
|
|
|
|
customize[23] = bnpcCustomizeData->extraFeature2OrBust;
|
|
|
|
customize[24] = bnpcCustomizeData->facePaint;
|
|
|
|
customize[25] = bnpcCustomizeData->facePaintColor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector< uint32_t > models( 10 );
|
|
|
|
uint64_t modelMain = 0;
|
|
|
|
uint64_t modeloff = 0;
|
|
|
|
if( bnpcBaseData->npcEquip != 0 )
|
|
|
|
{
|
|
|
|
auto npcEquipData = pExdData->get< Sapphire::Data::NpcEquip >( bnpcBaseData->npcEquip );
|
|
|
|
if( npcEquipData )
|
|
|
|
{
|
|
|
|
modelMain = npcEquipData->modelMainHand;
|
|
|
|
modeloff = npcEquipData->modelOffHand;
|
|
|
|
|
|
|
|
models[0] = npcEquipData->modelHead;
|
|
|
|
models[1] = npcEquipData->modelBody;
|
|
|
|
models[2] = npcEquipData->modelHands;
|
|
|
|
models[3] = npcEquipData->modelLegs;
|
|
|
|
models[4] = npcEquipData->modelFeet;
|
|
|
|
models[5] = npcEquipData->modelEars;
|
|
|
|
models[6] = npcEquipData->modelNeck;
|
|
|
|
models[7] = npcEquipData->modelWrists;
|
|
|
|
models[8] = npcEquipData->modelLeftRing;
|
|
|
|
models[9] = npcEquipData->modelRightRing;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto tmp = std::make_shared< Entity::BNpcTemplate >( 0, bnpcBaseId, nameId, modelMain, modeloff, 1, bnpcType, 0, 4,
|
|
|
|
bnpcBaseData->modelChara, 0, &models[0], &customize[0] );
|
|
|
|
|
|
|
|
auto bnpc = std::make_shared< Entity::BNpc >( getNextActorId(), tmp, levelData->x, levelData->y, levelData->z,
|
|
|
|
levelData->yaw, level, hp, shared_from_this(), m_pFw );
|
|
|
|
|
|
|
|
bnpc->setDirectorId( directorId );
|
|
|
|
return bnpc;
|
|
|
|
}
|