mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-27 14:57:44 +00:00
Not compilable atm, still moving stuff around
This commit is contained in:
parent
6579a5d841
commit
b85c1c244e
16 changed files with 1131 additions and 1188 deletions
|
@ -12,7 +12,6 @@ namespace Core
|
|||
class ItemContainer;
|
||||
class Inventory;
|
||||
class Session;
|
||||
class XMLConfig;
|
||||
class ZonePosition;
|
||||
|
||||
typedef boost::shared_ptr<Zone> ZonePtr;
|
||||
|
@ -20,7 +19,6 @@ namespace Core
|
|||
typedef boost::shared_ptr<ItemContainer> ItemContainerPtr;
|
||||
typedef boost::shared_ptr<Inventory> InventoryPtr;
|
||||
typedef boost::shared_ptr<Session> SessionPtr;
|
||||
typedef boost::shared_ptr<XMLConfig> XMLConfigPtr;
|
||||
typedef boost::shared_ptr<ZonePosition> ZonePositionPtr;
|
||||
|
||||
namespace StatusEffect
|
||||
|
|
|
@ -47,6 +47,10 @@ using namespace Core::Network::Packets;
|
|||
using namespace Core::Network::Packets::Server;
|
||||
using namespace Core::Network::ActorControl;
|
||||
|
||||
using InventoryMap = std::map< uint16_t, Core::ItemContainerPtr >;
|
||||
using InvSlotPair = std::pair< uint16_t, int8_t >;
|
||||
using InvSlotPairVec = std::vector< InvSlotPair >;
|
||||
|
||||
// player constructor
|
||||
Core::Entity::Player::Player() :
|
||||
Chara( ObjKind::Player ),
|
||||
|
@ -1023,7 +1027,7 @@ void Core::Entity::Player::update( int64_t currTime )
|
|||
{
|
||||
if( m_targetId && m_currentStance == Entity::Chara::Stance::Active && isAutoattackOn() )
|
||||
{
|
||||
auto mainWeap = m_pInventory->getItemAt( Common::GearSet0, Common::EquipSlot::MainHand );
|
||||
auto mainWeap = getItemAt( Common::GearSet0, Common::EquipSlot::MainHand );
|
||||
|
||||
// @TODO i dislike this, iterating over all in range actors when you already know the id of the actor you need...
|
||||
for( auto actor : m_inRangeActor )
|
||||
|
@ -1406,8 +1410,7 @@ uint32_t Core::Entity::Player::getPersistentEmote() const
|
|||
void Core::Entity::Player::autoAttack( CharaPtr pTarget )
|
||||
{
|
||||
|
||||
auto mainWeap = m_pInventory->getItemAt( Common::GearSet0,
|
||||
Common::EquipSlot::MainHand );
|
||||
auto mainWeap = getItemAt( Common::GearSet0, Common::EquipSlot::MainHand );
|
||||
|
||||
pTarget->onActionHostile( *this );
|
||||
//uint64_t tick = Util::getTimeMs();
|
||||
|
@ -1572,7 +1575,7 @@ void Core::Entity::Player::sendZonePackets()
|
|||
classInfoPacket->data().level1 = getLevel();
|
||||
queuePacket( classInfoPacket );
|
||||
|
||||
m_itemLevel = getInventory()->calculateEquippedGearItemLevel();
|
||||
m_itemLevel = calculateEquippedGearItemLevel();
|
||||
sendItemLevel();
|
||||
}
|
||||
|
||||
|
@ -1748,4 +1751,3 @@ bool Core::Entity::Player::isOnEnterEventDone() const
|
|||
return m_onEnterEventDone;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include <Util/SpawnIndexAllocator.h>
|
||||
|
||||
#include "Chara.h"
|
||||
#include "Inventory/Inventory.h"
|
||||
#include "Event/EventHandler.h"
|
||||
#include <map>
|
||||
#include <queue>
|
||||
|
@ -23,11 +22,13 @@ struct QueuedZoning
|
|||
float m_targetRotation;
|
||||
uint64_t m_queueTime;
|
||||
|
||||
QueuedZoning( uint16_t targetZone, const Common::FFXIVARR_POSITION3& targetPosition, uint64_t queuedTime, float targetRotation )
|
||||
: m_targetZone( targetZone )
|
||||
, m_targetPosition( targetPosition )
|
||||
, m_queueTime( queuedTime )
|
||||
, m_targetRotation( targetRotation ) {}
|
||||
QueuedZoning( uint16_t targetZone, const Common::FFXIVARR_POSITION3& targetPosition,
|
||||
uint64_t queuedTime, float targetRotation ) :
|
||||
m_targetZone( targetZone ),
|
||||
m_targetPosition( targetPosition ),
|
||||
m_queueTime( queuedTime ),
|
||||
m_targetRotation( targetRotation )
|
||||
{}
|
||||
};
|
||||
|
||||
/** Class representing the Player
|
||||
|
@ -221,7 +222,7 @@ public:
|
|||
/*! add an item to the first free slot in one of the 4 main containers */
|
||||
bool tryAddItem( uint16_t catalogId, uint32_t quantity );
|
||||
/*! add an item to a given container */
|
||||
bool addItem( uint16_t containerId, uint16_t catalogId, uint32_t quantity );
|
||||
// bool addItem( uint16_t containerId, uint16_t catalogId, uint32_t quantity );
|
||||
/*! equip an item to a specified slot */
|
||||
void equipItem( Common::EquipSlot equipSlotId, ItemPtr pItem, bool sendModel );
|
||||
/*! remove an item from an equipment slot */
|
||||
|
@ -232,8 +233,6 @@ public:
|
|||
uint16_t getItemLevel() const;
|
||||
/*! send player ilvl */
|
||||
void sendItemLevel();
|
||||
/*! get a const pointer to the inventory object */
|
||||
InventoryPtr getInventory() const;
|
||||
/*! get the current main hand model */
|
||||
uint64_t getModelMainWeapon() const;
|
||||
/*! get the current off hand model */
|
||||
|
@ -246,10 +245,8 @@ public:
|
|||
uint32_t getModelForSlot( Common::EquipSlot slot );
|
||||
/*! set the equipment model in a specified equipment slot */
|
||||
void setModelForSlot( Common::EquipSlot slot, uint32_t val );
|
||||
/*! return the current amount of currency of type */
|
||||
uint32_t getCurrency( uint8_t type ) const;
|
||||
/*! add amount to the currency of type */
|
||||
void addCurrency( uint8_t type, uint32_t amount );
|
||||
void addCurrency( Common::CurrencyType type, uint32_t amount );
|
||||
/*! remove amount from the currency of type */
|
||||
void removeCurrency( uint8_t type, uint32_t amount );
|
||||
/*! return the current amount of crystals of type */
|
||||
|
@ -493,7 +490,7 @@ public:
|
|||
/*! send status update */
|
||||
void sendStatusUpdate( bool toSelf = true ) override;
|
||||
/*! send the entire inventory sequence */
|
||||
void sendInventory() const;
|
||||
void sendInventory();
|
||||
/*! send active quest list */
|
||||
void sendQuestInfo();
|
||||
/*! send a quest specific message */
|
||||
|
@ -604,6 +601,56 @@ public:
|
|||
/*! checks if a spawn index is valid */
|
||||
bool isObjSpawnIndexValid( uint8_t index );
|
||||
|
||||
|
||||
// Inventory Handling
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void initInventory();
|
||||
|
||||
using InvSlotPair = std::pair< uint16_t, int8_t >;
|
||||
using InvSlotPairVec = std::vector< InvSlotPair >;
|
||||
|
||||
ItemPtr createItem( uint32_t catalogId, uint16_t quantity = 1 );
|
||||
bool loadInventory();
|
||||
InvSlotPairVec getSlotsOfItemsInInventory( uint32_t catalogId );
|
||||
InvSlotPair getFreeBagSlot();
|
||||
int16_t addItem( uint16_t inventoryId, int8_t slotId, uint32_t catalogId, uint16_t quantity = 1, bool isHq = false, bool silent = false );
|
||||
void moveItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot );
|
||||
void swapItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot );
|
||||
void discardItem( uint16_t fromInventoryId, uint8_t fromSlotId );
|
||||
void splitItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot, uint16_t splitCount );
|
||||
void mergeItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot );
|
||||
|
||||
ItemPtr getItemAt( uint16_t containerId, uint8_t slotId );
|
||||
|
||||
bool updateContainer( uint16_t containerId, uint8_t slotId, ItemPtr pItem );
|
||||
|
||||
/*! calculate and return player ilvl based off equipped gear */
|
||||
uint16_t calculateEquippedGearItemLevel();
|
||||
/*! return the current amount of currency of type */
|
||||
uint32_t getCurrency( Common::CurrencyType type );
|
||||
|
||||
void updateCurrencyDb();
|
||||
void updateBagDb( Common::InventoryType type );
|
||||
void updateMannequinDb( Common::InventoryType type );
|
||||
void updateItemDb( ItemPtr pItem ) const;
|
||||
void deleteItemDb( ItemPtr pItem ) const;
|
||||
|
||||
/*! return the crystal amount of currency of type */
|
||||
uint32_t getCrystal( Common::CrystalType type );
|
||||
/*! add amount to the crystal of type */
|
||||
bool addCrystal( Common::CrystalType type, uint32_t amount );
|
||||
/*! remove amount from the crystals of type */
|
||||
bool removeCrystal( Common::CrystalType type, uint32_t amount );
|
||||
bool isObtainable( uint32_t catalogId, uint8_t quantity );
|
||||
|
||||
void updateCrystalDb();
|
||||
|
||||
void send();
|
||||
|
||||
uint8_t getFreeSlotsInBags();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint64_t m_lastMoveTime;
|
||||
|
||||
uint8_t m_lastMoveflag;
|
||||
|
@ -625,8 +672,9 @@ private:
|
|||
bool m_onEnterEventDone;
|
||||
|
||||
private:
|
||||
using InventoryMap = std::map< uint16_t, Core::ItemContainerPtr >;
|
||||
|
||||
|
||||
InventoryMap m_inventoryMap;
|
||||
|
||||
Common::FFXIVARR_POSITION3 m_prevPos;
|
||||
uint32_t m_prevZoneType;
|
||||
|
@ -678,8 +726,6 @@ private:
|
|||
uint8_t m_openingSequence;
|
||||
|
||||
uint16_t m_itemLevel;
|
||||
InventoryPtr m_pInventory;
|
||||
|
||||
std::map< uint32_t, Event::EventHandlerPtr > m_eventHandlerMap;
|
||||
|
||||
std::queue< uint8_t > m_freeHateSlotQueue; // queue with "hate slots" free to be assigned
|
||||
|
|
|
@ -7,22 +7,104 @@
|
|||
#include "Network/PacketWrappers/ActorControlPacket142.h"
|
||||
#include "Network/PacketWrappers/ActorControlPacket143.h"
|
||||
|
||||
#include "Inventory/Inventory.h"
|
||||
#include "Inventory/Item.h"
|
||||
#include "Inventory/ItemContainer.h"
|
||||
#include "Inventory/ItemUtil.h"
|
||||
|
||||
#include "Player.h"
|
||||
#include "Framework.h"
|
||||
|
||||
extern Core::Framework g_framework;
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/algorithm/clamp.hpp>
|
||||
|
||||
#include <Network/PacketDef/Zone/ServerZoneDef.h>
|
||||
|
||||
#include <Exd/ExdDataGenerated.h>
|
||||
#include <Logging/Logger.h>
|
||||
#include <Database/DatabaseDef.h>
|
||||
|
||||
#include "Actor/Player.h"
|
||||
|
||||
#include "Network/PacketWrappers/ServerNoticePacket.h"
|
||||
#include "Network/PacketWrappers/ActorControlPacket143.h"
|
||||
|
||||
|
||||
#include "Framework.h"
|
||||
#include <Network/CommonActorControl.h>
|
||||
|
||||
extern Core::Framework g_fw;
|
||||
|
||||
using namespace Core::Common;
|
||||
using namespace Core::Network::Packets;
|
||||
using namespace Core::Network::Packets::Server;
|
||||
using namespace Core::Network::ActorControl;
|
||||
|
||||
Core::InventoryPtr Core::Entity::Player::getInventory() const
|
||||
|
||||
|
||||
|
||||
void Core::Entity::Player::initInventory()
|
||||
{
|
||||
return m_pInventory;
|
||||
auto setupContainer = [this]( InventoryType type )
|
||||
{ m_inventoryMap[type] = make_ItemContainer( type ); };
|
||||
|
||||
// main bags
|
||||
setupContainer( Bag0 );
|
||||
setupContainer( Bag1 );
|
||||
setupContainer( Bag2 );
|
||||
setupContainer( Bag3 );
|
||||
|
||||
// gear set
|
||||
setupContainer( GearSet0 );
|
||||
|
||||
// gil contianer
|
||||
setupContainer( Currency );
|
||||
|
||||
// crystals??
|
||||
setupContainer( Crystal );
|
||||
//m_inventoryMap[0x07D3] = ItemContainerPtr( new ItemContainer( UNKNOWN_0 ) );
|
||||
//m_inventoryMap[0x07D8] = ItemContainerPtr( new ItemContainer( UNKNOWN_1 ) );
|
||||
|
||||
// armory weapons - 0
|
||||
setupContainer( ArmoryMain );
|
||||
|
||||
// armory offhand - 1
|
||||
setupContainer( ArmoryOff );
|
||||
|
||||
//armory head - 2
|
||||
setupContainer( ArmoryHead );
|
||||
|
||||
//armory body - 3
|
||||
setupContainer( ArmoryBody );
|
||||
|
||||
//armory hand - 4
|
||||
setupContainer( ArmoryHand );
|
||||
|
||||
//armory waist - 5
|
||||
setupContainer( ArmoryWaist );
|
||||
|
||||
//armory legs - 6
|
||||
setupContainer( ArmoryLegs );
|
||||
|
||||
//armory feet - 7
|
||||
setupContainer( ArmoryFeet );
|
||||
|
||||
//neck
|
||||
setupContainer( ArmotyNeck );
|
||||
|
||||
//earring
|
||||
setupContainer( ArmoryEar );
|
||||
|
||||
//wrist
|
||||
setupContainer( ArmoryWrist );
|
||||
|
||||
//armory rings - 11
|
||||
setupContainer( ArmoryRing );
|
||||
|
||||
//soul crystals - 13
|
||||
setupContainer( ArmorySoulCrystal );
|
||||
|
||||
loadInventory();
|
||||
|
||||
}
|
||||
|
||||
void Core::Entity::Player::sendItemLevel()
|
||||
|
@ -121,7 +203,7 @@ void Core::Entity::Player::equipItem( Common::EquipSlot equipSlotId, ItemPtr pIt
|
|||
if( sendUpdate )
|
||||
{
|
||||
this->sendModel();
|
||||
m_itemLevel = getInventory()->calculateEquippedGearItemLevel();
|
||||
m_itemLevel = calculateEquippedGearItemLevel();
|
||||
sendItemLevel();
|
||||
}
|
||||
}
|
||||
|
@ -131,59 +213,83 @@ void Core::Entity::Player::unequipItem( Common::EquipSlot equipSlotId, ItemPtr p
|
|||
m_modelEquip[static_cast< uint8_t >( equipSlotId )] = 0;
|
||||
sendModel();
|
||||
|
||||
m_itemLevel = getInventory()->calculateEquippedGearItemLevel();
|
||||
m_itemLevel = calculateEquippedGearItemLevel();
|
||||
sendItemLevel();
|
||||
}
|
||||
|
||||
uint32_t Core::Entity::Player::getCurrency( uint8_t type ) const
|
||||
{
|
||||
return m_pInventory->getCurrency( static_cast< Common::CurrencyType >( type ) );
|
||||
}
|
||||
|
||||
// TODO: these next functions are so similar that they could likely be simplified
|
||||
void Core::Entity::Player::addCurrency( uint8_t type, uint32_t amount )
|
||||
void Core::Entity::Player::addCurrency( CurrencyType type, uint32_t amount )
|
||||
{
|
||||
if( !m_pInventory->addCurrency( static_cast< Common::CurrencyType >( type ), amount ) )
|
||||
return;
|
||||
auto currItem = m_inventoryMap[Currency]->getItem( static_cast< uint8_t >( type ) - 1 );
|
||||
|
||||
if( !currItem )
|
||||
{
|
||||
// TODO: map currency type to itemid
|
||||
currItem = createItem( 1 );
|
||||
m_inventoryMap[Currency]->setItem( static_cast< uint8_t >( type ) - 1, currItem );
|
||||
updateCurrencyDb();
|
||||
}
|
||||
|
||||
uint32_t currentAmount = currItem->getStackSize();
|
||||
currItem->setStackSize( currentAmount + amount );
|
||||
updateItemDb( currItem );
|
||||
|
||||
auto invUpPacket = makeZonePacket< FFXIVIpcUpdateInventorySlot >( getId() );
|
||||
invUpPacket->data().containerId = Common::InventoryType::Currency;
|
||||
invUpPacket->data().catalogId = 1;
|
||||
invUpPacket->data().quantity = m_pInventory->getCurrency( static_cast< Common::CurrencyType >( type ) );
|
||||
invUpPacket->data().quantity = getCurrency( type );
|
||||
invUpPacket->data().slot = static_cast< uint8_t >( type ) - 1;
|
||||
|
||||
queuePacket( invUpPacket );
|
||||
}
|
||||
|
||||
void Core::Entity::Player::removeCurrency( uint8_t type, uint32_t amount )
|
||||
void Core::Entity::Player::removeCurrency( Common::CurrencyType type, uint32_t amount )
|
||||
{
|
||||
if( !m_pInventory->removeCurrency( static_cast< Common::CurrencyType >( type ), amount ) )
|
||||
return;
|
||||
|
||||
auto currItem = m_inventoryMap[Currency]->getItem( static_cast< uint8_t >( type ) - 1 );
|
||||
|
||||
if( !currItem )
|
||||
return false;
|
||||
|
||||
uint32_t currentAmount = currItem->getStackSize();
|
||||
if( amount > currentAmount )
|
||||
currItem->setStackSize( 0 );
|
||||
else
|
||||
currItem->setStackSize( currentAmount - amount );
|
||||
|
||||
updateItemDb( currItem );
|
||||
auto invUpPacket = makeZonePacket< FFXIVIpcUpdateInventorySlot >( getId() );
|
||||
invUpPacket->data().containerId = Common::InventoryType::Currency;
|
||||
invUpPacket->data().catalogId = 1;
|
||||
invUpPacket->data().quantity = m_pInventory->getCurrency( static_cast< Common::CurrencyType >( type ) );
|
||||
invUpPacket->data().quantity = getCurrency( type );
|
||||
invUpPacket->data().slot = static_cast< uint8_t >( type ) - 1;
|
||||
|
||||
queuePacket( invUpPacket );
|
||||
}
|
||||
|
||||
|
||||
uint32_t Core::Entity::Player::getCrystal( uint8_t type ) const
|
||||
void Core::Entity::Player::addCrystal( Common::CrystalType type, uint32_t amount )
|
||||
{
|
||||
return m_pInventory->getCrystal( static_cast< Common::CrystalType >( type ) );
|
||||
}
|
||||
auto currItem = m_inventoryMap[Crystal]->getItem( static_cast< uint8_t >( type ) - 1 );
|
||||
|
||||
void Core::Entity::Player::addCrystal( uint8_t type, uint32_t amount )
|
||||
{
|
||||
if( !m_pInventory->addCrystal( static_cast< Common::CrystalType >( type ), amount ) )
|
||||
return;
|
||||
if( !currItem )
|
||||
{
|
||||
// TODO: map currency type to itemid
|
||||
currItem = createItem( static_cast< uint8_t >( type ) + 1 );
|
||||
m_inventoryMap[Crystal]->setItem( static_cast< uint8_t >( type ) - 1, currItem );
|
||||
updateCrystalDb();
|
||||
}
|
||||
|
||||
uint32_t currentAmount = currItem->getStackSize();
|
||||
|
||||
currItem->setStackSize( currentAmount + amount );
|
||||
|
||||
updateItemDb( currItem );
|
||||
|
||||
auto invUpPacket = makeZonePacket< FFXIVIpcUpdateInventorySlot >( getId() );
|
||||
invUpPacket->data().containerId = Common::InventoryType::Crystal;
|
||||
invUpPacket->data().catalogId = static_cast< uint8_t >( type ) + 1;
|
||||
invUpPacket->data().quantity = m_pInventory->getCrystal( static_cast< Common::CrystalType >( type ) );
|
||||
invUpPacket->data().quantity = getCrystal( type );
|
||||
invUpPacket->data().slot = static_cast< uint8_t >( type ) - 1;
|
||||
|
||||
queuePacket( invUpPacket );
|
||||
|
@ -192,15 +298,25 @@ void Core::Entity::Player::addCrystal( uint8_t type, uint32_t amount )
|
|||
static_cast< uint8_t >( type ) + 1, amount ) );
|
||||
}
|
||||
|
||||
void Core::Entity::Player::removeCrystal( uint8_t type, uint32_t amount )
|
||||
void Core::Entity::Player::removeCrystal( Common::CrystalType type, uint32_t amount )
|
||||
{
|
||||
if( !m_pInventory->removeCrystal( static_cast< Common::CrystalType >( type ), amount ) )
|
||||
auto currItem = m_inventoryMap[Crystal]->getItem( static_cast< uint8_t >( type ) - 1 );
|
||||
|
||||
if( !currItem )
|
||||
return;
|
||||
|
||||
uint32_t currentAmount = currItem->getStackSize();
|
||||
if( amount > currentAmount )
|
||||
currItem->setStackSize( 0 );
|
||||
else
|
||||
currItem->setStackSize( currentAmount - amount );
|
||||
|
||||
updateItemDb( currItem );
|
||||
|
||||
auto invUpPacket = makeZonePacket< FFXIVIpcUpdateInventorySlot >( getId() );
|
||||
invUpPacket->data().containerId = Common::InventoryType::Crystal;
|
||||
invUpPacket->data().catalogId = static_cast< uint8_t >( type ) + 1;
|
||||
invUpPacket->data().quantity = m_pInventory->getCrystal( static_cast< Common::CrystalType >( type ) );
|
||||
invUpPacket->data().quantity = getCrystal( static_cast< Common::CrystalType >( type ) );
|
||||
invUpPacket->data().slot = static_cast< uint8_t >( type ) - 1;
|
||||
|
||||
queuePacket( invUpPacket );
|
||||
|
@ -211,22 +327,543 @@ bool Core::Entity::Player::tryAddItem( uint16_t catalogId, uint32_t quantity )
|
|||
|
||||
for( uint16_t i = 0; i < 4; i++ )
|
||||
{
|
||||
if( m_pInventory->addItem( i, -1, catalogId, quantity ) != -1 )
|
||||
if( addItem( i, -1, catalogId, quantity ) != -1 )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Core::Entity::Player::addItem( uint16_t containerId, uint16_t catalogId, uint32_t quantity )
|
||||
/*bool Core::Entity::Player::addItem( uint16_t containerId, uint16_t catalogId, uint32_t quantity )
|
||||
{
|
||||
if( m_pInventory->addItem( containerId, -1, catalogId, quantity ) != -1 )
|
||||
if( addItem( containerId, -1, catalogId, quantity ) != -1 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}*/
|
||||
|
||||
void Core::Entity::Player::sendInventory() const
|
||||
void Core::Entity::Player::sendInventory()
|
||||
{
|
||||
m_pInventory->send();
|
||||
InventoryMap::iterator it;
|
||||
|
||||
int32_t count = 0;
|
||||
for( it = m_inventoryMap.begin(); it != m_inventoryMap.end(); ++it, count++ )
|
||||
{
|
||||
|
||||
auto pMap = it->second->getItemMap();
|
||||
auto itM = pMap.begin();
|
||||
|
||||
for( ; itM != pMap.end(); ++itM )
|
||||
{
|
||||
if( !itM->second )
|
||||
return;
|
||||
|
||||
if( it->second->getId() == InventoryType::Currency || it->second->getId() == InventoryType::Crystal )
|
||||
{
|
||||
auto currencyInfoPacket = makeZonePacket< FFXIVIpcCurrencyCrystalInfo >( getId() );
|
||||
currencyInfoPacket->data().sequence = count;
|
||||
currencyInfoPacket->data().catalogId = itM->second->getId();
|
||||
currencyInfoPacket->data().unknown = 1;
|
||||
currencyInfoPacket->data().quantity = itM->second->getStackSize();
|
||||
currencyInfoPacket->data().containerId = it->second->getId();
|
||||
currencyInfoPacket->data().slot = 0;
|
||||
queuePacket( currencyInfoPacket );
|
||||
}
|
||||
else
|
||||
{
|
||||
auto itemInfoPacket = makeZonePacket< FFXIVIpcItemInfo >( getId() );
|
||||
itemInfoPacket->data().sequence = count;
|
||||
itemInfoPacket->data().containerId = it->second->getId();
|
||||
itemInfoPacket->data().slot = itM->first;
|
||||
itemInfoPacket->data().quantity = itM->second->getStackSize();
|
||||
itemInfoPacket->data().catalogId = itM->second->getId();
|
||||
itemInfoPacket->data().condition = 30000;
|
||||
itemInfoPacket->data().spiritBond = 0;
|
||||
itemInfoPacket->data().hqFlag = itM->second->isHq() ? 1 : 0;
|
||||
queuePacket( itemInfoPacket );
|
||||
}
|
||||
}
|
||||
|
||||
auto containerInfoPacket = makeZonePacket< FFXIVIpcContainerInfo >( getId() );
|
||||
containerInfoPacket->data().sequence = count;
|
||||
containerInfoPacket->data().numItems = it->second->getEntryCount();
|
||||
containerInfoPacket->data().containerId = it->second->getId();
|
||||
queuePacket( containerInfoPacket );
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Core::Entity::Player::InvSlotPairVec Core::Entity::Player::getSlotsOfItemsInInventory( uint32_t catalogId )
|
||||
{
|
||||
InvSlotPairVec outVec;
|
||||
for( auto i : { Bag0, Bag1, Bag2, Bag3 } )
|
||||
{
|
||||
auto inv = m_inventoryMap[i];
|
||||
for( auto item : inv->getItemMap() )
|
||||
{
|
||||
if( item.second && item.second->getId() == catalogId )
|
||||
outVec.push_back( std::make_pair( i, static_cast< int8_t >( item.first ) ) );
|
||||
}
|
||||
}
|
||||
return outVec;
|
||||
}
|
||||
|
||||
Core::Entity::Player::InvSlotPair Core::Entity::Player::getFreeBagSlot()
|
||||
{
|
||||
for( auto i : { Bag0, Bag1, Bag2, Bag3 } )
|
||||
{
|
||||
auto freeSlot = static_cast< int8_t >( m_inventoryMap[i]->getFreeSlot() );
|
||||
|
||||
if( freeSlot != -1 )
|
||||
return std::make_pair( i, freeSlot );
|
||||
}
|
||||
// no room in inventory
|
||||
return std::make_pair( 0, -1 );
|
||||
}
|
||||
|
||||
Core::ItemPtr Core::Entity::Player::getItemAt( uint16_t containerId, uint8_t slotId )
|
||||
{
|
||||
return m_inventoryMap[containerId]->getItem( slotId );
|
||||
}
|
||||
|
||||
|
||||
uint32_t Core::Entity::Player::getCurrency( CurrencyType type )
|
||||
{
|
||||
|
||||
auto currItem = m_inventoryMap[Currency]->getItem( static_cast< uint8_t >( type ) - 1 );
|
||||
|
||||
if( !currItem )
|
||||
return 0;
|
||||
|
||||
return currItem->getStackSize();
|
||||
|
||||
}
|
||||
|
||||
uint32_t Core::Entity::Player::getCrystal( CrystalType type )
|
||||
{
|
||||
|
||||
auto currItem = m_inventoryMap[Crystal]->getItem( static_cast< uint8_t >( type ) - 1 );
|
||||
|
||||
if( !currItem )
|
||||
return 0;
|
||||
|
||||
return currItem->getStackSize();
|
||||
|
||||
}
|
||||
|
||||
void Core::Entity::Player::updateCurrencyDb()
|
||||
{
|
||||
auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >();
|
||||
int32_t firstItemPos = -1;
|
||||
std::string query = "UPDATE charaitemcurrency SET ";
|
||||
|
||||
for( int32_t i = 0; i <= 11; i++ )
|
||||
{
|
||||
auto currItem = m_inventoryMap[Currency]->getItem( i );
|
||||
|
||||
if( currItem )
|
||||
{
|
||||
if( firstItemPos == -1 )
|
||||
firstItemPos = i;
|
||||
|
||||
if( i > firstItemPos )
|
||||
query += ", ";
|
||||
|
||||
query += "container_" + std::to_string( i ) + " = " + std::to_string( currItem->getUId() );
|
||||
}
|
||||
}
|
||||
|
||||
query += " WHERE CharacterId = " + std::to_string( getId() );
|
||||
|
||||
pDb->execute( query );
|
||||
}
|
||||
|
||||
|
||||
void Core::Entity::Player::updateCrystalDb()
|
||||
{
|
||||
auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >();
|
||||
int32_t firstItemPos = -1;
|
||||
std::string query = "UPDATE charaitemcrystal SET ";
|
||||
|
||||
for( int32_t i = 0; i <= 11; i++ )
|
||||
{
|
||||
auto currItem = m_inventoryMap[Crystal]->getItem( i );
|
||||
|
||||
if( currItem )
|
||||
{
|
||||
if( firstItemPos == -1 )
|
||||
firstItemPos = i;
|
||||
|
||||
if( i > firstItemPos )
|
||||
query += ", ";
|
||||
|
||||
query += "container_" + std::to_string( i ) + " = " + std::to_string( currItem->getUId() );
|
||||
}
|
||||
}
|
||||
|
||||
query += " WHERE CharacterId = " + std::to_string( getId() );
|
||||
|
||||
pDb->execute( query );
|
||||
}
|
||||
|
||||
void Core::Entity::Player::updateBagDb( InventoryType type )
|
||||
{
|
||||
auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >();
|
||||
std::string query = "UPDATE charaiteminventory SET ";
|
||||
|
||||
for( int32_t i = 0; i <= 34; i++ )
|
||||
{
|
||||
auto currItem = m_inventoryMap[type]->getItem( i );
|
||||
|
||||
if( i > 0 )
|
||||
query += ", ";
|
||||
|
||||
query += "container_" + std::to_string( i ) + " = " + std::to_string( currItem ? currItem->getUId() : 0 );
|
||||
}
|
||||
|
||||
query += " WHERE CharacterId = " + std::to_string( getId() ) +
|
||||
" AND storageId = " + std::to_string( static_cast< uint16_t >( type ) );
|
||||
|
||||
pDb->execute( query );
|
||||
}
|
||||
|
||||
|
||||
void Core::Entity::Player::updateMannequinDb( InventoryType type )
|
||||
{
|
||||
auto pLog = g_fw.get< Logger >();
|
||||
auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >();
|
||||
std::string query = "UPDATE charaitemgearset SET ";
|
||||
|
||||
for( int32_t i = 0; i <= 13; i++ )
|
||||
{
|
||||
auto currItem = m_inventoryMap[type]->getItem( i );
|
||||
|
||||
if( i > 0 )
|
||||
query += ", ";
|
||||
|
||||
query += "container_" + std::to_string( i ) + " = " + std::to_string( currItem ? currItem->getUId() : 0 );
|
||||
}
|
||||
|
||||
query += " WHERE CharacterId = " + std::to_string( getId() ) +
|
||||
" AND storageId = " + std::to_string( static_cast< uint16_t >( type ) );
|
||||
|
||||
pLog->debug( query );
|
||||
pDb->execute( query );
|
||||
}
|
||||
|
||||
|
||||
void Core::Entity::Player::updateItemDb( Core::ItemPtr pItem ) const
|
||||
{
|
||||
auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >();
|
||||
pDb->execute( "UPDATE charaglobalitem SET stack = " + std::to_string( pItem->getStackSize() ) + " " +
|
||||
// TODO: add other attributes
|
||||
" WHERE itemId = " + std::to_string( pItem->getUId() ) );
|
||||
}
|
||||
|
||||
void Core::Entity::Player::deleteItemDb( Core::ItemPtr item ) const
|
||||
{
|
||||
auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >();
|
||||
pDb->execute( "UPDATE charaglobalitem SET IS_DELETE = 1 WHERE itemId = " + std::to_string( item->getUId() ) );
|
||||
}
|
||||
|
||||
|
||||
bool Core::Entity::Player::isObtainable( uint32_t catalogId, uint8_t quantity )
|
||||
{
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int16_t Core::Entity::Player::addItem( uint16_t inventoryId, int8_t slotId, uint32_t catalogId, uint16_t quantity, bool isHq, bool silent )
|
||||
{
|
||||
auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >();
|
||||
auto pExdData = g_fw.get< Data::ExdDataGenerated >();
|
||||
auto itemInfo = pExdData->get< Core::Data::Item >( catalogId );
|
||||
|
||||
// if item data doesn't exist or it's a blank field
|
||||
if( !itemInfo || itemInfo->levelItem == 0 )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int8_t rSlotId = -1;
|
||||
|
||||
//if( itemInfo->stack_size > 1 )
|
||||
//{
|
||||
// auto itemList = this->getSlotsOfItemsInInventory( catalogId );
|
||||
// // TODO: this is a stacked item so we need to see if the item is already in inventory and
|
||||
// // check how much free space we have on existing stacks before looking for empty slots.
|
||||
//}
|
||||
//else
|
||||
{
|
||||
auto freeSlot = getFreeBagSlot();
|
||||
inventoryId = freeSlot.first;
|
||||
rSlotId = freeSlot.second;
|
||||
|
||||
if( rSlotId == -1 )
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto item = createItem( catalogId, quantity );
|
||||
|
||||
item->setHq( isHq );
|
||||
|
||||
if( rSlotId != -1 )
|
||||
{
|
||||
|
||||
m_inventoryMap[inventoryId]->setItem( rSlotId, item );
|
||||
|
||||
pDb->execute( "UPDATE charaiteminventory SET container_" + std::to_string( rSlotId ) + " = " + std::to_string( item->getUId() ) +
|
||||
" WHERE storageId = " + std::to_string( inventoryId ) +
|
||||
" AND CharacterId = " + std::to_string( getId() ) );
|
||||
|
||||
|
||||
auto invUpPacket = makeZonePacket< FFXIVIpcUpdateInventorySlot >( getId() );
|
||||
invUpPacket->data().containerId = inventoryId;
|
||||
invUpPacket->data().catalogId = catalogId;
|
||||
invUpPacket->data().quantity = item->getStackSize();
|
||||
invUpPacket->data().hqFlag = item->isHq() ? 1 : 0;
|
||||
invUpPacket->data().slot = rSlotId;
|
||||
invUpPacket->data().condition = 30000;
|
||||
queuePacket( invUpPacket );
|
||||
|
||||
if( !silent )
|
||||
queuePacket( boost::make_shared< ActorControlPacket143 >( getId(), ItemObtainIcon,
|
||||
catalogId, item->getStackSize() ) );
|
||||
|
||||
}
|
||||
|
||||
return rSlotId;
|
||||
|
||||
}
|
||||
|
||||
void Core::Entity::Player::moveItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot )
|
||||
{
|
||||
|
||||
auto tmpItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId );
|
||||
auto& itemMap = m_inventoryMap[fromInventoryId]->getItemMap();
|
||||
|
||||
if( tmpItem == nullptr )
|
||||
return;
|
||||
|
||||
itemMap[fromSlotId].reset();
|
||||
|
||||
m_inventoryMap[toInventoryId]->setItem( toSlot, tmpItem );
|
||||
|
||||
if( toInventoryId != GearSet0 )
|
||||
updateBagDb( static_cast< InventoryType >( toInventoryId ) );
|
||||
|
||||
if( fromInventoryId != GearSet0 && fromInventoryId != toInventoryId )
|
||||
updateBagDb( static_cast< InventoryType >( fromInventoryId ) );
|
||||
|
||||
if( static_cast< InventoryType >( toInventoryId ) == GearSet0 )
|
||||
{
|
||||
equipItem( static_cast< EquipSlot >( toSlot ), tmpItem, true );
|
||||
updateMannequinDb( static_cast< InventoryType >( toInventoryId ) );
|
||||
}
|
||||
|
||||
if( static_cast< InventoryType >( fromInventoryId ) == GearSet0 )
|
||||
{
|
||||
unequipItem( static_cast< EquipSlot >( fromSlotId ), tmpItem );
|
||||
updateMannequinDb( static_cast< InventoryType >( fromInventoryId ) );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool Core::Entity::Player::updateContainer( uint16_t containerId, uint8_t slotId, ItemPtr pItem )
|
||||
{
|
||||
auto containerType = Items::Util::getContainerType( containerId );
|
||||
|
||||
m_inventoryMap[containerId]->setItem( slotId, pItem );
|
||||
|
||||
switch( containerType )
|
||||
{
|
||||
case Armory:
|
||||
case CurrencyCrystal:
|
||||
case Bag:
|
||||
{
|
||||
updateBagDb( static_cast< InventoryType >( containerId ) );
|
||||
break;
|
||||
}
|
||||
|
||||
case GearSet:
|
||||
{
|
||||
if( pItem )
|
||||
equipItem( static_cast< EquipSlot >( slotId ), pItem, true );
|
||||
else
|
||||
unequipItem( static_cast< EquipSlot >( slotId ), pItem );
|
||||
|
||||
updateMannequinDb( static_cast< InventoryType >( containerId ) );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Core::Entity::Player::splitItem( uint16_t fromInventoryId, uint8_t fromSlotId,
|
||||
uint16_t toInventoryId, uint8_t toSlot, uint16_t itemCount )
|
||||
{
|
||||
auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId );
|
||||
if( !fromItem )
|
||||
return;
|
||||
|
||||
// check we have enough items in the origin slot
|
||||
// nb: don't let the client 'split' a whole stack into another slot
|
||||
if( fromItem->getStackSize() < itemCount )
|
||||
// todo: correct the invalid item split? does retail do this or does it just ignore it?
|
||||
return;
|
||||
|
||||
// make sure toInventoryId & toSlot are actually free so we don't orphan an item
|
||||
if( m_inventoryMap[toInventoryId]->getItem( toSlot ) )
|
||||
// todo: correct invalid move? again, not sure what retail does here
|
||||
return;
|
||||
|
||||
auto newSlot = addItem( toInventoryId, toSlot, fromItem->getId(), itemCount, fromItem->isHq(), true );
|
||||
if( newSlot == -1 )
|
||||
return;
|
||||
|
||||
auto newItem = m_inventoryMap[toInventoryId]->getItem( static_cast< uint8_t >( newSlot ) );
|
||||
|
||||
fromItem->setStackSize( fromItem->getStackSize() - itemCount );
|
||||
|
||||
updateContainer( fromInventoryId, fromSlotId, fromItem );
|
||||
updateContainer( toInventoryId, toSlot, newItem );
|
||||
|
||||
updateItemDb( fromItem );
|
||||
}
|
||||
|
||||
void Core::Entity::Player::mergeItem( uint16_t fromInventoryId, uint8_t fromSlotId,
|
||||
uint16_t toInventoryId, uint8_t toSlot )
|
||||
{
|
||||
auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId );
|
||||
auto toItem = m_inventoryMap[toInventoryId]->getItem( toSlot );
|
||||
|
||||
if( !fromItem || !toItem )
|
||||
return;
|
||||
|
||||
if( fromItem->getId() != toItem->getId() )
|
||||
return;
|
||||
|
||||
uint32_t stackSize = fromItem->getStackSize() + toItem->getStackSize();
|
||||
uint32_t stackOverflow = stackSize - std::min< uint32_t >( fromItem->getMaxStackSize(), stackSize );
|
||||
|
||||
// we can destroy the original stack if there's no overflow
|
||||
if( stackOverflow == 0 )
|
||||
{
|
||||
m_inventoryMap[fromInventoryId]->removeItem( fromSlotId );
|
||||
deleteItemDb( fromItem );
|
||||
}
|
||||
else
|
||||
{
|
||||
fromItem->setStackSize( stackOverflow );
|
||||
updateItemDb( fromItem );
|
||||
}
|
||||
|
||||
|
||||
toItem->setStackSize( stackSize );
|
||||
updateItemDb( toItem );
|
||||
|
||||
updateContainer( fromInventoryId, fromSlotId, fromItem );
|
||||
updateContainer( toInventoryId, toSlot, toItem );
|
||||
}
|
||||
|
||||
void Core::Entity::Player::swapItem( uint16_t fromInventoryId, uint8_t fromSlotId,
|
||||
uint16_t toInventoryId, uint8_t toSlot )
|
||||
{
|
||||
auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId );
|
||||
auto toItem = m_inventoryMap[toInventoryId]->getItem( toSlot );
|
||||
auto& itemMap = m_inventoryMap[fromInventoryId]->getItemMap();
|
||||
|
||||
if( fromItem == nullptr || toItem == nullptr )
|
||||
return;
|
||||
|
||||
// An item is being moved from bag0-3 to equippment, meaning
|
||||
// the swapped out item will be placed in the matching armory.
|
||||
if( Items::Util::isEquipment( toInventoryId )
|
||||
&& !Items::Util::isEquipment( fromInventoryId )
|
||||
&& !Items::Util::isArmory( fromInventoryId ) )
|
||||
{
|
||||
updateContainer( fromInventoryId, fromSlotId, nullptr );
|
||||
fromInventoryId = Items::Util::getArmoryToEquipSlot( toSlot );
|
||||
fromSlotId = static_cast < uint8_t >( m_inventoryMap[fromInventoryId]->getFreeSlot() );
|
||||
}
|
||||
|
||||
auto containerTypeFrom = Items::Util::getContainerType( fromInventoryId );
|
||||
auto containerTypeTo = Items::Util::getContainerType( toInventoryId );
|
||||
|
||||
updateContainer( toInventoryId, toSlot, fromItem );
|
||||
updateContainer( fromInventoryId, fromSlotId, toItem );
|
||||
}
|
||||
|
||||
void Core::Entity::Player::discardItem( uint16_t fromInventoryId, uint8_t fromSlotId )
|
||||
{
|
||||
// i am not entirely sure how this should be generated or if it even is important for us...
|
||||
uint32_t transactionId = 1;
|
||||
|
||||
auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId );
|
||||
|
||||
deleteItemDb( fromItem );
|
||||
|
||||
m_inventoryMap[fromInventoryId]->removeItem( fromSlotId );
|
||||
updateContainer( fromInventoryId, fromSlotId, nullptr );
|
||||
|
||||
auto invTransPacket = makeZonePacket< FFXIVIpcInventoryTransaction >( getId() );
|
||||
invTransPacket->data().transactionId = transactionId;
|
||||
invTransPacket->data().ownerId = getId();
|
||||
invTransPacket->data().storageId = fromInventoryId;
|
||||
invTransPacket->data().catalogId = fromItem->getId();
|
||||
invTransPacket->data().stackSize = fromItem->getStackSize();
|
||||
invTransPacket->data().slotId = fromSlotId;
|
||||
invTransPacket->data().type = 7;
|
||||
queuePacket( invTransPacket );
|
||||
|
||||
auto invTransFinPacket = makeZonePacket< FFXIVIpcInventoryTransactionFinish >( getId() );
|
||||
invTransFinPacket->data().transactionId = transactionId;
|
||||
invTransFinPacket->data().transactionId1 = transactionId;
|
||||
queuePacket( invTransFinPacket );
|
||||
}
|
||||
|
||||
uint16_t Core::Entity::Player::calculateEquippedGearItemLevel()
|
||||
{
|
||||
uint32_t iLvlResult = 0;
|
||||
|
||||
auto gearSetMap = m_inventoryMap[GearSet0]->getItemMap();
|
||||
|
||||
auto it = gearSetMap.begin();
|
||||
|
||||
while( it != gearSetMap.end() )
|
||||
{
|
||||
auto currItem = it->second;
|
||||
|
||||
if( currItem )
|
||||
{
|
||||
iLvlResult += currItem->getItemLevel();
|
||||
|
||||
// If item is weapon and isn't one-handed
|
||||
if( currItem->isWeapon() && !Items::Util::isOneHandedWeapon( currItem->getCategory() ) )
|
||||
{
|
||||
iLvlResult += currItem->getItemLevel();
|
||||
}
|
||||
}
|
||||
|
||||
it++;
|
||||
}
|
||||
|
||||
return boost::algorithm::clamp( iLvlResult / 13, 0, 9999 );
|
||||
}
|
||||
|
||||
|
||||
uint8_t Core::Entity::Player::getFreeSlotsInBags()
|
||||
{
|
||||
uint8_t slots = 0;
|
||||
for( uint8_t container : { 0, 1, 2, 3 } )
|
||||
{
|
||||
slots += 34 - m_inventoryMap[container]->getEntryCount();
|
||||
}
|
||||
return slots;
|
||||
}
|
||||
|
|
|
@ -1070,7 +1070,7 @@ bool Core::Entity::Player::giveQuestRewards( uint32_t questId, uint32_t optional
|
|||
}
|
||||
|
||||
if( gilReward > 0 )
|
||||
addCurrency( 1, gilReward );
|
||||
addCurrency( CurrencyType::Gil, gilReward );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include "Zone/TerritoryMgr.h"
|
||||
#include "Zone/Zone.h"
|
||||
#include "Inventory/Item.h"
|
||||
#include "Inventory/ItemContainer.h"
|
||||
#include "Inventory/ItemUtil.h"
|
||||
|
||||
#include "ServerZone.h"
|
||||
#include "Framework.h"
|
||||
|
@ -200,9 +203,6 @@ bool Core::Entity::Player::load( uint32_t charId, SessionPtr pSession )
|
|||
m_modelSubWeapon = 0;
|
||||
m_lastTickTime = 0;
|
||||
|
||||
// TODO: remove Inventory and actually inline it in Player class
|
||||
m_pInventory = make_Inventory( this );
|
||||
|
||||
calculateStats();
|
||||
|
||||
// first login, run the script event
|
||||
|
@ -228,7 +228,9 @@ bool Core::Entity::Player::load( uint32_t charId, SessionPtr pSession )
|
|||
|
||||
setStateFlag( PlayerStateFlag::BetweenAreas );
|
||||
|
||||
m_pInventory->load();
|
||||
//m_pInventory->load();
|
||||
|
||||
initInventory();
|
||||
|
||||
initHateSlotQueue();
|
||||
|
||||
|
@ -554,3 +556,166 @@ void Core::Entity::Player::insertQuest( uint16_t questId, uint8_t index, uint8_t
|
|||
stmt->setInt( 12, 0 );
|
||||
pDb->execute( stmt );
|
||||
}
|
||||
|
||||
Core::ItemPtr Core::Entity::Player::createItem( uint32_t catalogId, uint16_t quantity )
|
||||
{
|
||||
auto pExdData = g_fw.get< Data::ExdDataGenerated >();
|
||||
auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >();
|
||||
auto itemInfo = pExdData->get< Core::Data::Item >( catalogId );
|
||||
|
||||
if( !itemInfo )
|
||||
return nullptr;
|
||||
|
||||
uint16_t itemAmount = quantity;
|
||||
|
||||
if( itemInfo->stackSize == 1 )
|
||||
itemAmount = 1;
|
||||
|
||||
if( !itemInfo )
|
||||
return nullptr;
|
||||
|
||||
uint8_t flags = 0;
|
||||
|
||||
ItemPtr pItem = make_Item( Items::Util::getNextUId(),
|
||||
catalogId,
|
||||
itemInfo->modelMain,
|
||||
itemInfo->modelSub );
|
||||
|
||||
pItem->setStackSize( itemAmount );
|
||||
|
||||
pDb->execute( "INSERT INTO charaglobalitem ( CharacterId, itemId, catalogId, stack, flags ) VALUES ( " +
|
||||
std::to_string( getId() ) + ", " +
|
||||
std::to_string( pItem->getUId() ) + ", " +
|
||||
std::to_string( pItem->getId() ) + ", " +
|
||||
std::to_string( itemAmount ) + ", " +
|
||||
std::to_string( flags ) + ");" );
|
||||
|
||||
return pItem;
|
||||
}
|
||||
|
||||
bool Core::Entity::Player::loadInventory()
|
||||
{
|
||||
auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >();
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// load active gearset
|
||||
auto res = pDb->query( "SELECT storageId, container_0, container_1, container_2, container_3, "
|
||||
"container_4, container_5, container_6, container_7, "
|
||||
"container_8, container_9, container_10, container_11, "
|
||||
"container_12, container_13 "
|
||||
"FROM charaitemgearset " \
|
||||
"WHERE CharacterId = " + std::to_string( getId() ) + " " \
|
||||
"ORDER BY storageId ASC;" );
|
||||
|
||||
while( res->next() )
|
||||
{
|
||||
uint16_t storageId = res->getUInt16( 1 );
|
||||
|
||||
for( uint32_t i = 1; i <= 14; i++ )
|
||||
{
|
||||
uint64_t uItemId = res->getUInt64( i + 1 );
|
||||
if( uItemId == 0 )
|
||||
continue;
|
||||
|
||||
ItemPtr pItem = Items::Util::loadItem( uItemId );
|
||||
|
||||
if( pItem == nullptr )
|
||||
continue;
|
||||
|
||||
m_inventoryMap[storageId]->getItemMap()[i - 1] = pItem;
|
||||
equipItem( static_cast< EquipSlot >( i - 1 ), pItem, false );
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Load Bags
|
||||
auto bagRes = pDb->query( "SELECT storageId, "
|
||||
"container_0, container_1, container_2, container_3, container_4, "
|
||||
"container_5, container_6, container_7, container_8, container_9, "
|
||||
"container_10, container_11, container_12, container_13, container_14, "
|
||||
"container_15, container_16, container_17, container_18, container_19, "
|
||||
"container_20, container_21, container_22, container_23, container_24, "
|
||||
"container_25, container_26, container_27, container_28, container_29, "
|
||||
"container_30, container_31, container_32, container_33, container_34 "
|
||||
"FROM charaiteminventory " \
|
||||
"WHERE CharacterId = " + std::to_string( getId() ) + " " \
|
||||
"ORDER BY storageId ASC;" );
|
||||
|
||||
while( bagRes->next() )
|
||||
{
|
||||
uint16_t storageId = bagRes->getUInt16( 1 );
|
||||
for( uint32_t i = 1; i <= 35; i++ )
|
||||
{
|
||||
uint64_t uItemId = bagRes->getUInt64( i + 1 );
|
||||
if( uItemId == 0 )
|
||||
continue;
|
||||
|
||||
ItemPtr pItem = Items::Util::loadItem( uItemId );
|
||||
|
||||
if( pItem == nullptr )
|
||||
continue;
|
||||
|
||||
m_inventoryMap[storageId]->getItemMap()[i - 1] = pItem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Load Currency
|
||||
auto curRes = pDb->query( "SELECT storageId, "
|
||||
"container_0, container_1, container_2, container_3, container_4, "
|
||||
"container_5, container_6, container_7, container_8, container_9, "
|
||||
"container_10, container_11 "
|
||||
"FROM charaitemcurrency " \
|
||||
"WHERE CharacterId = " + std::to_string( getId() ) + " " \
|
||||
"ORDER BY storageId ASC;" );
|
||||
|
||||
while( curRes->next() )
|
||||
{
|
||||
uint16_t storageId = curRes->getUInt16( 1 );
|
||||
for( uint32_t i = 1; i <= 12; i++ )
|
||||
{
|
||||
uint64_t uItemId = curRes->getUInt64( i + 1 );
|
||||
if( uItemId == 0 )
|
||||
continue;
|
||||
|
||||
ItemPtr pItem = Items::Util::loadItem( uItemId );
|
||||
|
||||
if( pItem == nullptr )
|
||||
continue;
|
||||
|
||||
m_inventoryMap[storageId]->getItemMap()[i - 1] = pItem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Load Crystals
|
||||
auto crystalRes = pDb->query( "SELECT storageId, "
|
||||
"container_0, container_1, container_2, container_3, container_4, "
|
||||
"container_5, container_6, container_7, container_8, container_9, "
|
||||
"container_10, container_11, container_12, container_13, container_14, "
|
||||
"container_15, container_16, container_17 "
|
||||
"FROM charaitemcrystal " \
|
||||
"WHERE CharacterId = " + std::to_string( getId() ) + " " \
|
||||
"ORDER BY storageId ASC;" );
|
||||
|
||||
while( crystalRes->next() )
|
||||
{
|
||||
uint16_t storageId = crystalRes->getUInt16( 1 );
|
||||
for( int32_t i = 1; i <= 17; i++ )
|
||||
{
|
||||
uint64_t uItemId = crystalRes->getUInt64( i + 1 );
|
||||
if( uItemId == 0 )
|
||||
continue;
|
||||
|
||||
ItemPtr pItem = Items::Util::loadItem( uItemId );
|
||||
|
||||
if( pItem == nullptr )
|
||||
continue;
|
||||
|
||||
m_inventoryMap[storageId]->getItemMap()[i - 1] = pItem;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -24,9 +24,7 @@ namespace Core
|
|||
TYPE_FORWARD( InstanceContent );
|
||||
TYPE_FORWARD( Item );
|
||||
TYPE_FORWARD( ItemContainer );
|
||||
TYPE_FORWARD( Inventory );
|
||||
TYPE_FORWARD( Session );
|
||||
TYPE_FORWARD( XMLConfig );
|
||||
TYPE_FORWARD( ZonePosition )
|
||||
|
||||
namespace StatusEffect
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,88 +0,0 @@
|
|||
#ifndef INVENTORY_H_
|
||||
#define INVENTORY_H_
|
||||
#include <map>
|
||||
#include <Common.h>
|
||||
#include "Forwards.h"
|
||||
|
||||
namespace Core
|
||||
{
|
||||
|
||||
class ItemContainer;
|
||||
|
||||
using InventoryMap = std::map< uint16_t, ItemContainerPtr >;
|
||||
class Inventory
|
||||
{
|
||||
public:
|
||||
Inventory( Entity::Player* pOwner );
|
||||
~Inventory();
|
||||
|
||||
using InvSlotPair = std::pair< uint16_t, int8_t >;
|
||||
typedef std::vector< InvSlotPair > InvSlotPairVec;
|
||||
|
||||
InvSlotPairVec getSlotsOfItemsInInventory( uint32_t catalogId );
|
||||
InvSlotPair getFreeBagSlot();
|
||||
int16_t addItem( uint16_t inventoryId, int8_t slotId, uint32_t catalogId, uint16_t quantity = 1, bool isHq = false, bool silent = false );
|
||||
void moveItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot );
|
||||
void swapItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot );
|
||||
void discardItem( uint16_t fromInventoryId, uint8_t fromSlotId );
|
||||
void splitItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot, uint16_t splitCount );
|
||||
void mergeItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot );
|
||||
|
||||
ItemPtr createItem( uint32_t catalogId, uint16_t quantity = 1 );
|
||||
|
||||
ItemPtr loadItem( uint64_t uId );
|
||||
|
||||
ItemPtr getItemAt( uint16_t containerId, uint8_t slotId );
|
||||
|
||||
bool updateContainer( uint16_t containerId, uint8_t slotId, ItemPtr pItem );
|
||||
|
||||
/*! heck if weapon category qualifies the weapon as onehanded */
|
||||
bool isOneHandedWeapon( Common::ItemUICategory weaponCategory );
|
||||
/*! calculate and return player ilvl based off equipped gear */
|
||||
uint16_t calculateEquippedGearItemLevel();
|
||||
/*! return the current amount of currency of type */
|
||||
uint32_t getCurrency( Common::CurrencyType type );
|
||||
/*! add amount to the current of type */
|
||||
bool addCurrency( Common::CurrencyType type, uint32_t amount );
|
||||
/*! remove amount from the currency of type */
|
||||
bool removeCurrency( Common::CurrencyType type, uint32_t amount );
|
||||
|
||||
void updateCurrencyDb();
|
||||
void updateBagDb( Common::InventoryType type );
|
||||
void updateMannequinDb( Common::InventoryType type );
|
||||
void updateItemDb( ItemPtr pItem ) const;
|
||||
void deleteItemDb( ItemPtr pItem ) const;
|
||||
|
||||
bool isArmory( uint16_t containerId );
|
||||
bool isEquipment( uint16_t containerId );
|
||||
uint16_t getArmoryToEquipSlot( uint8_t slotId );
|
||||
|
||||
/*! return the crystal amount of currency of type */
|
||||
uint32_t getCrystal( Common::CrystalType type );
|
||||
/*! add amount to the crystal of type */
|
||||
bool addCrystal( Common::CrystalType type, uint32_t amount );
|
||||
/*! remove amount from the crystals of type */
|
||||
bool removeCrystal( Common::CrystalType type, uint32_t amount );
|
||||
bool isObtainable( uint32_t catalogId, uint8_t quantity );
|
||||
|
||||
void updateCrystalDb();
|
||||
|
||||
bool load();
|
||||
|
||||
void send();
|
||||
|
||||
uint8_t getFreeSlotsInBags();
|
||||
|
||||
Common::ContainerType getContainerType( uint32_t containerId );
|
||||
|
||||
uint32_t getNextUId();
|
||||
|
||||
|
||||
private:
|
||||
Entity::Player* m_pOwner;
|
||||
InventoryMap m_inventoryMap;
|
||||
const uint32_t m_maxSlotSize = 999;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
|
@ -24,6 +24,7 @@ Core::Item::Item( uint64_t uId, uint32_t catalogId, uint64_t model1, uint64_t mo
|
|||
m_autoAttackDmg = static_cast< float >( m_weaponDmg * m_delayMs ) / 3000;
|
||||
m_category = static_cast< Common::ItemUICategory >( itemInfo->itemUICategory );
|
||||
m_itemLevel = itemInfo->levelItem;
|
||||
m_maxStackSize = itemInfo->stackSize;
|
||||
}
|
||||
|
||||
float Core::Item::getAutoAttackDmg() const
|
||||
|
@ -126,3 +127,8 @@ void Core::Item::setHq( bool isHq )
|
|||
{
|
||||
m_isHq = isHq;
|
||||
}
|
||||
|
||||
uint32_t Core::Item::getMaxStackSize() const
|
||||
{
|
||||
return m_maxStackSize;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,8 @@ public:
|
|||
|
||||
uint16_t getItemLevel() const;
|
||||
|
||||
uint32_t getMaxStackSize() const;
|
||||
|
||||
|
||||
protected:
|
||||
uint32_t m_id;
|
||||
|
@ -61,6 +63,7 @@ protected:
|
|||
Common::ItemUICategory m_category;
|
||||
|
||||
uint32_t m_stackSize;
|
||||
uint32_t m_maxStackSize;
|
||||
std::vector< uint8_t > m_classJobList;
|
||||
|
||||
uint64_t m_model1;
|
||||
|
|
171
src/servers/sapphire_zone/Inventory/ItemUtil.cpp
Normal file
171
src/servers/sapphire_zone/Inventory/ItemUtil.cpp
Normal file
|
@ -0,0 +1,171 @@
|
|||
#include "ItemUtil.h"
|
||||
|
||||
#include "ItemContainer.h"
|
||||
#include "Item.h"
|
||||
#include "Framework.h"
|
||||
#include <Network/CommonActorControl.h>
|
||||
|
||||
#include <Exd/ExdDataGenerated.h>
|
||||
#include <Logging/Logger.h>
|
||||
#include <Database/DatabaseDef.h>
|
||||
|
||||
|
||||
extern Core::Framework g_fw;
|
||||
|
||||
bool Core::Items::Util::isArmory( uint16_t containerId )
|
||||
{
|
||||
return
|
||||
containerId == Common::ArmoryBody ||
|
||||
containerId == Common::ArmoryEar ||
|
||||
containerId == Common::ArmoryFeet ||
|
||||
containerId == Common::ArmoryHand ||
|
||||
containerId == Common::ArmoryHead ||
|
||||
containerId == Common::ArmoryLegs ||
|
||||
containerId == Common::ArmoryMain ||
|
||||
containerId == Common::ArmoryOff ||
|
||||
containerId == Common::ArmoryRing ||
|
||||
containerId == Common::ArmoryWaist ||
|
||||
containerId == Common::ArmoryWrist;
|
||||
}
|
||||
|
||||
uint16_t Core::Items::Util::getArmoryToEquipSlot( uint8_t slotId )
|
||||
{
|
||||
switch( slotId )
|
||||
{
|
||||
case Common::Body:
|
||||
return Common::ArmoryBody;
|
||||
|
||||
case Common::Ear:
|
||||
return Common::ArmoryEar;
|
||||
|
||||
case Common::Feet:
|
||||
return Common::ArmoryFeet;
|
||||
|
||||
case Common::Hands:
|
||||
return Common::ArmoryHand;
|
||||
|
||||
case Common::Legs:
|
||||
return Common::ArmoryLegs;
|
||||
|
||||
case Common::MainHand:
|
||||
return Common::ArmoryMain;
|
||||
|
||||
case Common::OffHand:
|
||||
return Common::ArmoryOff;
|
||||
|
||||
case Common::Ring2:
|
||||
case Common::Ring1:
|
||||
return Common::ArmoryRing;
|
||||
|
||||
case Common::Waist:
|
||||
return Common::ArmoryWaist;
|
||||
|
||||
case Common::Wrist:
|
||||
return Common::ArmoryWrist;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Core::Items::Util::isEquipment( uint16_t containerId )
|
||||
{
|
||||
return containerId == Common::GearSet0;
|
||||
}
|
||||
|
||||
|
||||
bool Core::Items::Util::isOneHandedWeapon( Common::ItemUICategory weaponCategory )
|
||||
{
|
||||
switch ( weaponCategory )
|
||||
{
|
||||
case Common::ItemUICategory::AlchemistsPrimaryTool:
|
||||
case Common::ItemUICategory::ArmorersPrimaryTool:
|
||||
case Common::ItemUICategory::BotanistsPrimaryTool:
|
||||
case Common::ItemUICategory::CulinariansPrimaryTool:
|
||||
case Common::ItemUICategory::OnehandedConjurersArm:
|
||||
case Common::ItemUICategory::CarpentersPrimaryTool:
|
||||
case Common::ItemUICategory::FishersPrimaryTool:
|
||||
case Common::ItemUICategory::GladiatorsArm:
|
||||
case Common::ItemUICategory::GoldsmithsPrimaryTool:
|
||||
case Common::ItemUICategory::LeatherworkersPrimaryTool:
|
||||
case Common::ItemUICategory::MinersPrimaryTool:
|
||||
case Common::ItemUICategory::OnehandedThaumaturgesArm:
|
||||
case Common::ItemUICategory::WeaversPrimaryTool:
|
||||
case Common::ItemUICategory::BlacksmithsPrimaryTool:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Core::ItemPtr Core::Items::Util::loadItem( uint64_t uId )
|
||||
{
|
||||
auto pExdData = g_fw.get< Data::ExdDataGenerated >();
|
||||
auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >();
|
||||
// load actual item
|
||||
auto itemRes = pDb->query( "SELECT catalogId, stack, flags FROM charaglobalitem WHERE itemId = " + std::to_string( uId ) + ";" );
|
||||
if( !itemRes->next() )
|
||||
return nullptr;
|
||||
|
||||
try
|
||||
{
|
||||
auto itemInfo = pExdData->get< Core::Data::Item >( itemRes->getUInt( 1 ) );
|
||||
bool isHq = itemRes->getUInt( 3 ) == 1;
|
||||
|
||||
ItemPtr pItem = make_Item( uId,
|
||||
itemRes->getUInt( 1 ),
|
||||
itemInfo->modelMain,
|
||||
itemInfo->modelSub,
|
||||
isHq );
|
||||
|
||||
pItem->setStackSize( itemRes->getUInt( 2 ) );
|
||||
|
||||
return pItem;
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Core::Common::ContainerType Core::Items::Util::getContainerType( uint32_t containerId )
|
||||
{
|
||||
if( containerId < 5 )
|
||||
{
|
||||
return Common::Bag;
|
||||
}
|
||||
else if( containerId < 2000 )
|
||||
{
|
||||
return Common::GearSet;
|
||||
}
|
||||
else if( containerId < 3200 )
|
||||
{
|
||||
return Common::CurrencyCrystal;
|
||||
}
|
||||
else if( containerId < 3600 )
|
||||
{
|
||||
return Common::Armory;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Common::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t Core::Items::Util::getNextUId()
|
||||
{
|
||||
uint32_t charId = 0;
|
||||
auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >();
|
||||
auto pQR = pDb->query( "SELECT MAX(ItemId) FROM charaglobalitem" );
|
||||
|
||||
if( !pQR->next() )
|
||||
return 0x00500001;
|
||||
|
||||
charId = pQR->getUInt( 1 ) + 1;
|
||||
if( charId < 0x00500001 )
|
||||
return 0x00500001;
|
||||
|
||||
return charId;
|
||||
}
|
30
src/servers/sapphire_zone/Inventory/ItemUtil.h
Normal file
30
src/servers/sapphire_zone/Inventory/ItemUtil.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef SAPPHIRE_ITEMUTIL_H
|
||||
#define SAPPHIRE_ITEMUTIL_H
|
||||
|
||||
#include <Common.h>
|
||||
#include "Forwards.h"
|
||||
|
||||
namespace Core {
|
||||
namespace Items {
|
||||
namespace Util {
|
||||
|
||||
ItemPtr loadItem( uint64_t uId );
|
||||
|
||||
/*! check if weapon category qualifies the weapon as onehanded */
|
||||
bool isOneHandedWeapon( Common::ItemUICategory weaponCategory );
|
||||
|
||||
bool isArmory( uint16_t containerId );
|
||||
bool isEquipment( uint16_t containerId );
|
||||
uint16_t getArmoryToEquipSlot( uint8_t slotId );
|
||||
|
||||
Common::ContainerType getContainerType( uint32_t containerId );
|
||||
|
||||
uint32_t getNextUId();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif //SAPPHIRE_ITEMMGR_H
|
|
@ -196,7 +196,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::FFXIVARR_PACKET_R
|
|||
case GmCommand::Inspect:
|
||||
{
|
||||
player.sendNotice( "Name: " + targetPlayer->getName() +
|
||||
"\nGil: " + std::to_string( targetPlayer->getCurrency( 1 ) ) +
|
||||
"\nGil: " + std::to_string( targetPlayer->getCurrency( CurrencyType::Gil ) ) +
|
||||
"\nZone: " + targetPlayer->getCurrentZone()->getName() +
|
||||
"(" + std::to_string( targetPlayer->getZoneId() ) + ")" +
|
||||
"\nClass: " + std::to_string( static_cast< uint8_t >( targetPlayer->getClass() ) ) +
|
||||
|
@ -329,13 +329,13 @@ void Core::Network::GameConnection::gm1Handler( const Packets::FFXIVARR_PACKET_R
|
|||
}
|
||||
case GmCommand::Gil:
|
||||
{
|
||||
targetPlayer->addCurrency( 1, param1 );
|
||||
targetPlayer->addCurrency( CurrencyType::Gil, param1 );
|
||||
player.sendNotice( "Added " + std::to_string( param1 ) + " Gil for " + targetPlayer->getName() );
|
||||
break;
|
||||
}
|
||||
case GmCommand::Collect:
|
||||
{
|
||||
uint32_t gil = targetPlayer->getCurrency( 1 );
|
||||
uint32_t gil = targetPlayer->getCurrency( CurrencyType::Gil );
|
||||
|
||||
if( gil < param1 )
|
||||
{
|
||||
|
|
|
@ -58,31 +58,31 @@ void Core::Network::GameConnection::inventoryModifyHandler( const Packets::FFXIV
|
|||
|
||||
case InventoryOperation::Discard: // discard item action
|
||||
{
|
||||
player.getInventory()->discardItem( fromContainer, fromSlot );
|
||||
player.discardItem( fromContainer, fromSlot );
|
||||
}
|
||||
break;
|
||||
|
||||
case InventoryOperation::Move: // move item action
|
||||
{
|
||||
player.getInventory()->moveItem( fromContainer, fromSlot, toContainer, toSlot );
|
||||
player.moveItem( fromContainer, fromSlot, toContainer, toSlot );
|
||||
}
|
||||
break;
|
||||
|
||||
case InventoryOperation::Swap: // swap item action
|
||||
{
|
||||
player.getInventory()->swapItem( fromContainer, fromSlot, toContainer, toSlot );
|
||||
player.swapItem( fromContainer, fromSlot, toContainer, toSlot );
|
||||
}
|
||||
break;
|
||||
|
||||
case InventoryOperation::Merge: // merge stack action
|
||||
{
|
||||
player.getInventory()->mergeItem( fromContainer, fromSlot, toContainer, toSlot );
|
||||
player.mergeItem( fromContainer, fromSlot, toContainer, toSlot );
|
||||
}
|
||||
break;
|
||||
|
||||
case InventoryOperation::Split: // split stack action
|
||||
{
|
||||
player.getInventory()->splitItem( fromContainer, fromSlot, toContainer, toSlot, splitCount );
|
||||
player.splitItem( fromContainer, fromSlot, toContainer, toSlot, splitCount );
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include <Util/Util.h>
|
||||
#include "Actor/Player.h"
|
||||
#include "Forwards.h"
|
||||
#include "Inventory/Inventory.h"
|
||||
#include "Inventory/Item.h"
|
||||
#include "StatusEffect/StatusEffect.h"
|
||||
|
||||
|
@ -50,7 +49,7 @@ namespace Server {
|
|||
|
||||
memcpy( m_data.look, player.getLookArray(), 26 );
|
||||
|
||||
auto item = player.getInventory()->getItemAt( Common::GearSet0, Common::EquipSlot::MainHand );
|
||||
auto item = player.getItemAt( Common::GearSet0, Common::EquipSlot::MainHand );
|
||||
if( item )
|
||||
m_data.mainWeaponModel = item->getModelId1();
|
||||
m_data.secWeaponModel = player.getModelSubWeapon();
|
||||
|
|
Loading…
Add table
Reference in a new issue