2013-05-09 10:44:08 -04:00
/* EQEMu: Everquest Server Emulator
2016-03-24 18:50:31 -04:00
Copyright ( C ) 2001 - 2016 EQEMu Development Team ( http : //eqemulator.net)
2013-02-16 16:14:39 -08:00
2013-05-09 10:44:08 -04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; version 2 of the License .
2013-05-06 13:07:41 -04:00
2013-05-09 10:44:08 -04:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY except by those people which sell it , which
2013-02-16 16:14:39 -08:00
are required to give you total support for your newly bought product ;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
2013-05-09 10:44:08 -04:00
A PARTICULAR PURPOSE . See the GNU General Public License for more details .
2013-05-06 13:07:41 -04:00
2013-05-09 10:44:08 -04:00
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2013-02-16 16:14:39 -08:00
*/
2014-11-29 04:08:37 -06:00
2015-01-19 04:12:09 -06:00
# include "../common/global_define.h"
2015-01-10 15:26:38 -06:00
# include "../common/eqemu_logsys.h"
2015-01-18 04:03:45 -06:00
2014-08-21 19:33:02 -07:00
# include "../common/string_util.h"
2014-08-21 23:46:01 -07:00
# include "quest_parser_collection.h"
2014-11-29 04:08:37 -06:00
# include "worldserver.h"
# include "zonedb.h"
2014-11-29 04:18:18 -06:00
2013-02-16 16:14:39 -08:00
extern WorldServer worldserver ;
// @merth: this needs to be touched up
uint32 Client : : NukeItem ( uint32 itemnum , uint8 where_to_check ) {
if ( itemnum = = 0 )
return 0 ;
uint32 x = 0 ;
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * cur = nullptr ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
int i ;
2013-05-09 10:44:08 -04:00
if ( where_to_check & invWhereWorn ) {
2020-05-17 18:36:06 -07:00
for ( i = EQ : : invslot : : EQUIPMENT_BEGIN ; i < = EQ : : invslot : : EQUIPMENT_END ; i + + ) {
2013-05-09 10:44:08 -04:00
if ( GetItemIDAt ( i ) = = itemnum | | ( itemnum = = 0xFFFE & & GetItemIDAt ( i ) ! = INVALID_ID ) ) {
cur = m_inv . GetItem ( i ) ;
if ( cur & & cur - > GetItem ( ) - > Stackable ) {
x + = cur - > GetCharges ( ) ;
} else {
x + + ;
}
2018-08-13 22:32:36 -04:00
DeleteItemInInventory ( i , 0 , ( ( ( ( uint64 ) 1 < < i ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask ) ! = 0 ) ) ;
2013-05-09 10:44:08 -04:00
}
}
}
if ( where_to_check & invWhereCursor ) {
2020-05-17 18:36:06 -07:00
if ( GetItemIDAt ( EQ : : invslot : : slotCursor ) = = itemnum | | ( itemnum = = 0xFFFE & & GetItemIDAt ( EQ : : invslot : : slotCursor ) ! = INVALID_ID ) ) {
cur = m_inv . GetItem ( EQ : : invslot : : slotCursor ) ;
2013-05-09 10:44:08 -04:00
if ( cur & & cur - > GetItem ( ) - > Stackable ) {
x + = cur - > GetCharges ( ) ;
} else {
x + + ;
}
2020-05-17 18:36:06 -07:00
DeleteItemInInventory ( EQ : : invslot : : slotCursor , 0 , true ) ;
2013-05-09 10:44:08 -04:00
}
2020-05-17 18:36:06 -07:00
for ( i = EQ : : invbag : : CURSOR_BAG_BEGIN ; i < = EQ : : invbag : : CURSOR_BAG_END ; i + + ) {
2013-05-09 10:44:08 -04:00
if ( GetItemIDAt ( i ) = = itemnum | | ( itemnum = = 0xFFFE & & GetItemIDAt ( i ) ! = INVALID_ID ) ) {
cur = m_inv . GetItem ( i ) ;
if ( cur & & cur - > GetItem ( ) - > Stackable ) {
x + = cur - > GetCharges ( ) ;
} else {
x + + ;
}
DeleteItemInInventory ( i , 0 , true ) ;
}
}
}
if ( where_to_check & invWherePersonal ) {
2020-05-17 18:36:06 -07:00
for ( i = EQ : : invslot : : GENERAL_BEGIN ; i < = EQ : : invslot : : GENERAL_END ; i + + ) {
2013-05-09 10:44:08 -04:00
if ( GetItemIDAt ( i ) = = itemnum | | ( itemnum = = 0xFFFE & & GetItemIDAt ( i ) ! = INVALID_ID ) ) {
cur = m_inv . GetItem ( i ) ;
if ( cur & & cur - > GetItem ( ) - > Stackable ) {
x + = cur - > GetCharges ( ) ;
} else {
x + + ;
}
2018-08-13 22:32:36 -04:00
DeleteItemInInventory ( i , 0 , ( ( ( ( uint64 ) 1 < < i ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask ) ! = 0 ) ) ;
2013-05-09 10:44:08 -04:00
}
}
2020-05-17 18:36:06 -07:00
for ( i = EQ : : invbag : : GENERAL_BAGS_BEGIN ; i < = EQ : : invbag : : GENERAL_BAGS_END ; i + + ) {
2013-05-09 10:44:08 -04:00
if ( GetItemIDAt ( i ) = = itemnum | | ( itemnum = = 0xFFFE & & GetItemIDAt ( i ) ! = INVALID_ID ) ) {
cur = m_inv . GetItem ( i ) ;
if ( cur & & cur - > GetItem ( ) - > Stackable ) {
x + = cur - > GetCharges ( ) ;
} else {
x + + ;
}
2020-05-17 18:36:06 -07:00
DeleteItemInInventory ( i , 0 , ( ( ( ( uint64 ) 1 < < ( EQ : : invslot : : GENERAL_BEGIN + ( ( i - EQ : : invbag : : GENERAL_BAGS_BEGIN ) / EQ : : invbag : : SLOT_COUNT ) ) ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask ) ! = 0 ) ) ;
2013-05-09 10:44:08 -04:00
}
}
}
if ( where_to_check & invWhereBank ) {
2020-05-17 18:36:06 -07:00
for ( i = EQ : : invslot : : BANK_BEGIN ; i < = EQ : : invslot : : BANK_END ; i + + ) {
2013-05-09 10:44:08 -04:00
if ( GetItemIDAt ( i ) = = itemnum | | ( itemnum = = 0xFFFE & & GetItemIDAt ( i ) ! = INVALID_ID ) ) {
cur = m_inv . GetItem ( i ) ;
if ( cur & & cur - > GetItem ( ) - > Stackable ) {
x + = cur - > GetCharges ( ) ;
} else {
x + + ;
}
2020-05-17 18:36:06 -07:00
DeleteItemInInventory ( i , 0 , ( ( i - EQ : : invslot : : BANK_BEGIN ) > = GetInv ( ) . GetLookup ( ) - > InventoryTypeSize . Bank ) ) ;
2013-05-09 10:44:08 -04:00
}
}
2020-05-17 18:36:06 -07:00
for ( i = EQ : : invbag : : BANK_BAGS_BEGIN ; i < = EQ : : invbag : : BANK_BAGS_END ; i + + ) {
2013-05-09 10:44:08 -04:00
if ( GetItemIDAt ( i ) = = itemnum | | ( itemnum = = 0xFFFE & & GetItemIDAt ( i ) ! = INVALID_ID ) ) {
cur = m_inv . GetItem ( i ) ;
if ( cur & & cur - > GetItem ( ) - > Stackable ) {
x + = cur - > GetCharges ( ) ;
} else {
x + + ;
}
2020-05-17 18:36:06 -07:00
DeleteItemInInventory ( i , 0 , ( ( ( i - EQ : : invbag : : BANK_BAGS_BEGIN ) / EQ : : invbag : : SLOT_COUNT ) > = GetInv ( ) . GetLookup ( ) - > InventoryTypeSize . Bank ) ) ;
2013-05-09 10:44:08 -04:00
}
}
}
if ( where_to_check & invWhereSharedBank ) {
2020-05-17 18:36:06 -07:00
for ( i = EQ : : invslot : : SHARED_BANK_BEGIN ; i < = EQ : : invslot : : SHARED_BANK_END ; i + + ) {
2013-05-09 10:44:08 -04:00
if ( GetItemIDAt ( i ) = = itemnum | | ( itemnum = = 0xFFFE & & GetItemIDAt ( i ) ! = INVALID_ID ) ) {
cur = m_inv . GetItem ( i ) ;
if ( cur & & cur - > GetItem ( ) - > Stackable ) {
x + = cur - > GetCharges ( ) ;
} else {
x + + ;
}
DeleteItemInInventory ( i , 0 , true ) ;
}
}
2020-05-17 18:36:06 -07:00
for ( i = EQ : : invbag : : SHARED_BANK_BAGS_BEGIN ; i < = EQ : : invbag : : SHARED_BANK_BAGS_END ; i + + ) {
2013-05-09 10:44:08 -04:00
if ( GetItemIDAt ( i ) = = itemnum | | ( itemnum = = 0xFFFE & & GetItemIDAt ( i ) ! = INVALID_ID ) ) {
cur = m_inv . GetItem ( i ) ;
if ( cur & & cur - > GetItem ( ) - > Stackable ) {
x + = cur - > GetCharges ( ) ;
} else {
x + + ;
}
DeleteItemInInventory ( i , 0 , true ) ;
}
}
}
2013-02-16 16:14:39 -08:00
return x ;
}
2020-05-17 18:36:06 -07:00
bool Client : : CheckLoreConflict ( const EQ : : ItemData * item )
2015-02-06 09:58:57 -05:00
{
if ( ! item ) { return false ; }
if ( ! item - > LoreFlag ) { return false ; }
if ( item - > LoreGroup = = 0 ) { return false ; }
2013-02-16 16:14:39 -08:00
2015-02-06 09:58:57 -05:00
if ( item - > LoreGroup = = 0xFFFFFFFF ) // Standard lore items; look everywhere except the shared bank, return the result
2014-07-16 21:23:16 -04:00
return ( m_inv . HasItem ( item - > ID , 0 , ~ invWhereSharedBank ) ! = INVALID_INDEX ) ;
2013-02-16 16:14:39 -08:00
2015-02-06 09:58:57 -05:00
// If the item has a lore group, we check for other items with the same group and return the result
2014-07-16 21:23:16 -04:00
return ( m_inv . HasItemByLoreGroup ( item - > LoreGroup , ~ invWhereSharedBank ) ! = INVALID_INDEX ) ;
2013-02-16 16:14:39 -08:00
}
2014-12-15 17:55:23 -06:00
bool Client : : SummonItem ( uint32 item_id , int16 charges , uint32 aug1 , uint32 aug2 , uint32 aug3 , uint32 aug4 , uint32 aug5 , uint32 aug6 , bool attuned , uint16 to_slot , uint32 ornament_icon , uint32 ornament_idfile , uint32 ornament_hero_model ) {
State of Commit: Testable if you ask me (Akkadius) what you need to do
- Need to convert a list of functions and columns and should be ready to start intensive testing phase
- All preliminary tests show things working great
- All of player profile is saved and loaded from the database
- DBAsync has been completely removed from all code
- Removed zone/dbasync.cpp/.h
- Removed common/dbasync.cpp/.h
- Removed dbasync from cmake commmon and zone
- Cleaned up a ton of functions
- Added several tables to world CheckDatabaseConversions script:
- `character_skills`
- `character_languages`
- `character_bind`
- `character_alternate_abilities`
- `character_currency`
- `character_data`
- `character_spells`
- `character_memmed_spells`
- `character_disciplines`
- `character_material`
- `character_tribute`
- `character_bandolier`
- `character_potionbelt`
- Character select now loads from `character_data`
- Character creation now creates to `character_data`
- Updated function Database::UpdateName to use `character_data`
- Updated function Database::CheckUsedName to use `character_data`
- Updated function Database::MoveCharacterToZone to use `character_data`
- Updated function Database::SetLoginFlags to use `character_data`
- Updated function Database::SetFirstLogon to use `character_data`
- Updated function Database::SetLFG to use `character_data`
- Removed CopyCharacter functions and commands, to be recreated later since it never worked to begin with
- Removed SharedDatabase::SetPlayerProfile
- Trimmed down redundant case switch statements for World sendpackets to QueryServ
- Added Character Methods to Database class:
Loads:
bool LoadCharacterBandolier(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool LoadCharacterPotions(uint32 character_id, PlayerProfile_Struct* pp);
Saves:
bool SaveCharacterBindPoint(uint32 character_id, uint32 zone_id, uint32 instance_id, float x, float y, float z, float heading, uint8 is_home);
bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp);
bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level);
bool SaveCharacterSpellSwap(uint32 character_id, uint32 spell_id, uint32 from_slot, uint32 to_slot);
bool SaveCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool SaveCharacterMaterialColor(uint32 character_id, uint32 slot_id, uint32 color);
bool SaveCharacterSkill(uint32 character_id, uint32 skill_id, uint32 value);
bool SaveCharacterLanguage(uint32 character_id, uint32 lang_id, uint32 value);
bool SaveCharacterDisc(uint32 character_id, uint32 slot_id, uint32 disc_id);
bool SaveCharacterTribute(uint32 character_id, PlayerProfile_Struct* pp);
bool SaveCharacterBandolier(uint32 character_id, uint8 bandolier_id, uint8 bandolier_slot, uint32 item_id, uint32 icon, const char* bandolier_name);
bool SaveCharacterPotionBelt(uint32 character_id, uint8 potion_id, uint32 item_id, uint32 icon);
Deletes:
bool DeleteCharacterSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterMemorizedSpell(uint32 character_id, uint32 spell_id, uint32 slot_id);
bool DeleteCharacterDisc(uint32 character_id, uint32 slot_id);
bool DeleteCharacterBandolier(uint32 character_id, uint32 band_id);
2014-09-04 07:24:17 -05:00
this - > EVENT_ITEM_ScriptStopReturn ( ) ;
2014-08-21 17:59:52 -04:00
2014-03-18 06:00:46 -04:00
// TODO: update calling methods and script apis to handle a failure return
2014-03-17 04:53:47 -04:00
2020-05-17 18:36:06 -07:00
const EQ : : ItemData * item = database . GetItem ( item_id ) ;
2013-05-06 13:07:41 -04:00
2014-03-18 06:00:46 -04:00
// make sure the item exists
2014-03-17 04:53:47 -04:00
if ( item = = nullptr ) {
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " Item %u does not exist. " , item_id ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Player [{}] on account [{}] attempted to create an item with an invalid id. \n (Item: [{}], Aug1: [{}], Aug2: [{}], Aug3: [{}], Aug4: [{}], Aug5: [{}], Aug6: [{}]) \n " ,
2014-12-15 17:55:23 -06:00
GetName ( ) , account_name , item_id , aug1 , aug2 , aug3 , aug4 , aug5 , aug6 ) ;
2014-03-17 04:53:47 -04:00
return false ;
}
2014-03-18 06:00:46 -04:00
// check that there is not a lore conflict between base item and existing inventory
else if ( CheckLoreConflict ( item ) ) {
2014-03-17 04:53:47 -04:00
// DuplicateLoreMessage(item_id);
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " You already have a lore %s (%i) in your inventory. " , item - > Name , item_id ) ;
2014-03-17 04:53:47 -04:00
return false ;
}
2014-03-18 06:00:46 -04:00
// check to make sure we are augmenting an augmentable item
2016-05-21 04:54:18 -04:00
else if ( ( ( ! item - > IsClassCommon ( ) ) | | ( item - > AugType > 0 ) ) & & ( aug1 | aug2 | aug3 | aug4 | aug5 | aug6 ) ) {
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " You can not augment an augment or a non-common class item. " ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Player [{}] on account [{}] attempted to augment an augment or a non-common class item. \n (Item: [{}], Aug1: [{}], Aug2: [{}], Aug3: [{}], Aug4: [{}], Aug5: [{}], Aug5: [{}]) \n " ,
2014-12-15 17:55:23 -06:00
GetName ( ) , account_name , item - > ID , aug1 , aug2 , aug3 , aug4 , aug5 , aug6 ) ;
2013-05-06 13:07:41 -04:00
2014-03-18 06:00:46 -04:00
return false ;
}
2014-03-31 03:21:22 -04:00
// This code is ready to implement once the item load code is changed to process the 'minstatus' field.
// Checking #iteminfo in-game verfies that item->MinStatus is set to '0' regardless of field value.
// An optional sql script will also need to be added, once this goes live, to allow changing of the min status.
2014-03-18 06:00:46 -04:00
// check to make sure we are a GM if the item is GM-only
2014-03-17 04:53:47 -04:00
/*
2014-03-31 03:21:22 -04:00
else if ( item - > MinStatus & & ( ( this - > Admin ( ) < item - > MinStatus ) | | ( this - > Admin ( ) < RuleI ( GM , MinStatusToSummonItem ) ) ) ) {
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " You are not a GM or do not have the status to summon this item. " ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Player [{}] on account [{}] attempted to create a GM-only item with a status of [{}]. \n (Item: [{}], Aug1: [{}], Aug2: [{}], Aug3: [{}], Aug4: [{}], Aug5: [{}], Aug6: [{}], MinStatus: [{}]) \n " ,
2014-12-15 17:55:23 -06:00
GetName ( ) , account_name , this - > Admin ( ) , item - > ID , aug1 , aug2 , aug3 , aug4 , aug5 , aug6 , item - > MinStatus ) ;
2014-03-17 04:53:47 -04:00
return false ;
2014-03-31 03:21:22 -04:00
}
2014-03-17 04:53:47 -04:00
*/
2020-05-17 18:36:06 -07:00
uint32 augments [ EQ : : invaug : : SOCKET_COUNT ] = { aug1 , aug2 , aug3 , aug4 , aug5 , aug6 } ;
2014-03-17 04:53:47 -04:00
uint32 classes = item - > Classes ;
uint32 races = item - > Races ;
uint32 slots = item - > Slots ;
bool enforcewear = RuleB ( Inventory , EnforceAugmentWear ) ;
bool enforcerestr = RuleB ( Inventory , EnforceAugmentRestriction ) ;
bool enforceusable = RuleB ( Inventory , EnforceAugmentUsability ) ;
2020-05-17 18:36:06 -07:00
for ( int iter = EQ : : invaug : : SOCKET_BEGIN ; iter < = EQ : : invaug : : SOCKET_END ; + + iter ) {
const EQ : : ItemData * augtest = database . GetItem ( augments [ iter ] ) ;
2014-03-17 04:53:47 -04:00
2014-03-18 06:00:46 -04:00
if ( augtest = = nullptr ) {
if ( augments [ iter ] ) {
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " Augment %u (Aug%i) does not exist. " , augments [ iter ] , iter + 1 ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Player [{}] on account [{}] attempted to create an augment (Aug[{}]) with an invalid id. \n (Item: [{}], Aug1: [{}], Aug2: [{}], Aug3: [{}], Aug4: [{}], Aug5: [{}], Aug6: [{}]) \n " ,
2014-12-15 17:55:23 -06:00
GetName ( ) , account_name , ( iter + 1 ) , item - > ID , aug1 , aug2 , aug3 , aug4 , aug5 , aug6 ) ;
2014-03-18 06:00:46 -04:00
return false ;
}
}
else {
// check that there is not a lore conflict between augment and existing inventory
2014-03-17 04:53:47 -04:00
if ( CheckLoreConflict ( augtest ) ) {
// DuplicateLoreMessage(augtest->ID);
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " You already have a lore %s (%u) in your inventory. " , augtest - > Name , augtest - > ID ) ;
2014-03-17 04:53:47 -04:00
return false ;
}
2014-03-18 06:00:46 -04:00
// check that augment is an actual augment
else if ( augtest - > AugType = = 0 ) {
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " %s (%u) (Aug%i) is not an actual augment. " , augtest - > Name , augtest - > ID , iter + 1 ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Player [{}] on account [{}] attempted to use a non-augment item (Aug[{}]) as an augment. \n (Item: [{}], Aug1: [{}], Aug2: [{}], Aug3: [{}], Aug4: [{}], Aug5: [{}], Aug6: [{}]) \n " ,
2014-12-15 17:55:23 -06:00
GetName ( ) , account_name , item - > ID , ( iter + 1 ) , aug1 , aug2 , aug3 , aug4 , aug5 , aug6 ) ;
2014-03-18 06:00:46 -04:00
2014-03-17 04:53:47 -04:00
return false ;
}
2014-03-31 03:21:22 -04:00
// Same as GM check above
2014-03-18 06:00:46 -04:00
// check to make sure we are a GM if the augment is GM-only
/*
2014-03-31 03:21:22 -04:00
else if ( augtest - > MinStatus & & ( ( this - > Admin ( ) < augtest - > MinStatus ) | | ( this - > Admin ( ) < RuleI ( GM , MinStatusToSummonItem ) ) ) ) {
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " You are not a GM or do not have the status to summon this augment. " ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Player [{}] on account [{}] attempted to create a GM-only augment (Aug[{}]) with a status of [{}]. \n (Item: [{}], Aug1: [{}], Aug2: [{}], Aug3: [{}], Aug4: [{}], Aug5: [{}], MinStatus: [{}]) \n " ,
2014-12-15 17:55:23 -06:00
GetName ( ) , account_name , ( iter + 1 ) , this - > Admin ( ) , item - > ID , aug1 , aug2 , aug3 , aug4 , aug5 , aug6 , item - > MinStatus ) ;
2014-03-17 04:53:47 -04:00
return false ;
}
2014-03-18 06:00:46 -04:00
*/
2014-03-17 04:53:47 -04:00
2014-03-18 06:00:46 -04:00
// check for augment type allowance
2014-03-17 04:53:47 -04:00
if ( enforcewear ) {
2020-05-17 18:36:06 -07:00
if ( ( item - > AugSlotType [ iter ] = = EQ : : item : : AugTypeNone ) | | ! ( ( ( uint32 ) 1 < < ( item - > AugSlotType [ iter ] - 1 ) ) & augtest - > AugType ) ) {
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " Augment %u (Aug%i) is not acceptable wear on Item %u. " , augments [ iter ] , iter + 1 , item - > ID ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Player [{}] on account [{}] attempted to augment an item with an unacceptable augment type (Aug[{}]). \n (Item: [{}], Aug1: [{}], Aug2: [{}], Aug3: [{}], Aug4: [{}], Aug5: [{}], Aug6: [{}]) \n " ,
2014-12-15 17:55:23 -06:00
GetName ( ) , account_name , ( iter + 1 ) , item - > ID , aug1 , aug2 , aug3 , aug4 , aug5 , aug6 ) ;
2014-03-18 06:00:46 -04:00
return false ;
}
if ( item - > AugSlotVisible [ iter ] = = 0 ) {
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " Item %u has not evolved enough to accept Augment %u (Aug%i). " , item - > ID , augments [ iter ] , iter + 1 ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Player [{}] on account [{}] attempted to augment an unevolved item with augment type (Aug[{}]). \n (Item: [{}], Aug1: [{}], Aug2: [{}], Aug3: [{}], Aug4: [{}], Aug5: [{}], Aug6: [{}]) \n " ,
2014-12-15 17:55:23 -06:00
GetName ( ) , account_name , ( iter + 1 ) , item - > ID , aug1 , aug2 , aug3 , aug4 , aug5 , aug6 ) ;
2014-03-17 04:53:47 -04:00
return false ;
2013-02-16 16:14:39 -08:00
}
}
2014-03-17 04:53:47 -04:00
2014-03-18 06:00:46 -04:00
// check for augment to item restriction
2014-03-17 04:53:47 -04:00
if ( enforcerestr ) {
bool restrictfail = false ;
uint8 it = item - > ItemType ;
switch ( augtest - > AugRestrict ) {
2020-05-17 18:36:06 -07:00
case EQ : : item : : AugRestrictionAny :
2014-03-17 04:53:47 -04:00
break ;
2020-05-17 18:36:06 -07:00
case EQ : : item : : AugRestrictionArmor :
2014-03-17 04:53:47 -04:00
switch ( it ) {
2020-05-17 18:36:06 -07:00
case EQ : : item : : ItemTypeArmor :
2014-03-17 04:53:47 -04:00
break ;
default :
restrictfail = true ;
break ;
2013-02-16 16:14:39 -08:00
}
2014-03-17 04:53:47 -04:00
break ;
2020-05-17 18:36:06 -07:00
case EQ : : item : : AugRestrictionWeapons :
2014-03-17 04:53:47 -04:00
switch ( it ) {
2020-05-17 18:36:06 -07:00
case EQ : : item : : ItemType1HSlash :
case EQ : : item : : ItemType1HBlunt :
case EQ : : item : : ItemType1HPiercing :
case EQ : : item : : ItemTypeMartial :
case EQ : : item : : ItemType2HSlash :
case EQ : : item : : ItemType2HBlunt :
case EQ : : item : : ItemType2HPiercing :
case EQ : : item : : ItemTypeBow :
2014-03-17 04:53:47 -04:00
break ;
default :
restrictfail = true ;
break ;
2013-02-16 16:14:39 -08:00
}
2014-03-17 04:53:47 -04:00
break ;
2020-05-17 18:36:06 -07:00
case EQ : : item : : AugRestriction1HWeapons :
2014-03-17 04:53:47 -04:00
switch ( it ) {
2020-05-17 18:36:06 -07:00
case EQ : : item : : ItemType1HSlash :
case EQ : : item : : ItemType1HBlunt :
case EQ : : item : : ItemType1HPiercing :
case EQ : : item : : ItemTypeMartial :
2014-03-17 04:53:47 -04:00
break ;
default :
restrictfail = true ;
break ;
2013-02-16 16:14:39 -08:00
}
2014-03-17 04:53:47 -04:00
break ;
2020-05-17 18:36:06 -07:00
case EQ : : item : : AugRestriction2HWeapons :
2014-03-17 04:53:47 -04:00
switch ( it ) {
2020-05-17 18:36:06 -07:00
case EQ : : item : : ItemType2HSlash :
case EQ : : item : : ItemType2HBlunt :
case EQ : : item : : ItemType2HPiercing :
case EQ : : item : : ItemTypeBow :
2014-03-17 04:53:47 -04:00
break ;
default :
restrictfail = true ;
break ;
2013-02-16 16:14:39 -08:00
}
2014-03-17 04:53:47 -04:00
break ;
2020-05-17 18:36:06 -07:00
case EQ : : item : : AugRestriction1HSlash :
2014-03-17 04:53:47 -04:00
switch ( it ) {
2020-05-17 18:36:06 -07:00
case EQ : : item : : ItemType1HSlash :
2014-03-17 04:53:47 -04:00
break ;
default :
restrictfail = true ;
break ;
2013-02-16 16:14:39 -08:00
}
2014-03-17 04:53:47 -04:00
break ;
2020-05-17 18:36:06 -07:00
case EQ : : item : : AugRestriction1HBlunt :
2014-03-17 04:53:47 -04:00
switch ( it ) {
2020-05-17 18:36:06 -07:00
case EQ : : item : : ItemType1HBlunt :
2014-03-17 04:53:47 -04:00
break ;
default :
restrictfail = true ;
break ;
2013-02-16 16:14:39 -08:00
}
2014-03-17 04:53:47 -04:00
break ;
2020-05-17 18:36:06 -07:00
case EQ : : item : : AugRestrictionPiercing :
2014-03-17 04:53:47 -04:00
switch ( it ) {
2020-05-17 18:36:06 -07:00
case EQ : : item : : ItemType1HPiercing :
2014-03-17 04:53:47 -04:00
break ;
default :
restrictfail = true ;
break ;
}
break ;
2020-05-17 18:36:06 -07:00
case EQ : : item : : AugRestrictionHandToHand :
2014-03-17 04:53:47 -04:00
switch ( it ) {
2020-05-17 18:36:06 -07:00
case EQ : : item : : ItemTypeMartial :
2014-03-17 04:53:47 -04:00
break ;
default :
restrictfail = true ;
break ;
2013-02-16 16:14:39 -08:00
}
2014-03-17 04:53:47 -04:00
break ;
2020-05-17 18:36:06 -07:00
case EQ : : item : : AugRestriction2HSlash :
2014-03-17 04:53:47 -04:00
switch ( it ) {
2020-05-17 18:36:06 -07:00
case EQ : : item : : ItemType2HSlash :
2014-03-17 04:53:47 -04:00
break ;
default :
restrictfail = true ;
break ;
2013-02-16 16:14:39 -08:00
}
2014-03-17 04:53:47 -04:00
break ;
2020-05-17 18:36:06 -07:00
case EQ : : item : : AugRestriction2HBlunt :
2014-03-17 04:53:47 -04:00
switch ( it ) {
2020-05-17 18:36:06 -07:00
case EQ : : item : : ItemType2HBlunt :
2014-03-17 04:53:47 -04:00
break ;
default :
restrictfail = true ;
break ;
}
break ;
2020-05-17 18:36:06 -07:00
case EQ : : item : : AugRestriction2HPierce :
2014-03-17 04:53:47 -04:00
switch ( it ) {
2020-05-17 18:36:06 -07:00
case EQ : : item : : ItemType2HPiercing :
2014-03-17 04:53:47 -04:00
break ;
default :
restrictfail = true ;
break ;
}
break ;
2020-05-17 18:36:06 -07:00
case EQ : : item : : AugRestrictionBows :
2014-03-17 04:53:47 -04:00
switch ( it ) {
2020-05-17 18:36:06 -07:00
case EQ : : item : : ItemTypeBow :
2014-03-17 04:53:47 -04:00
break ;
default :
restrictfail = true ;
break ;
}
break ;
2020-05-17 18:36:06 -07:00
case EQ : : item : : AugRestrictionShields :
2014-03-17 04:53:47 -04:00
switch ( it ) {
2020-05-17 18:36:06 -07:00
case EQ : : item : : ItemTypeShield :
2014-03-17 04:53:47 -04:00
break ;
default :
restrictfail = true ;
break ;
}
break ;
2020-05-17 18:36:06 -07:00
case EQ : : item : : AugRestriction1HSlash1HBluntOrHandToHand :
2014-03-17 04:53:47 -04:00
switch ( it ) {
2020-05-17 18:36:06 -07:00
case EQ : : item : : ItemType1HSlash :
case EQ : : item : : ItemType1HBlunt :
case EQ : : item : : ItemTypeMartial :
2014-03-17 04:53:47 -04:00
break ;
default :
restrictfail = true ;
break ;
}
break ;
2020-05-17 18:36:06 -07:00
case EQ : : item : : AugRestriction1HBluntOrHandToHand :
2014-03-17 04:53:47 -04:00
switch ( it ) {
2020-05-17 18:36:06 -07:00
case EQ : : item : : ItemType1HBlunt :
case EQ : : item : : ItemTypeMartial :
2014-03-17 04:53:47 -04:00
break ;
default :
restrictfail = true ;
break ;
}
break ;
// These 3 are in-work
2020-05-17 18:36:06 -07:00
case EQ : : item : : AugRestrictionUnknown1 :
case EQ : : item : : AugRestrictionUnknown2 :
case EQ : : item : : AugRestrictionUnknown3 :
2014-03-17 04:53:47 -04:00
default :
restrictfail = true ;
break ;
2013-02-16 16:14:39 -08:00
}
2014-03-17 04:53:47 -04:00
if ( restrictfail ) {
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " Augment %u (Aug%i) is restricted from wear on Item %u. " , augments [ iter ] , ( iter + 1 ) , item - > ID ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Player [{}] on account [{}] attempted to augment an item with a restricted augment (Aug[{}]). \n (Item: [{}], Aug1: [{}], Aug2: [{}], Aug3: [{}], Aug4: [{}], Aug5: [{}], Aug6: [{}]) \n " ,
2014-12-15 17:55:23 -06:00
GetName ( ) , account_name , ( iter + 1 ) , item - > ID , aug1 , aug2 , aug3 , aug4 , aug5 , aug6 ) ;
2014-03-17 04:53:47 -04:00
return false ;
2013-02-16 16:14:39 -08:00
}
}
2014-03-17 04:53:47 -04:00
if ( enforceusable ) {
2014-03-18 06:00:46 -04:00
// check for class usability
if ( item - > Classes & & ! ( classes & = augtest - > Classes ) ) {
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " Augment %u (Aug%i) will result in an item not usable by any class. " , augments [ iter ] , ( iter + 1 ) ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Player [{}] on account [{}] attempted to create an item unusable by any class. \n (Item: [{}], Aug1: [{}], Aug2: [{}], Aug3: [{}], Aug4: [{}], Aug5: [{}], Aug6: [{}]) \n " ,
2014-12-15 17:55:23 -06:00
GetName ( ) , account_name , item - > ID , aug1 , aug2 , aug3 , aug4 , aug5 , aug6 ) ;
2014-03-17 04:53:47 -04:00
return false ;
}
2014-03-18 06:00:46 -04:00
// check for race usability
if ( item - > Races & & ! ( races & = augtest - > Races ) ) {
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " Augment %u (Aug%i) will result in an item not usable by any race. " , augments [ iter ] , ( iter + 1 ) ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Player [{}] on account [{}] attempted to create an item unusable by any race. \n (Item: [{}], Aug1: [{}], Aug2: [{}], Aug3: [{}], Aug4: [{}], Aug5: [{}], Aug6: [{}]) \n " ,
2014-12-15 17:55:23 -06:00
GetName ( ) , account_name , item - > ID , aug1 , aug2 , aug3 , aug4 , aug5 , aug6 ) ;
2014-03-17 04:53:47 -04:00
return false ;
}
2014-03-18 06:00:46 -04:00
// check for slot usability
if ( item - > Slots & & ! ( slots & = augtest - > Slots ) ) {
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " Augment %u (Aug%i) will result in an item not usable in any slot. " , augments [ iter ] , ( iter + 1 ) ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Player [{}] on account [{}] attempted to create an item unusable in any slot. \n (Item: [{}], Aug1: [{}], Aug2: [{}], Aug3: [{}], Aug4: [{}], Aug5: [{}], Aug6: [{}]) \n " ,
2014-12-15 17:55:23 -06:00
GetName ( ) , account_name , item - > ID , aug1 , aug2 , aug3 , aug4 , aug5 , aug6 ) ;
2014-03-17 04:53:47 -04:00
return false ;
}
2013-02-16 16:14:39 -08:00
}
}
}
2014-03-17 04:53:47 -04:00
2014-03-18 06:00:46 -04:00
// validation passed..so, set the charges and create the actual item
// if the item is stackable and the charge amount is -1 or 0 then set to 1 charge.
// removed && item->MaxCharges == 0 if -1 or 0 was passed max charges is irrelevant
if ( charges < = 0 & & item - > Stackable )
charges = 1 ;
// if the charges is -1, then no charge value was passed in set to max charges
else if ( charges = = - 1 )
charges = item - > MaxCharges ;
// in any other situation just use charges as passed
2014-03-17 04:53:47 -04:00
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * inst = database . CreateItem ( item , charges ) ;
2014-03-17 04:53:47 -04:00
if ( inst = = nullptr ) {
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " An unknown server error has occurred and your item was not created. " ) ;
2014-03-18 06:00:46 -04:00
// this goes to logfile since this is a major error
2019-09-02 03:10:03 -05:00
LogError ( " Player [{}] on account [{}] encountered an unknown item creation error. \n (Item: [{}], Aug1: [{}], Aug2: [{}], Aug3: [{}], Aug4: [{}], Aug5: [{}], Aug6: [{}]) \n " ,
2014-12-15 17:55:23 -06:00
GetName ( ) , account_name , item - > ID , aug1 , aug2 , aug3 , aug4 , aug5 , aug6 ) ;
2014-03-17 04:53:47 -04:00
return false ;
}
2014-03-18 06:00:46 -04:00
// add any validated augments
2020-05-17 18:36:06 -07:00
for ( int iter = EQ : : invaug : : SOCKET_BEGIN ; iter < = EQ : : invaug : : SOCKET_END ; + + iter ) {
2014-03-17 04:53:47 -04:00
if ( augments [ iter ] )
inst - > PutAugment ( & database , iter , augments [ iter ] ) ;
}
2014-03-18 06:00:46 -04:00
// attune item
2014-03-17 04:53:47 -04:00
if ( attuned & & inst - > GetItem ( ) - > Attuneable )
2014-12-15 17:55:23 -06:00
inst - > SetAttuned ( true ) ;
2014-11-26 13:57:18 -08:00
2014-12-13 13:53:55 -06:00
inst - > SetOrnamentIcon ( ornament_icon ) ;
inst - > SetOrnamentationIDFile ( ornament_idfile ) ;
inst - > SetOrnamentHeroModel ( ornament_hero_model ) ;
2014-03-17 04:53:47 -04:00
2014-03-18 06:00:46 -04:00
// check to see if item is usable in requested slot
2020-05-17 18:36:06 -07:00
if ( enforceusable & & ( to_slot > = EQ : : invslot : : EQUIPMENT_BEGIN & & to_slot < = EQ : : invslot : : EQUIPMENT_END ) ) {
2018-08-13 22:32:36 -04:00
uint32 slottest = to_slot ;
2014-03-18 06:00:46 -04:00
if ( ! ( slots & ( ( uint32 ) 1 < < slottest ) ) ) {
Message ( 0 , " This item is not equipable at slot %u - moving to cursor. " , to_slot ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Player [{}] on account [{}] attempted to equip an item unusable in slot [{}] - moved to cursor. \n (Item: [{}], Aug1: [{}], Aug2: [{}], Aug3: [{}], Aug4: [{}], Aug5: [{}], Aug6: [{}]) \n " ,
2014-12-15 17:55:23 -06:00
GetName ( ) , account_name , to_slot , item - > ID , aug1 , aug2 , aug3 , aug4 , aug5 , aug6 ) ;
2014-03-18 06:00:46 -04:00
2020-05-17 18:36:06 -07:00
to_slot = EQ : : invslot : : slotCursor ;
2014-03-18 06:00:46 -04:00
}
}
// put item into inventory
2020-05-17 18:36:06 -07:00
if ( to_slot = = EQ : : invslot : : slotCursor ) {
2014-03-17 04:53:47 -04:00
PushItemOnCursor ( * inst ) ;
2020-05-17 18:36:06 -07:00
SendItemPacket ( EQ : : invslot : : slotCursor , inst , ItemPacketLimbo ) ;
2014-03-17 04:53:47 -04:00
}
else {
PutItemInInventory ( to_slot , * inst , true ) ;
}
safe_delete ( inst ) ;
2014-03-18 06:00:46 -04:00
// discover item and any augments
2014-03-17 04:53:47 -04:00
if ( ( RuleB ( Character , EnableDiscoveredItems ) ) & & ! GetGM ( ) ) {
if ( ! IsDiscovered ( item_id ) )
DiscoverItem ( item_id ) ;
2014-12-13 13:53:55 -06:00
/*
// Augments should have been discovered prior to being placed on an item.
2020-05-17 18:36:06 -07:00
for ( int iter = AUG_BEGIN ; iter < EQ : : constants : : ITEM_COMMON_SIZE ; + + iter ) {
2014-03-17 04:53:47 -04:00
if ( augments [ iter ] & & ! IsDiscovered ( augments [ iter ] ) )
DiscoverItem ( augments [ iter ] ) ;
2013-02-16 16:14:39 -08:00
}
2014-12-13 13:53:55 -06:00
*/
2013-02-16 16:14:39 -08:00
}
2014-03-17 04:53:47 -04:00
return true ;
2013-02-16 16:14:39 -08:00
}
// Drop item from inventory to ground (generally only dropped from SLOT_CURSOR)
2016-12-18 20:20:27 -05:00
void Client : : DropItem ( int16 slot_id , bool recurse )
2013-02-16 16:14:39 -08:00
{
2019-09-02 02:50:39 -05:00
LogInventory ( " [{}] (char_id: [{}]) Attempting to drop item from slot [{}] on the ground " ,
2016-12-19 20:58:38 -05:00
GetCleanName ( ) , CharacterID ( ) , slot_id ) ;
2016-12-18 20:20:27 -05:00
if ( GetInv ( ) . CheckNoDrop ( slot_id , recurse ) & & RuleI ( World , FVNoDropFlag ) = = 0 | |
2016-12-19 20:58:38 -05:00
RuleI ( Character , MinStatusForNoDropExemptions ) < Admin ( ) & & RuleI ( World , FVNoDropFlag ) = = 2 )
{
auto invalid_drop = m_inv . GetItem ( slot_id ) ;
if ( ! invalid_drop ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Error in InventoryProfile::CheckNoDrop() - returned 'true' for empty slot " ) ;
2016-12-19 20:58:38 -05:00
}
else {
2017-04-01 03:51:46 -05:00
if ( LogSys . log_settings [ Logs : : Inventory ] . is_category_enabled ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " DropItem() Hack detected - full item parse: " ) ;
LogInventory ( " depth: 0, Item: [{}] (id: [{}]), IsDroppable: [{}] " ,
2018-09-11 20:05:43 -04:00
( invalid_drop - > GetItem ( ) ? invalid_drop - > GetItem ( ) - > Name : " null data " ) , invalid_drop - > GetID ( ) , ( invalid_drop - > IsDroppable ( false ) ? " true " : " false " ) ) ;
2016-12-19 20:58:38 -05:00
for ( auto iter1 : * invalid_drop - > GetContents ( ) ) { // depth 1
2019-09-02 02:50:39 -05:00
LogInventory ( " -depth: 1, Item: [{}] (id: [{}]), IsDroppable: [{}] " ,
2018-09-11 20:05:43 -04:00
( iter1 . second - > GetItem ( ) ? iter1 . second - > GetItem ( ) - > Name : " null data " ) , iter1 . second - > GetID ( ) , ( iter1 . second - > IsDroppable ( false ) ? " true " : " false " ) ) ;
2016-12-19 20:58:38 -05:00
for ( auto iter2 : * iter1 . second - > GetContents ( ) ) { // depth 2
2019-09-02 02:50:39 -05:00
LogInventory ( " --depth: 2, Item: [{}] (id: [{}]), IsDroppable: [{}] " ,
2018-09-11 20:05:43 -04:00
( iter2 . second - > GetItem ( ) ? iter2 . second - > GetItem ( ) - > Name : " null data " ) , iter2 . second - > GetID ( ) , ( iter2 . second - > IsDroppable ( false ) ? " true " : " false " ) ) ;
2016-12-19 20:58:38 -05:00
}
}
}
}
invalid_drop = nullptr ;
2013-02-16 16:14:39 -08:00
database . SetHackerFlag ( this - > AccountName ( ) , this - > GetCleanName ( ) , " Tried to drop an item on the ground that was nodrop! " ) ;
GetInv ( ) . DeleteItem ( slot_id ) ;
return ;
}
// Take control of item in client inventory
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * inst = m_inv . PopItem ( slot_id ) ;
2013-06-06 14:29:45 -07:00
if ( inst ) {
2017-04-01 03:51:46 -05:00
if ( LogSys . log_settings [ Logs : : Inventory ] . is_category_enabled ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " DropItem() Processing - full item parse: " ) ;
LogInventory ( " depth: 0, Item: [{}] (id: [{}]), IsDroppable: [{}] " ,
2018-09-11 20:05:43 -04:00
( inst - > GetItem ( ) ? inst - > GetItem ( ) - > Name : " null data " ) , inst - > GetID ( ) , ( inst - > IsDroppable ( false ) ? " true " : " false " ) ) ;
2016-12-19 20:58:38 -05:00
if ( ! inst - > IsDroppable ( false ) )
2019-09-01 22:05:44 -05:00
LogError ( " Non-droppable item being processed for drop by [{}] " , GetCleanName ( ) ) ;
2016-12-19 20:58:38 -05:00
for ( auto iter1 : * inst - > GetContents ( ) ) { // depth 1
2019-09-02 02:50:39 -05:00
LogInventory ( " -depth: 1, Item: [{}] (id: [{}]), IsDroppable: [{}] " ,
2018-09-11 20:05:43 -04:00
( iter1 . second - > GetItem ( ) ? iter1 . second - > GetItem ( ) - > Name : " null data " ) , iter1 . second - > GetID ( ) , ( iter1 . second - > IsDroppable ( false ) ? " true " : " false " ) ) ;
2016-12-19 20:58:38 -05:00
if ( ! iter1 . second - > IsDroppable ( false ) )
2019-09-01 22:05:44 -05:00
LogError ( " Non-droppable item being processed for drop by [{}] " , GetCleanName ( ) ) ;
2016-12-19 20:58:38 -05:00
for ( auto iter2 : * iter1 . second - > GetContents ( ) ) { // depth 2
2019-09-02 02:50:39 -05:00
LogInventory ( " --depth: 2, Item: [{}] (id: [{}]), IsDroppable: [{}] " ,
2018-09-11 20:05:43 -04:00
( iter2 . second - > GetItem ( ) ? iter2 . second - > GetItem ( ) - > Name : " null data " ) , iter2 . second - > GetID ( ) , ( iter2 . second - > IsDroppable ( false ) ? " true " : " false " ) ) ;
2016-12-19 20:58:38 -05:00
if ( ! iter2 . second - > IsDroppable ( false ) )
2019-09-01 22:05:44 -05:00
LogError ( " Non-droppable item being processed for drop by [{}] " , GetCleanName ( ) ) ;
2016-12-19 20:58:38 -05:00
}
}
}
2015-05-25 12:35:53 -04:00
int i = parse - > EventItem ( EVENT_DROP_ITEM , this , inst , nullptr , " " , slot_id ) ;
2013-06-06 14:29:45 -07:00
if ( i ! = 0 ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Item drop handled by [EVENT_DROP_ITEM] " ) ;
2013-06-06 14:29:45 -07:00
safe_delete ( inst ) ;
}
} else {
2013-02-16 16:14:39 -08:00
// Item doesn't exist in inventory!
2019-09-02 02:50:39 -05:00
LogInventory ( " DropItem() - No item found in slot [{}] " , slot_id ) ;
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " Error: Item not found in slot %i " , slot_id ) ;
2013-02-16 16:14:39 -08:00
return ;
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
// Save client inventory change to database
2020-05-17 18:36:06 -07:00
if ( slot_id = = EQ : : invslot : : slotCursor ) {
2014-12-22 20:51:56 -06:00
SendCursorBuffer ( ) ;
2015-02-06 07:57:15 -05:00
auto s = m_inv . cursor_cbegin ( ) , e = m_inv . cursor_cend ( ) ;
2013-02-16 16:14:39 -08:00
database . SaveCursor ( CharacterID ( ) , s , e ) ;
2013-06-06 14:29:45 -07:00
} else {
2013-05-04 18:06:58 -07:00
database . SaveInventory ( CharacterID ( ) , nullptr , slot_id ) ;
2013-06-06 14:29:45 -07:00
}
2013-02-16 16:14:39 -08:00
2013-06-12 15:04:26 -07:00
if ( ! inst )
return ;
2013-02-16 16:14:39 -08:00
// Package as zone object
2016-05-25 16:10:28 -04:00
auto object = new Object ( this , inst ) ;
2013-02-16 16:14:39 -08:00
entity_list . AddObject ( object , true ) ;
object - > StartDecay ( ) ;
2013-05-06 13:07:41 -04:00
2019-09-02 02:50:39 -05:00
LogInventory ( " Item drop handled ut assolet " ) ;
2018-07-22 12:39:34 -04:00
DropItemQS ( inst , false ) ;
2016-12-19 20:58:38 -05:00
2013-02-16 16:14:39 -08:00
safe_delete ( inst ) ;
}
2020-05-17 18:36:06 -07:00
void Client : : DropItemQS ( EQ : : ItemInstance * inst , bool pickup ) {
2018-07-22 12:39:34 -04:00
if ( RuleB ( QueryServ , PlayerDropItems ) ) {
QSPlayerDropItem_Struct qs_audit ;
std : : list < void * > event_details ;
memset ( & qs_audit , 0 , sizeof ( QSPlayerDropItem_Struct ) ) ;
qs_audit . char_id = this - > character_id ;
qs_audit . pickup = pickup ;
qs_audit . zone_id = this - > GetZoneID ( ) ;
qs_audit . x = ( int ) this - > GetX ( ) ;
qs_audit . y = ( int ) this - > GetY ( ) ;
qs_audit . z = ( int ) this - > GetZ ( ) ;
if ( inst ) {
auto detail = new QSDropItems_Struct ;
detail - > item_id = inst - > GetID ( ) ;
detail - > charges = inst - > IsClassBag ( ) ? 1 : inst - > GetCharges ( ) ;
detail - > aug_1 = inst - > GetAugmentItemID ( 1 ) ;
detail - > aug_2 = inst - > GetAugmentItemID ( 2 ) ;
detail - > aug_3 = inst - > GetAugmentItemID ( 3 ) ;
detail - > aug_4 = inst - > GetAugmentItemID ( 4 ) ;
detail - > aug_5 = inst - > GetAugmentItemID ( 5 ) ;
event_details . push_back ( detail ) ;
if ( inst - > IsClassBag ( ) ) {
2020-05-17 18:36:06 -07:00
for ( uint8 sub_slot = EQ : : invbag : : SLOT_BEGIN ; ( sub_slot < = EQ : : invbag : : SLOT_END ) ; + + sub_slot ) { // this is to catch ALL items
const EQ : : ItemInstance * bag_inst = inst - > GetItem ( sub_slot ) ;
2018-07-22 12:39:34 -04:00
if ( bag_inst ) {
detail = new QSDropItems_Struct ;
detail - > item_id = bag_inst - > GetID ( ) ;
detail - > charges = ( ! bag_inst - > IsStackable ( ) ? 1 : bag_inst - > GetCharges ( ) ) ;
detail - > aug_1 = bag_inst - > GetAugmentItemID ( 1 ) ;
detail - > aug_2 = bag_inst - > GetAugmentItemID ( 2 ) ;
detail - > aug_3 = bag_inst - > GetAugmentItemID ( 3 ) ;
detail - > aug_4 = bag_inst - > GetAugmentItemID ( 4 ) ;
detail - > aug_5 = bag_inst - > GetAugmentItemID ( 5 ) ;
event_details . push_back ( detail ) ;
}
}
}
}
qs_audit . _detail_count = event_details . size ( ) ;
auto qs_pack = new ServerPacket (
ServerOP_QSPlayerDropItem ,
sizeof ( QSPlayerDropItem_Struct ) +
( sizeof ( QSDropItems_Struct ) * qs_audit . _detail_count ) ) ;
QSPlayerDropItem_Struct * qs_buf = ( QSPlayerDropItem_Struct * ) qs_pack - > pBuffer ;
memcpy ( qs_buf , & qs_audit , sizeof ( QSPlayerDropItem_Struct ) ) ;
int offset = 0 ;
for ( auto iter = event_details . begin ( ) ; iter ! = event_details . end ( ) ; + + iter , + + offset ) {
QSDropItems_Struct * detail = reinterpret_cast < QSDropItems_Struct * > ( * iter ) ;
qs_buf - > items [ offset ] = * detail ;
safe_delete ( detail ) ;
}
event_details . clear ( ) ;
if ( worldserver . Connected ( ) )
worldserver . SendPacket ( qs_pack ) ;
safe_delete ( qs_pack ) ;
}
}
2013-02-16 16:14:39 -08:00
// Drop inst
2020-05-17 18:36:06 -07:00
void Client : : DropInst ( const EQ : : ItemInstance * inst )
2013-02-16 16:14:39 -08:00
{
if ( ! inst ) {
// Item doesn't exist in inventory!
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " Error: Item not found " ) ;
2013-02-16 16:14:39 -08:00
return ;
}
if ( inst - > GetItem ( ) - > NoDrop = = 0 )
{
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " This item is NODROP. Deleting. " ) ;
2013-02-16 16:14:39 -08:00
return ;
}
// Package as zone object
2016-05-25 16:10:28 -04:00
auto object = new Object ( this , inst ) ;
2013-02-16 16:14:39 -08:00
entity_list . AddObject ( object , true ) ;
object - > StartDecay ( ) ;
}
// Returns a slot's item ID (returns INVALID_ID if not found)
2014-08-15 04:15:37 -04:00
int32 Client : : GetItemIDAt ( int16 slot_id ) {
2020-05-17 18:36:06 -07:00
if ( slot_id < = EQ : : invslot : : POSSESSIONS_END & & slot_id > = EQ : : invslot : : POSSESSIONS_BEGIN ) {
2018-08-13 22:32:36 -04:00
if ( ( ( ( uint64 ) 1 < < slot_id ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask ) = = 0 )
return INVALID_ID ;
}
2020-05-17 18:36:06 -07:00
else if ( slot_id < = EQ : : invbag : : GENERAL_BAGS_END & & slot_id > = EQ : : invbag : : GENERAL_BAGS_BEGIN ) {
auto temp_slot = EQ : : invslot : : GENERAL_BEGIN + ( ( slot_id - EQ : : invbag : : GENERAL_BAGS_BEGIN ) / EQ : : invbag : : SLOT_COUNT ) ;
2018-08-13 22:32:36 -04:00
if ( ( ( ( uint64 ) 1 < < temp_slot ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask ) = = 0 )
return INVALID_ID ;
}
2020-05-17 18:36:06 -07:00
else if ( slot_id < = EQ : : invslot : : BANK_END & & slot_id > = EQ : : invslot : : BANK_BEGIN ) {
if ( ( slot_id - EQ : : invslot : : BANK_BEGIN ) > = GetInv ( ) . GetLookup ( ) - > InventoryTypeSize . Bank )
2018-08-13 22:32:36 -04:00
return INVALID_ID ;
}
2020-05-17 18:36:06 -07:00
else if ( slot_id < = EQ : : invbag : : BANK_BAGS_END & & slot_id > = EQ : : invbag : : BANK_BAGS_BEGIN ) {
auto temp_slot = ( slot_id - EQ : : invbag : : BANK_BAGS_BEGIN ) / EQ : : invbag : : SLOT_COUNT ;
2019-01-07 00:11:07 -05:00
if ( temp_slot > = GetInv ( ) . GetLookup ( ) - > InventoryTypeSize . Bank )
2018-08-13 22:32:36 -04:00
return INVALID_ID ;
}
2020-05-17 18:36:06 -07:00
const EQ : : ItemInstance * inst = m_inv [ slot_id ] ;
2013-02-16 16:14:39 -08:00
if ( inst )
return inst - > GetItem ( ) - > ID ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
// None found
return INVALID_ID ;
}
// Returns an augment's ID that's in an item (returns INVALID_ID if not found)
2015-01-15 21:24:26 -05:00
// Pass in the slot ID of the item and which augslot you want to check (0-5)
2014-08-15 04:15:37 -04:00
int32 Client : : GetAugmentIDAt ( int16 slot_id , uint8 augslot ) {
2020-05-17 18:36:06 -07:00
if ( slot_id < = EQ : : invslot : : POSSESSIONS_END & & slot_id > = EQ : : invslot : : POSSESSIONS_BEGIN ) {
2018-08-13 22:32:36 -04:00
if ( ( ( ( uint64 ) 1 < < slot_id ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask ) = = 0 )
return INVALID_ID ;
}
2020-05-17 18:36:06 -07:00
else if ( slot_id < = EQ : : invbag : : GENERAL_BAGS_END & & slot_id > = EQ : : invbag : : GENERAL_BAGS_BEGIN ) {
auto temp_slot = EQ : : invslot : : GENERAL_BEGIN + ( ( slot_id - EQ : : invbag : : GENERAL_BAGS_BEGIN ) / EQ : : invbag : : SLOT_COUNT ) ;
2018-08-13 22:32:36 -04:00
if ( ( ( ( uint64 ) 1 < < temp_slot ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask ) = = 0 )
return INVALID_ID ;
}
2020-05-17 18:36:06 -07:00
else if ( slot_id < = EQ : : invslot : : BANK_END & & slot_id > = EQ : : invslot : : BANK_BEGIN ) {
if ( ( slot_id - EQ : : invslot : : BANK_BEGIN ) > = GetInv ( ) . GetLookup ( ) - > InventoryTypeSize . Bank )
2018-08-13 22:32:36 -04:00
return INVALID_ID ;
}
2020-05-17 18:36:06 -07:00
else if ( slot_id < = EQ : : invbag : : BANK_BAGS_END & & slot_id > = EQ : : invbag : : BANK_BAGS_BEGIN ) {
auto temp_slot = ( slot_id - EQ : : invbag : : BANK_BAGS_BEGIN ) / EQ : : invbag : : SLOT_COUNT ;
2019-01-07 00:11:07 -05:00
if ( temp_slot > = GetInv ( ) . GetLookup ( ) - > InventoryTypeSize . Bank )
2018-08-13 22:32:36 -04:00
return INVALID_ID ;
}
2020-05-17 18:36:06 -07:00
const EQ : : ItemInstance * inst = m_inv [ slot_id ] ;
2015-01-15 21:24:26 -05:00
if ( inst & & inst - > GetAugmentItemID ( augslot ) ) {
return inst - > GetAugmentItemID ( augslot ) ;
}
2013-02-16 16:14:39 -08:00
// None found
return INVALID_ID ;
}
2015-02-06 09:58:57 -05:00
void Client : : SendCursorBuffer ( )
{
2014-12-20 01:52:58 -06:00
// Temporary work-around for the RoF+ Client Buffer
2014-12-22 20:51:56 -06:00
// Instead of dealing with client moving items in cursor buffer,
// we can just send the next item in the cursor buffer to the cursor.
2020-05-17 18:36:06 -07:00
if ( ClientVersion ( ) < EQ : : versions : : ClientVersion : : RoF ) { return ; }
2015-02-06 09:58:57 -05:00
if ( GetInv ( ) . CursorEmpty ( ) ) { return ; }
auto test_inst = GetInv ( ) . GetCursorItem ( ) ;
if ( test_inst = = nullptr ) { return ; }
auto test_item = test_inst - > GetItem ( ) ;
if ( test_item = = nullptr ) { return ; }
bool lore_pass = true ;
if ( test_item - > LoreGroup = = 0xFFFFFFFF ) {
lore_pass = ( m_inv . HasItem ( test_item - > ID , 0 , ~ ( invWhereSharedBank | invWhereCursor ) ) = = INVALID_INDEX ) ;
}
else if ( test_item - > LoreGroup ! = 0 ) {
lore_pass = ( m_inv . HasItemByLoreGroup ( test_item - > LoreGroup , ~ ( invWhereSharedBank | invWhereCursor ) ) = = INVALID_INDEX ) ;
}
if ( ! lore_pass ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " ([{}]) Duplicate lore items are not allowed - destroying item [{}](id:[{}]) on cursor " ,
2015-02-06 09:58:57 -05:00
GetName ( ) , test_item - > Name , test_item - > ID ) ;
2019-08-11 00:14:02 -05:00
MessageString ( Chat : : Loot , 290 ) ;
2015-02-06 09:58:57 -05:00
parse - > EventItem ( EVENT_DESTROY_ITEM , this , test_inst , nullptr , " " , 0 ) ;
2020-05-17 18:36:06 -07:00
DeleteItemInInventory ( EQ : : invslot : : slotCursor ) ;
2015-02-06 09:58:57 -05:00
SendCursorBuffer ( ) ;
}
else {
2020-05-17 18:36:06 -07:00
SendItemPacket ( EQ : : invslot : : slotCursor , test_inst , ItemPacketLimbo ) ;
2014-12-20 01:52:58 -06:00
}
}
2013-02-16 16:14:39 -08:00
// Remove item from inventory
void Client : : DeleteItemInInventory ( int16 slot_id , int8 quantity , bool client_update , bool update_db ) {
# if (EQDEBUG >= 5)
2019-09-01 23:54:24 -05:00
LogDebug ( " DeleteItemInInventory([{}], [{}], [{}]) " , slot_id , quantity , ( client_update ) ? " true " : " false " ) ;
2013-02-16 16:14:39 -08:00
# endif
// Added 'IsSlotValid(slot_id)' check to both segments of client packet processing.
// - cursor queue slots were slipping through and crashing client
if ( ! m_inv [ slot_id ] ) {
// Make sure the client deletes anything in this slot to match the server.
if ( client_update & & IsValidSlot ( slot_id ) ) {
EQApplicationPacket * outapp ;
outapp = new EQApplicationPacket ( OP_DeleteItem , sizeof ( DeleteItem_Struct ) ) ;
DeleteItem_Struct * delitem = ( DeleteItem_Struct * ) outapp - > pBuffer ;
delitem - > from_slot = slot_id ;
delitem - > to_slot = 0xFFFFFFFF ;
delitem - > number_in_stack = 0xFFFFFFFF ;
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
}
return ;
}
// start QS code
if ( RuleB ( QueryServ , PlayerLogDeletes ) ) {
uint16 delete_count = 0 ;
if ( m_inv [ slot_id ] ) { delete_count + = m_inv . GetItem ( slot_id ) - > GetTotalItemCount ( ) ; }
2016-05-25 16:10:28 -04:00
auto qspack =
new ServerPacket ( ServerOP_QSPlayerLogDeletes ,
sizeof ( QSPlayerLogDelete_Struct ) + ( sizeof ( QSDeleteItems_Struct ) * delete_count ) ) ;
2013-02-16 16:14:39 -08:00
QSPlayerLogDelete_Struct * qsaudit = ( QSPlayerLogDelete_Struct * ) qspack - > pBuffer ;
uint16 parent_offset = 0 ;
qsaudit - > char_id = character_id ;
qsaudit - > stack_size = quantity ;
qsaudit - > char_count = delete_count ;
qsaudit - > items [ parent_offset ] . char_slot = slot_id ;
qsaudit - > items [ parent_offset ] . item_id = m_inv [ slot_id ] - > GetID ( ) ;
qsaudit - > items [ parent_offset ] . charges = m_inv [ slot_id ] - > GetCharges ( ) ;
qsaudit - > items [ parent_offset ] . aug_1 = m_inv [ slot_id ] - > GetAugmentItemID ( 1 ) ;
qsaudit - > items [ parent_offset ] . aug_2 = m_inv [ slot_id ] - > GetAugmentItemID ( 2 ) ;
qsaudit - > items [ parent_offset ] . aug_3 = m_inv [ slot_id ] - > GetAugmentItemID ( 3 ) ;
qsaudit - > items [ parent_offset ] . aug_4 = m_inv [ slot_id ] - > GetAugmentItemID ( 4 ) ;
qsaudit - > items [ parent_offset ] . aug_5 = m_inv [ slot_id ] - > GetAugmentItemID ( 5 ) ;
2016-05-21 04:54:18 -04:00
if ( m_inv [ slot_id ] - > IsClassBag ( ) ) {
2020-05-17 18:36:06 -07:00
for ( uint8 bag_idx = EQ : : invbag : : SLOT_BEGIN ; bag_idx < m_inv [ slot_id ] - > GetItem ( ) - > BagSlots ; bag_idx + + ) {
EQ : : ItemInstance * bagitem = m_inv [ slot_id ] - > GetItem ( bag_idx ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
if ( bagitem ) {
2020-05-17 18:36:06 -07:00
int16 bagslot_id = EQ : : InventoryProfile : : CalcSlotId ( slot_id , bag_idx ) ;
2013-02-16 16:14:39 -08:00
2013-05-09 10:44:08 -04:00
qsaudit - > items [ + + parent_offset ] . char_slot = bagslot_id ;
qsaudit - > items [ parent_offset ] . item_id = bagitem - > GetID ( ) ;
qsaudit - > items [ parent_offset ] . charges = bagitem - > GetCharges ( ) ;
qsaudit - > items [ parent_offset ] . aug_1 = bagitem - > GetAugmentItemID ( 1 ) ;
qsaudit - > items [ parent_offset ] . aug_2 = bagitem - > GetAugmentItemID ( 2 ) ;
qsaudit - > items [ parent_offset ] . aug_3 = bagitem - > GetAugmentItemID ( 3 ) ;
qsaudit - > items [ parent_offset ] . aug_4 = bagitem - > GetAugmentItemID ( 4 ) ;
qsaudit - > items [ parent_offset ] . aug_5 = bagitem - > GetAugmentItemID ( 5 ) ;
2013-02-16 16:14:39 -08:00
}
}
}
if ( worldserver . Connected ( ) ) { worldserver . SendPacket ( qspack ) ; }
safe_delete ( qspack ) ;
}
// end QS code
bool isDeleted = m_inv . DeleteItem ( slot_id , quantity ) ;
2020-05-17 18:36:06 -07:00
const EQ : : ItemInstance * inst = nullptr ;
if ( slot_id = = EQ : : invslot : : slotCursor ) {
2015-02-06 07:57:15 -05:00
auto s = m_inv . cursor_cbegin ( ) , e = m_inv . cursor_cend ( ) ;
2013-05-09 10:44:08 -04:00
if ( update_db )
database . SaveCursor ( character_id , s , e ) ;
2013-02-16 16:14:39 -08:00
}
else {
// Save change to database
inst = m_inv [ slot_id ] ;
2013-05-09 10:44:08 -04:00
if ( update_db )
database . SaveInventory ( character_id , inst , slot_id ) ;
2013-02-16 16:14:39 -08:00
}
if ( client_update & & IsValidSlot ( slot_id ) ) {
2015-01-15 21:24:26 -05:00
EQApplicationPacket * outapp = nullptr ;
2013-02-16 16:14:39 -08:00
if ( inst ) {
2015-01-15 21:24:26 -05:00
if ( ! inst - > IsStackable ( ) & & ! isDeleted ) {
2013-02-16 16:14:39 -08:00
// Non stackable item with charges = Item with clicky spell effect ? Delete a charge.
outapp = new EQApplicationPacket ( OP_DeleteCharge , sizeof ( MoveItem_Struct ) ) ;
2015-01-15 21:24:26 -05:00
}
else {
2013-02-16 16:14:39 -08:00
// Stackable, arrows, etc ? Delete one from the stack
outapp = new EQApplicationPacket ( OP_DeleteItem , sizeof ( MoveItem_Struct ) ) ;
2015-01-15 21:24:26 -05:00
}
2013-02-16 16:14:39 -08:00
2015-01-15 21:24:26 -05:00
DeleteItem_Struct * delitem = ( DeleteItem_Struct * ) outapp - > pBuffer ;
delitem - > from_slot = slot_id ;
delitem - > to_slot = 0xFFFFFFFF ;
delitem - > number_in_stack = 0xFFFFFFFF ;
for ( int loop = 0 ; loop < quantity ; loop + + )
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
2013-02-16 16:14:39 -08:00
}
else {
2019-06-20 19:37:08 -04:00
outapp = new EQApplicationPacket ( OP_MoveItem , sizeof ( MoveItem_Struct ) ) ;
MoveItem_Struct * delitem = ( MoveItem_Struct * ) outapp - > pBuffer ;
2013-02-16 16:14:39 -08:00
delitem - > from_slot = slot_id ;
delitem - > to_slot = 0xFFFFFFFF ;
delitem - > number_in_stack = 0xFFFFFFFF ;
2015-01-15 21:24:26 -05:00
2013-02-16 16:14:39 -08:00
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
}
}
}
2020-05-17 18:36:06 -07:00
bool Client : : PushItemOnCursor ( const EQ : : ItemInstance & inst , bool client_update )
2013-02-16 16:14:39 -08:00
{
2019-09-02 02:50:39 -05:00
LogInventory ( " Putting item [{}] ([{}]) on the cursor " , inst . GetItem ( ) - > Name , inst . GetItem ( ) - > ID ) ;
2013-02-16 16:14:39 -08:00
m_inv . PushCursor ( inst ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
if ( client_update ) {
2020-05-17 18:36:06 -07:00
SendItemPacket ( EQ : : invslot : : slotCursor , & inst , ItemPacketLimbo ) ;
2013-02-16 16:14:39 -08:00
}
2013-05-06 13:07:41 -04:00
2015-02-06 07:57:15 -05:00
auto s = m_inv . cursor_cbegin ( ) , e = m_inv . cursor_cend ( ) ;
2013-02-16 16:14:39 -08:00
return database . SaveCursor ( CharacterID ( ) , s , e ) ;
}
2014-12-20 01:52:58 -06:00
// Puts an item into the person's inventory
// Any items already there will be removed from user's inventory
// (Also saves changes back to the database: this may be optimized in the future)
// client_update: Sends packet to client
2020-05-17 18:36:06 -07:00
bool Client : : PutItemInInventory ( int16 slot_id , const EQ : : ItemInstance & inst , bool client_update ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Putting item [{}] ([{}]) into slot [{}] " , inst . GetItem ( ) - > Name , inst . GetItem ( ) - > ID , slot_id ) ;
2014-08-22 20:48:11 -04:00
2020-05-17 18:36:06 -07:00
if ( slot_id = = EQ : : invslot : : slotCursor ) { // don't trust macros before conditional statements...
2014-08-22 20:48:11 -04:00
return PushItemOnCursor ( inst , client_update ) ;
2015-01-15 21:24:26 -05:00
}
else {
2013-02-16 16:14:39 -08:00
m_inv . PutItem ( slot_id , inst ) ;
2015-01-15 21:24:26 -05:00
}
2013-05-06 13:07:41 -04:00
2014-08-22 20:48:11 -04:00
if ( client_update )
2014-12-13 13:53:55 -06:00
{
2020-05-17 18:36:06 -07:00
SendItemPacket ( slot_id , & inst , ( ( slot_id = = EQ : : invslot : : slotCursor ) ? ItemPacketLimbo : ItemPacketTrade ) ) ;
//SendWearChange(EQ::InventoryProfile::CalcMaterialFromSlot(slot_id));
2014-12-13 13:53:55 -06:00
}
2020-05-17 18:36:06 -07:00
if ( slot_id = = EQ : : invslot : : slotCursor ) {
2015-02-06 07:57:15 -05:00
auto s = m_inv . cursor_cbegin ( ) , e = m_inv . cursor_cend ( ) ;
2013-02-16 16:14:39 -08:00
return database . SaveCursor ( this - > CharacterID ( ) , s , e ) ;
2014-08-22 20:48:11 -04:00
}
else {
2013-02-16 16:14:39 -08:00
return database . SaveInventory ( this - > CharacterID ( ) , & inst , slot_id ) ;
2014-08-22 20:48:11 -04:00
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
CalcBonuses ( ) ;
2015-01-15 21:24:26 -05:00
// a lot of wasted checks and calls coded above...
2013-02-16 16:14:39 -08:00
}
2020-05-17 18:36:06 -07:00
void Client : : PutLootInInventory ( int16 slot_id , const EQ : : ItemInstance & inst , ServerLootItem_Struct * * bag_item_data )
2013-02-16 16:14:39 -08:00
{
2019-09-02 02:50:39 -05:00
LogInventory ( " Putting loot item [{}] ([{}]) into slot [{}] " , inst . GetItem ( ) - > Name , inst . GetItem ( ) - > ID , slot_id ) ;
2013-05-06 13:07:41 -04:00
2015-03-03 04:08:52 -05:00
bool cursor_empty = m_inv . CursorEmpty ( ) ;
2013-05-06 13:07:41 -04:00
2020-05-17 18:36:06 -07:00
if ( slot_id = = EQ : : invslot : : slotCursor ) {
2015-03-03 04:08:52 -05:00
m_inv . PushCursor ( inst ) ;
2015-02-06 07:57:15 -05:00
auto s = m_inv . cursor_cbegin ( ) , e = m_inv . cursor_cend ( ) ;
2013-02-16 16:14:39 -08:00
database . SaveCursor ( this - > CharacterID ( ) , s , e ) ;
2015-01-15 21:24:26 -05:00
}
else {
2015-03-03 04:08:52 -05:00
m_inv . PutItem ( slot_id , inst ) ;
2013-02-16 16:14:39 -08:00
database . SaveInventory ( this - > CharacterID ( ) , & inst , slot_id ) ;
2015-01-15 21:24:26 -05:00
}
2013-02-16 16:14:39 -08:00
2015-03-03 04:08:52 -05:00
// Subordinate items in cursor buffer must be sent via ItemPacketSummonItem or we just overwrite the visible cursor and desync the client
2020-05-17 18:36:06 -07:00
if ( slot_id = = EQ : : invslot : : slotCursor & & ! cursor_empty ) {
2015-03-03 04:08:52 -05:00
// RoF+ currently has a specialized cursor handler
2020-05-17 18:36:06 -07:00
if ( ClientVersion ( ) < EQ : : versions : : ClientVersion : : RoF )
2016-05-27 03:38:13 -04:00
SendItemPacket ( slot_id , & inst , ItemPacketLimbo ) ;
2015-03-03 04:08:52 -05:00
}
else {
SendLootItemInPacket ( & inst , slot_id ) ;
}
if ( bag_item_data ) {
2020-05-17 18:36:06 -07:00
for ( int index = EQ : : invbag : : SLOT_BEGIN ; index < = EQ : : invbag : : SLOT_END ; + + index ) {
2015-03-03 04:08:52 -05:00
if ( bag_item_data [ index ] = = nullptr )
2013-02-16 16:14:39 -08:00
continue ;
2015-03-03 04:08:52 -05:00
2020-05-17 18:36:06 -07:00
const EQ : : ItemInstance * bagitem = database . CreateItem (
2015-03-03 04:08:52 -05:00
bag_item_data [ index ] - > item_id ,
bag_item_data [ index ] - > charges ,
bag_item_data [ index ] - > aug_1 ,
bag_item_data [ index ] - > aug_2 ,
bag_item_data [ index ] - > aug_3 ,
bag_item_data [ index ] - > aug_4 ,
bag_item_data [ index ] - > aug_5 ,
bag_item_data [ index ] - > aug_6 ,
bag_item_data [ index ] - > attuned
) ;
// Dump bag contents to cursor in the event that owning bag is not the first cursor item
// (This assumes that the data passed is correctly associated..no safety checks are implemented)
2020-05-17 18:36:06 -07:00
if ( slot_id = = EQ : : invslot : : slotCursor & & ! cursor_empty ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Putting bag loot item [{}] ([{}]) into slot [{}] (non-empty cursor override) " ,
2020-05-17 18:36:06 -07:00
inst . GetItem ( ) - > Name , inst . GetItem ( ) - > ID , EQ : : invslot : : slotCursor ) ;
2015-03-03 04:08:52 -05:00
2020-05-17 18:36:06 -07:00
PutLootInInventory ( EQ : : invslot : : slotCursor , * bagitem ) ;
2015-03-03 04:08:52 -05:00
}
else {
2020-05-17 18:36:06 -07:00
auto bag_slot = EQ : : InventoryProfile : : CalcSlotId ( slot_id , index ) ;
2015-03-03 04:08:52 -05:00
2019-09-02 02:50:39 -05:00
LogInventory ( " Putting bag loot item [{}] ([{}]) into slot [{}] (bag slot [{}]) " ,
2015-03-03 04:08:52 -05:00
inst . GetItem ( ) - > Name , inst . GetItem ( ) - > ID , bag_slot , index ) ;
PutLootInInventory ( bag_slot , * bagitem ) ;
}
2013-02-16 16:14:39 -08:00
safe_delete ( bagitem ) ;
}
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
CalcBonuses ( ) ;
}
2020-05-17 18:36:06 -07:00
bool Client : : TryStacking ( EQ : : ItemInstance * item , uint8 type , bool try_worn , bool try_cursor ) {
2013-02-16 16:14:39 -08:00
if ( ! item | | ! item - > IsStackable ( ) | | item - > GetCharges ( ) > = item - > GetItem ( ) - > StackSize )
return false ;
int16 i ;
uint32 item_id = item - > GetItem ( ) - > ID ;
2020-05-17 18:36:06 -07:00
for ( i = EQ : : invslot : : GENERAL_BEGIN ; i < = EQ : : invslot : : GENERAL_END ; i + + ) {
2018-08-13 22:32:36 -04:00
if ( ( ( uint64 ) 1 < < i ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask = = 0 )
continue ;
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * tmp_inst = m_inv . GetItem ( i ) ;
2013-02-16 16:14:39 -08:00
if ( tmp_inst & & tmp_inst - > GetItem ( ) - > ID = = item_id & & tmp_inst - > GetCharges ( ) < tmp_inst - > GetItem ( ) - > StackSize ) {
MoveItemCharges ( * item , i , type ) ;
CalcBonuses ( ) ;
2015-01-15 21:24:26 -05:00
if ( item - > GetCharges ( ) ) { // we didn't get them all
2013-02-16 16:14:39 -08:00
return AutoPutLootInInventory ( * item , try_worn , try_cursor , 0 ) ;
2015-01-15 21:24:26 -05:00
}
2013-02-16 16:14:39 -08:00
return true ;
}
}
2020-05-17 18:36:06 -07:00
for ( i = EQ : : invslot : : GENERAL_BEGIN ; i < = EQ : : invslot : : GENERAL_END ; i + + ) {
2018-08-13 22:32:36 -04:00
if ( ( ( uint64 ) 1 < < i ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask = = 0 )
continue ;
2020-05-17 18:36:06 -07:00
for ( uint8 j = EQ : : invbag : : SLOT_BEGIN ; j < = EQ : : invbag : : SLOT_END ; j + + ) {
uint16 slotid = EQ : : InventoryProfile : : CalcSlotId ( i , j ) ;
EQ : : ItemInstance * tmp_inst = m_inv . GetItem ( slotid ) ;
2013-02-16 16:14:39 -08:00
2015-01-15 21:24:26 -05:00
if ( tmp_inst & & tmp_inst - > GetItem ( ) - > ID = = item_id & & tmp_inst - > GetCharges ( ) < tmp_inst - > GetItem ( ) - > StackSize ) {
2013-02-16 16:14:39 -08:00
MoveItemCharges ( * item , slotid , type ) ;
CalcBonuses ( ) ;
2015-01-15 21:24:26 -05:00
if ( item - > GetCharges ( ) ) { // we didn't get them all
2013-02-16 16:14:39 -08:00
return AutoPutLootInInventory ( * item , try_worn , try_cursor , 0 ) ;
2015-01-15 21:24:26 -05:00
}
2013-02-16 16:14:39 -08:00
return true ;
}
}
}
return false ;
}
2015-01-15 21:24:26 -05:00
2013-02-16 16:14:39 -08:00
// Locate an available space in inventory to place an item
// and then put the item there
// The change will be saved to the database
2020-05-17 18:36:06 -07:00
bool Client : : AutoPutLootInInventory ( EQ : : ItemInstance & inst , bool try_worn , bool try_cursor , ServerLootItem_Struct * * bag_item_data )
2013-02-16 16:14:39 -08:00
{
// #1: Try to auto equip
2020-05-17 18:36:06 -07:00
if ( try_worn & & inst . IsEquipable ( GetBaseRace ( ) , GetClass ( ) ) & & inst . GetItem ( ) - > ReqLevel < = level & & ( ! inst . GetItem ( ) - > Attuneable | | inst . IsAttuned ( ) ) & & inst . GetItem ( ) - > ItemType ! = EQ : : item : : ItemTypeAugmentation ) {
for ( int16 i = EQ : : invslot : : EQUIPMENT_BEGIN ; i < = EQ : : invslot : : EQUIPMENT_END ; i + + ) {
2018-08-13 22:32:36 -04:00
if ( ( ( uint64 ) 1 < < i ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask = = 0 )
continue ;
2013-05-06 13:07:41 -04:00
2015-01-15 21:24:26 -05:00
if ( ! m_inv [ i ] ) {
2020-05-17 18:36:06 -07:00
if ( i = = EQ : : invslot : : slotPrimary & & inst . IsWeapon ( ) ) { // If item is primary slot weapon
2016-05-21 04:54:18 -04:00
if ( inst . GetItem ( ) - > IsType2HWeapon ( ) ) { // and uses 2hs \ 2hb \ 2hp
2020-05-17 18:36:06 -07:00
if ( m_inv [ EQ : : invslot : : slotSecondary ] ) { // and if secondary slot is not empty
2013-02-16 16:14:39 -08:00
continue ; // Can't auto-equip
}
}
}
2020-05-17 18:36:06 -07:00
if ( i = = EQ : : invslot : : slotSecondary & & m_inv [ EQ : : invslot : : slotPrimary ] ) { // check to see if primary slot is a two hander
if ( m_inv [ EQ : : invslot : : slotPrimary ] - > GetItem ( ) - > IsType2HWeapon ( ) )
2013-02-16 16:14:39 -08:00
continue ;
}
2020-05-17 18:36:06 -07:00
if ( i = = EQ : : invslot : : slotSecondary & & inst . IsWeapon ( ) & & ! CanThisClassDualWield ( ) ) {
2013-02-16 16:14:39 -08:00
continue ;
}
2015-01-15 21:24:26 -05:00
if ( inst . IsEquipable ( i ) ) { // Equippable at this slot?
2013-02-16 16:14:39 -08:00
//send worn to everyone...
PutLootInInventory ( i , inst ) ;
2020-05-17 18:36:06 -07:00
uint8 worn_slot_material = EQ : : InventoryProfile : : CalcMaterialFromSlot ( i ) ;
if ( worn_slot_material ! = EQ : : textures : : materialInvalid ) {
2013-02-16 16:14:39 -08:00
SendWearChange ( worn_slot_material ) ;
}
2013-06-21 14:20:30 -07:00
parse - > EventItem ( EVENT_EQUIP_ITEM , this , & inst , nullptr , " " , i ) ;
2013-02-16 16:14:39 -08:00
return true ;
}
}
}
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
// #2: Stackable item?
2015-01-15 21:24:26 -05:00
if ( inst . IsStackable ( ) ) {
if ( TryStacking ( & inst , ItemPacketTrade , try_worn , try_cursor ) )
2013-02-16 16:14:39 -08:00
return true ;
}
// #3: put it in inventory
2020-05-17 18:36:06 -07:00
bool is_arrow = ( inst . GetItem ( ) - > ItemType = = EQ : : item : : ItemTypeArrow ) ? true : false ;
2016-05-21 04:54:18 -04:00
int16 slot_id = m_inv . FindFreeSlot ( inst . IsClassBag ( ) , try_cursor , inst . GetItem ( ) - > Size , is_arrow ) ;
2015-01-15 21:24:26 -05:00
if ( slot_id ! = INVALID_INDEX ) {
2013-02-16 16:14:39 -08:00
PutLootInInventory ( slot_id , inst , bag_item_data ) ;
return true ;
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
return false ;
}
2015-01-31 17:03:44 -05:00
// helper function for AutoPutLootInInventory
2020-05-17 18:36:06 -07:00
void Client : : MoveItemCharges ( EQ : : ItemInstance & from , int16 to_slot , uint8 type )
2013-02-16 16:14:39 -08:00
{
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * tmp_inst = m_inv . GetItem ( to_slot ) ;
2013-02-16 16:14:39 -08:00
2015-01-15 21:24:26 -05:00
if ( tmp_inst & & tmp_inst - > GetCharges ( ) < tmp_inst - > GetItem ( ) - > StackSize ) {
2013-02-16 16:14:39 -08:00
// this is how much room is left on the item we're stacking onto
int charge_slots_left = tmp_inst - > GetItem ( ) - > StackSize - tmp_inst - > GetCharges ( ) ;
// this is how many charges we can move from the looted item to
// the item in the inventory
2015-01-15 21:24:26 -05:00
int charges_to_move = ( from . GetCharges ( ) < charge_slots_left ) ? from . GetCharges ( ) : charge_slots_left ;
2013-02-16 16:14:39 -08:00
tmp_inst - > SetCharges ( tmp_inst - > GetCharges ( ) + charges_to_move ) ;
from . SetCharges ( from . GetCharges ( ) - charges_to_move ) ;
SendLootItemInPacket ( tmp_inst , to_slot ) ;
2020-05-17 18:36:06 -07:00
if ( to_slot = = EQ : : invslot : : slotCursor ) {
2015-02-06 07:57:15 -05:00
auto s = m_inv . cursor_cbegin ( ) , e = m_inv . cursor_cend ( ) ;
2013-02-16 16:14:39 -08:00
database . SaveCursor ( this - > CharacterID ( ) , s , e ) ;
2015-01-15 21:24:26 -05:00
}
else {
2013-02-16 16:14:39 -08:00
database . SaveInventory ( this - > CharacterID ( ) , tmp_inst , to_slot ) ;
2015-01-15 21:24:26 -05:00
}
2013-02-16 16:14:39 -08:00
}
}
2015-01-15 21:24:26 -05:00
#if 0
2014-12-28 12:49:14 -05:00
// TODO: needs clean-up to save references
2016-10-16 05:10:54 -04:00
bool MakeItemLink ( char * & ret_link , const ItemData * item , uint32 aug0 , uint32 aug1 , uint32 aug2 , uint32 aug3 , uint32 aug4 , uint32 aug5 , uint8 evolving , uint8 evolvedlevel ) {
2013-02-16 16:14:39 -08:00
//we're sending back the entire "link", minus the null characters & item name
//that way, we can use it for regular links & Task links
//note: initiator needs to pass us ret_link
2014-12-25 00:00:57 -05:00
/*
2013-02-16 16:14:39 -08:00
- - - Usage - - -
Chat : " %c " " %s " " %s " " %c " , 0x12 , ret_link , inst - > GetItem ( ) - > name , 0x12
Task : " <a WndNotify= \" 27, " " %s " " \" > " " %s " " </a> " , ret_link , inst - > GetItem ( ) - > name
2014-12-25 00:00:57 -05:00
< a WndNotify = " 27,00960F000000000000000000000000000000000000000 " > Master ' s Book of Wood Elven Culture < / a >
http : //eqitems.13th-floor.org/phpBB2/viewtopic.php?p=510#510
*/
2013-05-06 13:07:41 -04:00
2014-12-25 00:00:57 -05:00
if ( ! item ) //have to have an item to make the link
2013-02-16 16:14:39 -08:00
return false ;
//format:
//0 itemid aug1 aug2 aug3 aug4 aug5 evolving? loregroup evolved level hash
//0 00000 00000 00000 00000 00000 00000 0 0000 0 00000000
//length:
//1 5 5 5 5 5 5 1 4 1 8 = 45
//evolving item info: http://eqitems.13th-floor.org/phpBB2/viewtopic.php?t=145#558
2014-12-25 11:04:01 -05:00
2013-02-16 16:14:39 -08:00
//int hash = GetItemLinkHash(inst); //eventually this will work (currently crashes zone), but for now we'll skip the extra overhead
2014-12-25 11:04:01 -05:00
int hash = NOT_USED ;
// Tested with UF and RoF..there appears to be a problem with using non-augment arguments below...
// Currently, enabling them causes misalignments in what the client expects. I haven't looked
// into it further to determine the cause..but, the function is setup to accept the parameters.
// Note: some links appear with '00000' in front of the name..so, it's likely we need to send
2015-02-23 19:57:47 -05:00
// some additional information when certain parameters are true
2014-12-28 12:49:14 -05:00
//switch (GetClientVersion()) {
switch ( 0 ) {
2014-12-25 11:04:01 -05:00
case EQClientRoF2 :
// This operator contains 14 parameter masks..but, only 13 parameter values.
2015-02-23 19:57:47 -05:00
// Even so, the client link appears ok... Need to figure out the discrepancy
2014-12-25 00:00:57 -05:00
MakeAnyLenString ( & ret_link , " %1X " " %05X " " %05X " " %05X " " %05X " " %05X " " %05X " " %05X " " %1X " " %1X " " %04X " " %1X " " %05X " " %08X " ,
2014-12-06 14:38:34 -06:00
0 ,
item - > ID ,
2014-12-25 00:00:57 -05:00
aug0 ,
aug1 ,
aug2 ,
aug3 ,
aug4 ,
aug5 ,
2014-12-25 11:04:01 -05:00
0 , //evolving,
0 , //item->LoreGroup,
0 , //evolvedlevel,
2014-12-06 14:38:34 -06:00
0 ,
hash
) ;
2014-12-25 11:04:01 -05:00
return true ;
case EQClientRoF :
2013-05-06 13:07:41 -04:00
MakeAnyLenString ( & ret_link , " %1X " " %05X " " %05X " " %05X " " %05X " " %05X " " %05X " " %05X " " %1X " " %04X " " %1X " " %05X " " %08X " ,
2013-02-16 16:14:39 -08:00
0 ,
2013-05-06 13:07:41 -04:00
item - > ID ,
2014-12-25 00:00:57 -05:00
aug0 ,
aug1 ,
aug2 ,
aug3 ,
aug4 ,
aug5 ,
2014-12-25 11:04:01 -05:00
0 , //evolving,
0 , //item->LoreGroup,
0 , //evolvedlevel,
2013-02-16 16:14:39 -08:00
0 ,
hash
2014-12-25 00:00:57 -05:00
) ;
2014-12-25 11:04:01 -05:00
return true ;
case EQClientUnderfoot :
case EQClientSoD :
case EQClientSoF :
2013-05-06 13:07:41 -04:00
MakeAnyLenString ( & ret_link , " %1X " " %05X " " %05X " " %05X " " %05X " " %05X " " %05X " " %1X " " %04X " " %1X " " %05X " " %08X " ,
2013-02-16 16:14:39 -08:00
0 ,
2013-05-06 13:07:41 -04:00
item - > ID ,
2014-12-25 00:00:57 -05:00
aug0 ,
aug1 ,
aug2 ,
aug3 ,
aug4 ,
2014-12-25 11:04:01 -05:00
0 , //evolving,
0 , //item->LoreGroup,
0 , //evolvedlevel,
2013-02-16 16:14:39 -08:00
0 ,
hash
2014-12-25 00:00:57 -05:00
) ;
2014-12-25 11:04:01 -05:00
return true ;
case EQClientTitanium :
2013-05-06 13:07:41 -04:00
MakeAnyLenString ( & ret_link , " %1X " " %05X " " %05X " " %05X " " %05X " " %05X " " %05X " " %1X " " %04X " " %1X " " %08X " ,
2013-02-16 16:14:39 -08:00
0 ,
2013-05-06 13:07:41 -04:00
item - > ID ,
2014-12-25 00:00:57 -05:00
aug0 ,
aug1 ,
aug2 ,
aug3 ,
aug4 ,
2014-12-25 11:04:01 -05:00
0 , //evolving,
0 , //item->LoreGroup,
0 , //evolvedlevel,
2013-02-16 16:14:39 -08:00
hash
2014-12-25 00:00:57 -05:00
) ;
2014-12-25 11:04:01 -05:00
return true ;
case EQClient62 :
default :
return false ;
2013-02-16 16:14:39 -08:00
}
}
2015-01-15 21:24:26 -05:00
# endif
2013-02-16 16:14:39 -08:00
2020-05-17 18:36:06 -07:00
int Client : : GetItemLinkHash ( const EQ : : ItemInstance * inst ) {
2013-02-16 16:14:39 -08:00
//pre-Titanium: http://eqitems.13th-floor.org/phpBB2/viewtopic.php?t=70&postdays=0&postorder=asc
//Titanium: http://eqitems.13th-floor.org/phpBB2/viewtopic.php?t=145
if ( ! inst ) //have to have an item to make the hash
return 0 ;
2013-05-06 13:07:41 -04:00
2020-05-17 18:36:06 -07:00
const EQ : : ItemData * item = inst - > GetItem ( ) ;
2013-02-16 16:14:39 -08:00
char * hash_str = 0 ;
/*register */ int hash = 0 ;
//now the fun part, since different types of items use different hashes...
if ( item - > ItemClass = = 0 & & item - > CharmFileID ) { //charm
MakeAnyLenString ( & hash_str , " %d%s-1-1-1-1-1%d %d %d %d %d %d %d %d %d " ,
item - > ID ,
item - > Name ,
item - > Light ,
item - > Icon ,
item - > Price ,
item - > Size ,
item - > Weight ,
item - > ItemClass ,
item - > ItemType ,
item - > Favor ,
item - > GuildFavor ) ;
} else if ( item - > ItemClass = = 2 ) { //book
MakeAnyLenString ( & hash_str , " %d%s%d%d%09X " ,
item - > ID ,
item - > Name ,
item - > Weight ,
item - > BookType ,
item - > Price ) ;
} else if ( item - > ItemClass = = 1 ) { //bag
MakeAnyLenString ( & hash_str , " %d%s%x%d%09X%d " ,
item - > ID ,
item - > Name ,
item - > BagSlots ,
item - > BagWR ,
item - > Price ,
item - > Weight ) ;
} else { //everything else
MakeAnyLenString ( & hash_str , " %d%s-1-1-1-1-1%d %d %d %d %d %d %d %d %d %d %d %d %d " ,
item - > ID ,
item - > Name ,
item - > Mana ,
item - > HP ,
item - > Favor ,
item - > Light ,
item - > Icon ,
item - > Price ,
item - > Weight ,
item - > ReqLevel ,
item - > Size ,
item - > ItemClass ,
item - > ItemType ,
item - > AC ,
item - > GuildFavor ) ;
}
//this currently crashes zone, so someone feel free to fix this so we can work with hashes:
//*** glibc detected *** double free or corruption (out): 0xb2403470 ***
/*
while ( * hash_str ! = ' \0 ' ) {
register int c = toupper ( * hash_str ) ;
asm volatile ( " \
imul $ 31 , % 1 , % 1 ; \
movzx % % ax , % % edx ; \
addl % % edx , % 1 ; \
movl % 1 , % 0 ; \
"
: " =r " ( hash )
: " D " ( hash ) , " a " ( c )
: " %edx "
) ;
// This is what the inline asm is doing:
// hash *= 0x1f;
// hash += (int)c;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
hash_str + + ;
}
*/
safe_delete_array ( hash_str ) ;
return hash ;
}
2020-05-17 18:36:06 -07:00
// This appears to still be in use... The core of this should be incorporated into class EQ::SayLinkEngine
void Client : : SendItemLink ( const EQ : : ItemInstance * inst , bool send_to_all )
2013-02-16 16:14:39 -08:00
{
/*
this stuff is old , live dosent do this anymore . they send a much smaller
packet with the item number in it , but I cant seem to find it right now
*/
if ( ! inst )
return ;
2013-05-06 13:07:41 -04:00
2020-05-17 18:36:06 -07:00
const EQ : : ItemData * item = inst - > GetItem ( ) ;
2013-02-16 16:14:39 -08:00
const char * name2 = & item - > Name [ 0 ] ;
2016-05-25 16:10:28 -04:00
auto outapp = new EQApplicationPacket ( OP_ItemLinkText , strlen ( name2 ) + 68 ) ;
2013-02-16 16:14:39 -08:00
char buffer2 [ 135 ] = { 0 } ;
char itemlink [ 135 ] = { 0 } ;
sprintf ( itemlink , " %c0%06u0%05u-%05u-%05u-%05u-%05u00000000%c " ,
0x12 ,
item - > ID ,
inst - > GetAugmentItemID ( 0 ) ,
inst - > GetAugmentItemID ( 1 ) ,
inst - > GetAugmentItemID ( 2 ) ,
inst - > GetAugmentItemID ( 3 ) ,
inst - > GetAugmentItemID ( 4 ) ,
0x12 ) ;
sprintf ( buffer2 , " %c%c%c%c%c%c%c%c%c%c%c%c%s " , 0x00 , 0x00 , 0x00 , 0x00 , 0xD3 , 0x01 , 0x00 , 0x00 , 0x1E , 0x01 , 0x00 , 0x00 , itemlink ) ;
memcpy ( outapp - > pBuffer , buffer2 , outapp - > size ) ;
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
if ( send_to_all = = false )
return ;
const char * charname = this - > GetName ( ) ;
outapp = new EQApplicationPacket ( OP_ItemLinkText , strlen ( itemlink ) + 14 + strlen ( charname ) ) ;
char buffer3 [ 150 ] = { 0 } ;
sprintf ( buffer3 , " %c%c%c%c%c%c%c%c%c%c%c%c%6s%c%s " , 0x00 , 0x00 , 0x00 , 0x00 , 0xD2 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , charname , 0x00 , itemlink ) ;
memcpy ( outapp - > pBuffer , buffer3 , outapp - > size ) ;
entity_list . QueueCloseClients ( this - > CastToMob ( ) , outapp , true , 200 , 0 , false ) ;
safe_delete ( outapp ) ;
}
2020-05-17 18:36:06 -07:00
void Client : : SendLootItemInPacket ( const EQ : : ItemInstance * inst , int16 slot_id )
2013-02-16 16:14:39 -08:00
{
SendItemPacket ( slot_id , inst , ItemPacketTrade ) ;
}
2014-07-16 21:23:16 -04:00
bool Client : : IsValidSlot ( uint32 slot ) {
2020-05-17 18:36:06 -07:00
if ( slot < = EQ : : invslot : : POSSESSIONS_END & & slot > = EQ : : invslot : : POSSESSIONS_BEGIN ) {
2018-08-13 22:32:36 -04:00
return ( ( ( ( uint64 ) 1 < < slot ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask ) ! = 0 ) ;
}
2020-05-17 18:36:06 -07:00
else if ( slot < = EQ : : invbag : : GENERAL_BAGS_END & & slot > = EQ : : invbag : : GENERAL_BAGS_BEGIN ) {
auto temp_slot = EQ : : invslot : : GENERAL_BEGIN + ( ( slot - EQ : : invbag : : GENERAL_BAGS_BEGIN ) / EQ : : invbag : : SLOT_COUNT ) ;
2018-08-13 22:32:36 -04:00
return ( ( ( ( uint64 ) 1 < < temp_slot ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask ) ! = 0 ) ;
}
2020-05-17 18:36:06 -07:00
else if ( slot < = EQ : : invslot : : BANK_END & & slot > = EQ : : invslot : : BANK_BEGIN ) {
return ( ( slot - EQ : : invslot : : BANK_BEGIN ) < GetInv ( ) . GetLookup ( ) - > InventoryTypeSize . Bank ) ;
2018-08-13 22:32:36 -04:00
}
2020-05-17 18:36:06 -07:00
else if ( slot < = EQ : : invbag : : BANK_BAGS_END & & slot > = EQ : : invbag : : BANK_BAGS_BEGIN ) {
auto temp_slot = ( slot - EQ : : invbag : : BANK_BAGS_BEGIN ) / EQ : : invbag : : SLOT_COUNT ;
2019-01-07 00:11:07 -05:00
return ( temp_slot < GetInv ( ) . GetLookup ( ) - > InventoryTypeSize . Bank ) ;
2018-08-13 22:32:36 -04:00
}
else if (
( slot = = ( uint32 ) INVALID_INDEX ) | |
2020-05-17 18:36:06 -07:00
( slot = = ( uint32 ) EQ : : invslot : : slotCursor ) | |
( slot < = EQ : : invbag : : CURSOR_BAG_END & & slot > = EQ : : invbag : : CURSOR_BAG_BEGIN ) | |
( slot < = EQ : : invslot : : TRIBUTE_END & & slot > = EQ : : invslot : : TRIBUTE_BEGIN ) | |
( slot < = EQ : : invslot : : SHARED_BANK_END & & slot > = EQ : : invslot : : SHARED_BANK_BEGIN ) | |
( slot < = EQ : : invbag : : SHARED_BANK_BAGS_END & & slot > = EQ : : invbag : : SHARED_BANK_BAGS_BEGIN ) | |
( slot < = EQ : : invslot : : TRADE_END & & slot > = EQ : : invslot : : TRADE_BEGIN ) | |
( slot < = EQ : : invslot : : WORLD_END & & slot > = EQ : : invslot : : WORLD_BEGIN )
2018-08-13 22:32:36 -04:00
) {
2013-02-16 16:14:39 -08:00
return true ;
2015-01-15 21:24:26 -05:00
}
2018-08-13 22:32:36 -04:00
return false ;
2013-02-16 16:14:39 -08:00
}
bool Client : : IsBankSlot ( uint32 slot )
{
2020-05-17 18:36:06 -07:00
if ( ( slot > = EQ : : invslot : : BANK_BEGIN & & slot < = EQ : : invslot : : BANK_END ) | |
( slot > = EQ : : invbag : : BANK_BAGS_BEGIN & & slot < = EQ : : invbag : : BANK_BAGS_END ) | |
( slot > = EQ : : invslot : : SHARED_BANK_BEGIN & & slot < = EQ : : invslot : : SHARED_BANK_END ) | |
( slot > = EQ : : invbag : : SHARED_BANK_BAGS_BEGIN & & slot < = EQ : : invbag : : SHARED_BANK_BAGS_END ) )
2013-02-16 16:14:39 -08:00
{
return true ;
}
return false ;
}
// Moves items around both internally and in the database
// In the future, this can be optimized by pushing all changes through one database REPLACE call
bool Client : : SwapItem ( MoveItem_Struct * move_in ) {
uint32 src_slot_check = move_in - > from_slot ;
uint32 dst_slot_check = move_in - > to_slot ;
uint32 stack_count_check = move_in - > number_in_stack ;
if ( ! IsValidSlot ( src_slot_check ) ) {
// SoF+ sends a Unix timestamp (should be int32) for src and dst slots every 10 minutes for some reason.
if ( src_slot_check < 2147483647 )
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " Warning: Invalid slot move from slot %u to slot %u with %u charges! " , src_slot_check , dst_slot_check , stack_count_check ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Invalid slot move from slot [{}] to slot [{}] with [{}] charges! " , src_slot_check , dst_slot_check , stack_count_check ) ;
2013-02-16 16:14:39 -08:00
return false ;
}
if ( ! IsValidSlot ( dst_slot_check ) ) {
// SoF+ sends a Unix timestamp (should be int32) for src and dst slots every 10 minutes for some reason.
if ( src_slot_check < 2147483647 )
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " Warning: Invalid slot move from slot %u to slot %u with %u charges! " , src_slot_check , dst_slot_check , stack_count_check ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Invalid slot move from slot [{}] to slot [{}] with [{}] charges! " , src_slot_check , dst_slot_check , stack_count_check ) ;
2013-02-16 16:14:39 -08:00
return false ;
}
2014-12-20 01:52:58 -06:00
if ( move_in - > from_slot = = move_in - > to_slot ) { // Item summon, no further processing needed
2013-02-16 16:14:39 -08:00
if ( RuleB ( QueryServ , PlayerLogMoves ) ) { QSSwapItemAuditor ( move_in ) ; } // QS Audit
2020-05-17 18:36:06 -07:00
if ( ClientVersion ( ) > = EQ : : versions : : ClientVersion : : RoF ) { return true ; } // Can't do RoF+
2015-02-06 09:58:57 -05:00
2020-05-17 18:36:06 -07:00
if ( move_in - > to_slot = = EQ : : invslot : : slotCursor ) {
auto test_inst = m_inv . GetItem ( EQ : : invslot : : slotCursor ) ;
2015-02-06 09:58:57 -05:00
if ( test_inst = = nullptr ) { return true ; }
auto test_item = test_inst - > GetItem ( ) ;
if ( test_item = = nullptr ) { return true ; }
if ( ! test_item - > LoreFlag ) { return true ; }
bool lore_pass = true ;
if ( test_item - > LoreGroup = = 0xFFFFFFFF ) {
lore_pass = ( m_inv . HasItem ( test_item - > ID , 0 , ~ ( invWhereSharedBank | invWhereCursor ) ) = = INVALID_INDEX ) ;
}
else if ( test_item - > LoreGroup ! = 0 ) {
lore_pass = ( m_inv . HasItemByLoreGroup ( test_item - > LoreGroup , ~ ( invWhereSharedBank | invWhereCursor ) ) = = INVALID_INDEX ) ;
}
if ( ! lore_pass ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " ([{}]) Duplicate lore items are not allowed - destroying item [{}](id:[{}]) on cursor " ,
2015-02-06 09:58:57 -05:00
GetName ( ) , test_item - > Name , test_item - > ID ) ;
2019-08-11 00:14:02 -05:00
MessageString ( Chat : : Loot , 290 ) ;
2015-02-06 09:58:57 -05:00
parse - > EventItem ( EVENT_DESTROY_ITEM , this , test_inst , nullptr , " " , 0 ) ;
2020-05-17 18:36:06 -07:00
DeleteItemInInventory ( EQ : : invslot : : slotCursor , 0 , true ) ;
2015-02-06 09:58:57 -05:00
}
}
2013-02-16 16:14:39 -08:00
return true ;
}
2013-05-06 13:07:41 -04:00
2014-07-16 21:23:16 -04:00
if ( move_in - > to_slot = = ( uint32 ) INVALID_INDEX ) {
2020-05-17 18:36:06 -07:00
if ( move_in - > from_slot = = ( uint32 ) EQ : : invslot : : slotCursor ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Client destroyed item from cursor slot [{}] " , move_in - > from_slot ) ;
2013-02-16 16:14:39 -08:00
if ( RuleB ( QueryServ , PlayerLogMoves ) ) { QSSwapItemAuditor ( move_in ) ; } // QS Audit
2013-06-06 14:29:45 -07:00
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * inst = m_inv . GetItem ( EQ : : invslot : : slotCursor ) ;
2013-06-06 14:29:45 -07:00
if ( inst ) {
2013-06-07 02:26:17 -07:00
parse - > EventItem ( EVENT_DESTROY_ITEM , this , inst , nullptr , " " , 0 ) ;
2013-06-06 14:29:45 -07:00
}
2013-02-16 16:14:39 -08:00
DeleteItemInInventory ( move_in - > from_slot ) ;
2014-12-22 20:51:56 -06:00
SendCursorBuffer ( ) ;
2014-12-20 01:52:58 -06:00
2013-02-16 16:14:39 -08:00
return true ; // Item destroyed by client
}
else {
2019-09-02 02:50:39 -05:00
LogInventory ( " Deleted item from slot [{}] as a result of an inventory container tradeskill combine " , move_in - > from_slot ) ;
2013-02-16 16:14:39 -08:00
if ( RuleB ( QueryServ , PlayerLogMoves ) ) { QSSwapItemAuditor ( move_in ) ; } // QS Audit
DeleteItemInInventory ( move_in - > from_slot ) ;
2014-12-20 01:52:58 -06:00
return true ; // Item deletion
2013-02-16 16:14:39 -08:00
}
}
2018-08-13 22:32:36 -04:00
if ( auto_attack ) {
2020-05-17 18:36:06 -07:00
if ( move_in - > from_slot = = EQ : : invslot : : slotPrimary | | move_in - > from_slot = = EQ : : invslot : : slotSecondary | | move_in - > from_slot = = EQ : : invslot : : slotRange )
2018-08-13 22:32:36 -04:00
SetAttackTimer ( ) ;
2020-05-17 18:36:06 -07:00
else if ( move_in - > to_slot = = EQ : : invslot : : slotPrimary | | move_in - > to_slot = = EQ : : invslot : : slotSecondary | | move_in - > to_slot = = EQ : : invslot : : slotRange )
2018-08-13 22:32:36 -04:00
SetAttackTimer ( ) ;
}
2013-02-16 16:14:39 -08:00
// Step 1: Variables
int16 src_slot_id = ( int16 ) move_in - > from_slot ;
int16 dst_slot_id = ( int16 ) move_in - > to_slot ;
2015-01-15 21:24:26 -05:00
if ( IsBankSlot ( src_slot_id ) | | IsBankSlot ( dst_slot_id ) | | IsBankSlot ( src_slot_check ) | | IsBankSlot ( dst_slot_check ) ) {
2013-02-16 16:14:39 -08:00
uint32 distance = 0 ;
NPC * banker = entity_list . GetClosestBanker ( this , distance ) ;
if ( ! banker | | distance > USE_NPC_RANGE2 )
{
2013-05-04 18:06:58 -07:00
char * hacked_string = nullptr ;
2013-05-06 13:07:41 -04:00
MakeAnyLenString ( & hacked_string , " Player tried to make use of a banker(items) but %s is non-existant or too far away (%u units). " ,
2013-02-16 16:14:39 -08:00
banker ? banker - > GetName ( ) : " UNKNOWN NPC " , distance ) ;
database . SetMQDetectionFlag ( AccountName ( ) , GetName ( ) , hacked_string , zone - > GetShortName ( ) ) ;
safe_delete_array ( hacked_string ) ;
2019-07-26 19:22:29 -07:00
Kick ( " Inventory desync " ) ; // Kicking player to avoid item loss do to client and server inventories not being sync'd
2013-02-16 16:14:39 -08:00
return false ;
}
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
//Setup
uint32 srcitemid = 0 ;
uint32 dstitemid = 0 ;
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * src_inst = m_inv . GetItem ( src_slot_id ) ;
EQ : : ItemInstance * dst_inst = m_inv . GetItem ( dst_slot_id ) ;
2013-02-16 16:14:39 -08:00
if ( src_inst ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Src slot [{}] has item [{}] ([{}]) with [{}] charges in it " , src_slot_id , src_inst - > GetItem ( ) - > Name , src_inst - > GetItem ( ) - > ID , src_inst - > GetCharges ( ) ) ;
2013-02-16 16:14:39 -08:00
srcitemid = src_inst - > GetItem ( ) - > ID ;
//SetTint(dst_slot_id,src_inst->GetColor());
if ( src_inst - > GetCharges ( ) > 0 & & ( src_inst - > GetCharges ( ) < ( int16 ) move_in - > number_in_stack | | move_in - > number_in_stack > src_inst - > GetItem ( ) - > StackSize ) )
{
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " Error: Insufficient number in stack. " ) ;
2013-02-16 16:14:39 -08:00
return false ;
}
}
if ( dst_inst ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Dest slot [{}] has item [{}] ([{}]) with [{}] charges in it " , dst_slot_id , dst_inst - > GetItem ( ) - > Name , dst_inst - > GetItem ( ) - > ID , dst_inst - > GetCharges ( ) ) ;
2013-02-16 16:14:39 -08:00
dstitemid = dst_inst - > GetItem ( ) - > ID ;
}
if ( Trader & & srcitemid > 0 ) {
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * srcbag ;
EQ : : ItemInstance * dstbag ;
2013-02-16 16:14:39 -08:00
uint32 srcbagid = 0 ;
uint32 dstbagid = 0 ;
2014-07-31 07:52:38 -04:00
2020-05-17 18:36:06 -07:00
if ( src_slot_id > = EQ : : invbag : : GENERAL_BAGS_BEGIN & & src_slot_id < = EQ : : invbag : : GENERAL_BAGS_END ) {
2014-07-31 07:52:38 -04:00
srcbag = m_inv . GetItem ( ( ( int ) ( src_slot_id / 10 ) ) - 3 ) ;
if ( srcbag )
srcbagid = srcbag - > GetItem ( ) - > ID ;
2013-02-16 16:14:39 -08:00
}
2020-05-17 18:36:06 -07:00
if ( dst_slot_id > = EQ : : invbag : : GENERAL_BAGS_BEGIN & & dst_slot_id < = EQ : : invbag : : GENERAL_BAGS_END ) {
2014-07-31 07:52:38 -04:00
dstbag = m_inv . GetItem ( ( ( int ) ( dst_slot_id / 10 ) ) - 3 ) ;
if ( dstbag )
dstbagid = dstbag - > GetItem ( ) - > ID ;
2013-02-16 16:14:39 -08:00
}
if ( srcitemid = = 17899 | | srcbagid = = 17899 | | dstitemid = = 17899 | | dstbagid = = 17899 ) {
this - > Trader_EndTrader ( ) ;
2019-08-11 00:00:55 -05:00
this - > Message ( Chat : : Red , " You cannot move your Trader Satchels, or items inside them, while Trading. " ) ;
2013-02-16 16:14:39 -08:00
}
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
// Step 2: Validate item in from_slot
// After this, we can assume src_inst is a valid ptr
2020-05-17 18:36:06 -07:00
if ( ! src_inst & & ( src_slot_id < EQ : : invslot : : WORLD_BEGIN | | src_slot_id > EQ : : invslot : : WORLD_END ) ) {
2013-02-16 16:14:39 -08:00
if ( dst_inst ) {
2013-05-06 13:07:41 -04:00
// If there is no source item, but there is a destination item,
2013-02-16 16:14:39 -08:00
// move the slots around before deleting the invalid source slot item,
// which is now in the destination slot.
move_in - > from_slot = dst_slot_check ;
move_in - > to_slot = src_slot_check ;
move_in - > number_in_stack = dst_inst - > GetCharges ( ) ;
2019-09-02 02:50:39 -05:00
if ( ! SwapItem ( move_in ) ) { LogInventory ( " Recursive SwapItem call failed due to non-existent destination item (charid: [{}], fromslot: [{}], toslot: [{}]) " , CharacterID ( ) , src_slot_id , dst_slot_id ) ; }
2013-02-16 16:14:39 -08:00
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
return false ;
}
//verify shared bank transactions in the database
2020-05-17 18:36:06 -07:00
if ( src_inst & & src_slot_id > = EQ : : invslot : : SHARED_BANK_BEGIN & & src_slot_id < = EQ : : invbag : : SHARED_BANK_BAGS_END ) {
2013-02-16 16:14:39 -08:00
if ( ! database . VerifyInventory ( account_id , src_slot_id , src_inst ) ) {
2019-09-01 22:05:44 -05:00
LogError ( " Player [{}] on account [{}] was found exploiting the shared bank. \n " , GetName ( ) , account_name ) ;
2013-02-16 16:14:39 -08:00
DeleteItemInInventory ( dst_slot_id , 0 , true ) ;
return ( false ) ;
}
2020-05-17 18:36:06 -07:00
if ( src_slot_id > = EQ : : invslot : : SHARED_BANK_BEGIN & & src_slot_id < = EQ : : invslot : : SHARED_BANK_END & & src_inst - > IsClassBag ( ) ) {
for ( uint8 idx = EQ : : invbag : : SLOT_BEGIN ; idx < = EQ : : invbag : : SLOT_END ; idx + + ) {
const EQ : : ItemInstance * baginst = src_inst - > GetItem ( idx ) ;
if ( baginst & & ! database . VerifyInventory ( account_id , EQ : : InventoryProfile : : CalcSlotId ( src_slot_id , idx ) , baginst ) ) {
DeleteItemInInventory ( EQ : : InventoryProfile : : CalcSlotId ( src_slot_id , idx ) , 0 , false ) ;
2013-02-16 16:14:39 -08:00
}
}
}
}
2020-05-17 18:36:06 -07:00
if ( dst_inst & & dst_slot_id > = EQ : : invslot : : SHARED_BANK_BEGIN & & dst_slot_id < = EQ : : invbag : : SHARED_BANK_BAGS_END ) {
2013-02-16 16:14:39 -08:00
if ( ! database . VerifyInventory ( account_id , dst_slot_id , dst_inst ) ) {
2019-09-01 22:05:44 -05:00
LogError ( " Player [{}] on account [{}] was found exploting the shared bank. \n " , GetName ( ) , account_name ) ;
2013-02-16 16:14:39 -08:00
DeleteItemInInventory ( src_slot_id , 0 , true ) ;
return ( false ) ;
}
2020-05-17 18:36:06 -07:00
if ( dst_slot_id > = EQ : : invslot : : SHARED_BANK_BEGIN & & dst_slot_id < = EQ : : invslot : : SHARED_BANK_END & & dst_inst - > IsClassBag ( ) ) {
for ( uint8 idx = EQ : : invbag : : SLOT_BEGIN ; idx < = EQ : : invbag : : SLOT_END ; idx + + ) {
const EQ : : ItemInstance * baginst = dst_inst - > GetItem ( idx ) ;
if ( baginst & & ! database . VerifyInventory ( account_id , EQ : : InventoryProfile : : CalcSlotId ( dst_slot_id , idx ) , baginst ) ) {
DeleteItemInInventory ( EQ : : InventoryProfile : : CalcSlotId ( dst_slot_id , idx ) , 0 , false ) ;
2013-02-16 16:14:39 -08:00
}
}
}
}
// Check for No Drop Hacks
Mob * with = trade - > With ( ) ;
2020-05-17 18:36:06 -07:00
if ( ( ( with & & with - > IsClient ( ) & & dst_slot_id > = EQ : : invslot : : TRADE_BEGIN & & dst_slot_id < = EQ : : invslot : : TRADE_END ) | |
( dst_slot_id > = EQ : : invslot : : SHARED_BANK_BEGIN & & dst_slot_id < = EQ : : invbag : : SHARED_BANK_BAGS_END ) )
2013-02-16 16:14:39 -08:00
& & GetInv ( ) . CheckNoDrop ( src_slot_id )
& & RuleI ( World , FVNoDropFlag ) = = 0 | | RuleI ( Character , MinStatusForNoDropExemptions ) < Admin ( ) & & RuleI ( World , FVNoDropFlag ) = = 2 ) {
2015-01-24 20:46:48 -05:00
auto ndh_inst = m_inv [ src_slot_id ] ;
std : : string ndh_item_data ;
if ( ndh_inst = = nullptr ) {
2020-05-17 18:36:06 -07:00
ndh_item_data . append ( " [nullptr on EQ::ItemInstance*] " ) ;
2015-01-24 20:46:48 -05:00
}
else {
auto ndh_item = ndh_inst - > GetItem ( ) ;
if ( ndh_item = = nullptr ) {
2016-10-16 05:10:54 -04:00
ndh_item_data . append ( " [nullptr on ItemData*] " ) ;
2015-01-24 20:46:48 -05:00
}
else {
ndh_item_data . append ( StringFormat ( " name=%s " , ndh_item - > Name ) ) ;
ndh_item_data . append ( StringFormat ( " , id=%u " , ndh_item - > ID ) ) ;
ndh_item_data . append ( StringFormat ( " , nodrop=%s(%u) " , ( ndh_item - > NoDrop = = 0 ? " true " : " false " ) , ndh_item - > NoDrop ) ) ;
}
}
2019-09-02 03:10:03 -05:00
LogError ( " WorldKick() of Player [{}](id:[{}], acct:[{}]) due to 'NoDrop Hack' detection >> SlotID:[{}], ItemData:[{}] " ,
2015-01-24 20:46:48 -05:00
GetName ( ) , CharacterID ( ) , AccountID ( ) , src_slot_id , ndh_item_data . c_str ( ) ) ;
ndh_inst = nullptr ;
2013-02-16 16:14:39 -08:00
DeleteItemInInventory ( src_slot_id ) ;
WorldKick ( ) ;
return false ;
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
// Step 3: Check for interaction with World Container (tradeskills)
2013-05-04 18:06:58 -07:00
if ( m_tradeskill_object ! = nullptr ) {
2020-05-17 18:36:06 -07:00
if ( src_slot_id > = EQ : : invslot : : WORLD_BEGIN & & src_slot_id < = EQ : : invslot : : WORLD_END ) {
2013-02-16 16:14:39 -08:00
// Picking up item from world container
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * inst = m_tradeskill_object - > PopItem ( EQ : : InventoryProfile : : CalcBagIdx ( src_slot_id ) ) ;
2013-02-16 16:14:39 -08:00
if ( inst ) {
PutItemInInventory ( dst_slot_id , * inst , false ) ;
safe_delete ( inst ) ;
}
if ( RuleB ( QueryServ , PlayerLogMoves ) ) { QSSwapItemAuditor ( move_in , true ) ; } // QS Audit
return true ;
}
2020-05-17 18:36:06 -07:00
else if ( dst_slot_id > = EQ : : invslot : : WORLD_BEGIN & & dst_slot_id < = EQ : : invslot : : WORLD_END ) {
2013-02-16 16:14:39 -08:00
// Putting item into world container, which may swap (or pile onto) with existing item
2020-05-17 18:36:06 -07:00
uint8 world_idx = EQ : : InventoryProfile : : CalcBagIdx ( dst_slot_id ) ;
EQ : : ItemInstance * world_inst = m_tradeskill_object - > PopItem ( world_idx ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
// Case 1: No item in container, unidirectional "Put"
2013-05-04 18:06:58 -07:00
if ( world_inst = = nullptr ) {
2013-02-16 16:14:39 -08:00
m_tradeskill_object - > PutItem ( world_idx , src_inst ) ;
m_inv . DeleteItem ( src_slot_id ) ;
}
else {
2020-05-17 18:36:06 -07:00
const EQ : : ItemData * world_item = world_inst - > GetItem ( ) ;
const EQ : : ItemData * src_item = src_inst - > GetItem ( ) ;
2013-02-16 16:14:39 -08:00
if ( world_item & & src_item ) {
// Case 2: Same item on cursor, stacks, transfer of charges needed
if ( ( world_item - > ID = = src_item - > ID ) & & src_inst - > IsStackable ( ) ) {
int16 world_charges = world_inst - > GetCharges ( ) ;
int16 src_charges = src_inst - > GetCharges ( ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
// Fill up destination stack as much as possible
world_charges + = src_charges ;
if ( world_charges > world_inst - > GetItem ( ) - > StackSize ) {
src_charges = world_charges - world_inst - > GetItem ( ) - > StackSize ;
world_charges = world_inst - > GetItem ( ) - > StackSize ;
}
else {
src_charges = 0 ;
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
world_inst - > SetCharges ( world_charges ) ;
2014-10-22 22:57:20 -04:00
m_tradeskill_object - > PutItem ( world_idx , world_inst ) ;
2013-02-16 16:14:39 -08:00
m_tradeskill_object - > Save ( ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
if ( src_charges = = 0 ) {
m_inv . DeleteItem ( src_slot_id ) ; // DB remove will occur below
}
else {
src_inst - > SetCharges ( src_charges ) ;
}
}
else {
// Case 3: Swap the item on user with item in world container
// World containers don't follow normal rules for swapping
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * inv_inst = m_inv . PopItem ( src_slot_id ) ;
2013-02-16 16:14:39 -08:00
m_tradeskill_object - > PutItem ( world_idx , inv_inst ) ;
m_inv . PutItem ( src_slot_id , * world_inst ) ;
safe_delete ( inv_inst ) ;
}
}
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
safe_delete ( world_inst ) ;
2020-05-17 18:36:06 -07:00
if ( src_slot_id = = EQ : : invslot : : slotCursor )
2014-12-21 12:14:37 -06:00
{
2014-12-20 01:52:58 -06:00
if ( dstitemid = = 0 )
{
2014-12-22 20:51:56 -06:00
SendCursorBuffer ( ) ;
2014-12-20 01:52:58 -06:00
}
2015-02-06 07:57:15 -05:00
auto s = m_inv . cursor_cbegin ( ) , e = m_inv . cursor_cend ( ) ;
2013-02-16 16:14:39 -08:00
database . SaveCursor ( character_id , s , e ) ;
2014-12-21 12:14:37 -06:00
}
else
{
2013-02-16 16:14:39 -08:00
database . SaveInventory ( character_id , m_inv [ src_slot_id ] , src_slot_id ) ;
2014-12-21 12:14:37 -06:00
}
2013-02-16 16:14:39 -08:00
if ( RuleB ( QueryServ , PlayerLogMoves ) ) { QSSwapItemAuditor ( move_in , true ) ; } // QS Audit
return true ;
}
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
// Step 4: Check for entity trade
2020-05-17 18:36:06 -07:00
if ( dst_slot_id > = EQ : : invslot : : TRADE_BEGIN & & dst_slot_id < = EQ : : invslot : : TRADE_END ) {
if ( src_slot_id ! = EQ : : invslot : : slotCursor ) {
2019-07-26 19:22:29 -07:00
Kick ( " Trade with non-cursor item " ) ;
2013-02-16 16:14:39 -08:00
return false ;
}
if ( with ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Trade item move from slot [{}] to slot [{}] (trade with [{}]) " , src_slot_id , dst_slot_id , with - > GetName ( ) ) ;
2013-02-16 16:14:39 -08:00
// Fill Trade list with items from cursor
2020-05-17 18:36:06 -07:00
if ( ! m_inv [ EQ : : invslot : : slotCursor ] ) {
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " Error: Cursor item not located on server! " ) ;
2013-02-16 16:14:39 -08:00
return false ;
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
// Add cursor item to trade bucket
// Also sends trade information to other client of trade session
if ( RuleB ( QueryServ , PlayerLogMoves ) ) { QSSwapItemAuditor ( move_in ) ; } // QS Audit
2014-08-22 20:48:11 -04:00
trade - > AddEntity ( dst_slot_id , move_in - > number_in_stack ) ;
2014-12-20 01:52:58 -06:00
if ( dstitemid = = 0 )
{
2014-12-22 20:51:56 -06:00
SendCursorBuffer ( ) ;
2014-12-20 01:52:58 -06:00
}
2013-02-16 16:14:39 -08:00
return true ;
} else {
if ( RuleB ( QueryServ , PlayerLogMoves ) ) { QSSwapItemAuditor ( move_in ) ; } // QS Audit
SummonItem ( src_inst - > GetID ( ) , src_inst - > GetCharges ( ) ) ;
2020-05-17 18:36:06 -07:00
DeleteItemInInventory ( EQ : : invslot : : slotCursor ) ;
2013-02-16 16:14:39 -08:00
return true ;
}
}
2013-05-06 13:07:41 -04:00
2014-12-20 01:52:58 -06:00
bool all_to_stack = false ;
2013-02-16 16:14:39 -08:00
// Step 5: Swap (or stack) items
if ( move_in - > number_in_stack > 0 ) {
// Determine if charged items can stack
if ( src_inst & & ! src_inst - > IsStackable ( ) ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Move from [{}] to [{}] with stack size [{}]. [{}] is not a stackable item. (charname: [{}]) " , src_slot_id , dst_slot_id , move_in - > number_in_stack , src_inst - > GetItem ( ) - > Name , GetName ( ) ) ;
2013-02-16 16:14:39 -08:00
return false ;
}
if ( dst_inst ) {
if ( src_inst - > GetID ( ) ! = dst_inst - > GetID ( ) ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Move from [{}] to [{}] with stack size [{}]. Incompatible item types: [{}] != [{}] " , src_slot_id , dst_slot_id , move_in - > number_in_stack , src_inst - > GetID ( ) , dst_inst - > GetID ( ) ) ;
2013-02-16 16:14:39 -08:00
return ( false ) ;
}
if ( dst_inst - > GetCharges ( ) < dst_inst - > GetItem ( ) - > StackSize ) {
//we have a chance of stacking.
2019-09-02 02:50:39 -05:00
LogInventory ( " Move from [{}] to [{}] with stack size [{}]. dest has [{}]/[{}] charges " , src_slot_id , dst_slot_id , move_in - > number_in_stack , dst_inst - > GetCharges ( ) , dst_inst - > GetItem ( ) - > StackSize ) ;
2013-02-16 16:14:39 -08:00
// Charges can be emptied into dst
uint16 usedcharges = dst_inst - > GetItem ( ) - > StackSize - dst_inst - > GetCharges ( ) ;
if ( usedcharges > move_in - > number_in_stack )
usedcharges = move_in - > number_in_stack ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
dst_inst - > SetCharges ( dst_inst - > GetCharges ( ) + usedcharges ) ;
src_inst - > SetCharges ( src_inst - > GetCharges ( ) - usedcharges ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
// Depleted all charges?
if ( src_inst - > GetCharges ( ) < 1 )
{
2019-09-02 02:50:39 -05:00
LogInventory ( " Dest ([{}]) now has [{}] charges, source ([{}]) was entirely consumed. ([{}] moved) " , dst_slot_id , dst_inst - > GetCharges ( ) , src_slot_id , usedcharges ) ;
2013-05-04 18:06:58 -07:00
database . SaveInventory ( CharacterID ( ) , nullptr , src_slot_id ) ;
2013-02-16 16:14:39 -08:00
m_inv . DeleteItem ( src_slot_id ) ;
2014-12-20 01:52:58 -06:00
all_to_stack = true ;
2013-02-16 16:14:39 -08:00
} else {
2019-09-02 02:50:39 -05:00
LogInventory ( " Dest ([{}]) now has [{}] charges, source ([{}]) has [{}] ([{}] moved) " , dst_slot_id , dst_inst - > GetCharges ( ) , src_slot_id , src_inst - > GetCharges ( ) , usedcharges ) ;
2013-02-16 16:14:39 -08:00
}
} else {
2019-09-02 02:50:39 -05:00
LogInventory ( " Move from [{}] to [{}] with stack size [{}]. Exceeds dest maximum stack size: [{}]/[{}] " , src_slot_id , dst_slot_id , move_in - > number_in_stack , ( src_inst - > GetCharges ( ) + dst_inst - > GetCharges ( ) ) , dst_inst - > GetItem ( ) - > StackSize ) ;
2013-02-16 16:14:39 -08:00
return false ;
}
}
else {
// Nothing in destination slot: split stack into two
if ( ( int16 ) move_in - > number_in_stack > = src_inst - > GetCharges ( ) ) {
// Move entire stack
2020-05-17 18:36:06 -07:00
EQ : : InventoryProfile : : SwapItemFailState fail_state = EQ : : InventoryProfile : : swapInvalid ;
2017-04-02 05:06:13 -04:00
if ( ! m_inv . SwapItem ( src_slot_id , dst_slot_id , fail_state ) ) { return false ; }
2019-09-02 02:50:39 -05:00
LogInventory ( " Move entire stack from [{}] to [{}] with stack size [{}]. Dest empty " , src_slot_id , dst_slot_id , move_in - > number_in_stack ) ;
2013-02-16 16:14:39 -08:00
}
else {
// Split into two
src_inst - > SetCharges ( src_inst - > GetCharges ( ) - move_in - > number_in_stack ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Split stack of [{}] ([{}]) from slot [{}] to [{}] with stack size [{}]. Src keeps [{}] " , src_inst - > GetItem ( ) - > Name , src_inst - > GetItem ( ) - > ID , src_slot_id , dst_slot_id , move_in - > number_in_stack , src_inst - > GetCharges ( ) ) ;
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * inst = database . CreateItem ( src_inst - > GetItem ( ) , move_in - > number_in_stack ) ;
2013-02-16 16:14:39 -08:00
m_inv . PutItem ( dst_slot_id , * inst ) ;
safe_delete ( inst ) ;
}
}
}
else {
// Not dealing with charges - just do direct swap
2020-05-17 18:36:06 -07:00
if ( src_inst & & ( dst_slot_id < = EQ : : invslot : : EQUIPMENT_END ) & & dst_slot_id > = EQ : : invslot : : EQUIPMENT_BEGIN ) {
2013-02-16 16:14:39 -08:00
if ( src_inst - > GetItem ( ) - > Attuneable ) {
2014-12-15 17:55:23 -06:00
src_inst - > SetAttuned ( true ) ;
2013-02-16 16:14:39 -08:00
}
if ( src_inst - > IsAugmented ( ) ) {
2020-05-17 18:36:06 -07:00
for ( int i = EQ : : invaug : : SOCKET_BEGIN ; i < = EQ : : invaug : : SOCKET_END ; i + + ) {
2013-02-16 16:14:39 -08:00
if ( src_inst - > GetAugment ( i ) ) {
if ( src_inst - > GetAugment ( i ) - > GetItem ( ) - > Attuneable ) {
2014-12-15 17:55:23 -06:00
src_inst - > GetAugment ( i ) - > SetAttuned ( true ) ;
2013-02-16 16:14:39 -08:00
}
}
}
}
SetMaterial ( dst_slot_id , src_inst - > GetItem ( ) - > ID ) ;
}
2017-04-02 05:06:13 -04:00
2020-05-17 18:36:06 -07:00
EQ : : InventoryProfile : : SwapItemFailState fail_state = EQ : : InventoryProfile : : swapInvalid ;
2017-04-02 16:21:13 -04:00
if ( ! m_inv . SwapItem ( src_slot_id , dst_slot_id , fail_state , GetBaseRace ( ) , GetBaseClass ( ) , GetDeity ( ) , GetLevel ( ) ) ) {
2017-04-02 05:06:13 -04:00
const char * fail_message = " The selected slot was invalid. " ;
2020-05-17 18:36:06 -07:00
if ( fail_state = = EQ : : InventoryProfile : : swapRaceClass | | fail_state = = EQ : : InventoryProfile : : swapDeity )
2017-04-02 05:06:13 -04:00
fail_message = " Your class, deity and/or race may not equip that item. " ;
2020-05-17 18:36:06 -07:00
else if ( fail_state = = EQ : : InventoryProfile : : swapLevel )
2017-04-02 05:06:13 -04:00
fail_message = " You are not sufficient level to use this item. " ;
2017-04-02 16:21:13 -04:00
if ( fail_message )
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " %s " , fail_message ) ;
2017-04-02 05:06:13 -04:00
return false ;
}
2019-09-02 02:50:39 -05:00
LogInventory ( " Moving entire item from slot [{}] to slot [{}] " , src_slot_id , dst_slot_id ) ;
2013-06-21 14:20:30 -07:00
2020-05-17 18:36:06 -07:00
if ( src_slot_id < = EQ : : invslot : : EQUIPMENT_END ) {
2013-06-21 14:20:30 -07:00
if ( src_inst ) {
parse - > EventItem ( EVENT_UNEQUIP_ITEM , this , src_inst , nullptr , " " , src_slot_id ) ;
}
if ( dst_inst ) {
parse - > EventItem ( EVENT_EQUIP_ITEM , this , dst_inst , nullptr , " " , src_slot_id ) ;
}
}
2020-05-17 18:36:06 -07:00
if ( dst_slot_id < = EQ : : invslot : : EQUIPMENT_END ) {
2013-06-21 14:20:30 -07:00
if ( dst_inst ) {
parse - > EventItem ( EVENT_UNEQUIP_ITEM , this , dst_inst , nullptr , " " , dst_slot_id ) ;
}
if ( src_inst ) {
parse - > EventItem ( EVENT_EQUIP_ITEM , this , src_inst , nullptr , " " , dst_slot_id ) ;
}
}
2013-02-16 16:14:39 -08:00
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
int matslot = SlotConvert2 ( dst_slot_id ) ;
2020-05-17 18:36:06 -07:00
if ( dst_slot_id < = EQ : : invslot : : EQUIPMENT_END & & matslot ! = EQ : : textures : : armorHead ) { // think this is to allow the client to update with /showhelm
2013-02-16 16:14:39 -08:00
SendWearChange ( matslot ) ;
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
// Step 7: Save change to the database
2020-05-17 18:36:06 -07:00
if ( src_slot_id = = EQ : : invslot : : slotCursor ) {
2014-12-20 01:52:58 -06:00
// If not swapping another item to cursor and stacking items were depleted
if ( dstitemid = = 0 | | all_to_stack = = true )
{
2014-12-22 20:51:56 -06:00
SendCursorBuffer ( ) ;
2014-12-20 01:52:58 -06:00
}
2015-02-06 07:57:15 -05:00
auto s = m_inv . cursor_cbegin ( ) , e = m_inv . cursor_cend ( ) ;
2013-02-16 16:14:39 -08:00
database . SaveCursor ( character_id , s , e ) ;
2015-01-15 21:24:26 -05:00
}
else {
2013-02-16 16:14:39 -08:00
database . SaveInventory ( character_id , m_inv . GetItem ( src_slot_id ) , src_slot_id ) ;
2015-01-15 21:24:26 -05:00
}
2014-07-31 07:52:38 -04:00
2020-05-17 18:36:06 -07:00
if ( dst_slot_id = = EQ : : invslot : : slotCursor ) {
2015-02-06 07:57:15 -05:00
auto s = m_inv . cursor_cbegin ( ) , e = m_inv . cursor_cend ( ) ;
2013-02-16 16:14:39 -08:00
database . SaveCursor ( character_id , s , e ) ;
2015-01-15 21:24:26 -05:00
}
else {
2013-02-16 16:14:39 -08:00
database . SaveInventory ( character_id , m_inv . GetItem ( dst_slot_id ) , dst_slot_id ) ;
2015-01-15 21:24:26 -05:00
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
if ( RuleB ( QueryServ , PlayerLogMoves ) ) { QSSwapItemAuditor ( move_in , true ) ; } // QS Audit
// Step 8: Re-calc stats
CalcBonuses ( ) ;
return true ;
}
void Client : : SwapItemResync ( MoveItem_Struct * move_slots ) {
2014-07-16 21:23:16 -04:00
// wow..this thing created a helluva memory leak...
// with any luck..this won't be needed in the future
2013-02-16 16:14:39 -08:00
// resync the 'from' and 'to' slots on an as-needed basis
2015-02-23 19:57:47 -05:00
// Not as effective as the full process, but less intrusive to gameplay
2019-09-02 02:50:39 -05:00
LogInventory ( " Inventory desyncronization. (charname: [{}], source: [{}], destination: [{}]) " , GetName ( ) , move_slots - > from_slot , move_slots - > to_slot ) ;
2019-08-11 00:00:55 -05:00
Message ( Chat : : Yellow , " Inventory Desyncronization detected: Resending slot data... " ) ;
2013-02-16 16:14:39 -08:00
2020-05-17 18:36:06 -07:00
if ( move_slots - > from_slot > = EQ : : invslot : : EQUIPMENT_BEGIN & & move_slots - > from_slot < = EQ : : invbag : : CURSOR_BAG_END ) {
int16 resync_slot = ( EQ : : InventoryProfile : : CalcSlotId ( move_slots - > from_slot ) = = INVALID_INDEX ) ? move_slots - > from_slot : EQ : : InventoryProfile : : CalcSlotId ( move_slots - > from_slot ) ;
2014-07-16 21:23:16 -04:00
if ( IsValidSlot ( resync_slot ) & & resync_slot ! = INVALID_INDEX ) {
2015-02-23 19:57:47 -05:00
// This prevents the client from crashing when closing any 'phantom' bags
2020-05-17 18:36:06 -07:00
const EQ : : ItemData * token_struct = database . GetItem ( 22292 ) ; // 'Copper Coin'
EQ : : ItemInstance * token_inst = database . CreateItem ( token_struct , 1 ) ;
2013-02-16 16:14:39 -08:00
SendItemPacket ( resync_slot , token_inst , ItemPacketTrade ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
if ( m_inv [ resync_slot ] ) { SendItemPacket ( resync_slot , m_inv [ resync_slot ] , ItemPacketTrade ) ; }
else {
2016-05-25 16:10:28 -04:00
auto outapp = new EQApplicationPacket ( OP_DeleteItem , sizeof ( DeleteItem_Struct ) ) ;
2013-02-16 16:14:39 -08:00
DeleteItem_Struct * delete_slot = ( DeleteItem_Struct * ) outapp - > pBuffer ;
delete_slot - > from_slot = resync_slot ;
delete_slot - > to_slot = 0xFFFFFFFF ;
delete_slot - > number_in_stack = 0xFFFFFFFF ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
}
2014-07-16 21:23:16 -04:00
safe_delete ( token_inst ) ;
2019-08-11 00:00:55 -05:00
Message ( Chat : : Lime , " Source slot %i resyncronized. " , move_slots - > from_slot ) ;
2013-02-16 16:14:39 -08:00
}
2019-08-11 00:00:55 -05:00
else { Message ( Chat : : Red , " Could not resyncronize source slot %i. " , move_slots - > from_slot ) ; }
2013-02-16 16:14:39 -08:00
}
else {
2020-05-17 18:36:06 -07:00
int16 resync_slot = ( EQ : : InventoryProfile : : CalcSlotId ( move_slots - > from_slot ) = = INVALID_INDEX ) ? move_slots - > from_slot : EQ : : InventoryProfile : : CalcSlotId ( move_slots - > from_slot ) ;
2014-07-16 21:23:16 -04:00
if ( IsValidSlot ( resync_slot ) & & resync_slot ! = INVALID_INDEX ) {
2013-02-16 16:14:39 -08:00
if ( m_inv [ resync_slot ] ) {
2020-05-17 18:36:06 -07:00
const EQ : : ItemData * token_struct = database . GetItem ( 22292 ) ; // 'Copper Coin'
EQ : : ItemInstance * token_inst = database . CreateItem ( token_struct , 1 ) ;
2013-02-16 16:14:39 -08:00
SendItemPacket ( resync_slot , token_inst , ItemPacketTrade ) ;
SendItemPacket ( resync_slot , m_inv [ resync_slot ] , ItemPacketTrade ) ;
2014-07-16 21:23:16 -04:00
safe_delete ( token_inst ) ;
2019-08-11 00:00:55 -05:00
Message ( Chat : : Lime , " Source slot %i resyncronized. " , move_slots - > from_slot ) ;
2013-02-16 16:14:39 -08:00
}
2019-08-11 00:00:55 -05:00
else { Message ( Chat : : Red , " Could not resyncronize source slot %i. " , move_slots - > from_slot ) ; }
2013-02-16 16:14:39 -08:00
}
2019-08-11 00:00:55 -05:00
else { Message ( Chat : : Red , " Could not resyncronize source slot %i. " , move_slots - > from_slot ) ; }
2013-02-16 16:14:39 -08:00
}
2020-05-17 18:36:06 -07:00
if ( move_slots - > to_slot > = EQ : : invslot : : EQUIPMENT_BEGIN & & move_slots - > to_slot < = EQ : : invbag : : CURSOR_BAG_END ) {
int16 resync_slot = ( EQ : : InventoryProfile : : CalcSlotId ( move_slots - > to_slot ) = = INVALID_INDEX ) ? move_slots - > to_slot : EQ : : InventoryProfile : : CalcSlotId ( move_slots - > to_slot ) ;
2014-07-16 21:23:16 -04:00
if ( IsValidSlot ( resync_slot ) & & resync_slot ! = INVALID_INDEX ) {
2020-05-17 18:36:06 -07:00
const EQ : : ItemData * token_struct = database . GetItem ( 22292 ) ; // 'Copper Coin'
EQ : : ItemInstance * token_inst = database . CreateItem ( token_struct , 1 ) ;
2013-02-16 16:14:39 -08:00
SendItemPacket ( resync_slot , token_inst , ItemPacketTrade ) ;
if ( m_inv [ resync_slot ] ) { SendItemPacket ( resync_slot , m_inv [ resync_slot ] , ItemPacketTrade ) ; }
else {
2016-05-25 16:10:28 -04:00
auto outapp = new EQApplicationPacket ( OP_DeleteItem , sizeof ( DeleteItem_Struct ) ) ;
2013-02-16 16:14:39 -08:00
DeleteItem_Struct * delete_slot = ( DeleteItem_Struct * ) outapp - > pBuffer ;
delete_slot - > from_slot = resync_slot ;
delete_slot - > to_slot = 0xFFFFFFFF ;
delete_slot - > number_in_stack = 0xFFFFFFFF ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
}
2014-07-16 21:23:16 -04:00
safe_delete ( token_inst ) ;
2019-08-11 00:00:55 -05:00
Message ( Chat : : Lime , " Destination slot %i resyncronized. " , move_slots - > to_slot ) ;
2013-02-16 16:14:39 -08:00
}
2019-08-11 00:00:55 -05:00
else { Message ( Chat : : Red , " Could not resyncronize destination slot %i. " , move_slots - > to_slot ) ; }
2013-02-16 16:14:39 -08:00
}
else {
2020-05-17 18:36:06 -07:00
int16 resync_slot = ( EQ : : InventoryProfile : : CalcSlotId ( move_slots - > to_slot ) = = INVALID_INDEX ) ? move_slots - > to_slot : EQ : : InventoryProfile : : CalcSlotId ( move_slots - > to_slot ) ;
2014-07-16 21:23:16 -04:00
if ( IsValidSlot ( resync_slot ) & & resync_slot ! = INVALID_INDEX ) {
2013-02-16 16:14:39 -08:00
if ( m_inv [ resync_slot ] ) {
2020-05-17 18:36:06 -07:00
const EQ : : ItemData * token_struct = database . GetItem ( 22292 ) ; // 'Copper Coin'
EQ : : ItemInstance * token_inst = database . CreateItem ( token_struct , 1 ) ;
2013-02-16 16:14:39 -08:00
SendItemPacket ( resync_slot , token_inst , ItemPacketTrade ) ;
SendItemPacket ( resync_slot , m_inv [ resync_slot ] , ItemPacketTrade ) ;
2014-07-16 21:23:16 -04:00
safe_delete ( token_inst ) ;
2019-08-11 00:00:55 -05:00
Message ( Chat : : Lime , " Destination slot %i resyncronized. " , move_slots - > to_slot ) ;
2013-02-16 16:14:39 -08:00
}
2019-08-11 00:00:55 -05:00
else { Message ( Chat : : Red , " Could not resyncronize destination slot %i. " , move_slots - > to_slot ) ; }
2013-02-16 16:14:39 -08:00
}
2019-08-11 00:00:55 -05:00
else { Message ( Chat : : Red , " Could not resyncronize destination slot %i. " , move_slots - > to_slot ) ; }
2013-02-16 16:14:39 -08:00
}
}
void Client : : QSSwapItemAuditor ( MoveItem_Struct * move_in , bool postaction_call ) {
int16 from_slot_id = static_cast < int16 > ( move_in - > from_slot ) ;
int16 to_slot_id = static_cast < int16 > ( move_in - > to_slot ) ;
int16 move_amount = static_cast < int16 > ( move_in - > number_in_stack ) ;
if ( ! m_inv [ from_slot_id ] & & ! m_inv [ to_slot_id ] ) { return ; }
uint16 move_count = 0 ;
if ( m_inv [ from_slot_id ] ) { move_count + = m_inv [ from_slot_id ] - > GetTotalItemCount ( ) ; }
if ( to_slot_id ! = from_slot_id ) { if ( m_inv [ to_slot_id ] ) { move_count + = m_inv [ to_slot_id ] - > GetTotalItemCount ( ) ; } }
2016-05-25 16:10:28 -04:00
auto qspack = new ServerPacket ( ServerOP_QSPlayerLogMoves ,
sizeof ( QSPlayerLogMove_Struct ) + ( sizeof ( QSMoveItems_Struct ) * move_count ) ) ;
2013-02-16 16:14:39 -08:00
QSPlayerLogMove_Struct * qsaudit = ( QSPlayerLogMove_Struct * ) qspack - > pBuffer ;
qsaudit - > char_id = character_id ;
qsaudit - > stack_size = move_amount ;
qsaudit - > char_count = move_count ;
qsaudit - > postaction = postaction_call ;
qsaudit - > from_slot = from_slot_id ;
qsaudit - > to_slot = to_slot_id ;
move_count = 0 ;
2020-05-17 18:36:06 -07:00
const EQ : : ItemInstance * from_inst = m_inv [ postaction_call ? to_slot_id : from_slot_id ] ;
2013-02-16 16:14:39 -08:00
if ( from_inst ) {
2013-05-09 10:44:08 -04:00
qsaudit - > items [ move_count ] . from_slot = from_slot_id ;
qsaudit - > items [ move_count ] . to_slot = to_slot_id ;
qsaudit - > items [ move_count ] . item_id = from_inst - > GetID ( ) ;
qsaudit - > items [ move_count ] . charges = from_inst - > GetCharges ( ) ;
qsaudit - > items [ move_count ] . aug_1 = from_inst - > GetAugmentItemID ( 1 ) ;
qsaudit - > items [ move_count ] . aug_2 = from_inst - > GetAugmentItemID ( 2 ) ;
qsaudit - > items [ move_count ] . aug_3 = from_inst - > GetAugmentItemID ( 3 ) ;
qsaudit - > items [ move_count ] . aug_4 = from_inst - > GetAugmentItemID ( 4 ) ;
qsaudit - > items [ move_count + + ] . aug_5 = from_inst - > GetAugmentItemID ( 5 ) ;
2013-02-16 16:14:39 -08:00
2020-05-17 18:36:06 -07:00
if ( from_inst - > IsType ( EQ : : item : : ItemClassBag ) ) {
for ( uint8 bag_idx = EQ : : invbag : : SLOT_BEGIN ; bag_idx < from_inst - > GetItem ( ) - > BagSlots ; bag_idx + + ) {
const EQ : : ItemInstance * from_baginst = from_inst - > GetItem ( bag_idx ) ;
2013-02-16 16:14:39 -08:00
if ( from_baginst ) {
2020-05-17 18:36:06 -07:00
qsaudit - > items [ move_count ] . from_slot = EQ : : InventoryProfile : : CalcSlotId ( from_slot_id , bag_idx ) ;
qsaudit - > items [ move_count ] . to_slot = EQ : : InventoryProfile : : CalcSlotId ( to_slot_id , bag_idx ) ;
2013-05-09 10:44:08 -04:00
qsaudit - > items [ move_count ] . item_id = from_baginst - > GetID ( ) ;
qsaudit - > items [ move_count ] . charges = from_baginst - > GetCharges ( ) ;
qsaudit - > items [ move_count ] . aug_1 = from_baginst - > GetAugmentItemID ( 1 ) ;
qsaudit - > items [ move_count ] . aug_2 = from_baginst - > GetAugmentItemID ( 2 ) ;
qsaudit - > items [ move_count ] . aug_3 = from_baginst - > GetAugmentItemID ( 3 ) ;
qsaudit - > items [ move_count ] . aug_4 = from_baginst - > GetAugmentItemID ( 4 ) ;
qsaudit - > items [ move_count + + ] . aug_5 = from_baginst - > GetAugmentItemID ( 5 ) ;
2013-02-16 16:14:39 -08:00
}
}
}
}
if ( to_slot_id ! = from_slot_id ) {
2020-05-17 18:36:06 -07:00
const EQ : : ItemInstance * to_inst = m_inv [ postaction_call ? from_slot_id : to_slot_id ] ;
2013-02-16 16:14:39 -08:00
if ( to_inst ) {
2013-05-09 10:44:08 -04:00
qsaudit - > items [ move_count ] . from_slot = to_slot_id ;
qsaudit - > items [ move_count ] . to_slot = from_slot_id ;
qsaudit - > items [ move_count ] . item_id = to_inst - > GetID ( ) ;
qsaudit - > items [ move_count ] . charges = to_inst - > GetCharges ( ) ;
qsaudit - > items [ move_count ] . aug_1 = to_inst - > GetAugmentItemID ( 1 ) ;
qsaudit - > items [ move_count ] . aug_2 = to_inst - > GetAugmentItemID ( 2 ) ;
qsaudit - > items [ move_count ] . aug_3 = to_inst - > GetAugmentItemID ( 3 ) ;
qsaudit - > items [ move_count ] . aug_4 = to_inst - > GetAugmentItemID ( 4 ) ;
qsaudit - > items [ move_count + + ] . aug_5 = to_inst - > GetAugmentItemID ( 5 ) ;
2013-02-16 16:14:39 -08:00
2020-05-17 18:36:06 -07:00
if ( to_inst - > IsType ( EQ : : item : : ItemClassBag ) ) {
for ( uint8 bag_idx = EQ : : invbag : : SLOT_BEGIN ; bag_idx < to_inst - > GetItem ( ) - > BagSlots ; bag_idx + + ) {
const EQ : : ItemInstance * to_baginst = to_inst - > GetItem ( bag_idx ) ;
2013-02-16 16:14:39 -08:00
if ( to_baginst ) {
2020-05-17 18:36:06 -07:00
qsaudit - > items [ move_count ] . from_slot = EQ : : InventoryProfile : : CalcSlotId ( to_slot_id , bag_idx ) ;
qsaudit - > items [ move_count ] . to_slot = EQ : : InventoryProfile : : CalcSlotId ( from_slot_id , bag_idx ) ;
2013-05-09 10:44:08 -04:00
qsaudit - > items [ move_count ] . item_id = to_baginst - > GetID ( ) ;
qsaudit - > items [ move_count ] . charges = to_baginst - > GetCharges ( ) ;
qsaudit - > items [ move_count ] . aug_1 = to_baginst - > GetAugmentItemID ( 1 ) ;
qsaudit - > items [ move_count ] . aug_2 = to_baginst - > GetAugmentItemID ( 2 ) ;
qsaudit - > items [ move_count ] . aug_3 = to_baginst - > GetAugmentItemID ( 3 ) ;
qsaudit - > items [ move_count ] . aug_4 = to_baginst - > GetAugmentItemID ( 4 ) ;
qsaudit - > items [ move_count + + ] . aug_5 = to_baginst - > GetAugmentItemID ( 5 ) ;
2013-02-16 16:14:39 -08:00
}
}
}
}
}
if ( move_count & & worldserver . Connected ( ) ) {
worldserver . SendPacket ( qspack ) ;
}
safe_delete ( qspack ) ;
}
2020-05-17 18:36:06 -07:00
void Client : : DyeArmor ( EQ : : TintProfile * dye ) {
2013-02-16 16:14:39 -08:00
int16 slot = 0 ;
2020-05-17 18:36:06 -07:00
for ( int i = EQ : : textures : : textureBegin ; i < = EQ : : textures : : LastTintableTexture ; i + + ) {
2016-06-01 04:58:52 -04:00
if ( ( m_pp . item_tint . Slot [ i ] . Color & 0x00FFFFFF ) ! = ( dye - > Slot [ i ] . Color & 0x00FFFFFF ) ) {
2013-02-16 16:14:39 -08:00
slot = m_inv . HasItem ( 32557 , 1 , invWherePersonal ) ;
2014-07-16 21:23:16 -04:00
if ( slot ! = INVALID_INDEX ) {
2013-02-16 16:14:39 -08:00
DeleteItemInInventory ( slot , 1 , true ) ;
uint8 slot2 = SlotConvert ( i ) ;
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * inst = this - > m_inv . GetItem ( slot2 ) ;
2013-02-16 16:14:39 -08:00
if ( inst ) {
2016-06-01 04:58:52 -04:00
uint32 armor_color = ( ( uint32 ) dye - > Slot [ i ] . Red < < 16 ) | ( ( uint32 ) dye - > Slot [ i ] . Green < < 8 ) | ( ( uint32 ) dye - > Slot [ i ] . Blue ) ;
2014-08-31 21:58:04 -05:00
inst - > SetColor ( armor_color ) ;
database . SaveCharacterMaterialColor ( this - > CharacterID ( ) , i , armor_color ) ;
2013-02-16 16:14:39 -08:00
database . SaveInventory ( CharacterID ( ) , inst , slot2 ) ;
2016-06-01 04:58:52 -04:00
if ( dye - > Slot [ i ] . UseTint )
m_pp . item_tint . Slot [ i ] . UseTint = 0xFF ;
2013-05-06 13:07:41 -04:00
else
2016-06-01 04:58:52 -04:00
m_pp . item_tint . Slot [ i ] . UseTint = 0x00 ;
2013-02-16 16:14:39 -08:00
}
2016-06-01 04:58:52 -04:00
m_pp . item_tint . Slot [ i ] . Blue = dye - > Slot [ i ] . Blue ;
m_pp . item_tint . Slot [ i ] . Red = dye - > Slot [ i ] . Red ;
m_pp . item_tint . Slot [ i ] . Green = dye - > Slot [ i ] . Green ;
2013-02-16 16:14:39 -08:00
SendWearChange ( i ) ;
}
else {
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " Could not locate A Vial of Prismatic Dye. " ) ;
2013-02-16 16:14:39 -08:00
return ;
}
}
}
2016-05-25 16:10:28 -04:00
auto outapp = new EQApplicationPacket ( OP_Dye , 0 ) ;
2013-02-16 16:14:39 -08:00
QueuePacket ( outapp ) ;
safe_delete ( outapp ) ;
2014-08-31 21:31:44 -05:00
2013-02-16 16:14:39 -08:00
}
2015-01-15 21:24:26 -05:00
#if 0
bool Client : : DecreaseByItemType ( uint32 type , uint8 amt ) {
2016-10-16 05:10:54 -04:00
const ItemData * TempItem = 0 ;
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * ins ;
2013-02-16 16:14:39 -08:00
int x ;
2020-05-17 18:36:06 -07:00
for ( x = EQ : : legacy : : POSSESSIONS_BEGIN ; x < = EQ : : legacy : : POSSESSIONS_END ; x + + )
2013-02-16 16:14:39 -08:00
{
TempItem = 0 ;
ins = GetInv ( ) . GetItem ( x ) ;
if ( ins )
TempItem = ins - > GetItem ( ) ;
if ( TempItem & & TempItem - > ItemType = = type )
{
if ( ins - > GetCharges ( ) < amt )
{
amt - = ins - > GetCharges ( ) ;
DeleteItemInInventory ( x , amt , true ) ;
}
else
{
DeleteItemInInventory ( x , amt , true ) ;
amt = 0 ;
}
if ( amt < 1 )
return true ;
}
}
2020-05-17 18:36:06 -07:00
for ( x = EQ : : legacy : : GENERAL_BAGS_BEGIN ; x < = EQ : : legacy : : GENERAL_BAGS_END ; x + + )
2013-02-16 16:14:39 -08:00
{
TempItem = 0 ;
ins = GetInv ( ) . GetItem ( x ) ;
if ( ins )
TempItem = ins - > GetItem ( ) ;
if ( TempItem & & TempItem - > ItemType = = type )
{
if ( ins - > GetCharges ( ) < amt )
{
amt - = ins - > GetCharges ( ) ;
DeleteItemInInventory ( x , amt , true ) ;
}
else
{
DeleteItemInInventory ( x , amt , true ) ;
amt = 0 ;
}
if ( amt < 1 )
return true ;
}
}
return false ;
2015-01-15 21:24:26 -05:00
}
# endif
2013-02-16 16:14:39 -08:00
bool Client : : DecreaseByID ( uint32 type , uint8 amt ) {
2020-05-17 18:36:06 -07:00
const EQ : : ItemData * TempItem = nullptr ;
EQ : : ItemInstance * ins = nullptr ;
2013-02-16 16:14:39 -08:00
int x ;
int num = 0 ;
2018-08-13 22:32:36 -04:00
2020-05-17 18:36:06 -07:00
for ( x = EQ : : invslot : : POSSESSIONS_BEGIN ; x < = EQ : : invslot : : POSSESSIONS_END ; + + x ) {
2018-08-13 22:32:36 -04:00
if ( num > = amt )
break ;
if ( ( ( uint64 ) 1 < < x ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask = = 0 )
continue ;
TempItem = nullptr ;
ins = GetInv ( ) . GetItem ( x ) ;
if ( ins )
TempItem = ins - > GetItem ( ) ;
if ( TempItem & & TempItem - > ID = = type )
num + = ins - > GetCharges ( ) ;
}
2020-05-17 18:36:06 -07:00
for ( x = EQ : : invbag : : GENERAL_BAGS_BEGIN ; x < = EQ : : invbag : : GENERAL_BAGS_END ; + + x ) {
2018-08-13 22:32:36 -04:00
if ( num > = amt )
break ;
2020-05-17 18:36:06 -07:00
if ( ( ( ( uint64 ) 1 < < ( EQ : : invslot : : GENERAL_BEGIN + ( ( x - EQ : : invbag : : GENERAL_BAGS_BEGIN ) / EQ : : invbag : : SLOT_COUNT ) ) ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask ) = = 0 )
2018-08-13 22:32:36 -04:00
continue ;
TempItem = nullptr ;
ins = GetInv ( ) . GetItem ( x ) ;
if ( ins )
TempItem = ins - > GetItem ( ) ;
if ( TempItem & & TempItem - > ID = = type )
num + = ins - > GetCharges ( ) ;
}
2020-05-17 18:36:06 -07:00
for ( x = EQ : : invbag : : CURSOR_BAG_BEGIN ; x < = EQ : : invbag : : CURSOR_BAG_END ; + + x ) {
2018-08-13 22:32:36 -04:00
if ( num > = amt )
break ;
2015-01-15 21:24:26 -05:00
TempItem = nullptr ;
2013-02-16 16:14:39 -08:00
ins = GetInv ( ) . GetItem ( x ) ;
if ( ins )
TempItem = ins - > GetItem ( ) ;
if ( TempItem & & TempItem - > ID = = type )
num + = ins - > GetCharges ( ) ;
}
2018-08-13 22:32:36 -04:00
2013-02-16 16:14:39 -08:00
if ( num < amt )
return false ;
2018-08-13 22:32:36 -04:00
2020-05-17 18:36:06 -07:00
for ( x = EQ : : invslot : : POSSESSIONS_BEGIN ; x < = EQ : : invslot : : POSSESSIONS_END ; + + x ) {
2018-08-13 22:32:36 -04:00
if ( amt < 1 )
break ;
if ( ( ( uint64 ) 1 < < x ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask = = 0 )
continue ;
2015-01-15 21:24:26 -05:00
TempItem = nullptr ;
2013-02-16 16:14:39 -08:00
ins = GetInv ( ) . GetItem ( x ) ;
if ( ins )
TempItem = ins - > GetItem ( ) ;
2018-08-13 22:32:36 -04:00
if ( TempItem & & TempItem - > ID ! = type )
continue ;
if ( ins - > GetCharges ( ) < amt ) {
amt - = ins - > GetCharges ( ) ;
DeleteItemInInventory ( x , amt , true ) ;
}
else {
DeleteItemInInventory ( x , amt , true ) ;
amt = 0 ;
}
}
2020-05-17 18:36:06 -07:00
for ( x = EQ : : invbag : : GENERAL_BAGS_BEGIN ; x < = EQ : : invbag : : GENERAL_BAGS_END ; + + x ) {
2018-08-13 22:32:36 -04:00
if ( amt < 1 )
break ;
2020-05-17 18:36:06 -07:00
if ( ( ( ( uint64 ) 1 < < ( EQ : : invslot : : GENERAL_BEGIN + ( ( x - EQ : : invbag : : GENERAL_BAGS_BEGIN ) / EQ : : invbag : : SLOT_COUNT ) ) ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask ) = = 0 )
2018-08-13 22:32:36 -04:00
continue ;
TempItem = nullptr ;
ins = GetInv ( ) . GetItem ( x ) ;
if ( ins )
TempItem = ins - > GetItem ( ) ;
if ( TempItem & & TempItem - > ID ! = type )
continue ;
if ( ins - > GetCharges ( ) < amt ) {
amt - = ins - > GetCharges ( ) ;
DeleteItemInInventory ( x , amt , true ) ;
}
else {
DeleteItemInInventory ( x , amt , true ) ;
amt = 0 ;
2013-02-16 16:14:39 -08:00
}
}
2018-08-13 22:32:36 -04:00
2020-05-17 18:36:06 -07:00
for ( x = EQ : : invbag : : CURSOR_BAG_BEGIN ; x < = EQ : : invbag : : CURSOR_BAG_END ; + + x ) {
2018-08-13 22:32:36 -04:00
if ( amt < 1 )
break ;
TempItem = nullptr ;
ins = GetInv ( ) . GetItem ( x ) ;
if ( ins )
TempItem = ins - > GetItem ( ) ;
if ( TempItem & & TempItem - > ID ! = type )
continue ;
if ( ins - > GetCharges ( ) < amt ) {
amt - = ins - > GetCharges ( ) ;
DeleteItemInInventory ( x , amt , true ) ;
}
else {
DeleteItemInInventory ( x , amt , true ) ;
amt = 0 ;
}
}
2013-02-16 16:14:39 -08:00
return true ;
}
2015-06-07 22:07:40 -04:00
static bool IsSummonedBagID ( uint32 item_id )
{
switch ( item_id ) {
case 17147 : // "Spiritual Prismatic Pack"
case 17303 : // "Spirit Pouch"
case 17304 : // "Dimensional Pocket"
case 17305 : // "Dimensional Hole"
case 17306 : // "Glowing Backpack"
case 17307 : // "Quiver of Marr"
case 17308 : // "Bandoleer of Luclin"
case 17309 : // "Pouch of Quellious"
case 17310 : // "Phantom Satchel"
case 17510 : // "Glowing Chest"
case 17900 : // "Grandmaster's Satchel"
case 57260 : // "Glowing Backpack"
case 57261 : // "Pouch of Quellious"
case 57262 : // "Phantom Satchel"
case 60224 : // "Faded-Glyph Tablet"
case 95199 : // "Beginner Artisan Satchel"
case 95200 : // "Apprentice Artisan Satchel"
case 95201 : // "Freshman Artisan Satchel"
case 95202 : // "Journeyman Artisan Satchel"
case 95203 : // "Expert Artisan Satchel"
case 95204 : // "Master Artisan Satchel"
//case 96960: // "Artisan Satchel" - no 12-slot disenchanted bags
return true ;
default :
return false ;
}
}
static uint32 GetDisenchantedBagID ( uint8 bag_slots )
{
switch ( bag_slots ) {
case 4 :
return 77772 ; // "Small Disenchanted Backpack"
case 6 :
return 77774 ; // "Disenchanted Backpack"
case 8 :
return 77776 ; // "Large Disenchanted Backpack"
case 10 :
return 77778 ; // "Huge Disenchanted Backpack"
default :
return 0 ; // no suitable conversions
}
}
2020-05-17 18:36:06 -07:00
static bool CopyBagContents ( EQ : : ItemInstance * new_bag , const EQ : : ItemInstance * old_bag )
2015-06-07 22:07:40 -04:00
{
if ( ! new_bag | | ! old_bag ) { return false ; }
if ( new_bag - > GetItem ( ) - > BagSlots < old_bag - > GetItem ( ) - > BagSlots ) { return false ; }
// pre-check for size comparisons
for ( auto bag_slot = 0 ; bag_slot < old_bag - > GetItem ( ) - > BagSlots ; + + bag_slot ) {
if ( ! old_bag - > GetItem ( bag_slot ) ) { continue ; }
if ( old_bag - > GetItem ( bag_slot ) - > GetItem ( ) - > Size > new_bag - > GetItem ( ) - > BagSize ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Copy Bag Contents: Failure due to [{}] is larger than size capacity of [{}] ([{}] > [{}]) " ,
2015-06-07 22:07:40 -04:00
old_bag - > GetItem ( bag_slot ) - > GetItem ( ) - > Name , new_bag - > GetItem ( ) - > Name , old_bag - > GetItem ( bag_slot ) - > GetItem ( ) - > Size , new_bag - > GetItem ( ) - > BagSize ) ;
return false ;
}
}
for ( auto bag_slot = 0 ; bag_slot < old_bag - > GetItem ( ) - > BagSlots ; + + bag_slot ) {
if ( ! old_bag - > GetItem ( bag_slot ) ) { continue ; }
new_bag - > PutItem ( bag_slot , * ( old_bag - > GetItem ( bag_slot ) ) ) ;
}
return true ;
}
void Client : : DisenchantSummonedBags ( bool client_update )
{
2020-05-17 18:36:06 -07:00
for ( auto slot_id = EQ : : invslot : : GENERAL_BEGIN ; slot_id < = EQ : : invslot : : GENERAL_END ; + + slot_id ) {
2018-08-13 22:32:36 -04:00
if ( ( ( uint64 ) 1 < < slot_id ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask = = 0 )
continue ; // not useable this session - will be disenchanted once player logs in on client that doesn't exclude affected slots
2015-06-07 22:07:40 -04:00
auto inst = m_inv [ slot_id ] ;
if ( ! inst ) { continue ; }
if ( ! IsSummonedBagID ( inst - > GetItem ( ) - > ID ) ) { continue ; }
2016-05-21 04:54:18 -04:00
if ( ! inst - > GetItem ( ) - > IsClassBag ( ) ) { continue ; }
2015-06-07 22:07:40 -04:00
if ( inst - > GetTotalItemCount ( ) = = 1 ) { continue ; }
auto new_id = GetDisenchantedBagID ( inst - > GetItem ( ) - > BagSlots ) ;
if ( ! new_id ) { continue ; }
auto new_item = database . GetItem ( new_id ) ;
if ( ! new_item ) { continue ; }
auto new_inst = database . CreateBaseItem ( new_item ) ;
if ( ! new_inst ) { continue ; }
if ( CopyBagContents ( new_inst , inst ) ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Disenchant Summoned Bags: Replacing [{}] with [{}] in slot [{}] " , inst - > GetItem ( ) - > Name , new_inst - > GetItem ( ) - > Name , slot_id ) ;
2015-06-07 22:07:40 -04:00
PutItemInInventory ( slot_id , * new_inst , client_update ) ;
}
safe_delete ( new_inst ) ;
}
2020-05-17 18:36:06 -07:00
for ( auto slot_id = EQ : : invslot : : BANK_BEGIN ; slot_id < = EQ : : invslot : : BANK_END ; + + slot_id ) {
if ( ( slot_id - EQ : : invslot : : BANK_BEGIN ) > = GetInv ( ) . GetLookup ( ) - > InventoryTypeSize . Bank )
2018-08-13 22:32:36 -04:00
continue ;
2015-06-07 22:07:40 -04:00
auto inst = m_inv [ slot_id ] ;
if ( ! inst ) { continue ; }
if ( ! IsSummonedBagID ( inst - > GetItem ( ) - > ID ) ) { continue ; }
2016-05-21 04:54:18 -04:00
if ( ! inst - > GetItem ( ) - > IsClassBag ( ) ) { continue ; }
2015-06-07 22:07:40 -04:00
if ( inst - > GetTotalItemCount ( ) = = 1 ) { continue ; }
auto new_id = GetDisenchantedBagID ( inst - > GetItem ( ) - > BagSlots ) ;
if ( ! new_id ) { continue ; }
auto new_item = database . GetItem ( new_id ) ;
if ( ! new_item ) { continue ; }
auto new_inst = database . CreateBaseItem ( new_item ) ;
if ( ! new_inst ) { continue ; }
if ( CopyBagContents ( new_inst , inst ) ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Disenchant Summoned Bags: Replacing [{}] with [{}] in slot [{}] " , inst - > GetItem ( ) - > Name , new_inst - > GetItem ( ) - > Name , slot_id ) ;
2015-06-07 22:07:40 -04:00
PutItemInInventory ( slot_id , * new_inst , client_update ) ;
}
safe_delete ( new_inst ) ;
}
2020-05-17 18:36:06 -07:00
for ( auto slot_id = EQ : : invslot : : SHARED_BANK_BEGIN ; slot_id < = EQ : : invslot : : SHARED_BANK_END ; + + slot_id ) {
2015-06-07 22:07:40 -04:00
auto inst = m_inv [ slot_id ] ;
if ( ! inst ) { continue ; }
if ( ! IsSummonedBagID ( inst - > GetItem ( ) - > ID ) ) { continue ; }
2016-05-21 04:54:18 -04:00
if ( ! inst - > GetItem ( ) - > IsClassBag ( ) ) { continue ; }
2015-06-07 22:07:40 -04:00
if ( inst - > GetTotalItemCount ( ) = = 1 ) { continue ; }
auto new_id = GetDisenchantedBagID ( inst - > GetItem ( ) - > BagSlots ) ;
if ( ! new_id ) { continue ; }
auto new_item = database . GetItem ( new_id ) ;
if ( ! new_item ) { continue ; }
auto new_inst = database . CreateBaseItem ( new_item ) ;
if ( ! new_inst ) { continue ; }
if ( CopyBagContents ( new_inst , inst ) ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Disenchant Summoned Bags: Replacing [{}] with [{}] in slot [{}] " , inst - > GetItem ( ) - > Name , new_inst - > GetItem ( ) - > Name , slot_id ) ;
2015-06-07 22:07:40 -04:00
PutItemInInventory ( slot_id , * new_inst , client_update ) ;
}
safe_delete ( new_inst ) ;
}
while ( ! m_inv . CursorEmpty ( ) ) {
2020-05-17 18:36:06 -07:00
auto inst = m_inv [ EQ : : invslot : : slotCursor ] ;
2015-06-07 22:07:40 -04:00
if ( ! inst ) { break ; }
if ( ! IsSummonedBagID ( inst - > GetItem ( ) - > ID ) ) { break ; }
2016-05-21 04:54:18 -04:00
if ( ! inst - > GetItem ( ) - > IsClassBag ( ) ) { break ; }
2015-06-07 22:07:40 -04:00
if ( inst - > GetTotalItemCount ( ) = = 1 ) { break ; }
auto new_id = GetDisenchantedBagID ( inst - > GetItem ( ) - > BagSlots ) ;
if ( ! new_id ) { break ; }
auto new_item = database . GetItem ( new_id ) ;
if ( ! new_item ) { break ; }
auto new_inst = database . CreateBaseItem ( new_item ) ;
if ( ! new_inst ) { break ; }
if ( CopyBagContents ( new_inst , inst ) ) {
2020-05-17 18:36:06 -07:00
LogInventory ( " Disenchant Summoned Bags: Replacing [{}] with [{}] in slot [{}] " , inst - > GetItem ( ) - > Name , new_inst - > GetItem ( ) - > Name , EQ : : invslot : : slotCursor ) ;
std : : list < EQ : : ItemInstance * > local ;
2015-06-07 22:07:40 -04:00
local . push_front ( new_inst ) ;
2020-05-17 18:36:06 -07:00
m_inv . PopItem ( EQ : : invslot : : slotCursor ) ;
2015-06-07 22:07:40 -04:00
safe_delete ( inst ) ;
while ( ! m_inv . CursorEmpty ( ) ) {
2020-05-17 18:36:06 -07:00
auto limbo_inst = m_inv . PopItem ( EQ : : invslot : : slotCursor ) ;
2015-06-07 22:07:40 -04:00
if ( limbo_inst = = nullptr ) { continue ; }
local . push_back ( limbo_inst ) ;
}
for ( auto iter = local . begin ( ) ; iter ! = local . end ( ) ; + + iter ) {
auto cur_inst = * iter ;
if ( cur_inst = = nullptr ) { continue ; }
m_inv . PushCursor ( * cur_inst ) ;
safe_delete ( cur_inst ) ;
}
local . clear ( ) ;
auto s = m_inv . cursor_cbegin ( ) , e = m_inv . cursor_cend ( ) ;
database . SaveCursor ( this - > CharacterID ( ) , s , e ) ;
}
else {
safe_delete ( new_inst ) ; // deletes disenchanted bag if not used
}
break ;
}
}
2015-01-15 21:24:26 -05:00
void Client : : RemoveNoRent ( bool client_update )
{
2020-05-17 18:36:06 -07:00
for ( auto slot_id = EQ : : invslot : : EQUIPMENT_BEGIN ; slot_id < = EQ : : invslot : : EQUIPMENT_END ; + + slot_id ) {
2018-08-13 22:32:36 -04:00
if ( ( ( uint64 ) 1 < < slot_id ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask = = 0 )
continue ;
2015-01-15 21:24:26 -05:00
auto inst = m_inv [ slot_id ] ;
2013-02-16 16:14:39 -08:00
if ( inst & & ! inst - > GetItem ( ) - > NoRent ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " NoRent Timer Lapse: Deleting [{}] from slot [{}] " , inst - > GetItem ( ) - > Name , slot_id ) ;
2013-02-16 16:14:39 -08:00
DeleteItemInInventory ( slot_id , 0 , client_update ) ;
}
}
2020-05-17 18:36:06 -07:00
for ( auto slot_id = EQ : : invslot : : GENERAL_BEGIN ; slot_id < = EQ : : invslot : : GENERAL_END ; + + slot_id ) {
2018-08-13 22:32:36 -04:00
if ( ( ( uint64 ) 1 < < slot_id ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask = = 0 )
continue ;
2015-01-15 21:24:26 -05:00
auto inst = m_inv [ slot_id ] ;
2014-09-05 16:16:56 -04:00
if ( inst & & ! inst - > GetItem ( ) - > NoRent ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " NoRent Timer Lapse: Deleting [{}] from slot [{}] " , inst - > GetItem ( ) - > Name , slot_id ) ;
2014-09-05 16:16:56 -04:00
DeleteItemInInventory ( slot_id , 0 , client_update ) ;
}
}
2020-05-17 18:36:06 -07:00
for ( auto slot_id = EQ : : invbag : : GENERAL_BAGS_BEGIN ; slot_id < = EQ : : invbag : : CURSOR_BAG_END ; + + slot_id ) {
auto temp_slot = EQ : : invslot : : GENERAL_BEGIN + ( ( slot_id - EQ : : invbag : : GENERAL_BAGS_BEGIN ) / EQ : : invbag : : SLOT_COUNT ) ;
2018-08-13 22:32:36 -04:00
if ( ( ( ( uint64 ) 1 < < temp_slot ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask ) = = 0 )
continue ;
2015-01-15 21:24:26 -05:00
auto inst = m_inv [ slot_id ] ;
2013-02-16 16:14:39 -08:00
if ( inst & & ! inst - > GetItem ( ) - > NoRent ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " NoRent Timer Lapse: Deleting [{}] from slot [{}] " , inst - > GetItem ( ) - > Name , slot_id ) ;
2013-02-16 16:14:39 -08:00
DeleteItemInInventory ( slot_id , 0 , client_update ) ;
}
}
2020-05-17 18:36:06 -07:00
for ( auto slot_id = EQ : : invslot : : BANK_BEGIN ; slot_id < = EQ : : invslot : : BANK_END ; + + slot_id ) {
if ( ( slot_id - EQ : : invslot : : BANK_BEGIN ) > = GetInv ( ) . GetLookup ( ) - > InventoryTypeSize . Bank )
2018-08-13 22:32:36 -04:00
continue ;
2015-01-15 21:24:26 -05:00
auto inst = m_inv [ slot_id ] ;
2013-02-16 16:14:39 -08:00
if ( inst & & ! inst - > GetItem ( ) - > NoRent ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " NoRent Timer Lapse: Deleting [{}] from slot [{}] " , inst - > GetItem ( ) - > Name , slot_id ) ;
2013-02-16 16:14:39 -08:00
DeleteItemInInventory ( slot_id , 0 , false ) ; // Can't delete from client Bank slots
}
}
2020-05-17 18:36:06 -07:00
for ( auto slot_id = EQ : : invbag : : BANK_BAGS_BEGIN ; slot_id < = EQ : : invbag : : BANK_BAGS_END ; + + slot_id ) {
auto temp_slot = ( slot_id - EQ : : invbag : : BANK_BAGS_BEGIN ) / EQ : : invbag : : SLOT_COUNT ;
2019-01-07 00:11:07 -05:00
if ( temp_slot > = GetInv ( ) . GetLookup ( ) - > InventoryTypeSize . Bank )
2018-08-13 22:32:36 -04:00
continue ;
2015-01-15 21:24:26 -05:00
auto inst = m_inv [ slot_id ] ;
2013-02-16 16:14:39 -08:00
if ( inst & & ! inst - > GetItem ( ) - > NoRent ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " NoRent Timer Lapse: Deleting [{}] from slot [{}] " , inst - > GetItem ( ) - > Name , slot_id ) ;
2013-02-16 16:14:39 -08:00
DeleteItemInInventory ( slot_id , 0 , false ) ; // Can't delete from client Bank Container slots
}
}
2020-05-17 18:36:06 -07:00
for ( auto slot_id = EQ : : invslot : : SHARED_BANK_BEGIN ; slot_id < = EQ : : invslot : : SHARED_BANK_END ; + + slot_id ) {
2015-01-15 21:24:26 -05:00
auto inst = m_inv [ slot_id ] ;
2013-02-16 16:14:39 -08:00
if ( inst & & ! inst - > GetItem ( ) - > NoRent ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " NoRent Timer Lapse: Deleting [{}] from slot [{}] " , inst - > GetItem ( ) - > Name , slot_id ) ;
2013-02-16 16:14:39 -08:00
DeleteItemInInventory ( slot_id , 0 , false ) ; // Can't delete from client Shared Bank slots
}
}
2020-05-17 18:36:06 -07:00
for ( auto slot_id = EQ : : invbag : : SHARED_BANK_BAGS_BEGIN ; slot_id < = EQ : : invbag : : SHARED_BANK_BAGS_END ; + + slot_id ) {
2015-01-15 21:24:26 -05:00
auto inst = m_inv [ slot_id ] ;
2013-02-16 16:14:39 -08:00
if ( inst & & ! inst - > GetItem ( ) - > NoRent ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " NoRent Timer Lapse: Deleting [{}] from slot [{}] " , inst - > GetItem ( ) - > Name , slot_id ) ;
2013-02-16 16:14:39 -08:00
DeleteItemInInventory ( slot_id , 0 , false ) ; // Can't delete from client Shared Bank Container slots
}
}
2014-09-05 16:16:56 -04:00
if ( ! m_inv . CursorEmpty ( ) ) {
2020-05-17 18:36:06 -07:00
std : : list < EQ : : ItemInstance * > local ;
2014-09-05 16:16:56 -04:00
while ( ! m_inv . CursorEmpty ( ) ) {
2020-05-17 18:36:06 -07:00
auto inst = m_inv . PopItem ( EQ : : invslot : : slotCursor ) ;
2015-01-15 21:24:26 -05:00
if ( inst = = nullptr ) { continue ; }
local . push_back ( inst ) ;
2014-09-05 16:16:56 -04:00
}
2015-01-15 21:24:26 -05:00
for ( auto iter = local . begin ( ) ; iter ! = local . end ( ) ; + + iter ) {
auto inst = * iter ;
if ( inst = = nullptr ) { continue ; }
if ( ! inst - > GetItem ( ) - > NoRent ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " NoRent Timer Lapse: Deleting [{}] from `Limbo` " , inst - > GetItem ( ) - > Name ) ;
2015-01-15 21:24:26 -05:00
}
else {
m_inv . PushCursor ( * inst ) ;
}
safe_delete ( inst ) ;
2014-09-05 16:16:56 -04:00
}
2015-01-15 21:24:26 -05:00
local . clear ( ) ;
2014-09-05 16:16:56 -04:00
2015-02-06 07:57:15 -05:00
auto s = m_inv . cursor_cbegin ( ) , e = m_inv . cursor_cend ( ) ;
2014-09-05 16:46:03 -04:00
database . SaveCursor ( this - > CharacterID ( ) , s , e ) ;
2014-09-05 16:16:56 -04:00
}
2013-02-16 16:14:39 -08:00
}
// Two new methods to alleviate perpetual login desyncs
2015-01-15 21:24:26 -05:00
void Client : : RemoveDuplicateLore ( bool client_update )
{
2020-05-17 18:36:06 -07:00
for ( auto slot_id = EQ : : invslot : : EQUIPMENT_BEGIN ; slot_id < = EQ : : invslot : : EQUIPMENT_END ; + + slot_id ) {
2018-08-13 22:32:36 -04:00
if ( ( ( uint64 ) 1 < < slot_id ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask = = 0 )
continue ;
2015-01-15 21:24:26 -05:00
auto inst = m_inv . PopItem ( slot_id ) ;
if ( inst = = nullptr ) { continue ; }
if ( CheckLoreConflict ( inst - > GetItem ( ) ) ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Lore Duplication Error: Deleting [{}] from slot [{}] " , inst - > GetItem ( ) - > Name , slot_id ) ;
2015-01-15 21:24:26 -05:00
database . SaveInventory ( character_id , nullptr , slot_id ) ;
2013-02-16 16:14:39 -08:00
}
2015-01-15 21:24:26 -05:00
else {
m_inv . PutItem ( slot_id , * inst ) ;
2013-02-16 16:14:39 -08:00
}
2015-01-15 21:24:26 -05:00
safe_delete ( inst ) ;
2013-02-16 16:14:39 -08:00
}
2015-01-15 21:24:26 -05:00
2020-05-17 18:36:06 -07:00
for ( auto slot_id = EQ : : invslot : : GENERAL_BEGIN ; slot_id < = EQ : : invslot : : GENERAL_END ; + + slot_id ) {
2018-08-13 22:32:36 -04:00
if ( ( ( uint64 ) 1 < < slot_id ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask = = 0 )
continue ;
2015-01-15 21:24:26 -05:00
auto inst = m_inv . PopItem ( slot_id ) ;
if ( inst = = nullptr ) { continue ; }
if ( CheckLoreConflict ( inst - > GetItem ( ) ) ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Lore Duplication Error: Deleting [{}] from slot [{}] " , inst - > GetItem ( ) - > Name , slot_id ) ;
2015-01-15 21:24:26 -05:00
database . SaveInventory ( character_id , nullptr , slot_id ) ;
}
else {
m_inv . PutItem ( slot_id , * inst ) ;
2013-05-06 13:07:41 -04:00
}
2015-01-15 21:24:26 -05:00
safe_delete ( inst ) ;
2014-09-05 16:16:56 -04:00
}
2020-05-17 18:36:06 -07:00
for ( auto slot_id = EQ : : invbag : : GENERAL_BAGS_BEGIN ; slot_id < = EQ : : invbag : : CURSOR_BAG_END ; + + slot_id ) {
auto temp_slot = EQ : : invslot : : GENERAL_BEGIN + ( ( slot_id - EQ : : invbag : : GENERAL_BAGS_BEGIN ) / EQ : : invbag : : SLOT_COUNT ) ;
2018-08-13 22:32:36 -04:00
if ( ( ( ( uint64 ) 1 < < temp_slot ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask ) = = 0 )
continue ;
2015-01-15 21:24:26 -05:00
auto inst = m_inv . PopItem ( slot_id ) ;
if ( inst = = nullptr ) { continue ; }
if ( CheckLoreConflict ( inst - > GetItem ( ) ) ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Lore Duplication Error: Deleting [{}] from slot [{}] " , inst - > GetItem ( ) - > Name , slot_id ) ;
2015-01-15 21:24:26 -05:00
database . SaveInventory ( character_id , nullptr , slot_id ) ;
2013-02-16 16:14:39 -08:00
}
2015-01-15 21:24:26 -05:00
else {
m_inv . PutItem ( slot_id , * inst ) ;
}
safe_delete ( inst ) ;
2013-02-16 16:14:39 -08:00
}
2020-05-17 18:36:06 -07:00
for ( auto slot_id = EQ : : invslot : : BANK_BEGIN ; slot_id < = EQ : : invslot : : BANK_END ; + + slot_id ) {
if ( ( slot_id - EQ : : invslot : : BANK_BEGIN ) > = GetInv ( ) . GetLookup ( ) - > InventoryTypeSize . Bank )
2018-08-13 22:32:36 -04:00
continue ;
2015-01-15 21:24:26 -05:00
auto inst = m_inv . PopItem ( slot_id ) ;
if ( inst = = nullptr ) { continue ; }
if ( CheckLoreConflict ( inst - > GetItem ( ) ) ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Lore Duplication Error: Deleting [{}] from slot [{}] " , inst - > GetItem ( ) - > Name , slot_id ) ;
2015-01-15 21:24:26 -05:00
database . SaveInventory ( character_id , nullptr , slot_id ) ;
2013-02-16 16:14:39 -08:00
}
2015-01-15 21:24:26 -05:00
else {
m_inv . PutItem ( slot_id , * inst ) ;
2013-02-16 16:14:39 -08:00
}
2015-01-15 21:24:26 -05:00
safe_delete ( inst ) ;
2013-02-16 16:14:39 -08:00
}
2020-05-17 18:36:06 -07:00
for ( auto slot_id = EQ : : invbag : : BANK_BAGS_BEGIN ; slot_id < = EQ : : invbag : : BANK_BAGS_END ; + + slot_id ) {
auto temp_slot = ( slot_id - EQ : : invbag : : BANK_BAGS_BEGIN ) / EQ : : invbag : : SLOT_COUNT ;
2019-01-07 00:11:07 -05:00
if ( temp_slot > = GetInv ( ) . GetLookup ( ) - > InventoryTypeSize . Bank )
2018-08-13 22:32:36 -04:00
continue ;
2015-01-15 21:24:26 -05:00
auto inst = m_inv . PopItem ( slot_id ) ;
if ( inst = = nullptr ) { continue ; }
if ( CheckLoreConflict ( inst - > GetItem ( ) ) ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Lore Duplication Error: Deleting [{}] from slot [{}] " , inst - > GetItem ( ) - > Name , slot_id ) ;
2015-01-15 21:24:26 -05:00
database . SaveInventory ( character_id , nullptr , slot_id ) ;
2013-02-16 16:14:39 -08:00
}
2015-01-15 21:24:26 -05:00
else {
m_inv . PutItem ( slot_id , * inst ) ;
2013-02-16 16:14:39 -08:00
}
2015-01-15 21:24:26 -05:00
safe_delete ( inst ) ;
2013-02-16 16:14:39 -08:00
}
2015-02-23 19:57:47 -05:00
// Shared Bank and Shared Bank Containers are not checked due to their allowing duplicate lore items
2014-09-05 16:16:56 -04:00
if ( ! m_inv . CursorEmpty ( ) ) {
2020-05-17 18:36:06 -07:00
std : : list < EQ : : ItemInstance * > local_1 ;
std : : list < EQ : : ItemInstance * > local_2 ;
2014-09-05 16:16:56 -04:00
while ( ! m_inv . CursorEmpty ( ) ) {
2020-05-17 18:36:06 -07:00
auto inst = m_inv . PopItem ( EQ : : invslot : : slotCursor ) ;
2015-01-15 21:24:26 -05:00
if ( inst = = nullptr ) { continue ; }
local_1 . push_back ( inst ) ;
2014-09-05 16:16:56 -04:00
}
2015-01-15 21:24:26 -05:00
for ( auto iter = local_1 . begin ( ) ; iter ! = local_1 . end ( ) ; + + iter ) {
auto inst = * iter ;
if ( inst = = nullptr ) { continue ; }
2014-09-05 16:16:56 -04:00
if ( CheckLoreConflict ( inst - > GetItem ( ) ) ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Lore Duplication Error: Deleting [{}] from `Limbo` " , inst - > GetItem ( ) - > Name ) ;
2015-01-15 21:24:26 -05:00
safe_delete ( inst ) ;
2014-09-05 16:16:56 -04:00
}
else {
2015-01-15 21:24:26 -05:00
local_2 . push_back ( inst ) ;
2014-09-05 16:16:56 -04:00
}
}
2015-01-15 21:24:26 -05:00
local_1 . clear ( ) ;
2014-09-05 16:16:56 -04:00
2015-01-15 21:24:26 -05:00
for ( auto iter = local_2 . begin ( ) ; iter ! = local_2 . end ( ) ; + + iter ) {
auto inst = * iter ;
if ( inst = = nullptr ) { continue ; }
2014-09-05 16:16:56 -04:00
if ( ! inst - > GetItem ( ) - > LoreFlag | |
( ( inst - > GetItem ( ) - > LoreGroup = = - 1 ) & & ( m_inv . HasItem ( inst - > GetID ( ) , 0 , invWhereCursor ) = = INVALID_INDEX ) ) | |
2015-01-15 21:24:26 -05:00
( inst - > GetItem ( ) - > LoreGroup & & ( ~ inst - > GetItem ( ) - > LoreGroup ) & & ( m_inv . HasItemByLoreGroup ( inst - > GetItem ( ) - > LoreGroup , invWhereCursor ) = = INVALID_INDEX ) )
) {
m_inv . PushCursor ( * inst ) ;
2014-09-05 16:16:56 -04:00
}
else {
2019-09-02 02:50:39 -05:00
LogInventory ( " Lore Duplication Error: Deleting [{}] from `Limbo` " , inst - > GetItem ( ) - > Name ) ;
2014-09-05 16:16:56 -04:00
}
2015-01-15 21:24:26 -05:00
safe_delete ( inst ) ;
2014-09-05 16:16:56 -04:00
}
2015-01-15 21:24:26 -05:00
local_2 . clear ( ) ;
2014-09-05 16:16:56 -04:00
2015-02-06 07:57:15 -05:00
auto s = m_inv . cursor_cbegin ( ) , e = m_inv . cursor_cend ( ) ;
2014-09-05 16:46:03 -04:00
database . SaveCursor ( this - > CharacterID ( ) , s , e ) ;
2014-09-05 16:16:56 -04:00
}
2013-02-16 16:14:39 -08:00
}
2015-01-15 21:24:26 -05:00
void Client : : MoveSlotNotAllowed ( bool client_update )
{
2020-05-17 18:36:06 -07:00
for ( auto slot_id = EQ : : invslot : : EQUIPMENT_BEGIN ; slot_id < = EQ : : invslot : : EQUIPMENT_END ; + + slot_id ) {
2013-02-16 16:14:39 -08:00
if ( m_inv [ slot_id ] & & ! m_inv [ slot_id ] - > IsSlotAllowed ( slot_id ) ) {
2015-01-15 21:24:26 -05:00
auto inst = m_inv . PopItem ( slot_id ) ;
2020-05-17 18:36:06 -07:00
bool is_arrow = ( inst - > GetItem ( ) - > ItemType = = EQ : : item : : ItemTypeArrow ) ? true : false ;
2016-05-21 04:54:18 -04:00
int16 free_slot_id = m_inv . FindFreeSlot ( inst - > IsClassBag ( ) , true , inst - > GetItem ( ) - > Size , is_arrow ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Slot Assignment Error: Moving [{}] from slot [{}] to [{}] " , inst - > GetItem ( ) - > Name , slot_id , free_slot_id ) ;
2013-02-16 16:14:39 -08:00
PutItemInInventory ( free_slot_id , * inst , client_update ) ;
2013-05-04 18:06:58 -07:00
database . SaveInventory ( character_id , nullptr , slot_id ) ;
2013-02-16 16:14:39 -08:00
safe_delete ( inst ) ;
}
}
2018-08-13 22:32:36 -04:00
// added this check to move any client-based excluded slots
2020-05-17 18:36:06 -07:00
//for (auto slot_id = EQ::invslot::POSSESSIONS_BEGIN; slot_id <= EQ::invslot::POSSESSIONS_END; ++slot_id) {
2018-08-13 22:32:36 -04:00
// if (((uint64)1 << slot_id) & GetInv().GetLookup()->PossessionsBitmask != 0)
// continue;
// if (m_inv[slot_id]) { // this is currently dangerous for bag-based movements since limbo does not save bag slots
// auto inst = m_inv.PopItem(slot_id);
2020-05-17 18:36:06 -07:00
// bool is_arrow = (inst->GetItem()->ItemType == EQ::item::ItemTypeArrow) ? true : false;
2018-08-13 22:32:36 -04:00
// int16 free_slot_id = m_inv.FindFreeSlot(inst->IsClassBag(), true, inst->GetItem()->Size, is_arrow);
2019-09-02 02:50:39 -05:00
// LogInventory("Slot Assignment Error: Moving [{}] from slot [{}] to [{}]", inst->GetItem()->Name, slot_id, free_slot_id);
2018-08-13 22:32:36 -04:00
// PutItemInInventory(free_slot_id, *inst, client_update);
// database.SaveInventory(character_id, nullptr, slot_id);
// safe_delete(inst);
// }
//}
2013-02-16 16:14:39 -08:00
2015-02-23 19:57:47 -05:00
// No need to check inventory, cursor, bank or shared bank since they allow max item size and containers
2013-02-16 16:14:39 -08:00
// Code can be added to check item size vs. container size, but it is left to attrition for now.
}
// these functions operate with a material slot, which is from 0 to 8
2018-12-31 03:18:59 -06:00
uint32 Client : : GetEquippedItemFromTextureSlot ( uint8 material_slot ) const
2013-02-16 16:14:39 -08:00
{
2018-12-31 03:18:59 -06:00
int16 inventory_slot ;
2020-05-17 18:36:06 -07:00
const EQ : : ItemInstance * item ;
2013-02-16 16:14:39 -08:00
2020-05-17 18:36:06 -07:00
if ( material_slot > EQ : : textures : : LastTexture ) {
2013-02-16 16:14:39 -08:00
return 0 ;
}
2020-05-17 18:36:06 -07:00
inventory_slot = EQ : : InventoryProfile : : CalcSlotFromMaterial ( material_slot ) ;
2018-12-31 03:18:59 -06:00
if ( inventory_slot = = INVALID_INDEX ) {
2013-02-16 16:14:39 -08:00
return 0 ;
}
2013-05-06 13:07:41 -04:00
2018-12-31 03:18:59 -06:00
item = m_inv . GetItem ( inventory_slot ) ;
2013-02-16 16:14:39 -08:00
2018-12-31 03:18:59 -06:00
if ( item & & item - > GetItem ( ) ) {
2013-02-16 16:14:39 -08:00
return item - > GetItem ( ) - > ID ;
}
return 0 ;
}
2015-01-15 21:24:26 -05:00
#if 0
2013-02-16 16:14:39 -08:00
int32 Client : : GetEquipmentMaterial ( uint8 material_slot )
{
2016-10-16 05:10:54 -04:00
const ItemData * item ;
2013-05-06 13:07:41 -04:00
2018-12-31 23:19:48 -06:00
item = database . GetItem ( GetEquippedItemFromTextureSlot ( material_slot ) ) ;
2013-02-16 16:14:39 -08:00
if ( item ! = 0 )
{
return item - > Material ;
}
return 0 ;
}
2015-01-15 21:24:26 -05:00
# endif
2013-02-16 16:14:39 -08:00
uint32 Client : : GetEquipmentColor ( uint8 material_slot ) const
{
2020-05-17 18:36:06 -07:00
if ( material_slot > EQ : : textures : : LastTexture )
2013-02-16 16:14:39 -08:00
return 0 ;
2020-05-17 18:36:06 -07:00
const EQ : : ItemData * item = database . GetItem ( GetEquippedItemFromTextureSlot ( material_slot ) ) ;
2015-01-15 21:24:26 -05:00
if ( item ! = nullptr )
2016-06-01 04:58:52 -04:00
return ( ( m_pp . item_tint . Slot [ material_slot ] . UseTint ) ? m_pp . item_tint . Slot [ material_slot ] . Color : item - > Color ) ;
2013-02-16 16:14:39 -08:00
return 0 ;
}
// Send an item packet (including all subitems of the item)
2020-05-17 18:36:06 -07:00
void Client : : SendItemPacket ( int16 slot_id , const EQ : : ItemInstance * inst , ItemPacketType packet_type )
2013-02-16 16:14:39 -08:00
{
if ( ! inst )
return ;
2013-05-06 13:07:41 -04:00
2020-04-21 00:40:18 -04:00
if ( packet_type ! = ItemPacketMerchant ) {
2020-05-17 18:36:06 -07:00
if ( slot_id < = EQ : : invslot : : POSSESSIONS_END & & slot_id > = EQ : : invslot : : POSSESSIONS_BEGIN ) {
2020-04-21 00:40:18 -04:00
if ( ( ( ( uint64 ) 1 < < slot_id ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask ) = = 0 ) {
LogError ( " Item not sent to merchant : slot [{}] " , slot_id ) ;
return ;
}
}
2020-05-17 18:36:06 -07:00
else if ( slot_id < = EQ : : invbag : : GENERAL_BAGS_END & & slot_id > = EQ : : invbag : : GENERAL_BAGS_BEGIN ) {
auto temp_slot = EQ : : invslot : : GENERAL_BEGIN + ( ( slot_id - EQ : : invbag : : GENERAL_BAGS_BEGIN ) / EQ : : invbag : : SLOT_COUNT ) ;
2020-04-21 00:40:18 -04:00
if ( ( ( ( uint64 ) 1 < < temp_slot ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask ) = = 0 ) {
LogError ( " Item not sent to merchant2 : slot [{}] " , slot_id ) ;
return ;
}
}
2020-05-17 18:36:06 -07:00
else if ( slot_id < = EQ : : invslot : : BANK_END & & slot_id > = EQ : : invslot : : BANK_BEGIN ) {
if ( ( slot_id - EQ : : invslot : : BANK_BEGIN ) > = GetInv ( ) . GetLookup ( ) - > InventoryTypeSize . Bank ) {
2020-04-21 00:40:18 -04:00
LogError ( " Item not sent to merchant3 : slot [{}] " , slot_id ) ;
return ;
}
}
2020-05-17 18:36:06 -07:00
else if ( slot_id < = EQ : : invbag : : BANK_BAGS_END & & slot_id > = EQ : : invbag : : BANK_BAGS_BEGIN ) {
auto temp_slot = ( slot_id - EQ : : invbag : : BANK_BAGS_BEGIN ) / EQ : : invbag : : SLOT_COUNT ;
2020-04-21 00:40:18 -04:00
if ( temp_slot > = GetInv ( ) . GetLookup ( ) - > InventoryTypeSize . Bank ) {
LogError ( " Item not sent to merchant4 : slot [{}] " , slot_id ) ;
return ;
}
}
2018-08-13 22:32:36 -04:00
}
// Serialize item into |-delimited string (Titanium- uses '|' delimiter .. newer clients use pure data serialization)
2013-05-22 16:17:19 -04:00
std : : string packet = inst - > Serialize ( slot_id ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
EmuOpcode opcode = OP_Unknown ;
2013-05-04 18:06:58 -07:00
EQApplicationPacket * outapp = nullptr ;
ItemPacket_Struct * itempacket = nullptr ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
// Construct packet
opcode = ( packet_type = = ItemPacketViewLink ) ? OP_ItemLinkResponse : OP_ItemPacket ;
outapp = new EQApplicationPacket ( opcode , packet . length ( ) + sizeof ( ItemPacket_Struct ) ) ;
itempacket = ( ItemPacket_Struct * ) outapp - > pBuffer ;
memcpy ( itempacket - > SerializedItem , packet . c_str ( ) , packet . length ( ) ) ;
itempacket - > PacketType = packet_type ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
# if EQDEBUG >= 9
DumpPacket ( outapp ) ;
# endif
FastQueuePacket ( & outapp ) ;
}
2020-05-17 18:36:06 -07:00
EQApplicationPacket * Client : : ReturnItemPacket ( int16 slot_id , const EQ : : ItemInstance * inst , ItemPacketType packet_type )
2013-02-16 16:14:39 -08:00
{
if ( ! inst )
2015-01-15 21:24:26 -05:00
return nullptr ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
// Serialize item into |-delimited string
2013-05-22 16:17:19 -04:00
std : : string packet = inst - > Serialize ( slot_id ) ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
EmuOpcode opcode = OP_Unknown ;
2013-05-04 18:06:58 -07:00
EQApplicationPacket * outapp = nullptr ;
BulkItemPacket_Struct * itempacket = nullptr ;
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
// Construct packet
opcode = OP_ItemPacket ;
outapp = new EQApplicationPacket ( opcode , packet . length ( ) + 1 ) ;
itempacket = ( BulkItemPacket_Struct * ) outapp - > pBuffer ;
memcpy ( itempacket - > SerializedItem , packet . c_str ( ) , packet . length ( ) ) ;
# if EQDEBUG >= 9
DumpPacket ( outapp ) ;
# endif
return outapp ;
}
2015-02-14 16:36:30 -05:00
static int16 BandolierSlotToWeaponSlot ( int BandolierSlot )
{
switch ( BandolierSlot )
{
case bandolierPrimary :
2020-05-17 18:36:06 -07:00
return EQ : : invslot : : slotPrimary ;
2015-02-14 16:36:30 -05:00
case bandolierSecondary :
2020-05-17 18:36:06 -07:00
return EQ : : invslot : : slotSecondary ;
2015-02-14 16:36:30 -05:00
case bandolierRange :
2020-05-17 18:36:06 -07:00
return EQ : : invslot : : slotRange ;
2015-02-14 16:36:30 -05:00
default :
2020-05-17 18:36:06 -07:00
return EQ : : invslot : : slotAmmo ;
2013-02-16 16:14:39 -08:00
}
}
2015-02-14 16:36:30 -05:00
void Client : : CreateBandolier ( const EQApplicationPacket * app )
{
2013-02-16 16:14:39 -08:00
// Store bandolier set with the number and name passed by the client, along with the items that are currently
// in the players weapon slots.
BandolierCreate_Struct * bs = ( BandolierCreate_Struct * ) app - > pBuffer ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Char: [{}] Creating Bandolier Set [{}], Set Name: [{}] " , GetName ( ) , bs - > Number , bs - > Name ) ;
2015-02-14 16:36:30 -05:00
strcpy ( m_pp . bandoliers [ bs - > Number ] . Name , bs - > Name ) ;
2013-02-16 16:14:39 -08:00
2020-05-17 18:36:06 -07:00
const EQ : : ItemInstance * InvItem = nullptr ;
const EQ : : ItemData * BaseItem = nullptr ;
2015-02-14 16:36:30 -05:00
int16 WeaponSlot = 0 ;
2013-02-16 16:14:39 -08:00
2016-06-02 20:07:25 -04:00
database . DeleteCharacterBandolier ( this - > CharacterID ( ) , bs - > Number ) ;
2015-02-14 16:36:30 -05:00
for ( int BandolierSlot = bandolierPrimary ; BandolierSlot < = bandolierAmmo ; BandolierSlot + + ) {
2013-02-16 16:14:39 -08:00
WeaponSlot = BandolierSlotToWeaponSlot ( BandolierSlot ) ;
InvItem = GetInv ( ) [ WeaponSlot ] ;
if ( InvItem ) {
BaseItem = InvItem - > GetItem ( ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Char: [{}] adding item [{}] to slot [{}] " , GetName ( ) , BaseItem - > Name , WeaponSlot ) ;
2015-02-14 16:36:30 -05:00
m_pp . bandoliers [ bs - > Number ] . Items [ BandolierSlot ] . ID = BaseItem - > ID ;
m_pp . bandoliers [ bs - > Number ] . Items [ BandolierSlot ] . Icon = BaseItem - > Icon ;
database . SaveCharacterBandolier ( this - > CharacterID ( ) , bs - > Number , BandolierSlot , m_pp . bandoliers [ bs - > Number ] . Items [ BandolierSlot ] . ID , m_pp . bandoliers [ bs - > Number ] . Items [ BandolierSlot ] . Icon , bs - > Name ) ;
2013-02-16 16:14:39 -08:00
}
else {
2019-09-02 02:50:39 -05:00
LogInventory ( " Char: [{}] no item in slot [{}] " , GetName ( ) , WeaponSlot ) ;
2015-02-14 16:36:30 -05:00
m_pp . bandoliers [ bs - > Number ] . Items [ BandolierSlot ] . ID = 0 ;
m_pp . bandoliers [ bs - > Number ] . Items [ BandolierSlot ] . Icon = 0 ;
2013-02-16 16:14:39 -08:00
}
}
}
2015-02-14 16:36:30 -05:00
void Client : : RemoveBandolier ( const EQApplicationPacket * app )
{
2013-02-16 16:14:39 -08:00
BandolierDelete_Struct * bds = ( BandolierDelete_Struct * ) app - > pBuffer ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Char: [{}] removing set " , GetName ( ) , bds - > Number ) ;
2015-02-14 16:36:30 -05:00
memset ( m_pp . bandoliers [ bds - > Number ] . Name , 0 , 32 ) ;
for ( int i = bandolierPrimary ; i < = bandolierAmmo ; i + + ) {
m_pp . bandoliers [ bds - > Number ] . Items [ i ] . ID = 0 ;
m_pp . bandoliers [ bds - > Number ] . Items [ i ] . Icon = 0 ;
2013-02-16 16:14:39 -08:00
}
2015-02-14 16:36:30 -05:00
database . DeleteCharacterBandolier ( this - > CharacterID ( ) , bds - > Number ) ;
2013-02-16 16:14:39 -08:00
}
2015-02-14 16:36:30 -05:00
void Client : : SetBandolier ( const EQApplicationPacket * app )
{
2013-02-16 16:14:39 -08:00
// Swap the weapons in the given bandolier set into the character's weapon slots and return
// any items currently in the weapon slots to inventory.
BandolierSet_Struct * bss = ( BandolierSet_Struct * ) app - > pBuffer ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Char: [{}] activating set [{}] " , GetName ( ) , bss - > Number ) ;
2015-02-14 16:36:30 -05:00
int16 slot = 0 ;
int16 WeaponSlot = 0 ;
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * BandolierItems [ 4 ] ; // Temporary holding area for the weapons we pull out of their inventory
2013-02-16 16:14:39 -08:00
// First we pull the items for this bandolier set out of their inventory, this makes space to put the
// currently equipped items back.
2015-02-14 16:36:30 -05:00
for ( int BandolierSlot = bandolierPrimary ; BandolierSlot < = bandolierAmmo ; BandolierSlot + + ) {
2013-02-16 16:14:39 -08:00
// If this bandolier set has an item in this position
2015-02-14 16:36:30 -05:00
if ( m_pp . bandoliers [ bss - > Number ] . Items [ BandolierSlot ] . ID ) {
2013-02-16 16:14:39 -08:00
WeaponSlot = BandolierSlotToWeaponSlot ( BandolierSlot ) ;
// Check if the player has the item specified in the bandolier set on them.
//
2015-02-14 16:36:30 -05:00
slot = m_inv . HasItem ( m_pp . bandoliers [ bss - > Number ] . Items [ BandolierSlot ] . ID , 1 ,
2013-05-09 10:44:08 -04:00
invWhereWorn | invWherePersonal ) ;
2013-02-16 16:14:39 -08:00
2013-05-06 13:07:41 -04:00
// removed 'invWhereCursor' argument from above and implemented slots 30, 331-340 checks here
2014-07-16 21:23:16 -04:00
if ( slot = = INVALID_INDEX ) {
2020-05-17 18:36:06 -07:00
if ( m_inv . GetItem ( EQ : : invslot : : slotCursor ) ) {
if ( m_inv . GetItem ( EQ : : invslot : : slotCursor ) - > GetItem ( ) - > ID = = m_pp . bandoliers [ bss - > Number ] . Items [ BandolierSlot ] . ID & &
m_inv . GetItem ( EQ : : invslot : : slotCursor ) - > GetCharges ( ) > = 1 ) { // '> 0' the same, but this matches Inventory::_HasItem conditional check
slot = EQ : : invslot : : slotCursor ;
2015-01-15 21:24:26 -05:00
}
2020-05-17 18:36:06 -07:00
else if ( m_inv . GetItem ( EQ : : invslot : : slotCursor ) - > GetItem ( ) - > ItemClass = = 1 ) {
for ( int16 CursorBagSlot = EQ : : invbag : : CURSOR_BAG_BEGIN ; CursorBagSlot < = EQ : : invbag : : CURSOR_BAG_END ; CursorBagSlot + + ) {
2013-02-16 16:14:39 -08:00
if ( m_inv . GetItem ( CursorBagSlot ) ) {
2015-02-14 16:36:30 -05:00
if ( m_inv . GetItem ( CursorBagSlot ) - > GetItem ( ) - > ID = = m_pp . bandoliers [ bss - > Number ] . Items [ BandolierSlot ] . ID & &
2013-02-16 16:14:39 -08:00
m_inv . GetItem ( CursorBagSlot ) - > GetCharges ( ) > = 1 ) { // ditto
slot = CursorBagSlot ;
break ;
}
}
}
}
}
}
// if the player has this item in their inventory,
2014-07-16 21:23:16 -04:00
if ( slot ! = INVALID_INDEX ) {
2013-02-16 16:14:39 -08:00
// Pull the item out of the inventory
BandolierItems [ BandolierSlot ] = m_inv . PopItem ( slot ) ;
// If ammo with charges, only take one charge out to put in the range slot, that is what
// the client does.
2013-05-06 13:07:41 -04:00
if ( ( ( BandolierSlot = = bandolierAmmo ) | | ( BandolierSlot = = bandolierRange ) ) & &
2013-05-09 10:44:08 -04:00
BandolierItems [ BandolierSlot ] & & BandolierItems [ BandolierSlot ] - > IsStackable ( ) ) {
2013-02-16 16:14:39 -08:00
int Charges = BandolierItems [ BandolierSlot ] - > GetCharges ( ) ;
// If there is more than one charge
if ( Charges > 1 ) {
BandolierItems [ BandolierSlot ] - > SetCharges ( Charges - 1 ) ;
// Take one charge out and put the rest back
m_inv . PutItem ( slot , * BandolierItems [ BandolierSlot ] ) ;
database . SaveInventory ( character_id , BandolierItems [ BandolierSlot ] , slot ) ;
BandolierItems [ BandolierSlot ] - > SetCharges ( 1 ) ;
}
2015-01-15 21:24:26 -05:00
else { // Remove the item from the inventory
2013-02-16 16:14:39 -08:00
database . SaveInventory ( character_id , 0 , slot ) ;
2015-01-15 21:24:26 -05:00
}
2013-02-16 16:14:39 -08:00
}
2015-01-15 21:24:26 -05:00
else { // Remove the item from the inventory
2013-02-16 16:14:39 -08:00
database . SaveInventory ( character_id , 0 , slot ) ;
2015-01-15 21:24:26 -05:00
}
2013-02-16 16:14:39 -08:00
}
else { // The player doesn't have the required weapon with them.
BandolierItems [ BandolierSlot ] = 0 ;
2014-07-16 21:23:16 -04:00
if ( slot = = INVALID_INDEX ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Character does not have required bandolier item for slot [{}] " , WeaponSlot ) ;
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * InvItem = m_inv . PopItem ( WeaponSlot ) ;
2013-02-16 16:14:39 -08:00
if ( InvItem ) {
2013-05-06 13:07:41 -04:00
// If there was an item in that weapon slot, put it in the inventory
2019-09-02 02:50:39 -05:00
LogInventory ( " returning item [{}] in weapon slot [{}] to inventory " ,
2015-01-21 16:40:46 -06:00
InvItem - > GetItem ( ) - > Name , WeaponSlot ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " returning item [{}] in weapon slot [{}] to inventory " , InvItem - > GetItem ( ) - > Name , WeaponSlot ) ;
2015-01-15 21:24:26 -05:00
if ( MoveItemToInventory ( InvItem ) ) {
2013-02-16 16:14:39 -08:00
database . SaveInventory ( character_id , 0 , WeaponSlot ) ;
2019-09-01 22:05:44 -05:00
LogError ( " returning item [{}] in weapon slot [{}] to inventory " , InvItem - > GetItem ( ) - > Name , WeaponSlot ) ;
2015-01-15 21:24:26 -05:00
}
else {
2019-09-01 22:05:44 -05:00
LogError ( " Char: [{}], ERROR returning [{}] to inventory " , GetName ( ) , InvItem - > GetItem ( ) - > Name ) ;
2015-01-15 21:24:26 -05:00
}
2013-02-16 16:14:39 -08:00
safe_delete ( InvItem ) ;
}
}
}
}
}
// Now we move the required weapons into the character weapon slots, and return any items we are replacing
// back to inventory.
//
2015-02-14 16:36:30 -05:00
for ( int BandolierSlot = bandolierPrimary ; BandolierSlot < = bandolierAmmo ; BandolierSlot + + ) {
2013-02-16 16:14:39 -08:00
// Find the inventory slot corresponding to this bandolier slot
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
WeaponSlot = BandolierSlotToWeaponSlot ( BandolierSlot ) ;
// if there is an item in this Bandolier slot ?
2015-02-14 16:36:30 -05:00
if ( m_pp . bandoliers [ bss - > Number ] . Items [ BandolierSlot ] . ID ) {
2013-02-16 16:14:39 -08:00
// if the player has this item in their inventory, and it is not already where it needs to be
if ( BandolierItems [ BandolierSlot ] ) {
// Pull the item that we are going to replace
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * InvItem = m_inv . PopItem ( WeaponSlot ) ;
2013-02-16 16:14:39 -08:00
// Put the item specified in the bandolier where it needs to be
m_inv . PutItem ( WeaponSlot , * BandolierItems [ BandolierSlot ] ) ;
safe_delete ( BandolierItems [ BandolierSlot ] ) ;
// Update the database, save the item now in the weapon slot
database . SaveInventory ( character_id , m_inv . GetItem ( WeaponSlot ) , WeaponSlot ) ;
if ( InvItem ) {
// If there was already an item in that weapon slot that we replaced, find a place to put it
2015-01-15 21:24:26 -05:00
if ( ! MoveItemToInventory ( InvItem ) ) {
2019-09-01 22:05:44 -05:00
LogError ( " Char: [{}], ERROR returning [{}] to inventory " , GetName ( ) , InvItem - > GetItem ( ) - > Name ) ;
2015-01-15 21:24:26 -05:00
}
2013-02-16 16:14:39 -08:00
safe_delete ( InvItem ) ;
}
}
}
else {
// This bandolier set has no item for this slot, so take whatever is in the weapon slot and
// put it in the player's inventory.
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * InvItem = m_inv . PopItem ( WeaponSlot ) ;
2013-02-16 16:14:39 -08:00
if ( InvItem ) {
2019-09-02 02:50:39 -05:00
LogInventory ( " Bandolier has no item for slot [{}], returning item [{}] to inventory " , WeaponSlot , InvItem - > GetItem ( ) - > Name ) ;
2013-05-06 13:07:41 -04:00
// If there was an item in that weapon slot, put it in the inventory
2015-01-15 21:24:26 -05:00
if ( MoveItemToInventory ( InvItem ) ) {
2013-02-16 16:14:39 -08:00
database . SaveInventory ( character_id , 0 , WeaponSlot ) ;
2015-01-15 21:24:26 -05:00
}
else {
2019-09-01 22:05:44 -05:00
LogError ( " Char: [{}], ERROR returning [{}] to inventory " , GetName ( ) , InvItem - > GetItem ( ) - > Name ) ;
2015-01-15 21:24:26 -05:00
}
2013-02-16 16:14:39 -08:00
safe_delete ( InvItem ) ;
}
}
}
// finally, recalculate any stat bonuses from the item change
CalcBonuses ( ) ;
}
2020-05-17 18:36:06 -07:00
bool Client : : MoveItemToInventory ( EQ : : ItemInstance * ItemToReturn , bool UpdateClient ) {
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
// This is a support function for Client::SetBandolier, however it can be used anywhere it's functionality is required.
//
2013-05-06 13:07:41 -04:00
// When the client moves items around as Bandolier sets are activated, it does not send details to the
2013-02-16 16:14:39 -08:00
// server of what item it has moved to which slot. It assumes the server knows what it will do.
//
2013-05-06 13:07:41 -04:00
// The standard EQEmu auto inventory routines do not behave as the client does when manipulating bandoliers.
2013-02-16 16:14:39 -08:00
// The client will look in each main inventory slot. If it finds a bag in a slot, it will then look inside
// the bag for a free slot.
//
// This differs from the standard EQEmu method of looking in all 8 inventory slots first to find an empty slot, and
// then going back and looking in bags. There are also other differences related to how it moves stackable items back
// to inventory.
//
// Rather than alter the current auto inventory behaviour, just in case something
// depends on current behaviour, this routine operates the same as the client when moving items back to inventory when
// swapping bandolier sets.
2015-01-15 21:24:26 -05:00
if ( ! ItemToReturn ) {
return false ;
}
2013-02-16 16:14:39 -08:00
2019-09-02 02:50:39 -05:00
LogInventory ( " Char: [{}] Returning [{}] to inventory " , GetName ( ) , ItemToReturn - > GetItem ( ) - > Name ) ;
2013-02-16 16:14:39 -08:00
uint32 ItemID = ItemToReturn - > GetItem ( ) - > ID ;
// If the item is stackable (ammo in range slot), try stacking it with other items of the same type
//
if ( ItemToReturn - > IsStackable ( ) ) {
2020-05-17 18:36:06 -07:00
for ( int16 i = EQ : : invslot : : GENERAL_BEGIN ; i < = EQ : : invslot : : slotCursor ; i + + ) { // changed slot max to 30 from 29. client will stack into slot 30 (bags too) before moving.
2018-08-13 22:32:36 -04:00
if ( ( ( uint64 ) 1 < < i ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask = = 0 )
continue ;
2013-02-16 16:14:39 -08:00
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * InvItem = m_inv . GetItem ( i ) ;
2013-02-16 16:14:39 -08:00
if ( InvItem & & ( InvItem - > GetItem ( ) - > ID = = ItemID ) & & ( InvItem - > GetCharges ( ) < InvItem - > GetItem ( ) - > StackSize ) ) {
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
int ChargeSlotsLeft = InvItem - > GetItem ( ) - > StackSize - InvItem - > GetCharges ( ) ;
2015-01-15 21:24:26 -05:00
int ChargesToMove = ItemToReturn - > GetCharges ( ) < ChargeSlotsLeft ? ItemToReturn - > GetCharges ( ) : ChargeSlotsLeft ;
2013-02-16 16:14:39 -08:00
InvItem - > SetCharges ( InvItem - > GetCharges ( ) + ChargesToMove ) ;
if ( UpdateClient )
SendItemPacket ( i , InvItem , ItemPacketTrade ) ;
database . SaveInventory ( character_id , m_inv . GetItem ( i ) , i ) ;
ItemToReturn - > SetCharges ( ItemToReturn - > GetCharges ( ) - ChargesToMove ) ;
2013-05-06 13:07:41 -04:00
if ( ! ItemToReturn - > GetCharges ( ) )
2013-02-16 16:14:39 -08:00
return true ;
}
// If there is a bag in this slot, look inside it.
//
2016-05-21 04:54:18 -04:00
if ( InvItem & & InvItem - > IsClassBag ( ) ) {
2013-02-16 16:14:39 -08:00
2020-05-17 18:36:06 -07:00
int16 BaseSlotID = EQ : : InventoryProfile : : CalcSlotId ( i , EQ : : invbag : : SLOT_BEGIN ) ;
2013-02-16 16:14:39 -08:00
uint8 BagSize = InvItem - > GetItem ( ) - > BagSlots ;
uint8 BagSlot ;
2020-05-17 18:36:06 -07:00
for ( BagSlot = EQ : : invbag : : SLOT_BEGIN ; BagSlot < BagSize ; BagSlot + + ) {
2013-02-16 16:14:39 -08:00
InvItem = m_inv . GetItem ( BaseSlotID + BagSlot ) ;
2013-05-09 10:44:08 -04:00
if ( InvItem & & ( InvItem - > GetItem ( ) - > ID = = ItemID ) & &
( InvItem - > GetCharges ( ) < InvItem - > GetItem ( ) - > StackSize ) ) {
2013-02-16 16:14:39 -08:00
int ChargeSlotsLeft = InvItem - > GetItem ( ) - > StackSize - InvItem - > GetCharges ( ) ;
2015-01-15 21:24:26 -05:00
int ChargesToMove = ItemToReturn - > GetCharges ( ) < ChargeSlotsLeft ? ItemToReturn - > GetCharges ( ) : ChargeSlotsLeft ;
2013-02-16 16:14:39 -08:00
InvItem - > SetCharges ( InvItem - > GetCharges ( ) + ChargesToMove ) ;
if ( UpdateClient )
2015-01-15 21:24:26 -05:00
SendItemPacket ( BaseSlotID + BagSlot , m_inv . GetItem ( BaseSlotID + BagSlot ) , ItemPacketTrade ) ;
2013-02-16 16:14:39 -08:00
2015-01-15 21:24:26 -05:00
database . SaveInventory ( character_id , m_inv . GetItem ( BaseSlotID + BagSlot ) , BaseSlotID + BagSlot ) ;
2013-02-16 16:14:39 -08:00
ItemToReturn - > SetCharges ( ItemToReturn - > GetCharges ( ) - ChargesToMove ) ;
2013-05-06 13:07:41 -04:00
if ( ! ItemToReturn - > GetCharges ( ) )
2013-02-16 16:14:39 -08:00
return true ;
2013-05-06 13:07:41 -04:00
}
2013-02-16 16:14:39 -08:00
}
}
}
}
// We have tried stacking items, now just try and find an empty slot.
2020-05-17 18:36:06 -07:00
for ( int16 i = EQ : : invslot : : GENERAL_BEGIN ; i < = EQ : : invslot : : slotCursor ; i + + ) { // changed slot max to 30 from 29. client will move into slot 30 (bags too) before pushing onto cursor.
2018-08-13 22:32:36 -04:00
if ( ( ( uint64 ) 1 < < i ) & GetInv ( ) . GetLookup ( ) - > PossessionsBitmask = = 0 )
continue ;
2013-02-16 16:14:39 -08:00
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * InvItem = m_inv . GetItem ( i ) ;
2013-02-16 16:14:39 -08:00
if ( ! InvItem ) {
// Found available slot in personal inventory
m_inv . PutItem ( i , * ItemToReturn ) ;
if ( UpdateClient )
SendItemPacket ( i , ItemToReturn , ItemPacketTrade ) ;
database . SaveInventory ( character_id , m_inv . GetItem ( i ) , i ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Char: [{}] Storing in main inventory slot [{}] " , GetName ( ) , i ) ;
2013-02-16 16:14:39 -08:00
return true ;
}
2020-05-17 18:36:06 -07:00
if ( InvItem - > IsClassBag ( ) & & EQ : : InventoryProfile : : CanItemFitInContainer ( ItemToReturn - > GetItem ( ) , InvItem - > GetItem ( ) ) ) {
2013-02-16 16:14:39 -08:00
2020-05-17 18:36:06 -07:00
int16 BaseSlotID = EQ : : InventoryProfile : : CalcSlotId ( i , EQ : : invbag : : SLOT_BEGIN ) ;
2013-02-16 16:14:39 -08:00
uint8 BagSize = InvItem - > GetItem ( ) - > BagSlots ;
2020-05-17 18:36:06 -07:00
for ( uint8 BagSlot = EQ : : invbag : : SLOT_BEGIN ; BagSlot < BagSize ; BagSlot + + ) {
2013-02-16 16:14:39 -08:00
InvItem = m_inv . GetItem ( BaseSlotID + BagSlot ) ;
if ( ! InvItem ) {
// Found available slot within bag
m_inv . PutItem ( BaseSlotID + BagSlot , * ItemToReturn ) ;
if ( UpdateClient )
SendItemPacket ( BaseSlotID + BagSlot , ItemToReturn , ItemPacketTrade ) ;
database . SaveInventory ( character_id , m_inv . GetItem ( BaseSlotID + BagSlot ) , BaseSlotID + BagSlot ) ;
2019-09-02 02:50:39 -05:00
LogInventory ( " Char: [{}] Storing in bag slot [{}] " , GetName ( ) , BaseSlotID + BagSlot ) ;
2013-02-16 16:14:39 -08:00
return true ;
}
}
}
}
2013-05-06 13:07:41 -04:00
2013-02-16 16:14:39 -08:00
// Store on the cursor
2013-05-06 13:07:41 -04:00
//
2019-09-02 02:50:39 -05:00
LogInventory ( " Char: [{}] No space, putting on the cursor " , GetName ( ) ) ;
2013-02-16 16:14:39 -08:00
PushItemOnCursor ( * ItemToReturn , UpdateClient ) ;
return true ;
}
2014-10-28 11:35:26 -04:00
bool Client : : InterrogateInventory ( Client * requester , bool log , bool silent , bool allowtrip , bool & error , bool autolog )
{
if ( ! requester )
return false ;
2020-05-17 18:36:06 -07:00
std : : map < int16 , const EQ : : ItemInstance * > instmap ;
2014-10-28 11:35:26 -04:00
// build reference map
2020-05-17 18:36:06 -07:00
for ( int16 index = EQ : : invslot : : POSSESSIONS_BEGIN ; index < = EQ : : invslot : : POSSESSIONS_END ; + + index ) {
2015-01-15 21:24:26 -05:00
auto inst = m_inv [ index ] ;
if ( inst = = nullptr ) { continue ; }
instmap [ index ] = inst ;
}
2020-05-17 18:36:06 -07:00
for ( int16 index = EQ : : invslot : : TRIBUTE_BEGIN ; index < = EQ : : invslot : : TRIBUTE_END ; + + index ) {
2015-01-15 21:24:26 -05:00
auto inst = m_inv [ index ] ;
if ( inst = = nullptr ) { continue ; }
instmap [ index ] = inst ;
}
2020-05-17 18:36:06 -07:00
for ( int16 index = EQ : : invslot : : BANK_BEGIN ; index < = EQ : : invslot : : BANK_END ; + + index ) {
2015-01-15 21:24:26 -05:00
auto inst = m_inv [ index ] ;
if ( inst = = nullptr ) { continue ; }
instmap [ index ] = inst ;
}
2020-05-17 18:36:06 -07:00
for ( int16 index = EQ : : invslot : : SHARED_BANK_BEGIN ; index < = EQ : : invslot : : SHARED_BANK_END ; + + index ) {
2015-01-15 21:24:26 -05:00
auto inst = m_inv [ index ] ;
if ( inst = = nullptr ) { continue ; }
instmap [ index ] = inst ;
}
2020-05-17 18:36:06 -07:00
for ( int16 index = EQ : : invslot : : TRADE_BEGIN ; index < = EQ : : invslot : : TRADE_END ; + + index ) {
2015-01-15 21:24:26 -05:00
auto inst = m_inv [ index ] ;
if ( inst = = nullptr ) { continue ; }
instmap [ index ] = inst ;
}
auto tsobject = GetTradeskillObject ( ) ;
if ( tsobject ! = nullptr ) {
2020-05-17 18:36:06 -07:00
for ( int16 index = EQ : : invslot : : SLOT_BEGIN ; index < EQ : : invtype : : WORLD_SIZE ; + + index ) {
2015-01-15 21:24:26 -05:00
auto inst = tsobject - > GetItem ( index ) ;
if ( inst = = nullptr ) { continue ; }
2020-05-17 18:36:06 -07:00
instmap [ EQ : : invslot : : WORLD_BEGIN + index ] = inst ;
2015-01-15 21:24:26 -05:00
}
}
2014-10-28 11:35:26 -04:00
int limbo = 0 ;
2015-02-06 07:57:15 -05:00
for ( auto cursor_itr = m_inv . cursor_cbegin ( ) ; cursor_itr ! = m_inv . cursor_cend ( ) ; + + cursor_itr , + + limbo ) {
2016-04-07 17:21:55 -04:00
// m_inv.cursor_begin() is referenced as SlotCursor in MapPossessions above
2015-02-06 07:57:15 -05:00
if ( cursor_itr = = m_inv . cursor_cbegin ( ) )
2014-10-28 11:35:26 -04:00
continue ;
instmap [ 8000 + limbo ] = * cursor_itr ;
}
// call InterrogateInventory_ for error check
2016-05-25 16:10:28 -04:00
for ( auto instmap_itr = instmap . begin ( ) ; ( instmap_itr ! = instmap . end ( ) ) & & ( ! error ) ; + + instmap_itr ) {
2014-10-28 11:35:26 -04:00
InterrogateInventory_ ( true , requester , instmap_itr - > first , INVALID_INDEX , instmap_itr - > second , nullptr , log , silent , error , 0 ) ;
2015-01-15 21:24:26 -05:00
}
2014-10-28 11:35:26 -04:00
if ( autolog & & error & & ( ! log ) )
log = true ;
2015-01-15 21:24:26 -05:00
if ( log ) {
2019-09-01 22:05:44 -05:00
LogError ( " Client::InterrogateInventory() called for [{}] by [{}] with an error state of [{}] " , GetName ( ) , requester - > GetName ( ) , ( error ? " TRUE " : " FALSE " ) ) ;
2015-01-15 21:24:26 -05:00
}
if ( ! silent ) {
2019-08-11 00:27:04 -05:00
requester - > Message ( Chat : : Default , " --- Inventory Interrogation Report for %s (requested by: %s, error state: %s) --- " , GetName ( ) , requester - > GetName ( ) , ( error ? " TRUE " : " FALSE " ) ) ;
2015-01-15 21:24:26 -05:00
}
2014-10-28 11:35:26 -04:00
// call InterrogateInventory_ for report
2016-05-25 16:10:28 -04:00
for ( auto instmap_itr = instmap . begin ( ) ; ( instmap_itr ! = instmap . end ( ) ) ; + + instmap_itr ) {
2014-10-28 11:35:26 -04:00
InterrogateInventory_ ( false , requester , instmap_itr - > first , INVALID_INDEX , instmap_itr - > second , nullptr , log , silent , error , 0 ) ;
2015-01-15 21:24:26 -05:00
}
2014-10-28 11:35:26 -04:00
if ( error ) {
2019-08-11 00:00:55 -05:00
Message ( Chat : : Red , " An error has been discovered in your inventory! " ) ;
Message ( Chat : : Red , " Do not log out, zone or re-arrange items until this " ) ;
Message ( Chat : : Red , " issue has been resolved or item loss may occur! " ) ;
2014-10-28 11:35:26 -04:00
if ( allowtrip )
TripInterrogateInvState ( ) ;
}
if ( log ) {
2019-09-01 22:05:44 -05:00
LogError ( " Target interrogate inventory flag: [{}] " , ( GetInterrogateInvState ( ) ? " TRUE " : " FALSE " ) ) ;
2019-09-01 23:54:24 -05:00
LogDebug ( " [CLIENT] Client::InterrogateInventory() -- End " ) ;
2014-10-28 11:35:26 -04:00
}
if ( ! silent ) {
2019-08-11 00:27:04 -05:00
requester - > Message ( Chat : : Default , " Target interrogation flag: %s " , ( GetInterrogateInvState ( ) ? " TRUE " : " FALSE " ) ) ;
requester - > Message ( Chat : : Default , " --- End of Interrogation Report --- " ) ;
2014-10-28 11:35:26 -04:00
}
instmap . clear ( ) ;
return true ;
}
2020-05-17 18:36:06 -07:00
void Client : : InterrogateInventory_ ( bool errorcheck , Client * requester , int16 head , int16 index , const EQ : : ItemInstance * inst , const EQ : : ItemInstance * parent , bool log , bool silent , bool & error , int depth )
2014-10-28 11:35:26 -04:00
{
if ( depth > = 10 ) {
2019-09-01 23:54:24 -05:00
LogDebug ( " [CLIENT] Client::InterrogateInventory_() - Recursion count has exceeded the maximum allowable (You have a REALLY BIG PROBLEM!!) " ) ;
2014-10-28 11:35:26 -04:00
return ;
}
if ( errorcheck ) {
if ( InterrogateInventory_error ( head , index , inst , parent , depth ) ) {
error = true ;
}
else {
2015-01-15 21:24:26 -05:00
if ( inst ) {
2020-05-17 18:36:06 -07:00
for ( int16 sub = EQ : : invbag : : SLOT_BEGIN ; ( sub < = EQ : : invbag : : SLOT_END ) & & ( ! error ) ; + + sub ) { // treat any EQ::ItemInstance as having the max internal slots available
2014-10-28 11:35:26 -04:00
if ( inst - > GetItem ( sub ) )
InterrogateInventory_ ( true , requester , head , sub , inst - > GetItem ( sub ) , inst , log , silent , error , depth + 1 ) ;
2015-01-15 21:24:26 -05:00
}
}
2014-10-28 11:35:26 -04:00
}
}
else {
bool localerror = InterrogateInventory_error ( head , index , inst , parent , depth ) ;
std : : string i ;
std : : string p ;
std : : string e ;
2015-01-15 21:24:26 -05:00
if ( inst ) { i = StringFormat ( " %s (id: %u, cls: %u, aug_t: %u) " , inst - > GetItem ( ) - > Name , inst - > GetItem ( ) - > ID , inst - > GetItem ( ) - > ItemClass , inst - > GetItem ( ) - > AugType ) ; }
2014-10-28 11:35:26 -04:00
else { i = " NONE " ; }
2015-01-15 21:24:26 -05:00
if ( parent ) { p = StringFormat ( " %s (id: %u, cls: %u, aug_t: %u), index: %i " , parent - > GetItem ( ) - > Name , parent - > GetItem ( ) - > ID , parent - > GetItem ( ) - > ItemClass , parent - > GetItem ( ) - > AugType , index ) ; }
2014-10-28 11:35:26 -04:00
else { p = " NONE " ; }
if ( localerror ) { e = " [ERROR] " ; }
else { e = " " ; }
2015-01-15 21:24:26 -05:00
if ( log ) {
2019-09-02 03:10:03 -05:00
LogError ( " Head: [{}], Depth: [{}], Instance: [{}], Parent: [{}][{}] " ,
2015-01-15 21:24:26 -05:00
head , depth , i . c_str ( ) , p . c_str ( ) , e . c_str ( ) ) ;
}
if ( ! silent ) {
2019-08-11 00:00:55 -05:00
requester - > Message ( Chat : : Gray , " %i:%i - inst: %s - parent: %s%s " ,
2015-01-15 21:24:26 -05:00
head , depth , i . c_str ( ) , p . c_str ( ) , e . c_str ( ) ) ;
}
2014-10-28 11:35:26 -04:00
2015-01-15 21:24:26 -05:00
if ( inst ) {
2020-05-17 18:36:06 -07:00
for ( int16 sub = EQ : : invbag : : SLOT_BEGIN ; ( sub < = EQ : : invbag : : SLOT_END ) ; + + sub ) {
2014-10-28 11:35:26 -04:00
if ( inst - > GetItem ( sub ) )
InterrogateInventory_ ( false , requester , head , sub , inst - > GetItem ( sub ) , inst , log , silent , error , depth + 1 ) ;
2015-01-15 21:24:26 -05:00
}
}
2014-10-28 11:35:26 -04:00
}
return ;
}
2020-05-17 18:36:06 -07:00
bool Client : : InterrogateInventory_error ( int16 head , int16 index , const EQ : : ItemInstance * inst , const EQ : : ItemInstance * parent , int depth )
2014-10-28 11:35:26 -04:00
{
// very basic error checking - can be elaborated upon if more in-depth testing is needed...
if (
2020-05-17 18:36:06 -07:00
( head > = EQ : : invslot : : EQUIPMENT_BEGIN & & head < = EQ : : invslot : : EQUIPMENT_END ) | |
( head > = EQ : : invslot : : TRIBUTE_BEGIN & & head < = EQ : : invslot : : TRIBUTE_END ) | |
( head > = EQ : : invslot : : WORLD_BEGIN & & head < = EQ : : invslot : : WORLD_END ) | |
2018-08-13 22:32:36 -04:00
( head > = 8000 & & head < = 8101 ) ) {
2014-10-28 11:35:26 -04:00
switch ( depth )
{
case 0 : // requirement: inst is extant
if ( ! inst )
return true ;
break ;
case 1 : // requirement: parent is common and inst is augment
if ( ( ! parent ) | | ( ! inst ) )
return true ;
2020-05-17 18:36:06 -07:00
if ( ! parent - > IsType ( EQ : : item : : ItemClassCommon ) )
2014-10-28 11:35:26 -04:00
return true ;
2020-05-17 18:36:06 -07:00
if ( index > EQ : : invaug : : SOCKET_END )
2014-10-28 11:35:26 -04:00
return true ;
break ;
default : // requirement: none (something bad happened...)
return true ;
}
}
else if (
2020-05-17 18:36:06 -07:00
( head > = EQ : : invslot : : GENERAL_BEGIN & & head < = EQ : : invslot : : GENERAL_END ) | |
( head = = EQ : : invslot : : slotCursor ) | |
( head > = EQ : : invslot : : BANK_BEGIN & & head < = EQ : : invslot : : BANK_END ) | |
( head > = EQ : : invslot : : SHARED_BANK_BEGIN & & head < = EQ : : invslot : : SHARED_BANK_END ) | |
( head > = EQ : : invslot : : TRADE_BEGIN & & head < = EQ : : invslot : : TRADE_END ) ) {
2014-10-28 11:35:26 -04:00
switch ( depth )
{
case 0 : // requirement: inst is extant
if ( ! inst )
return true ;
break ;
case 1 : // requirement: parent is common and inst is augment ..or.. parent is container and inst is extant
if ( ( ! parent ) | | ( ! inst ) )
return true ;
2020-05-17 18:36:06 -07:00
if ( parent - > IsType ( EQ : : item : : ItemClassBag ) )
2014-10-28 11:35:26 -04:00
break ;
2016-05-21 04:54:18 -04:00
if ( parent - > IsClassBook ( ) )
2014-10-28 11:35:26 -04:00
return true ;
2016-05-21 04:54:18 -04:00
if ( parent - > IsClassCommon ( ) ) {
2014-10-28 11:35:26 -04:00
if ( ! ( inst - > GetItem ( ) - > AugType > 0 ) )
return true ;
2020-05-17 18:36:06 -07:00
if ( index > EQ : : invaug : : SOCKET_END )
2014-10-28 11:35:26 -04:00
return true ;
}
break ;
case 2 : // requirement: parent is common and inst is augment
if ( ( ! parent ) | | ( ! inst ) )
return true ;
2020-05-17 18:36:06 -07:00
if ( parent - > IsType ( EQ : : item : : ItemClassBag ) )
2014-10-28 11:35:26 -04:00
return true ;
2016-05-21 04:54:18 -04:00
if ( parent - > IsClassBook ( ) )
2014-10-28 11:35:26 -04:00
return true ;
2016-05-21 04:54:18 -04:00
if ( parent - > IsClassCommon ( ) ) {
2014-10-28 11:35:26 -04:00
if ( ! ( inst - > GetItem ( ) - > AugType > 0 ) )
return true ;
2020-05-17 18:36:06 -07:00
if ( index > EQ : : invaug : : SOCKET_END )
2014-10-28 11:35:26 -04:00
return true ;
}
break ;
default : // requirement: none (something bad happened again...)
return true ;
}
}
else {
return true ;
}
return false ;
}
2020-05-17 18:36:06 -07:00
void EQ : : InventoryProfile : : SetCustomItemData ( uint32 character_id , int16 slot_id , std : : string identifier , std : : string value ) {
EQ : : ItemInstance * inst = GetItem ( slot_id ) ;
2013-05-09 10:44:08 -04:00
if ( inst ) {
inst - > SetCustomData ( identifier , value ) ;
database . SaveInventory ( character_id , inst , slot_id ) ;
}
2013-02-16 16:14:39 -08:00
}
2020-05-17 18:36:06 -07:00
void EQ : : InventoryProfile : : SetCustomItemData ( uint32 character_id , int16 slot_id , std : : string identifier , int value ) {
EQ : : ItemInstance * inst = GetItem ( slot_id ) ;
2013-05-09 10:44:08 -04:00
if ( inst ) {
inst - > SetCustomData ( identifier , value ) ;
database . SaveInventory ( character_id , inst , slot_id ) ;
}
2013-02-16 16:14:39 -08:00
}
2020-05-17 18:36:06 -07:00
void EQ : : InventoryProfile : : SetCustomItemData ( uint32 character_id , int16 slot_id , std : : string identifier , float value ) {
EQ : : ItemInstance * inst = GetItem ( slot_id ) ;
2013-05-09 10:44:08 -04:00
if ( inst ) {
inst - > SetCustomData ( identifier , value ) ;
database . SaveInventory ( character_id , inst , slot_id ) ;
}
2013-02-16 16:14:39 -08:00
}
2020-05-17 18:36:06 -07:00
void EQ : : InventoryProfile : : SetCustomItemData ( uint32 character_id , int16 slot_id , std : : string identifier , bool value ) {
EQ : : ItemInstance * inst = GetItem ( slot_id ) ;
2013-05-09 10:44:08 -04:00
if ( inst ) {
inst - > SetCustomData ( identifier , value ) ;
database . SaveInventory ( character_id , inst , slot_id ) ;
}
2013-02-16 16:14:39 -08:00
}
2020-05-17 18:36:06 -07:00
std : : string EQ : : InventoryProfile : : GetCustomItemData ( int16 slot_id , std : : string identifier ) {
EQ : : ItemInstance * inst = GetItem ( slot_id ) ;
2013-05-09 10:44:08 -04:00
if ( inst ) {
return inst - > GetCustomData ( identifier ) ;
}
return " " ;
2013-02-16 16:14:39 -08:00
}