Greetings!
Please Read Post Below for Important Line Change
You may want to call me the 'Nerf Master' after this one, but here it is:
These following changes will prevent players from auto-equipping items they loot if they do not now ALSO meet the Required Level.
As well, the secondary slot must now be empty for a player to auto-equip a 2-Hander from a corpse. This does not affect looting much, items which cannot be equipped now will move to your inventory.
The second change will validate characters logging in \ zoning, and will delete all item configurations deemed 'impossible' (basically, right now it just deletes any items equipped before Req. Level or 2Hand + Secondary configurations).
As always, these changes are implemented on The Green Leaf server-build (which will be available open-source, once I get a site up). If you run into build errors, you may want to check my other posts to see if there are any pre-req changes you need to make.
common\database.h - around line 434 (after ConvertItemBlob) add:
Code:
bool Database::ValidateInventory( uint32 char_id, PlayerProfile_Struct* pp, Inventory* inv )
{
if( !pp || !inv ) // null?
return false;
bool valid = true;
ItemInst *item = 0;
for( int i = 0; i < 22; ++i ) // Worn slots
{
item = inv->GetItem(i);
if( item == 0 )
continue;
if( item->IsType( ItemTypeCommon ) )
{
// Make sure no-one has equipped items their Race, Class, or Level cannot use.
if( !item->IsEquipable( pp->race, pp->class_, pp->level ) ) // if item shouldn't be equipped
{
inv->DeleteItem( i ); // Delete from inventory
item = 0; // Null the item
SaveInventory( char_id, item, i ); // Save change
valid = false; // Inventory was invalid, flag it
}
// Make sure no-one has equipped 2 handed weapons & a secondary item
else if( i == SLOT_PRIMARY && item->IsWeapon() )
{
if( (item->GetItem()->Common.Skill == 1) || (item->GetItem()->Common.Skill == 4) || (item->GetItem()->Common.Skill == 35) ) // 2 handed weapons
{
if( inv->GetItem(SLOT_SECONDARY) ) // and if secondary slot is not empty
{
inv->DeleteItem( i ); // Delete from inventory
item = 0; // Null the item
SaveInventory( char_id, item, i ); // Save change
valid = false; // Inventory was invalid, flag it
}
}
}
}
}
return valid;
}
common\database.cpp - around line 2231 (bottom of GetCharacterInfoForLogin_result) change to this:
Code:
if (guilddbid)
*guilddbid = atoi(row[7]);
if (guildrank)
*guildrank = atoi(row[8]);
// bUsh - ValidateInventory
// Retrieve character inventory
bool getInv = GetInventory(char_id, inv);
if ( !ValidateInventory( char_id, pp, inv ) )
{
LogFile->write(EQEMuLog::Status, "Player inventory has been validated");
}
return getInv;
// bUsh - ValidateInventory End
}
return false;
}
common\item.h - around line 310, change virtual IsEquipable arg list:
Code:
virtual bool IsEquipable(int16 race, int16 class_, uint8 level) const;
as well as around line 383:
Code:
virtual bool IsEquipable(int16 race, int16 class_, uint8 level) const;
common\item.cpp - around line 178, change function arg list:
Code:
bool ItemInst::IsEquipable(int16, int16, uint8) const
and around line 208, change entire IsEquipable function to:
Code:
// Can item be equipped?
bool ItemCommonInst::IsEquipable(int16 race, int16 class_, uint8 level) const
{
if (!m_item)
return false;
bool israce = false;
bool isclass = false;
bool islevel = false;
if (m_item->EquipSlots == 0) {
return false;
}
uint32 classes_ = m_item->Common.Classes;
uint32 races_ = m_item->Common.Races;
uint8 level_ = m_item->Common.RequiredLevel;
// @merth: can this be optimized? i.e., will (race & common->Races) suffice?
for (int cur_class = 1; cur_class<=15; cur_class++) {
if (classes_ % 2 == 1) {
if (cur_class == class_) {
isclass = true;
}
}
classes_ >>= 1;
}
for (int cur_race = 1; cur_race <= 14; cur_race++) {
if (races_ %2 == 1) {
if (cur_race == race) {
israce = true;
}
}
races_ >>= 1;
}
if( level_ <= level )
islevel = true;
return (israce && isclass && islevel);
}
Finally:
zone\client.cpp - around line 2350 (autoputlootininventory), change entire first if block (auto equip) to:
Code:
// #1: Try to auto equip
if (try_worn && inst.IsEquipable(GetRace(), GetClass(), GetLevel()))
{
for (sint16 i = 0; i < 22; i++)
{
if (!m_inv[i])
{
if( i == SLOT_PRIMARY && inst.IsWeapon() ) // If item is primary slot weapon
{
if( (inst.GetItem()->Common.Skill == 1) || (inst.GetItem()->Common.Skill == 4) || (inst.GetItem()->Common.Skill == 35) ) // and uses 2hs \ 2hb \ 2hp
{
if( m_inv[SLOT_SECONDARY] ) // and if secondary slot is not empty
{
continue; // Can't auto-equip
}
}
}
if
(
i == SLOT_SECONDARY &&
inst.IsWeapon() &&
!CanThisClassDualWield()
)
{
continue;
}
if (inst.IsEquipable(i)) // Equippable at this slot?
{
PutLootInInventory(i, inst);
return true;
}
}
}
}
You're done! Tell me if I missed anything.
ValidateInventory can be modified to include any new checks for item errors etc.
Enjoy - this made a lot of sploiters on my server angry, Oh well!
