mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-26 06:27:45 +00:00
Merge pull request #377 from NotAdam/develop
addItem is way less retarded now, stacks are automagically filled first
This commit is contained in:
commit
84393acf15
23 changed files with 251 additions and 184 deletions
|
@ -17,7 +17,7 @@ CREATE TABLE IF NOT EXISTS `characlass` (
|
|||
`ClassIdx` int(3) DEFAULT '0',
|
||||
`Exp` int(10) DEFAULT '0',
|
||||
`Lvl` int(5) DEFAULT '0',
|
||||
PRIMARY KEY (`CharacterId`)
|
||||
INDEX `CharacterId` (`CharacterId`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
|
||||
|
||||
-- Dumping data for table sapphire.characlass: 0 rows
|
||||
|
|
|
@ -49,3 +49,5 @@ ALTER TABLE `charainfo` CHANGE `Minions` `Minions` BINARY(37) NULL DEFAULT NULL;
|
|||
ALTER TABLE `charainfo` CHANGE `QuestCompleteFlags` `QuestCompleteFlags` VARBINARY(396) NULL DEFAULT NULL;
|
||||
ALTER TABLE `charainfo` ADD COLUMN `EquipDisplayFlags` INT(3) NULL DEFAULT '0' AFTER `GMRank`;
|
||||
ALTER TABLE `charainfo` ADD COLUMN `Pose` INT(3) NULL DEFAULT '0' AFTER `EquipDisplayFlags`;
|
||||
|
||||
ALTER TABLE `characlass` DROP PRIMARY KEY, ADD INDEX `CharacterId` (`CharacterId`);
|
|
@ -44,7 +44,7 @@ namespace Common {
|
|||
French = 8
|
||||
};
|
||||
|
||||
enum EquipSlot : uint8_t
|
||||
enum GearSetSlot : uint8_t
|
||||
{
|
||||
MainHand = 0,
|
||||
OffHand = 1,
|
||||
|
@ -62,6 +62,46 @@ namespace Common {
|
|||
SoulCrystal = 13,
|
||||
};
|
||||
|
||||
enum EquipSlotCategory : uint8_t
|
||||
{
|
||||
Unequippable = 0,
|
||||
|
||||
// main slots
|
||||
|
||||
CharaMainHand = 1,
|
||||
CharaOffHand = 2,
|
||||
CharaHead = 3,
|
||||
CharaBody = 4,
|
||||
CharaHands = 5,
|
||||
CharaWaist = 6,
|
||||
CharaLegs = 7,
|
||||
CharaFeet = 8,
|
||||
CharaEars = 9,
|
||||
CharaNeck = 10,
|
||||
CharaWrist = 11,
|
||||
CharaRing = 12,
|
||||
CharaSoulCrystal = 17,
|
||||
|
||||
// specials
|
||||
|
||||
/*! Cannot equip gear to offhand slot */
|
||||
MainTwoHandedWeapon = 13,
|
||||
/*! Can be equipped in either main or offhand slot */
|
||||
MainOrOffHand = 14, // unused
|
||||
/*! Cannot equip gear to head */
|
||||
BodyDisallowHead = 15,
|
||||
/*! Cannot equip gear to hands, legs and feet slots */
|
||||
BodyDisallowHandsLegsFeet = 16,
|
||||
/*! Cannot equip gear to feet slot */
|
||||
LegsDisallowFeet = 18,
|
||||
/*! Cannot equp gear to head, hands, legs, feet slots */
|
||||
BodyDisallowAll = 19,
|
||||
/*! Cannot equip gear to hands slot */
|
||||
BodyDisallowHands = 20,
|
||||
/*! Cannot equip gear to legs & feet slots */
|
||||
BodyDisallowLegsFeet = 21,
|
||||
};
|
||||
|
||||
enum InventoryType : uint16_t
|
||||
{
|
||||
Bag0 = 0,
|
||||
|
@ -87,7 +127,7 @@ namespace Common {
|
|||
ArmoryWaist = 3204,
|
||||
ArmoryLegs = 3205,
|
||||
ArmoryFeet = 3206,
|
||||
ArmotyNeck = 3207,
|
||||
ArmoryNeck = 3207,
|
||||
ArmoryEar = 3208,
|
||||
ArmoryWrist = 3209,
|
||||
ArmoryRing = 3300,
|
||||
|
@ -600,8 +640,8 @@ namespace Common {
|
|||
HideWeapon = 0x2,
|
||||
HideLegacyMark = 0x4,
|
||||
|
||||
StoreNewItemsInArmouryChest = 0x5,
|
||||
StoreCraftedItemsInInventory = 0x6,
|
||||
StoreNewItemsInArmouryChest = 0x10,
|
||||
StoreCraftedItemsInInventory = 0x20,
|
||||
|
||||
Visor = 0x40,
|
||||
};
|
||||
|
|
|
@ -2314,6 +2314,7 @@ Core::Data::Item::Item( uint32_t row_id, Core::Data::ExdDataGenerated* exdData )
|
|||
isUnique = exdData->getField< bool >( row, 20 );
|
||||
isUntradable = exdData->getField< bool >( row, 21 );
|
||||
isIndisposable = exdData->getField< bool >( row, 22 );
|
||||
isEquippable = exdData->getField< bool >( row, 23 );
|
||||
priceMid = exdData->getField< uint32_t >( row, 24 );
|
||||
priceLow = exdData->getField< uint32_t >( row, 25 );
|
||||
canBeHq = exdData->getField< bool >( row, 26 );
|
||||
|
|
|
@ -2406,6 +2406,7 @@ struct Item
|
|||
bool isUnique;
|
||||
bool isUntradable;
|
||||
bool isIndisposable;
|
||||
bool isEquippable;
|
||||
uint32_t priceMid;
|
||||
uint32_t priceLow;
|
||||
bool canBeHq;
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 61712f8f11892d12ad6878a80b9b89b318908558
|
||||
Subproject commit 8c260396dde22977cbee4af537757427d2049ee2
|
|
@ -42,10 +42,10 @@ private:
|
|||
default: itemId = 4426; break;
|
||||
}
|
||||
|
||||
auto item = player.addItem( Common::InventoryType::ArmoryRing, -1, itemId, 1, false, true );
|
||||
auto item = player.addItem( itemId, 1, false, true );
|
||||
|
||||
if( item )
|
||||
player.equipItem( Common::EquipSlot::Ring2, item, true );
|
||||
player.equipItem( Common::GearSetSlot::Ring2, item, true );
|
||||
|
||||
player.setOpeningSequence( 1 );
|
||||
Scene00001( player );
|
||||
|
|
|
@ -57,10 +57,10 @@ private:
|
|||
default: itemId = 4426; break;
|
||||
}
|
||||
|
||||
auto item = player.addItem( Common::InventoryType::ArmoryRing, -1, itemId, 1, false, true );
|
||||
auto item = player.addItem( itemId, 1, false, true );
|
||||
|
||||
if( item )
|
||||
player.equipItem( Common::EquipSlot::Ring2, item, true );
|
||||
player.equipItem( Common::GearSetSlot::Ring2, item, true );
|
||||
|
||||
player.setOpeningSequence( 1 );
|
||||
Scene00001( player );
|
||||
|
|
|
@ -43,10 +43,10 @@ private:
|
|||
default: itemId = 4426; break;
|
||||
}
|
||||
|
||||
auto item = player.addItem( Common::InventoryType::ArmoryRing, -1, itemId, 1, false, true );
|
||||
auto item = player.addItem( itemId, 1, false, true );
|
||||
|
||||
if( item )
|
||||
player.equipItem( Common::EquipSlot::Ring2, item, true );
|
||||
player.equipItem( Common::GearSetSlot::Ring2, item, true );
|
||||
|
||||
player.setOpeningSequence( 1 );
|
||||
Scene00001( player );
|
||||
|
|
|
@ -217,6 +217,9 @@ namespace Core {
|
|||
startTown = 3;
|
||||
startZone = 182;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// "(AccountId, CharacterId, ContentId, Name, Hp, Mp, "
|
||||
|
@ -289,7 +292,7 @@ namespace Core {
|
|||
createInvDbContainer( InventoryType::ArmoryLegs );
|
||||
createInvDbContainer( InventoryType::ArmoryFeet );
|
||||
|
||||
createInvDbContainer( InventoryType::ArmotyNeck );
|
||||
createInvDbContainer( InventoryType::ArmoryNeck );
|
||||
createInvDbContainer( InventoryType::ArmoryEar );
|
||||
createInvDbContainer( InventoryType::ArmoryWrist );
|
||||
createInvDbContainer( InventoryType::ArmoryRing );
|
||||
|
@ -353,15 +356,15 @@ namespace Core {
|
|||
insertDbGlobalItem( 15133, ringUid );
|
||||
|
||||
g_charaDb.execute( "INSERT INTO charaitemgearset (storageId, CharacterId, "
|
||||
"container_" + std::to_string( EquipSlot::MainHand ) + ", "
|
||||
"container_" + std::to_string( EquipSlot::Body ) + ", "
|
||||
"container_" + std::to_string( EquipSlot::Hands ) + ", "
|
||||
"container_" + std::to_string( EquipSlot::Legs ) + ", "
|
||||
"container_" + std::to_string( EquipSlot::Feet ) + ", "
|
||||
"container_" + std::to_string( EquipSlot::Neck ) + ", "
|
||||
"container_" + std::to_string( EquipSlot::Ear ) + ", "
|
||||
"container_" + std::to_string( EquipSlot::Wrist ) + ", "
|
||||
"container_" + std::to_string( EquipSlot::Ring1 ) + ", "
|
||||
"container_" + std::to_string( GearSetSlot::MainHand ) + ", "
|
||||
"container_" + std::to_string( GearSetSlot::Body ) + ", "
|
||||
"container_" + std::to_string( GearSetSlot::Hands ) + ", "
|
||||
"container_" + std::to_string( GearSetSlot::Legs ) + ", "
|
||||
"container_" + std::to_string( GearSetSlot::Feet ) + ", "
|
||||
"container_" + std::to_string( GearSetSlot::Neck ) + ", "
|
||||
"container_" + std::to_string( GearSetSlot::Ear ) + ", "
|
||||
"container_" + std::to_string( GearSetSlot::Wrist ) + ", "
|
||||
"container_" + std::to_string( GearSetSlot::Ring1 ) + ", "
|
||||
"UPDATE_DATE ) "
|
||||
"VALUES ( " + std::to_string( InventoryType::GearSet0 ) + ", " + std::to_string( m_id ) + ", " +
|
||||
std::to_string( uniqueId ) + ", " +
|
||||
|
|
|
@ -155,7 +155,7 @@ namespace Core {
|
|||
return m_gmInvis;
|
||||
}
|
||||
|
||||
bool setGmInvis( bool invis )
|
||||
void setGmInvis( bool invis )
|
||||
{
|
||||
m_gmInvis = invis;
|
||||
}
|
||||
|
|
|
@ -704,6 +704,12 @@ uint8_t Core::Entity::Player::getLevelForClass( Common::ClassJob pClass ) const
|
|||
return static_cast< uint8_t >( m_classArray[classJobIndex] );
|
||||
}
|
||||
|
||||
bool Core::Entity::Player::isClassJobUnlocked( Common::ClassJob classJob ) const
|
||||
{
|
||||
// todo: need to properly check if a job is unlocked, at the moment we just check the class array which will return true for every job if the base class is unlocked
|
||||
return getLevelForClass( classJob ) != 0;
|
||||
}
|
||||
|
||||
uint32_t Core::Entity::Player::getExp() const
|
||||
{
|
||||
auto pExdData = g_fw.get< Data::ExdDataGenerated >();
|
||||
|
@ -774,12 +780,12 @@ void Core::Entity::Player::sendModel()
|
|||
sendToInRangeSet( boost::make_shared< ModelEquipPacket >( *getAsPlayer() ), true );
|
||||
}
|
||||
|
||||
uint32_t Core::Entity::Player::getModelForSlot( Common::EquipSlot slot )
|
||||
uint32_t Core::Entity::Player::getModelForSlot( Common::GearSetSlot slot )
|
||||
{
|
||||
return m_modelEquip[slot];
|
||||
}
|
||||
|
||||
void Core::Entity::Player::setModelForSlot( Common::EquipSlot slot, uint32_t val )
|
||||
void Core::Entity::Player::setModelForSlot( Common::GearSetSlot slot, uint32_t val )
|
||||
{
|
||||
m_modelEquip[slot] = val;
|
||||
}
|
||||
|
@ -1028,7 +1034,7 @@ void Core::Entity::Player::update( int64_t currTime )
|
|||
{
|
||||
if( m_targetId && m_currentStance == Entity::Chara::Stance::Active && isAutoattackOn() )
|
||||
{
|
||||
auto mainWeap = getItemAt( Common::GearSet0, Common::EquipSlot::MainHand );
|
||||
auto mainWeap = getItemAt( Common::GearSet0, Common::GearSetSlot::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 )
|
||||
|
@ -1411,7 +1417,7 @@ uint32_t Core::Entity::Player::getPersistentEmote() const
|
|||
void Core::Entity::Player::autoAttack( CharaPtr pTarget )
|
||||
{
|
||||
|
||||
auto mainWeap = getItemAt( Common::GearSet0, Common::EquipSlot::MainHand );
|
||||
auto mainWeap = getItemAt( Common::GearSet0, Common::GearSetSlot::MainHand );
|
||||
|
||||
pTarget->onActionHostile( *this );
|
||||
//uint64_t tick = Util::getTimeMs();
|
||||
|
|
|
@ -222,14 +222,10 @@ public:
|
|||
|
||||
// Inventory / Item / Currency
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/*! 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 );
|
||||
/*! equip an item to a specified slot */
|
||||
void equipItem( Common::EquipSlot equipSlotId, ItemPtr pItem, bool sendModel );
|
||||
void equipItem( Common::GearSetSlot equipSlotId, ItemPtr pItem, bool sendModel );
|
||||
/*! remove an item from an equipment slot */
|
||||
void unequipItem( Common::EquipSlot equipSlotId, ItemPtr pItem );
|
||||
void unequipItem( Common::GearSetSlot equipSlotId, ItemPtr pItem );
|
||||
/*! equip a weapon, possibly forcing a job change */
|
||||
void equipWeapon( ItemPtr pItem );
|
||||
/*! get player ilvl */
|
||||
|
@ -245,9 +241,9 @@ public:
|
|||
/*! return a const pointer to the model array */
|
||||
const uint32_t* getModelArray() const;
|
||||
/*! return the equipment model in a specified equipment slot */
|
||||
uint32_t getModelForSlot( Common::EquipSlot slot );
|
||||
uint32_t getModelForSlot( Common::GearSetSlot slot );
|
||||
/*! set the equipment model in a specified equipment slot */
|
||||
void setModelForSlot( Common::EquipSlot slot, uint32_t val );
|
||||
void setModelForSlot( Common::GearSetSlot slot, uint32_t val );
|
||||
/*! add amount to the currency of type */
|
||||
void addCurrency( Common::CurrencyType type, uint32_t amount );
|
||||
/*! remove amount from the currency of type */
|
||||
|
@ -261,6 +257,8 @@ public:
|
|||
uint8_t getLevel() const override;
|
||||
/*! returns the level of the provided class / job */
|
||||
uint8_t getLevelForClass( Common::ClassJob pClass ) const;
|
||||
/*! returns if the classjob is unlocked */
|
||||
bool isClassJobUnlocked( Common::ClassJob classJob ) const;
|
||||
/*! returns the exp of the currently active class / job */
|
||||
uint32_t getExp() const;
|
||||
/*! sets the exp of the currently active class / job */
|
||||
|
@ -612,7 +610,7 @@ public:
|
|||
bool loadInventory();
|
||||
InvSlotPairVec getSlotsOfItemsInInventory( uint32_t catalogId );
|
||||
InvSlotPair getFreeBagSlot();
|
||||
Core::ItemPtr addItem( uint16_t inventoryId, int8_t slotId, uint32_t catalogId, uint16_t quantity = 1, bool isHq = false, bool slient = false );
|
||||
Core::ItemPtr addItem( uint32_t catalogId, uint32_t quantity = 1, bool isHq = false, bool slient = 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 );
|
||||
|
|
|
@ -88,7 +88,7 @@ void Core::Entity::Player::initInventory()
|
|||
setupContainer( ArmoryFeet, 34, "charaiteminventory", true );
|
||||
|
||||
//neck
|
||||
setupContainer( ArmotyNeck, 34, "charaiteminventory", true );
|
||||
setupContainer( ArmoryNeck, 34, "charaiteminventory", true );
|
||||
|
||||
//earring
|
||||
setupContainer( ArmoryEar, 34, "charaiteminventory", true );
|
||||
|
@ -115,63 +115,28 @@ void Core::Entity::Player::sendItemLevel()
|
|||
queuePacket( boost::make_shared< ActorControlPacket142 >( getId(), SetItemLevel, getItemLevel(), 0 ) );
|
||||
}
|
||||
|
||||
// TODO: This has to be redone and simplified
|
||||
void Core::Entity::Player::equipWeapon( ItemPtr pItem )
|
||||
{
|
||||
ClassJob currentClass = static_cast< ClassJob >( getClass() );
|
||||
auto exdData = g_fw.get< Core::Data::ExdDataGenerated >();
|
||||
if( !exdData )
|
||||
return;
|
||||
|
||||
switch( pItem->getCategory() )
|
||||
{
|
||||
case ItemUICategory::PugilistsArm:
|
||||
if( currentClass != ClassJob::Pugilist &&
|
||||
currentClass != ClassJob::Monk )
|
||||
setClassJob( ClassJob::Pugilist );
|
||||
break;
|
||||
case ItemUICategory::GladiatorsArm:
|
||||
if( currentClass != ClassJob::Gladiator &&
|
||||
currentClass != ClassJob::Paladin )
|
||||
setClassJob( ClassJob::Gladiator );
|
||||
break;
|
||||
case ItemUICategory::MaraudersArm:
|
||||
if( currentClass != ClassJob::Marauder &&
|
||||
currentClass != ClassJob::Warrior )
|
||||
setClassJob( ClassJob::Marauder );
|
||||
break;
|
||||
case ItemUICategory::ArchersArm:
|
||||
if( currentClass != ClassJob::Archer &&
|
||||
currentClass != ClassJob::Bard )
|
||||
setClassJob( ClassJob::Archer );
|
||||
break;
|
||||
case ItemUICategory::LancersArm:
|
||||
if( currentClass != ClassJob::Lancer &&
|
||||
currentClass != ClassJob::Dragoon )
|
||||
setClassJob( ClassJob::Lancer );
|
||||
break;
|
||||
case ItemUICategory::OnehandedThaumaturgesArm:
|
||||
case ItemUICategory::TwohandedThaumaturgesArm:
|
||||
if( currentClass != ClassJob::Thaumaturge &&
|
||||
currentClass != ClassJob::Blackmage )
|
||||
setClassJob( ClassJob::Thaumaturge );
|
||||
break;
|
||||
case ItemUICategory::OnehandedConjurersArm:
|
||||
case ItemUICategory::TwohandedConjurersArm:
|
||||
if( currentClass != ClassJob::Conjurer &&
|
||||
currentClass != ClassJob::Whitemage )
|
||||
setClassJob( ClassJob::Conjurer );
|
||||
break;
|
||||
case ItemUICategory::ArcanistsGrimoire:
|
||||
if( currentClass != ClassJob::Arcanist &&
|
||||
currentClass != ClassJob::Summoner &&
|
||||
currentClass != ClassJob::Scholar )
|
||||
setClassJob( ClassJob::Arcanist );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
auto itemInfo = exdData->get< Core::Data::Item >( pItem->getId() );
|
||||
auto itemClassJob = itemInfo->classJobUse;
|
||||
|
||||
auto currentClass = getClass();
|
||||
auto newClassJob = static_cast< ClassJob >( itemClassJob );
|
||||
|
||||
if( isClassJobUnlocked( newClassJob ) )
|
||||
return;
|
||||
|
||||
// todo: check if soul crystal is equipped and use job instead
|
||||
|
||||
setClassJob( newClassJob );
|
||||
}
|
||||
|
||||
// equip an item
|
||||
void Core::Entity::Player::equipItem( Common::EquipSlot equipSlotId, ItemPtr pItem, bool sendUpdate )
|
||||
void Core::Entity::Player::equipItem( Common::GearSetSlot equipSlotId, ItemPtr pItem, bool sendUpdate )
|
||||
{
|
||||
|
||||
//g_framework.getLogger().debug( "Equipping into slot " + std::to_string( equipSlotId ) );
|
||||
|
@ -181,18 +146,18 @@ void Core::Entity::Player::equipItem( Common::EquipSlot equipSlotId, ItemPtr pIt
|
|||
|
||||
switch( equipSlotId )
|
||||
{
|
||||
case Common::EquipSlot::MainHand:
|
||||
case Common::GearSetSlot::MainHand:
|
||||
m_modelMainWeapon = model;
|
||||
m_modelSubWeapon = model2;
|
||||
// TODO: add job change upon changing weapon if needed
|
||||
// equipWeapon( pItem );
|
||||
break;
|
||||
|
||||
case Common::EquipSlot::OffHand:
|
||||
case Common::GearSetSlot::OffHand:
|
||||
m_modelSubWeapon = model;
|
||||
break;
|
||||
|
||||
case Common::EquipSlot::SoulCrystal:
|
||||
case Common::GearSetSlot::SoulCrystal:
|
||||
// TODO: add Job change on equipping crystal
|
||||
// change job
|
||||
break;
|
||||
|
@ -211,7 +176,7 @@ void Core::Entity::Player::equipItem( Common::EquipSlot equipSlotId, ItemPtr pIt
|
|||
}
|
||||
}
|
||||
|
||||
void Core::Entity::Player::unequipItem( Common::EquipSlot equipSlotId, ItemPtr pItem )
|
||||
void Core::Entity::Player::unequipItem( Common::GearSetSlot equipSlotId, ItemPtr pItem )
|
||||
{
|
||||
m_modelEquip[static_cast< uint8_t >( equipSlotId )] = 0;
|
||||
sendModel();
|
||||
|
@ -320,17 +285,6 @@ void Core::Entity::Player::removeCrystal( Common::CrystalType type, uint32_t amo
|
|||
queuePacket( invUpdate );
|
||||
}
|
||||
|
||||
bool Core::Entity::Player::tryAddItem( uint16_t catalogId, uint32_t quantity )
|
||||
{
|
||||
|
||||
for( uint16_t i = 0; i < 4; i++ )
|
||||
{
|
||||
if( addItem( i, -1, catalogId, quantity ) )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Core::Entity::Player::sendInventory()
|
||||
{
|
||||
InventoryMap::iterator it;
|
||||
|
@ -495,7 +449,7 @@ bool Core::Entity::Player::isObtainable( uint32_t catalogId, uint8_t quantity )
|
|||
}
|
||||
|
||||
|
||||
Core::ItemPtr Core::Entity::Player::addItem( uint16_t inventoryId, int8_t slotId, uint32_t catalogId, uint16_t quantity, bool isHq, bool silent )
|
||||
Core::ItemPtr Core::Entity::Player::addItem( uint32_t catalogId, uint32_t quantity, bool isHq, bool silent )
|
||||
{
|
||||
auto pDb = g_fw.get< Db::DbWorkerPool< Db::CharaDbConnection > >();
|
||||
auto pExdData = g_fw.get< Data::ExdDataGenerated >();
|
||||
|
@ -507,57 +461,100 @@ Core::ItemPtr Core::Entity::Player::addItem( uint16_t inventoryId, int8_t slotId
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
int8_t rSlotId = -1;
|
||||
quantity = std::min< uint32_t >( quantity, itemInfo->stackSize );
|
||||
|
||||
//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
|
||||
// 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;
|
||||
|
||||
std::vector< uint16_t > bags = { Bag0, Bag1, Bag2, Bag3 };
|
||||
|
||||
// add the related armoury bag to the applicable bags and try and fill a free slot there before falling back to regular inventory
|
||||
if( itemInfo->isEquippable && getEquipDisplayFlags() & StoreNewItemsInArmouryChest )
|
||||
{
|
||||
auto freeSlot = getFreeBagSlot();
|
||||
inventoryId = freeSlot.first;
|
||||
rSlotId = freeSlot.second;
|
||||
auto bag = Items::Util::getCharaEquipSlotCategoryToArmoryId( itemInfo->equipSlotCategory );
|
||||
|
||||
if( rSlotId == -1 )
|
||||
return nullptr;
|
||||
bags.insert( bags.begin(), bag );
|
||||
}
|
||||
|
||||
auto item = createItem( catalogId, quantity );
|
||||
for( auto bag : bags )
|
||||
{
|
||||
auto storage = m_storageMap[bag];
|
||||
|
||||
for( uint8_t slot = 0; slot < storage->getMaxSize(); slot++ )
|
||||
{
|
||||
auto item = storage->getItem( slot );
|
||||
|
||||
// add any items that are stackable
|
||||
if( item && !itemInfo->isEquippable && item->getId() == catalogId )
|
||||
{
|
||||
uint32_t count = item->getStackSize();
|
||||
uint32_t maxStack = item->getMaxStackSize();
|
||||
|
||||
// if slot is full, skip it
|
||||
if( count >= maxStack )
|
||||
continue;
|
||||
|
||||
// check slot is same quality
|
||||
if( item->isHq() != isHq )
|
||||
continue;
|
||||
|
||||
// update stack
|
||||
uint32_t newStackSize = count + quantity;
|
||||
if( newStackSize > maxStack )
|
||||
{
|
||||
quantity = newStackSize - maxStack;
|
||||
newStackSize = maxStack;
|
||||
}
|
||||
|
||||
item->setStackSize( newStackSize );
|
||||
writeItem( item );
|
||||
|
||||
auto slotUpdate = boost::make_shared< UpdateInventorySlotPacket >( getId(), slot, bag, *item );
|
||||
queuePacket( slotUpdate );
|
||||
|
||||
// return existing stack if we have no overflow - items fit into a preexisting stack
|
||||
if( quantity == 0 )
|
||||
{
|
||||
queuePacket( boost::make_shared< ActorControlPacket143 >( getId(), ItemObtainIcon, catalogId, originalQuantity ) );
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
}
|
||||
else if( !item && !foundFreeSlot )
|
||||
{
|
||||
freeBagSlot = { bag, slot };
|
||||
foundFreeSlot = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// couldn't find a free slot and we still have some quantity of items left, shits fucked
|
||||
if( !foundFreeSlot )
|
||||
return nullptr;
|
||||
|
||||
auto item = createItem( catalogId, quantity );
|
||||
item->setHq( isHq );
|
||||
|
||||
if( rSlotId != -1 )
|
||||
{
|
||||
auto storage = m_storageMap[freeBagSlot.first];
|
||||
storage->setItem( freeBagSlot.second, item );
|
||||
|
||||
auto storage = m_storageMap[inventoryId];
|
||||
storage->setItem( rSlotId, item );
|
||||
|
||||
pDb->execute( "UPDATE " + storage->getTableName() + " SET container_" +
|
||||
std::to_string( rSlotId ) + " = " + std::to_string( item->getUId() ) +
|
||||
" WHERE storageId = " + std::to_string( inventoryId ) +
|
||||
" AND CharacterId = " + std::to_string( getId() ) );
|
||||
writeInventory( static_cast< InventoryType >( freeBagSlot.first ) );
|
||||
|
||||
if( !silent )
|
||||
{
|
||||
auto invUpdate = boost::make_shared< UpdateInventorySlotPacket >( getId(),
|
||||
rSlotId,
|
||||
inventoryId,
|
||||
*item );
|
||||
|
||||
auto invUpdate = boost::make_shared< UpdateInventorySlotPacket >( getId(), freeBagSlot.second, freeBagSlot.first, *item );
|
||||
queuePacket( invUpdate );
|
||||
|
||||
queuePacket( boost::make_shared< ActorControlPacket143 >( getId(), ItemObtainIcon,
|
||||
catalogId, item->getStackSize() ) );
|
||||
}
|
||||
|
||||
|
||||
queuePacket( boost::make_shared< ActorControlPacket143 >( getId(), ItemObtainIcon, catalogId, originalQuantity ) );
|
||||
}
|
||||
|
||||
return item;
|
||||
|
||||
}
|
||||
|
||||
void Core::Entity::Player::moveItem( uint16_t fromInventoryId, uint8_t fromSlotId, uint16_t toInventoryId, uint8_t toSlot )
|
||||
|
@ -579,10 +576,10 @@ void Core::Entity::Player::moveItem( uint16_t fromInventoryId, uint8_t fromSlotI
|
|||
writeInventory( static_cast< InventoryType >( fromInventoryId ) );
|
||||
|
||||
if( static_cast< InventoryType >( toInventoryId ) == GearSet0 )
|
||||
equipItem( static_cast< EquipSlot >( toSlot ), tmpItem, true );
|
||||
equipItem( static_cast< GearSetSlot >( toSlot ), tmpItem, true );
|
||||
|
||||
if( static_cast< InventoryType >( fromInventoryId ) == GearSet0 )
|
||||
unequipItem( static_cast< EquipSlot >( fromSlotId ), tmpItem );
|
||||
unequipItem( static_cast< GearSetSlot >( fromSlotId ), tmpItem );
|
||||
|
||||
|
||||
}
|
||||
|
@ -606,9 +603,9 @@ bool Core::Entity::Player::updateContainer( uint16_t storageId, uint8_t slotId,
|
|||
case GearSet:
|
||||
{
|
||||
if( pItem )
|
||||
equipItem( static_cast< EquipSlot >( slotId ), pItem, true );
|
||||
equipItem( static_cast< GearSetSlot >( slotId ), pItem, true );
|
||||
else
|
||||
unequipItem( static_cast< EquipSlot >( slotId ), pItem );
|
||||
unequipItem( static_cast< GearSetSlot >( slotId ), pItem );
|
||||
|
||||
writeInventory( static_cast< InventoryType >( storageId ) );
|
||||
break;
|
||||
|
@ -641,7 +638,7 @@ void Core::Entity::Player::splitItem( uint16_t fromInventoryId, uint8_t fromSlot
|
|||
// todo: correct invalid move? again, not sure what retail does here
|
||||
return;
|
||||
|
||||
auto newItem = addItem( toInventoryId, toSlot, fromItem->getId(), itemCount, fromItem->isHq(), true );
|
||||
auto newItem = addItem( fromItem->getId(), itemCount, fromItem->isHq(), true );
|
||||
if( !newItem )
|
||||
return;
|
||||
|
||||
|
@ -705,7 +702,7 @@ void Core::Entity::Player::swapItem( uint16_t fromInventoryId, uint8_t fromSlotI
|
|||
&& !Items::Util::isArmory( fromInventoryId ) )
|
||||
{
|
||||
updateContainer( fromInventoryId, fromSlotId, nullptr );
|
||||
fromInventoryId = Items::Util::getArmoryToEquipSlot( toSlot );
|
||||
fromInventoryId = Items::Util::getCharaEquipSlotCategoryToArmoryId( toSlot );
|
||||
fromSlotId = static_cast < uint8_t >( m_storageMap[fromInventoryId]->getFreeSlot() );
|
||||
}
|
||||
|
||||
|
|
|
@ -1059,14 +1059,14 @@ bool Core::Entity::Player::giveQuestRewards( uint32_t questId, uint32_t optional
|
|||
{
|
||||
for( uint32_t i = 0; i < questInfo->itemReward0.size(); i++ )
|
||||
{
|
||||
addItem( -1, questInfo->itemReward0.at( i ), questInfo->itemCountReward0.at( i ) );
|
||||
addItem( questInfo->itemCountReward0.at( i ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( optionalItemCount > 0 )
|
||||
{
|
||||
auto itemId = questInfo->itemReward1.at( optionalChoice );
|
||||
addItem( -1, itemId, questInfo->itemCountReward1.at( optionalChoice ) );
|
||||
addItem( questInfo->itemCountReward1.at( optionalChoice ) );
|
||||
}
|
||||
|
||||
if( gilReward > 0 )
|
||||
|
|
|
@ -617,7 +617,7 @@ bool Core::Entity::Player::loadInventory()
|
|||
continue;
|
||||
|
||||
m_storageMap[storageId]->getItemMap()[i - 1] = pItem;
|
||||
equipItem( static_cast< EquipSlot >( i - 1 ), pItem, false );
|
||||
equipItem( static_cast< GearSetSlot >( i - 1 ), pItem, false );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -267,7 +267,7 @@ void Core::DebugCommandHandler::set( char * data, Entity::Player& player, boost:
|
|||
uint32_t val;
|
||||
sscanf( params.c_str(), "%d %d", &slot, &val );
|
||||
|
||||
player.setModelForSlot( static_cast< Common::EquipSlot >( slot ), val );
|
||||
player.setModelForSlot( static_cast< Common::GearSetSlot >( slot ), val );
|
||||
player.sendModel();
|
||||
player.sendDebug( "Model updated" );
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ int8_t Core::ItemContainer::getFreeSlot()
|
|||
Core::ItemPtr Core::ItemContainer::getItem( uint8_t slotId )
|
||||
{
|
||||
|
||||
if( ( slotId > m_size ) || ( slotId == -1 ) )
|
||||
if( ( slotId > m_size ) )
|
||||
{
|
||||
auto pLog = g_fw.get< Logger >();
|
||||
pLog->error( "Slot out of range " + std::to_string( slotId ) );
|
||||
|
@ -94,7 +94,7 @@ Core::ItemPtr Core::ItemContainer::getItem( uint8_t slotId )
|
|||
|
||||
void Core::ItemContainer::setItem( uint8_t slotId, ItemPtr pItem )
|
||||
{
|
||||
if( ( slotId > m_size ) )
|
||||
if( slotId > m_size )
|
||||
return;
|
||||
|
||||
m_itemMap[slotId] = pItem;
|
||||
|
|
|
@ -25,46 +25,65 @@ bool Core::Items::Util::isArmory( uint16_t containerId )
|
|||
containerId == Common::ArmoryOff ||
|
||||
containerId == Common::ArmoryRing ||
|
||||
containerId == Common::ArmoryWaist ||
|
||||
containerId == Common::ArmoryWrist;
|
||||
containerId == Common::ArmoryWrist ||
|
||||
containerId == Common::ArmorySoulCrystal;
|
||||
}
|
||||
|
||||
uint16_t Core::Items::Util::getArmoryToEquipSlot( uint8_t slotId )
|
||||
uint16_t Core::Items::Util::getCharaEquipSlotCategoryToArmoryId( uint8_t slotId )
|
||||
{
|
||||
|
||||
switch( slotId )
|
||||
{
|
||||
case Common::Body:
|
||||
case Common::CharaHead:
|
||||
return Common::ArmoryHead;
|
||||
|
||||
case Common::CharaBody:
|
||||
case Common::BodyDisallowHead:
|
||||
case Common::BodyDisallowHandsLegsFeet:
|
||||
case Common::BodyDisallowAll:
|
||||
case Common::BodyDisallowHands:
|
||||
case Common::BodyDisallowLegsFeet:
|
||||
return Common::ArmoryBody;
|
||||
|
||||
case Common::Ear:
|
||||
case Common::CharaEars:
|
||||
return Common::ArmoryEar;
|
||||
|
||||
case Common::Feet:
|
||||
case Common::CharaFeet:
|
||||
return Common::ArmoryFeet;
|
||||
|
||||
case Common::Hands:
|
||||
case Common::CharaHands:
|
||||
return Common::ArmoryHand;
|
||||
|
||||
case Common::Legs:
|
||||
case Common::CharaLegs:
|
||||
case Common::LegsDisallowFeet:
|
||||
return Common::ArmoryLegs;
|
||||
|
||||
case Common::MainHand:
|
||||
case Common::CharaMainHand:
|
||||
case Common::MainTwoHandedWeapon:
|
||||
case Common::MainOrOffHand:
|
||||
return Common::ArmoryMain;
|
||||
|
||||
case Common::OffHand:
|
||||
case Common::CharaOffHand:
|
||||
return Common::ArmoryOff;
|
||||
|
||||
case Common::Ring2:
|
||||
case Common::Ring1:
|
||||
case Common::CharaRing:
|
||||
return Common::ArmoryRing;
|
||||
|
||||
case Common::Waist:
|
||||
case Common::CharaWaist:
|
||||
return Common::ArmoryWaist;
|
||||
|
||||
case Common::Wrist:
|
||||
case Common::CharaWrist:
|
||||
return Common::ArmoryWrist;
|
||||
}
|
||||
|
||||
case Common::CharaNeck:
|
||||
return Common::ArmoryNeck;
|
||||
|
||||
case Common::CharaSoulCrystal:
|
||||
return Common::ArmorySoulCrystal;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace Util {
|
|||
|
||||
bool isArmory( uint16_t containerId );
|
||||
bool isEquipment( uint16_t containerId );
|
||||
uint16_t getArmoryToEquipSlot( uint8_t slotId );
|
||||
uint16_t getCharaEquipSlotCategoryToArmoryId( uint8_t slotId );
|
||||
|
||||
Common::ContainerType getContainerType( uint32_t containerId );
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::FFXIVARR_PACKET_R
|
|||
else
|
||||
{
|
||||
auto inRange = player.getInRangeActors();
|
||||
for( auto actor : inRange )
|
||||
for( auto& actor : inRange )
|
||||
{
|
||||
if( actor->getId() == param3 )
|
||||
targetActor = actor;
|
||||
|
@ -323,7 +323,7 @@ void Core::Network::GameConnection::gm1Handler( const Packets::FFXIVARR_PACKET_R
|
|||
return;
|
||||
}
|
||||
|
||||
if( !targetPlayer->addItem( -1, param1, quantity ) )
|
||||
if( !targetPlayer->addItem( param1, quantity ) )
|
||||
player.sendUrgent( "Item " + std::to_string( param1 ) + " could not be added to inventory." );
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -28,11 +28,11 @@ private:
|
|||
{
|
||||
m_data.mainWeapon = player.getModelMainWeapon();
|
||||
m_data.offWeapon = player.getModelSubWeapon();
|
||||
m_data.models[0] = player.getModelForSlot( Common::EquipSlot::Head );
|
||||
m_data.models[1] = player.getModelForSlot( Common::EquipSlot::Body );
|
||||
m_data.models[2] = player.getModelForSlot( Common::EquipSlot::Hands );
|
||||
m_data.models[3] = player.getModelForSlot( Common::EquipSlot::Legs );
|
||||
m_data.models[4] = player.getModelForSlot( Common::EquipSlot::Feet );
|
||||
m_data.models[0] = player.getModelForSlot( Common::GearSetSlot::Head );
|
||||
m_data.models[1] = player.getModelForSlot( Common::GearSetSlot::Body );
|
||||
m_data.models[2] = player.getModelForSlot( Common::GearSetSlot::Hands );
|
||||
m_data.models[3] = player.getModelForSlot( Common::GearSetSlot::Legs );
|
||||
m_data.models[4] = player.getModelForSlot( Common::GearSetSlot::Feet );
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -49,16 +49,16 @@ namespace Server {
|
|||
|
||||
memcpy( m_data.look, player.getLookArray(), 26 );
|
||||
|
||||
auto item = player.getItemAt( Common::GearSet0, Common::EquipSlot::MainHand );
|
||||
auto item = player.getItemAt( Common::GearSet0, Common::GearSetSlot::MainHand );
|
||||
if( item )
|
||||
m_data.mainWeaponModel = item->getModelId1();
|
||||
m_data.secWeaponModel = player.getModelSubWeapon();
|
||||
|
||||
m_data.models[0] = player.getModelForSlot( Common::EquipSlot::Head );
|
||||
m_data.models[1] = player.getModelForSlot( Common::EquipSlot::Body );
|
||||
m_data.models[2] = player.getModelForSlot( Common::EquipSlot::Hands );
|
||||
m_data.models[3] = player.getModelForSlot( Common::EquipSlot::Legs );
|
||||
m_data.models[4] = player.getModelForSlot( Common::EquipSlot::Feet );
|
||||
m_data.models[0] = player.getModelForSlot( Common::GearSetSlot::Head );
|
||||
m_data.models[1] = player.getModelForSlot( Common::GearSetSlot::Body );
|
||||
m_data.models[2] = player.getModelForSlot( Common::GearSetSlot::Hands );
|
||||
m_data.models[3] = player.getModelForSlot( Common::GearSetSlot::Legs );
|
||||
m_data.models[4] = player.getModelForSlot( Common::GearSetSlot::Feet );
|
||||
strcpy( m_data.name, player.getName().c_str() );
|
||||
|
||||
m_data.pos.x = player.getPos().x;
|
||||
|
|
Loading…
Add table
Reference in a new issue