mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-27 14:57:44 +00:00
Merge pull request #885 from Skyliegirl33/master
[3.x] Dyeing implemented and inventory fixes
This commit is contained in:
commit
d73e63a93c
14 changed files with 195 additions and 10 deletions
|
@ -548,6 +548,7 @@ namespace Sapphire::Network::ActorControl
|
|||
REQUEST_SALVAGE_SUCCESS_RATE = 0x1B2,
|
||||
MOBHUNT_RECEIPT_ORDER = 0x1B3,
|
||||
MOBHUNT_BREAK_ORDER = 0x1B4,
|
||||
DYE_ITEM = 0x1B5,
|
||||
EMOTE = 0x1F4,
|
||||
EMOTE_WITH_WARP = 0x1F5,
|
||||
EMOTE_CANCEL = 0x1F6,
|
||||
|
|
|
@ -1145,6 +1145,12 @@ namespace Sapphire::Network::Packets::WorldPackets::Server
|
|||
ZoneProtoDownNormalItem item;
|
||||
};
|
||||
|
||||
struct FFXIVIpcUpdateItem : FFXIVIpcBasePacket< UpdateItem >
|
||||
{
|
||||
uint32_t contextId;
|
||||
ZoneProtoDownNormalItem item;
|
||||
};
|
||||
|
||||
struct FFXIVIpcItemSize : FFXIVIpcBasePacket< ItemSize >
|
||||
{
|
||||
uint32_t contextId;
|
||||
|
|
70
src/world/Action/ItemManipulationAction.cpp
Normal file
70
src/world/Action/ItemManipulationAction.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
#include "ItemManipulationAction.h"
|
||||
|
||||
#include <Exd/ExdData.h>
|
||||
|
||||
#include "Script/ScriptMgr.h"
|
||||
|
||||
#include "Actor/Player.h"
|
||||
#include "Actor/BNpc.h"
|
||||
|
||||
#include <Logging/Logger.h>
|
||||
|
||||
#include <Service.h>
|
||||
#include "WorldServer.h"
|
||||
|
||||
using namespace Sapphire;
|
||||
using namespace Sapphire::World::Action;
|
||||
using namespace Sapphire::Network::Packets::WorldPackets::Server;
|
||||
|
||||
ItemManipulationAction::ItemManipulationAction( Entity::CharaPtr source, uint32_t actionId, uint16_t sequence,
|
||||
std::shared_ptr< Excel::ExcelStruct< Excel::Action > > actionData, uint32_t delayTime ) :
|
||||
m_delayTimeMs( delayTime )
|
||||
{
|
||||
m_id = actionId;
|
||||
m_pSource = std::move( source );
|
||||
m_actionData = std::move( actionData );
|
||||
m_sequence = sequence;
|
||||
}
|
||||
|
||||
void ItemManipulationAction::start()
|
||||
{
|
||||
assert( m_pSource );
|
||||
m_startTime = Common::Util::getTimeMs();
|
||||
|
||||
onStart();
|
||||
|
||||
execute();
|
||||
}
|
||||
|
||||
void ItemManipulationAction::execute()
|
||||
{
|
||||
assert( m_pSource );
|
||||
|
||||
m_effectBuilder->buildAndSendPackets( m_hitActors );
|
||||
}
|
||||
|
||||
void ItemManipulationAction::onFinish()
|
||||
{
|
||||
auto& scriptMgr = Common::Service< Scripting::ScriptMgr >::ref();
|
||||
|
||||
// send execute event to action script
|
||||
scriptMgr.onExecute( *this );
|
||||
}
|
||||
|
||||
bool ItemManipulationAction::update()
|
||||
{
|
||||
// action has not been started yet
|
||||
if( m_startTime == 0 )
|
||||
return false;
|
||||
|
||||
uint64_t tickCount = Common::Util::getTimeMs();
|
||||
uint32_t delayTime = m_delayTimeMs;
|
||||
|
||||
if( std::difftime( static_cast< time_t >( tickCount ), static_cast< time_t >( m_startTime ) ) > delayTime )
|
||||
{
|
||||
onFinish();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
26
src/world/Action/ItemManipulationAction.h
Normal file
26
src/world/Action/ItemManipulationAction.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include "Action.h"
|
||||
#include <Exd/Structs.h>
|
||||
|
||||
namespace Sapphire::World::Action
|
||||
{
|
||||
class ItemManipulationAction : public Action
|
||||
{
|
||||
public:
|
||||
ItemManipulationAction( Entity::CharaPtr source, uint32_t actionId, uint16_t sequence,
|
||||
std::shared_ptr< Excel::ExcelStruct< Excel::Action > > actionData, uint32_t delayTime );
|
||||
virtual ~ItemManipulationAction() = default;
|
||||
|
||||
void start() override;
|
||||
|
||||
void execute() override;
|
||||
|
||||
bool update() override;
|
||||
|
||||
private:
|
||||
void onFinish();
|
||||
|
||||
uint32_t m_delayTimeMs{};
|
||||
};
|
||||
}
|
|
@ -1624,13 +1624,19 @@ void Player::dyeItemFromDyeingInfo()
|
|||
if( !itemToDye || !dyeToUse )
|
||||
return;
|
||||
|
||||
uint32_t stainColorID = dyeToUse->getAdditionalData();
|
||||
itemToDye->setStain( stainColorID );
|
||||
if( !removeItem( dyeToUse->getId() ) )
|
||||
return;
|
||||
|
||||
// TODO: subtract/remove dye used
|
||||
uint32_t stainColorID = dyeToUse->getAdditionalData();
|
||||
bool shouldDye = stainColorID != 0;
|
||||
bool invalidateGearSet = stainColorID != itemToDye->getStain();
|
||||
itemToDye->setStain( stainColorID );
|
||||
|
||||
insertInventoryItem( static_cast< Sapphire::Common::InventoryType >( itemToDyeContainer ), static_cast< uint16_t >( itemToDyeSlot ), itemToDye );
|
||||
writeItem( itemToDye );
|
||||
|
||||
auto dyePkt = makeActorControlSelf( getId(), DyeMsg, itemToDye->getId(), shouldDye, invalidateGearSet );
|
||||
queuePacket( dyePkt );
|
||||
}
|
||||
|
||||
void Player::resetObjSpawnIndex()
|
||||
|
|
|
@ -722,6 +722,8 @@ namespace Sapphire::Entity
|
|||
|
||||
ItemPtr addItem( uint32_t catalogId, uint32_t quantity = 1, bool isHq = false, bool slient = false, bool canMerge = true );
|
||||
|
||||
bool removeItem( uint32_t catalogId, uint32_t quantity = 1, bool isHq = false );
|
||||
|
||||
void moveItem( uint16_t fromInventoryId, uint16_t fromSlotId, uint16_t toInventoryId, uint16_t toSlot );
|
||||
|
||||
void swapItem( uint16_t fromInventoryId, uint16_t fromSlotId, uint16_t toInventoryId, uint16_t toSlot );
|
||||
|
|
|
@ -720,6 +720,54 @@ Sapphire::ItemPtr Sapphire::Entity::Player::addItem( uint32_t catalogId, uint32_
|
|||
return item;
|
||||
}
|
||||
|
||||
bool Sapphire::Entity::Player::removeItem( uint32_t catalogId, uint32_t quantity, bool isHq )
|
||||
{
|
||||
std::vector< uint16_t > bags = { Bag0, Bag1, Bag2, Bag3 };
|
||||
|
||||
for( auto bag : bags )
|
||||
{
|
||||
auto storage = m_storageMap[ bag ];
|
||||
|
||||
for( uint16_t slot = 0; slot < storage->getMaxSize(); slot++ )
|
||||
{
|
||||
if( quantity == 0 )
|
||||
break;
|
||||
|
||||
auto item = storage->getItem( slot );
|
||||
|
||||
// remove any matching items
|
||||
if( item && item->getId() == catalogId )
|
||||
{
|
||||
uint32_t count = item->getStackSize();
|
||||
uint32_t maxStack = item->getMaxStackSize();
|
||||
|
||||
// check slot is same quality
|
||||
if( item->isHq() != isHq )
|
||||
continue;
|
||||
|
||||
// update stack
|
||||
int32_t newStackSize = count - quantity;
|
||||
if( newStackSize <= 0 )
|
||||
{
|
||||
quantity = std::abs( newStackSize );
|
||||
discardItem( bag, slot );
|
||||
}
|
||||
else
|
||||
{
|
||||
quantity = 0;
|
||||
item->setStackSize( newStackSize );
|
||||
|
||||
insertInventoryItem( static_cast< Sapphire::Common::InventoryType >( bag ), slot, item );
|
||||
|
||||
writeItem( item );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return quantity == 0;
|
||||
}
|
||||
|
||||
void
|
||||
Sapphire::Entity::Player::moveItem( uint16_t fromInventoryId, uint16_t fromSlotId, uint16_t toInventoryId, uint16_t toSlot )
|
||||
{
|
||||
|
|
|
@ -87,6 +87,7 @@ TYPE_FORWARD( EventAction );
|
|||
TYPE_FORWARD( ItemAction );
|
||||
TYPE_FORWARD( EventItemAction );
|
||||
TYPE_FORWARD( MountAction );
|
||||
TYPE_FORWARD( ItemManipulationAction );
|
||||
TYPE_FORWARD( EffectBuilder );
|
||||
TYPE_FORWARD( EffectResult );
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "Action/ItemAction.h"
|
||||
#include "Action/EventItemAction.h"
|
||||
#include "Action/MountAction.h"
|
||||
#include "Action/ItemManipulationAction.h"
|
||||
#include "Script/ScriptMgr.h"
|
||||
#include "Actor/Player.h"
|
||||
|
||||
|
@ -45,6 +46,19 @@ void ActionMgr::handlePlacedPlayerAction( Entity::Player& player, uint32_t actio
|
|||
bootstrapAction( player, action, actionData );
|
||||
}
|
||||
|
||||
void ActionMgr::handleItemManipulationAction( Entity::Player& player, uint32_t actionId,
|
||||
Excel::ExcelStructPtr< Excel::Action > actionData, uint16_t sequence )
|
||||
{
|
||||
auto action = Action::make_ItemManipulationAction( player.getAsPlayer(), actionId, sequence, actionData, 2500 ); // todo: maybe the delay can be retrieved from data
|
||||
|
||||
player.setCurrentAction( action );
|
||||
|
||||
if( !action->init() )
|
||||
return;
|
||||
|
||||
action->start();
|
||||
}
|
||||
|
||||
void ActionMgr::handleTargetedPlayerAction( Entity::Player& player, uint32_t actionId,
|
||||
Excel::ExcelStructPtr< Excel::Action > actionData, uint64_t targetId, uint16_t sequence )
|
||||
{
|
||||
|
|
|
@ -22,6 +22,9 @@ namespace Sapphire::World::Manager
|
|||
|
||||
bool cacheActionLut();
|
||||
|
||||
void handleItemManipulationAction( Entity::Player& player, uint32_t actionId,
|
||||
Excel::ExcelStructPtr< Excel::Action > actionData, uint16_t sequence );
|
||||
|
||||
void handleTargetedPlayerAction( Entity::Player& player, uint32_t actionId,
|
||||
std::shared_ptr< Excel::ExcelStruct< Excel::Action > > actionData, uint64_t targetId, uint16_t sequence );
|
||||
void handlePlacedPlayerAction( Entity::Player& player, uint32_t actionId,
|
||||
|
|
|
@ -47,7 +47,12 @@ void Sapphire::Network::GameConnection::actionRequest( const Packets::FFXIVARR_P
|
|||
if( !action )
|
||||
return;
|
||||
|
||||
actionMgr.handleTargetedPlayerAction( player, actionId, action, targetId, sequence );
|
||||
auto category = static_cast< Common::ActionCategory >( action->data().Category );
|
||||
|
||||
if( category == Common::ActionCategory::ItemManipulation )
|
||||
actionMgr.handleItemManipulationAction( player, actionId, action, sequence );
|
||||
else
|
||||
actionMgr.handleTargetedPlayerAction( player, actionId, action, targetId, sequence );
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ void Sapphire::Network::GameConnection::itemOperation( const Packets::FFXIVARR_P
|
|||
const auto packet = ZoneChannelPacket< FFXIVIpcClientInventoryItemOperation >( inPacket );
|
||||
|
||||
const auto operationType = packet.data().OperationType;
|
||||
const auto splitCount = packet.data().SrcStack;
|
||||
const auto splitCount = packet.data().DstStack;
|
||||
|
||||
const auto fromSlot = packet.data().SrcContainerIndex;
|
||||
const auto fromContainer = packet.data().SrcStorageId;
|
||||
|
|
|
@ -182,6 +182,8 @@ const char* packetCommandToString( uint16_t commandId )
|
|||
return "MOBHUNT_RECEIPT_ORDER";
|
||||
case MOBHUNT_BREAK_ORDER:
|
||||
return "MOBHUNT_BREAK_ORDER";
|
||||
case DYE_ITEM:
|
||||
return "DYE_ITEM";
|
||||
case EMOTE:
|
||||
return "EMOTE";
|
||||
case EMOTE_WITH_WARP:
|
||||
|
@ -623,7 +625,7 @@ void Sapphire::Network::GameConnection::commandHandler( const Packets::FFXIVARR_
|
|||
player.teleportQuery( static_cast< uint16_t >( param11 ) );
|
||||
break;
|
||||
}
|
||||
/* case PacketCommand::DyeItem: // Dye item
|
||||
case PacketCommand::DYE_ITEM: // Dye item
|
||||
{
|
||||
// param11 = item to dye container
|
||||
// param12 = item to dye slot
|
||||
|
@ -631,7 +633,7 @@ void Sapphire::Network::GameConnection::commandHandler( const Packets::FFXIVARR_
|
|||
// param4 = dye bag slot
|
||||
player.setDyeingInfo( param11, param12, param2, param4 );
|
||||
break;
|
||||
}*/
|
||||
}
|
||||
case PacketCommand::DIRECTOR_INIT_RETURN: // Director init finish
|
||||
{
|
||||
pZone->onInitDirector( player );
|
||||
|
|
|
@ -11,17 +11,17 @@ namespace Sapphire::Network::Packets::WorldPackets::Server
|
|||
/**
|
||||
* @brief The update inventory-slot packet.
|
||||
*/
|
||||
class UpdateInventorySlotPacket : public ZoneChannelPacket< FFXIVIpcNormalItem >
|
||||
class UpdateInventorySlotPacket : public ZoneChannelPacket< FFXIVIpcUpdateItem >
|
||||
{
|
||||
public:
|
||||
UpdateInventorySlotPacket( uint32_t playerId, uint16_t slot, uint16_t storageId, const Item& item, uint32_t contextId ) :
|
||||
ZoneChannelPacket< FFXIVIpcNormalItem >( playerId, playerId )
|
||||
ZoneChannelPacket< FFXIVIpcUpdateItem >( playerId, playerId )
|
||||
{
|
||||
initialize( slot, storageId, item, contextId );
|
||||
};
|
||||
|
||||
UpdateInventorySlotPacket( uint32_t playerId, uint16_t slot, uint16_t storageId, uint32_t contextId ) :
|
||||
ZoneChannelPacket< FFXIVIpcNormalItem >( playerId, playerId )
|
||||
ZoneChannelPacket< FFXIVIpcUpdateItem >( playerId, playerId )
|
||||
{
|
||||
initialize( slot, storageId, contextId );
|
||||
};
|
||||
|
@ -37,6 +37,7 @@ namespace Sapphire::Network::Packets::WorldPackets::Server
|
|||
m_data.item.flags = static_cast< uint8_t >( item.isHq() ? 1 : 0 );
|
||||
m_data.item.refine = item.getSpiritbond();
|
||||
m_data.item.stain = static_cast< uint8_t >( item.getStain() );
|
||||
m_data.item.durability = item.getDurability();
|
||||
m_data.item.signatureId = 0;
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue