mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-27 06:47:45 +00:00
Merge pull request #318 from NotAdam/develop
add item splitting and stacking
This commit is contained in:
commit
c0fd27f73b
4 changed files with 98 additions and 16 deletions
|
@ -69,11 +69,11 @@ namespace Packets {
|
||||||
|
|
||||||
SocialRequestError = 0x00AD,
|
SocialRequestError = 0x00AD,
|
||||||
|
|
||||||
Playtime = 0x00DF, // updated 4.2
|
|
||||||
CFRegistered = 0x00B8, // updated 4.1
|
CFRegistered = 0x00B8, // updated 4.1
|
||||||
SocialRequestResponse = 0x00BB, // updated 4.1
|
SocialRequestResponse = 0x00BB, // updated 4.1
|
||||||
CancelAllianceForming = 0x00C6, // updated 4.2
|
CancelAllianceForming = 0x00C6, // updated 4.2
|
||||||
|
|
||||||
|
Playtime = 0x00F5, // updated 4.3
|
||||||
Chat = 0x00F7, // updated 4.3
|
Chat = 0x00F7, // updated 4.3
|
||||||
SocialList = 0x00FD, // updated 4.3
|
SocialList = 0x00FD, // updated 4.3
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,7 @@ Core::ItemPtr Core::Inventory::getItemAt( uint16_t containerId, uint8_t slotId )
|
||||||
return m_inventoryMap[containerId]->getItem( slotId );
|
return m_inventoryMap[containerId]->getItem( slotId );
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::ItemPtr Core::Inventory::createItem( uint32_t catalogId, uint8_t quantity )
|
Core::ItemPtr Core::Inventory::createItem( uint32_t catalogId, uint16_t quantity )
|
||||||
{
|
{
|
||||||
auto pExdData = g_fw.get< Data::ExdDataGenerated >();
|
auto pExdData = g_fw.get< Data::ExdDataGenerated >();
|
||||||
auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >();
|
auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >();
|
||||||
|
@ -144,7 +144,7 @@ Core::ItemPtr Core::Inventory::createItem( uint32_t catalogId, uint8_t quantity
|
||||||
|
|
||||||
uint8_t flags = 0;
|
uint8_t flags = 0;
|
||||||
|
|
||||||
std::string itemName( itemInfo->name );
|
// std::string itemName( itemInfo->name );
|
||||||
|
|
||||||
ItemPtr pItem( new Item( catalogId ) );
|
ItemPtr pItem( new Item( catalogId ) );
|
||||||
|
|
||||||
|
@ -404,6 +404,12 @@ void Core::Inventory::updateItemDb( Core::ItemPtr pItem ) const
|
||||||
" WHERE itemId = " + std::to_string( pItem->getUId() ) );
|
" WHERE itemId = " + std::to_string( pItem->getUId() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Core::Inventory::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::Inventory::removeCurrency( CurrencyType type, uint32_t amount )
|
bool Core::Inventory::removeCurrency( CurrencyType type, uint32_t amount )
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -473,7 +479,7 @@ bool Core::Inventory::isObtainable( uint32_t catalogId, uint8_t quantity )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int16_t Core::Inventory::addItem( uint16_t inventoryId, int8_t slotId, uint32_t catalogId, uint8_t quantity )
|
int16_t Core::Inventory::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 pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >();
|
||||||
auto pExdData = g_fw.get< Data::ExdDataGenerated >();
|
auto pExdData = g_fw.get< Data::ExdDataGenerated >();
|
||||||
|
@ -505,6 +511,8 @@ int16_t Core::Inventory::addItem( uint16_t inventoryId, int8_t slotId, uint32_t
|
||||||
|
|
||||||
auto item = createItem( catalogId, quantity );
|
auto item = createItem( catalogId, quantity );
|
||||||
|
|
||||||
|
item->setHq( isHq );
|
||||||
|
|
||||||
if( rSlotId != -1 )
|
if( rSlotId != -1 )
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -523,7 +531,8 @@ int16_t Core::Inventory::addItem( uint16_t inventoryId, int8_t slotId, uint32_t
|
||||||
invUpPacket.data().condition = 30000;
|
invUpPacket.data().condition = 30000;
|
||||||
m_pOwner->queuePacket( invUpPacket );
|
m_pOwner->queuePacket( invUpPacket );
|
||||||
|
|
||||||
m_pOwner->queuePacket( ActorControlPacket143( m_pOwner->getId(), ItemObtainIcon, catalogId, item->getStackSize() ) );
|
if( !silent )
|
||||||
|
m_pOwner->queuePacket( ActorControlPacket143( m_pOwner->getId(), ItemObtainIcon, catalogId, item->getStackSize() ) );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,6 +607,71 @@ bool Core::Inventory::updateContainer( uint16_t containerId, uint8_t slotId, Ite
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Core::Inventory::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::Inventory::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 >( m_maxSlotSize, 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::Inventory::swapItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot )
|
void Core::Inventory::swapItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot )
|
||||||
{
|
{
|
||||||
auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId );
|
auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId );
|
||||||
|
@ -632,6 +706,8 @@ void Core::Inventory::discardItem( uint16_t fromInventoryId, uint8_t fromSlotId
|
||||||
|
|
||||||
auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId );
|
auto fromItem = m_inventoryMap[fromInventoryId]->getItem( fromSlotId );
|
||||||
|
|
||||||
|
deleteItemDb( fromItem );
|
||||||
|
|
||||||
m_inventoryMap[fromInventoryId]->removeItem( fromSlotId );
|
m_inventoryMap[fromInventoryId]->removeItem( fromSlotId );
|
||||||
updateContainer( fromInventoryId, fromSlotId, nullptr );
|
updateContainer( fromInventoryId, fromSlotId, nullptr );
|
||||||
|
|
||||||
|
|
|
@ -140,12 +140,14 @@ public:
|
||||||
|
|
||||||
InvSlotPairVec getSlotsOfItemsInInventory( uint32_t catalogId );
|
InvSlotPairVec getSlotsOfItemsInInventory( uint32_t catalogId );
|
||||||
InvSlotPair getFreeBagSlot();
|
InvSlotPair getFreeBagSlot();
|
||||||
int16_t addItem( uint16_t inventoryId, int8_t slotId, uint32_t catalogId, uint8_t quantity = 1 );
|
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 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 swapItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot );
|
||||||
void discardItem( uint16_t fromInventoryId, uint8_t fromSlotId );
|
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, uint8_t quantity = 1 );
|
ItemPtr createItem( uint32_t catalogId, uint16_t quantity = 1 );
|
||||||
|
|
||||||
ItemPtr loadItem( uint64_t uId );
|
ItemPtr loadItem( uint64_t uId );
|
||||||
|
|
||||||
|
@ -168,6 +170,7 @@ public:
|
||||||
void updateBagDb( InventoryType type );
|
void updateBagDb( InventoryType type );
|
||||||
void updateMannequinDb( InventoryType type );
|
void updateMannequinDb( InventoryType type );
|
||||||
void updateItemDb( ItemPtr pItem ) const;
|
void updateItemDb( ItemPtr pItem ) const;
|
||||||
|
void deleteItemDb( ItemPtr pItem ) const;
|
||||||
|
|
||||||
bool isArmory( uint16_t containerId );
|
bool isArmory( uint16_t containerId );
|
||||||
bool isEquipment( uint16_t containerId );
|
bool isEquipment( uint16_t containerId );
|
||||||
|
@ -197,6 +200,7 @@ public:
|
||||||
private:
|
private:
|
||||||
Entity::Player* m_pOwner;
|
Entity::Player* m_pOwner;
|
||||||
InventoryMap m_inventoryMap;
|
InventoryMap m_inventoryMap;
|
||||||
|
const uint32_t m_maxSlotSize = 999;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,8 @@ void Core::Network::GameConnection::inventoryModifyHandler( const Packets::GameP
|
||||||
uint8_t toSlot = inPacket.getValAt< uint8_t >( 0x44 );
|
uint8_t toSlot = inPacket.getValAt< uint8_t >( 0x44 );
|
||||||
uint16_t fromContainer = inPacket.getValAt< uint16_t >( 0x2C );
|
uint16_t fromContainer = inPacket.getValAt< uint16_t >( 0x2C );
|
||||||
uint16_t toContainer = inPacket.getValAt< uint16_t >( 0x40 );
|
uint16_t toContainer = inPacket.getValAt< uint16_t >( 0x40 );
|
||||||
|
// todo: check packet handler in game and see if this is sent as a u16 or u32
|
||||||
|
uint16_t splitCount = inPacket.getValAt< uint16_t >( 0x48 );
|
||||||
|
|
||||||
ZoneChannelPacket< FFXIVIpcInventoryActionAck > ackPacket( player.getId() );
|
ZoneChannelPacket< FFXIVIpcInventoryActionAck > ackPacket( player.getId() );
|
||||||
ackPacket.data().sequence = seq;
|
ackPacket.data().sequence = seq;
|
||||||
|
@ -83,13 +85,13 @@ void Core::Network::GameConnection::inventoryModifyHandler( const Packets::GameP
|
||||||
|
|
||||||
case InventoryOperation::Merge: // merge stack action
|
case InventoryOperation::Merge: // merge stack action
|
||||||
{
|
{
|
||||||
|
player.getInventory()->mergeItem( fromContainer, fromSlot, toContainer, toSlot );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InventoryOperation::Split: // split stack action
|
case InventoryOperation::Split: // split stack action
|
||||||
{
|
{
|
||||||
|
player.getInventory()->splitItem( fromContainer, fromSlot, toContainer, toSlot, splitCount );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue