1
Fork 0
mirror of https://github.com/SapphireServer/Sapphire.git synced 2025-04-26 06:27:45 +00:00
This commit is contained in:
Mordred 2018-09-17 23:10:59 +02:00
commit ddb3b69bd6
24 changed files with 454 additions and 72 deletions

View file

@ -3,7 +3,7 @@ root = true
# find plugin for your editor here: http://editorconfig.org/#download
[*.{cpp,h,chai,inc}]
indent_style = space
indent_size = 3
indent_size = 2
end_of_line = lf
trim_trailing_whitespace = true
indent_brace_style = Allman

View file

@ -22,7 +22,7 @@ When making a PR, please make sure that it follows our style guidelines and good
### Coding style
Indentations are Allman-style based, 3-space, no tabs.
Indentations are Allman-style based, 2-space, no tabs.
Space between arguments in function calls, as well as for types.
Example (shortened from ActionHandler.cpp):
@ -30,30 +30,30 @@ Example (shortened from ActionHandler.cpp):
```cpp
switch( commandId )
{
case 0x01: // Toggle sheathe
{
if ( param11 == 1 )
pPlayer->setStance( Entity::Chara::Stance::Active );
else
{
pPlayer->setStance( Entity::Chara::Stance::Passive );
pPlayer->setAutoattack( false );
}
case 0x01: // Toggle sheathe
{
if( param11 == 1 )
pPlayer->setStance( Entity::Chara::Stance::Active );
else
{
pPlayer->setStance( Entity::Chara::Stance::Passive );
pPlayer->setAutoattack( false );
}
pPlayer->sendToInRangeSet( ActorControlPacket142( pPlayer->getId(), 0, param11, 1 ) );
pPlayer->sendToInRangeSet( ActorControlPacket142( pPlayer->getId(), 0, param11, 1 ) );
break;
}
case 0x03: // Change target
{
uint64_t targetId = inPacket.getValAt< uint64_t >( 0x24 );
pPlayer->changeTarget( targetId );
break;
}
default:
{
break;
}
break;
}
case 0x03: // Change target
{
uint64_t targetId = inPacket.getValAt< uint64_t >( 0x24 );
pPlayer->changeTarget( targetId );
break;
}
default:
{
break;
}
}
```

View file

@ -183,5 +183,11 @@ void Core::Db::ZoneDbConnection::doPrepareStatements()
"FROM bnpctemplate WHERE 1;",
CONNECTION_BOTH);
prepareStatement( CHARA_ITEMGLOBAL_UP,
"UPDATE charaglobalitem SET stack = ?, durability = ?, stain = ? WHERE ItemId = ?;",
CONNECTION_BOTH );
prepareStatement( CHARA_ITEMGLOBAL_DELETE,
"UPDATE charaglobalitem SET IS_DELETE = 1 WHERE ItemId = ?;",
CONNECTION_BOTH );
}

View file

@ -73,6 +73,8 @@ enum ZoneDbStatements : uint32_t
CHARA_ITEMINV_INS,
CHARA_ITEMGLOBAL_INS,
CHARA_ITEMGLOBAL_UP,
CHARA_ITEMGLOBAL_DELETE,
ZONE_SEL_BNPCTEMPLATES,

View file

@ -240,6 +240,7 @@ enum ClientTriggerType
FinishZoning = 0xC9,
Teleport = 0xCA,
Examine = 0x12C,
MarkPlayer = 0x12D, // Mark player, visible to party only
SetTitleReq = 0x12E,
TitleList = 0x12F,
@ -249,7 +250,7 @@ enum ClientTriggerType
ClearWaymarks = 0x13A,
CameraMode = 0x13B, // param12, 1 = camera mode enable, 0 = disable
CharaNameReq = 0x13D, // requests character name by content id
HuntingLogDetails = 0x194,
Timers = 0x1AB,
@ -269,6 +270,10 @@ enum ClientTriggerType
AchievementComp = 0x203,
AchievementCatChat = 0x206,
QuestJournalUpdateQuestVisibility = 0x2BE,
QuestJournalClosed = 0x2BF,
AbandonQuest = 0x320,
DirectorInitFinish = 0x321,

View file

@ -76,16 +76,20 @@ enum ServerZoneIpcType :
SocialRequestResponse = 0x00BB, // updated 4.1
CancelAllianceForming = 0x00C6, // updated 4.2
Playtime = 0x00F5, // updated 4.3
Chat = 0x00F7, // updated 4.3
SocialList = 0x00FD, // updated 4.3
UpdateSearchInfo = 0x0100, // updated 4.3
InitSearchInfo = 0x0101, // updated 4.3
ExamineSearchComment = 0x0102, // updated 4.1
ServerNotice = 0x0106, // updated 4.3
SetOnlineStatus = 0x0107, // updated 4.3
CountdownInitiate = 0x0111, // updated 4.3
CountdownCancel = 0x0112, // updated 4.3
@ -94,6 +98,8 @@ enum ServerZoneIpcType :
LogMessage = 0x00D0,
LinkshellList = 0x011C, // updated 4.3
ExamineFreeCompanyInfo = 0x013A, // updated 4.1
CharaFreeCompanyTag = 0x013B, // updated 4.3
FreeCompanyBoardMsg = 0x013C, // updated 4.3
FreeCompanyInfo = 0x013D, // updated 4.3
@ -130,7 +136,8 @@ enum ServerZoneIpcType :
PlayerStateFlags = 0x0184, // updated 4.3
PlayerClassInfo = 0x0185, // updated 4.3
ModelEquip = 0x0186, // updated 4.3
Examine = 0x0187, // updated 4.3
CharaNameReq = 0x0189, // updated 4.3
UpdateClassInfo = 0x018A, // updated 4.3
ItemInfo = 0x0190, // updated 4.3
@ -190,7 +197,7 @@ enum ServerZoneIpcType :
// Unknown IPC types that still need to be sent
// TODO: figure all these out properly
IPCTYPE_UNK_320 = 0x024C, // updated 4.3
IPCTYPE_UNK_320 = 0x024C, // updated 4.3
IPCTYPE_UNK_322 = 0x024E, // updated 4.3
};
@ -224,6 +231,8 @@ enum ClientZoneIpcType :
SocialListHandler = 0x00DB, // updated 4.3
ReqSearchInfoHandler = 0x00E0, // updated 4.3
ReqExamineSearchCommentHandler = 0x00E1, // updated 4.1
SetSearchInfoHandler = 0x00DE, // updated 4.3
BlackListHandler = 0x00EC, // updated 4.3
@ -232,6 +241,7 @@ enum ClientZoneIpcType :
LinkshellListHandler = 0x00F4, // updated 4.3
SearchMarketboard = 0x0103, // updated 4.3
ReqExamineFcInfo = 0x010F, // updated 4.1
FcInfoReqHandler = 0x011A, // updated 4.2

View file

@ -140,6 +140,16 @@ struct FFXIVIpcInitSearchInfo :
char padding[5];
};
struct FFXIVIpcExamineSearchComment :
FFXIVIpcBasePacket< ExamineSearchComment >
{
uint32_t charId;
// packet only has 196 bytes after the charid
// likely utf8
char searchComment[195];
char padding;
};
/**
* Structural representation of the packet sent by the server
* to display a server notice message
@ -200,6 +210,25 @@ struct FFXIVIpcLinkshellList :
} entry[8];
};
struct FFXIVIpcExamineFreeCompanyInfo :
FFXIVIpcBasePacket< ExamineFreeCompanyInfo >
{
char unknown[0x20]; // likely fc allegiance/icon/housing info etc
uint32_t charId;
uint32_t fcTimeCreated;
char unknown2[0x10];
uint16_t unknown3;
char fcName[0x14]; // 20 char limit
uint16_t padding;
char fcTag[0x05]; // 5 char tag limit
uint16_t padding2; // null terminator?
char fcLeader[0x20]; // leader name (32 bytes)
char fcSlogan[192]; // source: https://ffxiv.gamerescape.com/wiki/Free_Company (packet cap confirms this size also)
char padding3; // null terminator?
char fcEstateProfile[20]; // todo: size needs confirmation
uint32_t padding4;
};
struct FFXIVIpcStatusEffectList :
FFXIVIpcBasePacket< StatusEffectList >
{
@ -685,7 +714,7 @@ struct FFXIVIpcInitZone :
uint8_t bitmask;
uint16_t unknown5;
uint16_t festivalId;
uint16_t unknown7;
uint16_t additionalFestivalId;
uint32_t unknown8;
Common::FFXIVARR_POSITION3 pos;
};
@ -950,6 +979,54 @@ struct FFXIVIpcModelEquip :
/* 003C */ uint32_t padding2;
};
struct FFXIVIpcExamine :
FFXIVIpcBasePacket< Examine >
{
uint8_t unkFlag1;
uint8_t unkFlag2;
char classJob;
char level;
uint16_t padding;
uint16_t titleId;
char grandCompany;
char grandCompanyRank;
char unknown[6];
uint32_t u6_fromPSpawn;
uint32_t u7_fromPSpawn;
char padding1[8];
uint64_t mainWeaponModel;
uint64_t secWeaponModel;
char unknown2[16];
struct ItemData
{
uint32_t catalogId;
uint32_t appearanceCatalogId;
uint64_t crafterId;
uint8_t quality;
uint8_t unknown[3];
struct Materia
{
uint16_t materiaId;
uint16_t tier;
} materia[5];
} entries[14];
char name[32];
char padding2;
char unk3[16];
char look[26];
char padding3[5];
uint32_t models[10];
char unknown4[200];
};
struct FFXIVIpcCharaNameReq :
FFXIVIpcBasePacket< CharaNameReq >
{
uint64_t contentId;
char name[32];
};
/**
* Structural representation of the packet sent by the server
* to update a players appearance
@ -969,7 +1046,7 @@ struct FFXIVIpcItemInfo :
uint8_t unknown2;
uint16_t condition;
uint16_t spiritBond;
uint16_t color;
uint16_t stain;
uint32_t glamourCatalogId;
uint16_t materia1;
uint16_t materia2;

View file

@ -29,36 +29,31 @@ private:
// Entities found in the script data of the quest
static constexpr auto Actor0 = 1000430;
static constexpr auto Ritem0 = 4552;
static constexpr uint32_t Ritem0 = 4552;
static constexpr auto Seq0Actor0 = 0;
static constexpr auto Seq1Actor0 = 1;
static constexpr auto Seq1Actor0Npctradeno = 99;
static constexpr auto Seq1Actor0Npctradeok = 100;
public:
SubFst029() :
EventScript( 65708 )
{
};
SubFst029() : EventScript( 65708 )
{};
~SubFst029()
{
};
{};
void onTalk( uint32_t eventId, Entity::Player& player, uint64_t actorId ) override
{
auto actor = Event::mapEventActorToRealActor( static_cast< uint32_t >( actorId ) );
//NOT SAFE - CRASH
/*if( actor == SubFst029::Actor0 && !player.hasQuest( getId() ) )
if( actor == SubFst029::Actor0 && !player.hasQuest( getId() ) )
{
Scene00000( player );
}
if( actor == SubFst029::Actor0 && player.getQuestSeq ( getId() ) == 255 )
{
Scene00001( player );
}*/
}
}
private:
@ -80,7 +75,7 @@ private:
player.playScene( getId(), 1, HIDE_HOTBAR,
[ & ]( Entity::Player& player, const Event::SceneResult& result )
{
if( result.param2 == 1 )
if( result.param2 == 1 && player.collectHandInItems( { Ritem0 } ) )
{
Scene00100( player );
}

View file

@ -1563,7 +1563,8 @@ void Core::Entity::Player::sendZonePackets()
initZonePacket->data().weatherId = static_cast< uint8_t >( getCurrentZone()->getCurrentWeather() );
initZonePacket->data().bitmask = 0x1;
initZonePacket->data().unknown5 = 0x2A;
initZonePacket->data().festivalId = getCurrentZone()->getCurrentFestival();
initZonePacket->data().festivalId = getCurrentZone()->getCurrentFestival().first;
initZonePacket->data().additionalFestivalId = getCurrentZone()->getCurrentFestival().second;
initZonePacket->data().pos.x = getPos().x;
initZonePacket->data().pos.y = getPos().y;
initZonePacket->data().pos.z = getPos().z;

View file

@ -360,6 +360,13 @@ public:
Common::GearModelSlot equipSlotToModelSlot( Common::GearSetSlot slot );
/*!
* Collect real item handins from container
* @param itemIds a vector of each catalog id to collect
* @return true if all items were handed in
*/
bool collectHandInItems( std::vector< uint32_t > itemIds );
// Class / Job / Exp
//////////////////////////////////////////////////////////////////////////////////////////////////////
/*! returns the level of the currently active class / job */

View file

@ -364,9 +364,10 @@ void Core::Entity::Player::sendInventory()
itemInfoPacket->data().slot = itM->first;
itemInfoPacket->data().quantity = itM->second->getStackSize();
itemInfoPacket->data().catalogId = itM->second->getId();
itemInfoPacket->data().condition = 30000;
itemInfoPacket->data().condition = itM->second->getDurability();
itemInfoPacket->data().spiritBond = 0;
itemInfoPacket->data().hqFlag = itM->second->isHq() ? 1 : 0;
itemInfoPacket->data().stain = itM->second->getStain();
queuePacket( itemInfoPacket );
}
}
@ -474,15 +475,26 @@ void Core::Entity::Player::writeInventory( InventoryType type )
void Core::Entity::Player::writeItem( Core::ItemPtr pItem ) const
{
auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >();
pDb->execute( "UPDATE charaglobalitem SET stack = " + std::to_string( pItem->getStackSize() ) + " " +
// TODO: add other attributes
" WHERE itemId = " + std::to_string( pItem->getUId() ) );
auto stmt = pDb->getPreparedStatement( Db::CHARA_ITEMGLOBAL_UP );
// todo: add more fields
stmt->setInt( 1, pItem->getStackSize() );
stmt->setInt( 2, pItem->getDurability() );
stmt->setInt( 3, pItem->getStain() );
stmt->setInt64( 4, pItem->getUId() );
pDb->directExecute( stmt );
}
void Core::Entity::Player::deleteItemDb( Core::ItemPtr item ) const
{
auto pDb = g_fw.get< Db::DbWorkerPool< Db::ZoneDbConnection > >();
pDb->execute( "UPDATE charaglobalitem SET IS_DELETE = 1 WHERE itemId = " + std::to_string( item->getUId() ) );
auto stmt = pDb->getPreparedStatement( Db::CHARA_ITEMGLOBAL_DELETE );
stmt->setInt64( 1, item->getUId() );
pDb->directExecute( stmt );
}
@ -510,8 +522,6 @@ Core::ItemPtr Core::Entity::Player::addItem( uint32_t catalogId, uint32_t quanti
// used for item obtain notification
uint32_t originalQuantity = quantity;
// todo: for now we're just going to add any items to main inv
std::pair< uint16_t, uint8_t > freeBagSlot;
bool foundFreeSlot = false;
@ -827,3 +837,37 @@ uint8_t Core::Entity::Player::getFreeSlotsInBags()
}
return slots;
}
bool Core::Entity::Player::collectHandInItems( std::vector< uint32_t > itemIds )
{
// todo: figure out how the game gets the required stack count
const auto& container = m_storageMap[ HandIn ];
std::vector< uint8_t > foundItems;
auto itemMap = container->getItemMap();
for( auto& item : itemMap )
{
for( auto needle : itemIds )
{
if( item.second->getId() == needle )
{
foundItems.push_back( item.first );
break;
}
}
}
// couldn't find all the items required
if( foundItems.size() != itemIds.size() )
return false;
// remove items
for( auto item : foundItems )
{
container->removeItem( item );
}
return true;
}

View file

@ -304,9 +304,11 @@ void Core::DebugCommandHandler::set( char* data, Entity::Player& player, boost::
else if( subCommand == "festival" )
{
uint16_t festivalId;
sscanf( params.c_str(), "%hu", &festivalId );
uint16_t additionalId;
pTerriMgr->setCurrentFestival( festivalId );
sscanf( params.c_str(), "%hu %hu", &festivalId, &additionalId );
pTerriMgr->setCurrentFestival( festivalId, additionalId );
}
else if( subCommand == "festivaldisable" )
{

View file

@ -12,7 +12,9 @@ Core::Item::Item( uint64_t uId, uint32_t catalogId, uint64_t model1, uint64_t mo
m_uId( uId ),
m_model1( model1 ),
m_model2( model2 ),
m_isHq( isHq )
m_isHq( isHq ),
m_stain( 0 ),
m_durability( 30000 )
{
auto pExdData = g_fw.get< Data::ExdDataGenerated >();
auto itemInfo = pExdData->get< Core::Data::Item >( catalogId );
@ -132,3 +134,23 @@ uint32_t Core::Item::getMaxStackSize() const
{
return m_maxStackSize;
}
uint16_t Core::Item::getDurability() const
{
return m_durability;
}
void Core::Item::setDurability( uint16_t durability )
{
m_durability = durability;
}
uint16_t Core::Item::getStain() const
{
return m_stain;
}
void Core::Item::setStain( uint16_t stain )
{
m_stain = stain;
}

View file

@ -55,6 +55,12 @@ public:
uint32_t getMaxStackSize() const;
uint16_t getDurability() const;
void setDurability( uint16_t durability );
uint16_t getStain() const;
void setStain( uint16_t stain );
protected:
uint32_t m_id;
@ -78,6 +84,8 @@ protected:
uint16_t m_weaponDmg;
float m_autoAttackDmg;
uint16_t m_itemLevel;
uint16_t m_durability;
uint16_t m_stain;
};

View file

@ -60,14 +60,15 @@ Core::Network::GameConnection::GameConnection( Core::Network::HivePtr pHive,
&GameConnection::setSearchInfoHandler );
setZoneHandler( ClientZoneIpcType::ReqSearchInfoHandler, "ReqSearchInfoHandler",
&GameConnection::reqSearchInfoHandler );
setZoneHandler( ClientZoneIpcType::ReqExamineSearchCommentHandler, "ReqExamineSearchCommentHandler",
&GameConnection::reqExamineSearchCommentHandler );
setZoneHandler( ClientZoneIpcType::BlackListHandler, "BlackListHandler", &GameConnection::blackListHandler );
setZoneHandler( ClientZoneIpcType::LinkshellListHandler, "LinkshellListHandler",
&GameConnection::linkshellListHandler );
setZoneHandler( ClientZoneIpcType::FcInfoReqHandler, "FcInfoReqHandler", &GameConnection::fcInfoReqHandler );
setZoneHandler( ClientZoneIpcType::ReqExamineFcInfo, "ReqExamineFcInfo", &GameConnection::reqExamineFcInfo );
setZoneHandler( ClientZoneIpcType::ZoneLineHandler, "ZoneLineHandler", &GameConnection::zoneLineHandler );
setZoneHandler( ClientZoneIpcType::ClientTrigger, "ClientTrigger", &GameConnection::clientTriggerHandler );

View file

@ -110,6 +110,10 @@ public:
DECLARE_HANDLER( reqSearchInfoHandler );
DECLARE_HANDLER( reqExamineSearchCommentHandler );
DECLARE_HANDLER( reqExamineFcInfo );
DECLARE_HANDLER( updatePositionHandler );
DECLARE_HANDLER( chatHandler );

View file

@ -13,6 +13,8 @@
#include "Zone/ZonePosition.h"
#include "Network/GameConnection.h"
#include "Network/PacketWrappers/ExaminePacket.h"
#include "Network/PacketWrappers/InitUIPacket.h"
#include "Network/PacketWrappers/PingPacket.h"
#include "Network/PacketWrappers/MoveActorPacket.h"
@ -27,6 +29,7 @@
#include "Action/Action.h"
#include "Action/ActionTeleport.h"
#include "Session.h"
#include "ServerZone.h"
#include "Forwards.h"
@ -40,6 +43,21 @@ using namespace Core::Network::Packets;
using namespace Core::Network::Packets::Server;
using namespace Core::Network::ActorControl;
void examineHandler( Core::Entity::Player& player, uint32_t targetId )
{
using namespace Core;
auto pSession = g_fw.get< Core::ServerZone >()->getSession( targetId );
if( pSession )
{
auto pTarget = pSession->getPlayer();
if( pTarget )
{
player.queuePacket( boost::make_shared< ExaminePacket >( player, pTarget ) );
}
}
}
void Core::Network::GameConnection::clientTriggerHandler( const Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
{
@ -118,6 +136,12 @@ void Core::Network::GameConnection::clientTriggerHandler( const Packets::FFXIVAR
player.getCurrentAction()->setInterrupted();
break;
}
case ClientTriggerType::Examine:
{
uint32_t targetId = param11;
examineHandler( player, targetId );
break;
}
case ClientTriggerType::MarkPlayer: // Mark player
{
break;
@ -138,6 +162,22 @@ void Core::Network::GameConnection::clientTriggerHandler( const Packets::FFXIVAR
player.updateHowtosSeen( howToId );
break;
}
case ClientTriggerType::CharaNameReq:
{
uint64_t targetContentId = param1;
// todo: look up player by content id
/*
auto packet = makeZonePacket< FFXIVIpcCharaNameReq >( player.getId() );
packet->data().contentId = targetContentId;
// lookup the name
strcpy( packet->data().name, name );
player.queuePacket( packet );
*/
break;
}
case ClientTriggerType::EmoteReq: // emote
{
uint64_t targetId = player.getTargetId();
@ -256,6 +296,11 @@ void Core::Network::GameConnection::clientTriggerHandler( const Packets::FFXIVAR
player.exitInstance();
break;
}
case ClientTriggerType::AbandonQuest:
{
player.removeQuest( static_cast< uint16_t >( param1 ) );
break;
}
default:

View file

@ -105,6 +105,55 @@ void Core::Network::GameConnection::reqSearchInfoHandler( const Core::Network::P
queueOutPacket( searchInfoPacket );
}
void Core::Network::GameConnection::reqExamineSearchCommentHandler( const Core::Network::Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
{
auto targetId = *reinterpret_cast< const uint32_t* >( &inPacket.data[ 0x10 ] );
auto pSession = g_fw.get< Core::ServerZone >()->getSession( targetId );
g_fw.get< Core::Logger >()->debug( std::to_string( targetId ) );
if( pSession )
{
auto pPlayer = pSession->getPlayer();
if( pPlayer )
{
// retail sends the requester's id as both (isForSelf)
auto searchInfoPacket = makeZonePacket< FFXIVIpcExamineSearchComment >( player.getId() );
searchInfoPacket->data().charId = targetId;
strcpy( searchInfoPacket->data().searchComment, pPlayer->getSearchMessage() );
player.queuePacket( searchInfoPacket );
}
}
}
void Core::Network::GameConnection::reqExamineFcInfo( const Core::Network::Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
{
auto targetId = *reinterpret_cast< const uint32_t* >( &inPacket.data[ 0x18 ] );
auto pSession = g_fw.get< Core::ServerZone >()->getSession( targetId );
g_fw.get< Core::Logger >()->debug( std::to_string( targetId ) );
if( pSession )
{
auto pPlayer = pSession->getPlayer();
if( pPlayer )
{
// retail sends the requester's id as both (isForSelf)
auto examineFcInfoPacket = makeZonePacket< FFXIVIpcExamineFreeCompanyInfo >( player.getId() );
examineFcInfoPacket->data().charId = targetId;
// todo: populate with fc info
player.queuePacket( examineFcInfoPacket );
}
}
}
void Core::Network::GameConnection::linkshellListHandler( const Core::Network::Packets::FFXIVARR_PACKET_RAW& inPacket,
Entity::Player& player )
{

View file

@ -0,0 +1,87 @@
#ifndef _CORE_NETWORK_PACKETS_EXAMINEPACKET_H
#define _CORE_NETWORK_PACKETS_EXAMINEPACKET_H
#include <Network/PacketDef/Zone/ServerZoneDef.h>
#include <Network/GamePacketNew.h>
#include <Util/Util.h>
#include "Actor/Player.h"
#include "Forwards.h"
#include "Inventory/Item.h"
#include "StatusEffect/StatusEffect.h"
namespace Core {
namespace Network {
namespace Packets {
namespace Server {
/**
* @brief The Examine response packet.
*/
class ExaminePacket :
public ZoneChannelPacket< FFXIVIpcExamine >
{
public:
ExaminePacket( Entity::Player& player, Entity::PlayerPtr pTarget ) :
ZoneChannelPacket< FFXIVIpcExamine >( pTarget->getId(), player.getId() )
{
initialize( player, pTarget );
};
private:
void initialize( Entity::Player& player, Entity::PlayerPtr pTarget )
{
assert( pTarget );
{
// todo: this packet needs mapping out
strcpy( m_data.name, pTarget->getName().c_str() );
m_data.classJob = static_cast< uint8_t >( pTarget->getClass() );
m_data.level = pTarget->getLevel();
m_data.unkFlag1 = 4;
m_data.unkFlag2 = 1;
m_data.titleId = pTarget->getTitle();
m_data.grandCompany = pTarget->getGc();
m_data.grandCompanyRank = pTarget->getGcRankArray()[m_data.grandCompany];
m_data.mainWeaponModel = pTarget->getModelMainWeapon();
m_data.secWeaponModel = pTarget->getModelSubWeapon();
memcpy( m_data.look, pTarget->getLookArray(), sizeof( m_data.look ) );
m_data.models[ Common::GearModelSlot::ModelHead ] = player.getModelForSlot( Common::GearModelSlot::ModelHead );
m_data.models[ Common::GearModelSlot::ModelBody ] = player.getModelForSlot( Common::GearModelSlot::ModelBody );
m_data.models[ Common::GearModelSlot::ModelHands ] = player.getModelForSlot( Common::GearModelSlot::ModelHands );
m_data.models[ Common::GearModelSlot::ModelLegs ] = player.getModelForSlot( Common::GearModelSlot::ModelLegs );
m_data.models[ Common::GearModelSlot::ModelFeet ] = player.getModelForSlot( Common::GearModelSlot::ModelFeet );
m_data.models[ Common::GearModelSlot::ModelNeck ] = player.getModelForSlot( Common::GearModelSlot::ModelNeck );
m_data.models[ Common::GearModelSlot::ModelEar ] = player.getModelForSlot( Common::GearModelSlot::ModelEar );
m_data.models[ Common::GearModelSlot::ModelRing1 ] = player.getModelForSlot( Common::GearModelSlot::ModelRing1 );
m_data.models[ Common::GearModelSlot::ModelRing2 ] = player.getModelForSlot( Common::GearModelSlot::ModelRing2 );
m_data.models[ Common::GearModelSlot::ModelWrist ] = player.getModelForSlot( Common::GearModelSlot::ModelWrist );
// todo: main/sub/other stuff too
for( auto i = 0; i < Common::GearSetSlot::SoulCrystal + 1; ++i )
{
auto pItem = pTarget->getItemAt( Common::InventoryType::GearSet0, i );
if( pItem )
{
auto& entry = m_data.entries[i];
entry.catalogId = pItem->getId();
entry.quality = pItem->isHq();
//entry.appearanceCatalogId = pItem->getGlamourId()
// todo: glamour/materia etc.
}
}
}
};
};
}
}
}
}
#endif /*_CORE_NETWORK_PACKETS_EXAMINEPACKET_H*/

View file

@ -61,6 +61,7 @@ private:
m_data.models[ Common::GearModelSlot::ModelRing1 ] = player.getModelForSlot( Common::GearModelSlot::ModelRing1 );
m_data.models[ Common::GearModelSlot::ModelRing2 ] = player.getModelForSlot( Common::GearModelSlot::ModelRing2 );
m_data.models[ Common::GearModelSlot::ModelWrist ] = player.getModelForSlot( Common::GearModelSlot::ModelWrist );
strcpy( m_data.name, player.getName().c_str() );
m_data.pos.x = player.getPos().x;

View file

@ -417,18 +417,18 @@ Core::ZonePtr Core::TerritoryMgr::getLinkedInstance( uint32_t playerId ) const
return nullptr;
}
const uint16_t Core::TerritoryMgr::getCurrentFestival() const
const std::pair< uint16_t, uint16_t >& Core::TerritoryMgr::getCurrentFestival() const
{
return m_currentFestival;
}
void Core::TerritoryMgr::setCurrentFestival( uint16_t festivalId )
void Core::TerritoryMgr::setCurrentFestival( uint16_t festivalId, uint16_t additionalFestival )
{
m_currentFestival = festivalId;
m_currentFestival = { festivalId, additionalFestival };
for( const auto& zone : m_zoneSet )
{
zone->setCurrentFestival( m_currentFestival );
zone->setCurrentFestival( festivalId, additionalFestival );
}
}

View file

@ -123,11 +123,23 @@ public:
/*! returns an instancePtr if the player is still bound to an isntance */
ZonePtr getLinkedInstance( uint32_t playerId ) const;
void setCurrentFestival( uint16_t festivalId );
/*!
* @brief Sets the current festival for every zone
* @param festivalId A valid festival id from festival.exd
* @param additionalFestival A valid festival id from festival.exd, this is shown in addition to the first festival
*/
void setCurrentFestival( uint16_t festivalId, uint16_t additionalFestival = 0 );
/*!
* @brief Disables the current festival(s) in every zone
*/
void disableCurrentFestival();
const uint16_t getCurrentFestival() const;
/*!
* @brief Gets the current festival set on the server
* @return a pair with the 2 festivals currently active
*/
const std::pair< uint16_t, uint16_t >& getCurrentFestival() const;
private:
using TerritoryTypeDetailCache = std::unordered_map< uint16_t, Data::TerritoryTypePtr >;
@ -165,8 +177,10 @@ private:
/*! set of ZonePtrs for quick iteration*/
std::set< ZonePtr > m_instanceZoneSet;
/*! id of current festival to set for public zones from festival.exd */
uint16_t m_currentFestival;
/*! current festival(s) to set for public zones from festival.exd */
std::pair< uint16_t, uint16_t > m_currentFestival;
public:
/*! returns a list of instanceContent InstanceIds currently active */

View file

@ -53,7 +53,6 @@ Core::Zone::Zone() :
m_currentWeather( Weather::FairSkies ),
m_weatherOverride( Weather::None ),
m_lastMobUpdate( 0 ),
m_currentFestivalId( 0 ),
m_nextEObjId( 0x400D0000 )
{
}
@ -130,20 +129,20 @@ Weather Core::Zone::getCurrentWeather() const
return m_currentWeather;
}
uint16_t Core::Zone::getCurrentFestival() const
const Core::FestivalPair& Core::Zone::getCurrentFestival() const
{
return m_currentFestivalId;
return m_currentFestival;
}
void Core::Zone::setCurrentFestival( uint16_t festivalId )
void Core::Zone::setCurrentFestival( uint16_t festivalId, uint16_t additionalFestivalId )
{
m_currentFestivalId = festivalId;
m_currentFestival = { festivalId, additionalFestivalId };
for( const auto& playerEntry : m_playerMap )
{
auto player = playerEntry.second;
auto enableFestival = makeActorControl143( player->getId(), SetFestival, m_currentFestivalId );
auto enableFestival = makeActorControl143( player->getId(), SetFestival, festivalId, additionalFestivalId );
playerEntry.second->queuePacket( enableFestival );
}
}

View file

@ -23,6 +23,8 @@ class Session;
class ZonePosition;
using SessionSet = std::set< SessionPtr >;
using FestivalPair = std::pair< uint16_t, uint16_t >;
namespace Data {
struct InstanceContent;
struct TerritoryType;
@ -49,7 +51,8 @@ protected:
uint64_t m_lastMobUpdate;
uint16_t m_currentFestivalId;
FestivalPair m_currentFestival;
boost::shared_ptr< Data::TerritoryType > m_territoryTypeInfo;
std::map< uint8_t, int32_t > m_weatherRateMap;
@ -68,9 +71,9 @@ public:
Common::Weather getCurrentWeather() const;
uint16_t getCurrentFestival() const;
const FestivalPair& getCurrentFestival() const;
void setCurrentFestival( uint16_t festivalId );
void setCurrentFestival( uint16_t festivalId, uint16_t additionalFestivalId = 0 );
virtual bool init();