/* EQ2Emulator: Everquest II Server Emulator Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net) This file is part of EQ2Emulator. EQ2Emulator 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, either version 3 of the License, or (at your option) any later version. EQ2Emulator is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with EQ2Emulator. If not, see . */ #include "Items.h" #include "../Spells.h" #include "../Quests.h" #include "../Player.h" #include "../classes.h" #include "math.h" #include "../World.h" #include "../LuaInterface.h" #include "../../common/Log.h" #include "../Entity.h" #include "../Recipes/Recipe.h" #include #include #include #include "../Rules/Rules.h" extern World world; extern MasterSpellList master_spell_list; extern MasterQuestList master_quest_list; extern MasterRecipeList master_recipe_list; extern ConfigReader configReader; extern LuaInterface* lua_interface; extern RuleManager rule_manager; MasterItemList::MasterItemList(){ AddMappedItemStat(ITEM_STAT_ADORNING, std::string("adorning")); AddMappedItemStat(ITEM_STAT_AGGRESSION, std::string("aggression")); AddMappedItemStat(ITEM_STAT_ARTIFICING, std::string("artificing")); AddMappedItemStat(ITEM_STAT_ARTISTRY, std::string("artistry")); AddMappedItemStat(ITEM_STAT_CHEMISTRY, std::string("chemistry")); AddMappedItemStat(ITEM_STAT_CRUSHING, std::string("crushing")); AddMappedItemStat(ITEM_STAT_DEFENSE, std::string("defense")); AddMappedItemStat(ITEM_STAT_DEFLECTION, std::string("deflection")); AddMappedItemStat(ITEM_STAT_DISRUPTION, std::string("disruption")); AddMappedItemStat(ITEM_STAT_FISHING, std::string("fishing")); AddMappedItemStat(ITEM_STAT_FLETCHING, std::string("fletching")); AddMappedItemStat(ITEM_STAT_FOCUS, std::string("focus")); AddMappedItemStat(ITEM_STAT_FORESTING, std::string("foresting")); AddMappedItemStat(ITEM_STAT_GATHERING, std::string("gathering")); AddMappedItemStat(ITEM_STAT_METAL_SHAPING, std::string("metal shaping")); AddMappedItemStat(ITEM_STAT_METALWORKING, std::string("metalworking")); AddMappedItemStat(ITEM_STAT_MINING, std::string("mining")); AddMappedItemStat(ITEM_STAT_MINISTRATION, std::string("ministration")); AddMappedItemStat(ITEM_STAT_ORDINATION, std::string("ordination")); AddMappedItemStat(ITEM_STAT_ADORNING, std::string("adorning")); AddMappedItemStat(ITEM_STAT_PARRY, std::string("parry")); AddMappedItemStat(ITEM_STAT_PIERCING, std::string("piercing")); AddMappedItemStat(ITEM_STAT_RANGED, std::string("ranged")); AddMappedItemStat(ITEM_STAT_SAFE_FALL, std::string("safe fall")); AddMappedItemStat(ITEM_STAT_SCRIBING, std::string("scribing")); AddMappedItemStat(ITEM_STAT_SCULPTING, std::string("sculpting")); AddMappedItemStat(ITEM_STAT_SLASHING, std::string("slashing")); AddMappedItemStat(ITEM_STAT_SUBJUGATION, std::string("subjugation")); AddMappedItemStat(ITEM_STAT_SWIMMING, std::string("swimming")); AddMappedItemStat(ITEM_STAT_TAILORING, std::string("tailoring")); AddMappedItemStat(ITEM_STAT_TINKERING, std::string("tinkering")); AddMappedItemStat(ITEM_STAT_TRANSMUTING, std::string("transmuting")); AddMappedItemStat(ITEM_STAT_TRAPPING, std::string("trapping")); AddMappedItemStat(ITEM_STAT_WEAPON_SKILLS, std::string("weapon skills")); } void MasterItemList::AddMappedItemStat(int32 id, std::string lower_case_name) { mappedItemStatsStrings[lower_case_name] = id; mappedItemStatTypeIDs[id] = lower_case_name; } MasterItemList::~MasterItemList(){ RemoveAll(); map>::iterator itr; for (itr = broker_item_map.begin(); itr != broker_item_map.end(); itr++) { VersionRange* range = itr->first; delete range; } broker_item_map.clear(); } void MasterItemList::AddBrokerItemMapRange(int32 min_version, int32 max_version, int64 client_bitmask, int64 server_bitmask) { map>::iterator itr = FindBrokerItemMapVersionRange(min_version, max_version); if (itr != broker_item_map.end()) { itr->second.insert(make_pair(client_bitmask, server_bitmask)); return; } VersionRange* range = new VersionRange(min_version, max_version); broker_item_map[range][client_bitmask] = server_bitmask; } map>::iterator MasterItemList::FindBrokerItemMapVersionRange(int32 min_version, int32 max_version) { map>::iterator itr; for (itr = broker_item_map.begin(); itr != broker_item_map.end(); itr++) { VersionRange* range = itr->first; // if min and max version are both in range if (range->GetMinVersion() <= min_version && max_version <= range->GetMaxVersion()) return itr; // if the min version is in range, but max range is 0 else if (range->GetMinVersion() <= min_version && range->GetMaxVersion() == 0) return itr; // if min version is 0 and max_version has a cap else if (range->GetMinVersion() == 0 && max_version <= range->GetMaxVersion()) return itr; } return broker_item_map.end(); } map>::iterator MasterItemList::FindBrokerItemMapByVersion(int32 version) { map>::iterator enditr = broker_item_map.end(); map>::iterator itr; for (itr = broker_item_map.begin(); itr != broker_item_map.end(); itr++) { VersionRange* range = itr->first; // if min and max version are both in range if(range->GetMinVersion() == 0 && range->GetMaxVersion() == 0) enditr = itr; else if (version >= range->GetMinVersion() && version <= range->GetMaxVersion()) return itr; } return enditr; } vector* MasterItemList::GetItems(string name, int64 itype, int64 ltype, int64 btype, int64 minprice, int64 maxprice, int8 minskill, int8 maxskill, string seller, string adornment, int8 mintier, int8 maxtier, int16 minlevel, int16 maxlevel, sint8 itemclass){ vector* ret = new vector; map::iterator iter; Item* item = 0; const char* chkname = 0; //const char* chkseller = 0; //const char* chkadornment = 0; if(name.length() > 0) chkname = name.c_str(); //if(seller.length() > 0) // chkseller = seller.c_str(); //if(adornment.length() > 0) // chkadornment = adornment.c_str(); LogWrite(ITEM__WARNING, 0, "Item", "Get Items: %s (itype: %llu, ltype: %llu, btype: %llu, minskill: %u, maxskill: %u, mintier: %u, maxtier: %u, minlevel: %u, maxlevel: %u itemclass %i)", name.c_str(), itype, ltype, btype, minskill, maxskill, mintier, maxtier, minlevel, maxlevel, itemclass); bool should_add = true; for(iter = items.begin();iter != items.end(); iter++){ item = iter->second; if(item){ if(itype != ITEM_BROKER_TYPE_ANY && itype != ITEM_BROKER_TYPE_ANY64BIT){ should_add = false; switch(itype){ case ITEM_BROKER_TYPE_ADORNMENT:{ if(item->IsAdornment()) should_add = true; break; } case ITEM_BROKER_TYPE_AMMO:{ if(item->IsAmmo()) should_add = true; break; } case ITEM_BROKER_TYPE_ATTUNEABLE:{ if(item->CheckFlag(ATTUNEABLE)) should_add = true; break; } case ITEM_BROKER_TYPE_BAG:{ if(item->IsBag()) should_add = true; break; } case ITEM_BROKER_TYPE_BAUBLE:{ if(item->IsBauble()) should_add = true; break; } case ITEM_BROKER_TYPE_BOOK:{ if(item->IsBook()) should_add = true; break; } case ITEM_BROKER_TYPE_CHAINARMOR:{ if(item->IsChainArmor()) should_add = true; break; } case ITEM_BROKER_TYPE_CLOAK:{ if(item->IsCloak()) should_add = true; break; } case ITEM_BROKER_TYPE_CLOTHARMOR:{ if(item->IsClothArmor()) should_add = true; break; } case ITEM_BROKER_TYPE_COLLECTABLE:{ if(item->IsCollectable()) should_add = true; break; } case ITEM_BROKER_TYPE_CRUSHWEAPON:{ if(item->IsCrushWeapon() && (item->weapon_info->wield_type == ITEM_WIELD_TYPE_DUAL || item->weapon_info->wield_type == ITEM_WIELD_TYPE_SINGLE)) should_add = true; break; } case ITEM_BROKER_TYPE_DRINK:{ if(item->IsFoodDrink()) should_add = true; break; } case ITEM_BROKER_TYPE_FOOD:{ if(item->IsFoodFood()) should_add = true; break; } case ITEM_BROKER_TYPE_HOUSEITEM:{ if(item->IsHouseItem()) should_add = true; break; } case ITEM_BROKER_TYPE_JEWELRY:{ if(item->IsJewelry()) should_add = true; break; } case ITEM_BROKER_TYPE_LEATHERARMOR:{ if(item->IsLeatherArmor()) should_add = true; break; } case ITEM_BROKER_TYPE_LORE:{ if(item->CheckFlag(LORE)) should_add = true; break; } case ITEM_BROKER_TYPE_MISC:{ if(item->IsMisc()) should_add = true; break; } case ITEM_BROKER_TYPE_PIERCEWEAPON:{ if(item->IsPierceWeapon() && (item->weapon_info->wield_type == ITEM_WIELD_TYPE_DUAL || item->weapon_info->wield_type == ITEM_WIELD_TYPE_SINGLE)) should_add = true; break; } case ITEM_BROKER_TYPE_PLATEARMOR:{ if(item->IsPlateArmor()) should_add = true; break; } case ITEM_BROKER_TYPE_POISON:{ if(item->IsPoison()) should_add = true; break; } case ITEM_BROKER_TYPE_POTION:{ if(item->IsPotion()) should_add = true; break; } case ITEM_BROKER_TYPE_RECIPEBOOK:{ if(item->IsRecipeBook()) should_add = true; break; } case ITEM_BROKER_TYPE_SALESDISPLAY:{ if(item->IsSalesDisplay()) should_add = true; break; } case ITEM_BROKER_TYPE_SHIELD:{ if(item->IsShield()) should_add = true; break; } case ITEM_BROKER_TYPE_SLASHWEAPON:{ if(item->IsSlashWeapon() && (item->weapon_info->wield_type == ITEM_WIELD_TYPE_DUAL || item->weapon_info->wield_type == ITEM_WIELD_TYPE_SINGLE)) should_add = true; break; } case ITEM_BROKER_TYPE_SPELLSCROLL:{ if(item->IsSpellScroll()) should_add = true; break; } case ITEM_BROKER_TYPE_TINKERED:{ if(item->tinkered == 1) should_add = true; break; } case ITEM_BROKER_TYPE_TRADESKILL:{ if(item->crafted == 1) should_add = true; break; } case ITEM_BROKER_TYPE_2H_CRUSH:{ should_add = item->IsWeapon() && item->weapon_info->wield_type == ITEM_WIELD_TYPE_TWO_HAND && item->generic_info.skill_req1 == SKILL_ID_STAFF; break; } case ITEM_BROKER_TYPE_2H_PIERCE:{ should_add = item->IsWeapon() && item->weapon_info->wield_type == ITEM_WIELD_TYPE_TWO_HAND && item->generic_info.skill_req1 == SKILL_ID_GREATSPEAR; break; } case ITEM_BROKER_TYPE_2H_SLASH:{ should_add = item->IsWeapon() && item->weapon_info->wield_type == ITEM_WIELD_TYPE_TWO_HAND && item->generic_info.skill_req1 == SKILL_ID_GREATSWORD; break; } } if(!should_add) continue; } if(ltype != ITEM_BROKER_SLOT_ANY){ should_add = false; switch(ltype){ case ITEM_BROKER_SLOT_AMMO:{ should_add = item->HasSlot(EQ2_AMMO_SLOT); break; } case ITEM_BROKER_SLOT_CHARM:{ should_add = item->HasSlot(EQ2_CHARM_SLOT_1, EQ2_CHARM_SLOT_2); break; } case ITEM_BROKER_SLOT_CHEST:{ should_add = item->HasSlot(EQ2_CHEST_SLOT); break; } case ITEM_BROKER_SLOT_CLOAK:{ should_add = item->HasSlot(EQ2_CLOAK_SLOT); break; } case ITEM_BROKER_SLOT_DRINK:{ should_add = item->HasSlot(EQ2_DRINK_SLOT); break; } case ITEM_BROKER_SLOT_EARS:{ should_add = item->HasSlot(EQ2_EARS_SLOT_1, EQ2_EARS_SLOT_2); break; } case ITEM_BROKER_SLOT_FEET:{ should_add = item->HasSlot(EQ2_FEET_SLOT); break; } case ITEM_BROKER_SLOT_FOOD:{ should_add = item->HasSlot(EQ2_FOOD_SLOT); break; } case ITEM_BROKER_SLOT_FOREARMS:{ should_add = item->HasSlot(EQ2_FOREARMS_SLOT); break; } case ITEM_BROKER_SLOT_HANDS:{ should_add = item->HasSlot(EQ2_HANDS_SLOT); break; } case ITEM_BROKER_SLOT_HEAD:{ should_add = item->HasSlot(EQ2_HEAD_SLOT); break; } case ITEM_BROKER_SLOT_LEGS:{ should_add = item->HasSlot(EQ2_LEGS_SLOT); break; } case ITEM_BROKER_SLOT_NECK:{ should_add = item->HasSlot(EQ2_NECK_SLOT); break; } case ITEM_BROKER_SLOT_PRIMARY:{ should_add = item->HasSlot(EQ2_PRIMARY_SLOT); break; } case ITEM_BROKER_SLOT_PRIMARY_2H:{ should_add = item->HasSlot(EQ2_PRIMARY_SLOT) && item->IsWeapon() && item->weapon_info->wield_type == ITEM_WIELD_TYPE_TWO_HAND; break; } case ITEM_BROKER_SLOT_RANGE_WEAPON:{ should_add = item->HasSlot(EQ2_RANGE_SLOT); break; } case ITEM_BROKER_SLOT_RING:{ should_add = item->HasSlot(EQ2_LRING_SLOT, EQ2_RRING_SLOT); break; } case ITEM_BROKER_SLOT_SECONDARY:{ should_add = item->HasSlot(EQ2_SECONDARY_SLOT); break; } case ITEM_BROKER_SLOT_SHOULDERS:{ should_add = item->HasSlot(EQ2_SHOULDERS_SLOT); break; } case ITEM_BROKER_SLOT_WAIST:{ should_add = item->HasSlot(EQ2_WAIST_SLOT); break; } case ITEM_BROKER_SLOT_WRIST:{ should_add = item->HasSlot(EQ2_LWRIST_SLOT, EQ2_RWRIST_SLOT); break; } } if(!should_add) continue; } if(btype != 0xFFFFFFFF){ vector::iterator itr; bool stat_found = false; should_add = false; switch(btype){ case ITEM_BROKER_STAT_TYPE_NONE:{ if (item->item_stats.size() == 0) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_DEF:{ stat_found = item->HasStat(ITEM_STAT_DEFENSE, GetItemStatNameByID(ITEM_STAT_DEFENSE)); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_STR:{ stat_found = item->HasStat(ITEM_STAT_STR); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_STA:{ stat_found = item->HasStat(ITEM_STAT_STA); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_AGI:{ stat_found = item->HasStat(ITEM_STAT_AGI); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_WIS:{ stat_found = item->HasStat(ITEM_STAT_WIS); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_INT:{ stat_found = item->HasStat(ITEM_STAT_INT); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_HEALTH:{ stat_found = item->HasStat(ITEM_STAT_HEALTH); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_POWER:{ stat_found = item->HasStat(ITEM_STAT_POWER); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_HEAT:{ stat_found = item->HasStat(ITEM_STAT_VS_HEAT); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_COLD:{ stat_found = item->HasStat(ITEM_STAT_VS_COLD); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_MAGIC:{ stat_found = item->HasStat(ITEM_STAT_VS_MAGIC); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_MENTAL:{ stat_found = item->HasStat(ITEM_STAT_VS_MENTAL); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_DIVINE:{ stat_found = item->HasStat(ITEM_STAT_VS_DIVINE); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_POISON:{ stat_found = item->HasStat(ITEM_STAT_VS_POISON); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_DISEASE:{ stat_found = item->HasStat(ITEM_STAT_VS_DISEASE); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_CRUSH:{ stat_found = item->HasStat(ITEM_STAT_DMG_CRUSH); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_SLASH:{ stat_found = item->HasStat(ITEM_STAT_DMG_SLASH); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_PIERCE:{ stat_found = item->HasStat(ITEM_STAT_DMG_PIERCE); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_CRITICAL: { stat_found = item->HasStat(ITEM_STAT_CRITICALMITIGATION); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_DBL_ATTACK:{ stat_found = item->HasStat(ITEM_STAT_MULTIATTACKCHANCE); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_ABILITY_MOD:{ stat_found = item->HasStat(ITEM_STAT_ABILITY_MODIFIER); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_POTENCY:{ stat_found = item->HasStat(ITEM_STAT_POTENCY); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_AEAUTOATTACK:{ stat_found = item->HasStat(ITEM_STAT_AEAUTOATTACKCHANCE); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_ATTACKSPEED:{ stat_found = item->HasStat(ITEM_STAT_ATTACKSPEED); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_BLOCKCHANCE:{ stat_found = item->HasStat(ITEM_STAT_EXTRASHIELDBLOCKCHANCE); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_CASTINGSPEED:{ stat_found = item->HasStat(ITEM_STAT_ABILITYCASTINGSPEED); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_CRITBONUS:{ stat_found = item->HasStat(ITEM_STAT_CRITBONUS); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_CRITCHANCE:{ stat_found = item->HasStat(ITEM_STAT_MELEECRITCHANCE); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_DPS:{ stat_found = item->HasStat(ITEM_STAT_DPS); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_FLURRYCHANCE:{ stat_found = item->HasStat(ITEM_STAT_FLURRY); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_HATEGAIN:{ stat_found = item->HasStat(ITEM_STAT_HATEGAINMOD); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_MITIGATION:{ stat_found = item->HasStat(ITEM_STAT_ARMORMITIGATIONINCREASE); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_MULTI_ATTACK:{ stat_found = item->HasStat(ITEM_STAT_MULTIATTACKCHANCE); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_RECOVERY:{ stat_found = item->HasStat(ITEM_STAT_ABILITYRECOVERYSPEED); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_REUSE_SPEED:{ stat_found = item->HasStat(ITEM_STAT_ABILITYREUSESPEED); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_SPELL_WPNDMG:{ stat_found = item->HasStat(ITEM_STAT_SPELLWEAPONDAMAGEBONUS); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_STRIKETHROUGH:{ stat_found = item->HasStat(ITEM_STAT_STRIKETHROUGH); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_TOUGHNESS:{ stat_found = item->HasStat(ITEM_STAT_PVPTOUGHNESS); if (stat_found) should_add = true; break; } case ITEM_BROKER_STAT_TYPE_WEAPONDMG:{ stat_found = item->HasStat(ITEM_STAT_WEAPONDAMAGEBONUS); if (stat_found) should_add = true; break; } default: { LogWrite(ITEM__DEBUG, 0, "Item", "Unknown item broker stat type %u", btype); LogWrite(ITEM__DEBUG, 0, "Item", "If you have a client before the new expansion this may be the reason. Please be patient while we update items to support the new client.", btype); break; } } if (!should_add) continue; } if(itemclass > 0){ int64 tmpVal = ((int64)2) << (itemclass-1); should_add = (item->generic_info.adventure_classes & tmpVal); if(!should_add && !(item->generic_info.tradeskill_classes & tmpVal)) continue; } if(chkname && item->lowername.find(chkname) >= 0xFFFFFFFF) continue; if(item->generic_info.adventure_default_level == 0 && item->generic_info.tradeskill_default_level == 0 && minlevel > 0 && maxlevel > 0){ if(item->details.recommended_level < minlevel) continue; if(item->details.recommended_level > maxlevel) continue; } else{ if(minlevel > 0 && ((item->generic_info.adventure_default_level == 0 && item->generic_info.tradeskill_default_level == 0) || (item->generic_info.adventure_default_level > 0 && item->generic_info.adventure_default_level < minlevel) || (item->generic_info.tradeskill_default_level > 0 && item->generic_info.tradeskill_default_level < minlevel))) continue; if(maxlevel > 0 && ((item->generic_info.adventure_default_level > 0 && item->generic_info.adventure_default_level > maxlevel) || (item->generic_info.tradeskill_default_level > 0 && item->generic_info.tradeskill_default_level > maxlevel))) continue; } // mintier of 1 is 'ANY' if(mintier > 1 && item->details.tier < mintier) continue; if(maxtier > 0 && item->details.tier > maxtier) continue; /* these skill values are not fields provided in the UI beyond CLASSIC ** They are also not in line with skill_min, they provide a scale of 0-6, obselete is 0, 6 is red (cannot be used) if(minskill > 0 && item->generic_info.skill_min < minskill) continue; if(maxskill > 0 && item->generic_info.skill_min > maxskill) continue; */ ret->push_back(item); } } return ret; } vector* MasterItemList::GetItems(map criteria, Client* client_to_map){ string name, seller, adornment; int64 itype = ITEM_BROKER_TYPE_ANY64BIT; int64 ltype = ITEM_BROKER_TYPE_ANY64BIT; int64 btype = ITEM_BROKER_TYPE_ANY64BIT; int64 minprice = 0; int64 maxprice = 0; int8 minskill = 0; int8 maxskill = 0; int8 mintier = 0; int8 maxtier = 0; int16 minlevel = 0; int16 maxlevel = 0; sint8 itemclass = 0; int32 itemID = 0; if (criteria.count("ITEM") > 0) { if (IsNumber(criteria["ITEM"].c_str())) { itemID = atoul(criteria["ITEM"].c_str()); Item* itm = GetItem(itemID); vector* ret = new vector; if (itm) ret->push_back(itm); return ret; } else name = criteria["ITEM"]; } if(criteria.count("MINSKILL") > 0) minskill = (int8)ParseIntValue(criteria["MINSKILL"]); if(criteria.count("MAXSKILL") > 0) maxskill = (int8)ParseIntValue(criteria["MAXSKILL"]); if(criteria.count("MINTIER") > 0) mintier = (int8)ParseIntValue(criteria["MINTIER"]); if(criteria.count("MAXTIER") > 0) maxtier = (int8)ParseIntValue(criteria["MAXTIER"]); if(criteria.count("MINLEVEL") > 0) minlevel = (int16)ParseIntValue(criteria["MINLEVEL"]); if(criteria.count("MAXLEVEL") > 0) maxlevel = (int16)ParseIntValue(criteria["MAXLEVEL"]); if(criteria.count("ITYPE") > 0) itype = ParseLongLongValue(criteria["ITYPE"]); if(criteria.count("LTYPE") > 0) ltype = ParseLongLongValue(criteria["LTYPE"]); if(criteria.count("BTYPE") > 0) btype = ParseLongLongValue(criteria["BTYPE"]); if(criteria.count("SKILLNAME") > 0) itemclass = world.GetClassID(criteria["SKILLNAME"].c_str()); if(client_to_map) { map>::iterator itr = FindBrokerItemMapByVersion(client_to_map->GetVersion()); if(itr != broker_item_map.end() && itr->second.find(btype) != itr->second.end()) { LogWrite(ITEM__DEBUG, 0, "Item", "Found broker mapping, btype %u becomes %llu", btype, itr->second[btype]); btype = itr->second[btype]; } } return GetItems(name, itype, ltype, btype, minprice, maxprice, minskill, maxskill, seller, adornment, mintier, maxtier, minlevel, maxlevel, itemclass); } void MasterItemList::ResetUniqueID(int32 new_id){ next_unique_id = new_id; } int32 MasterItemList::NextUniqueID(){ next_unique_id++; if(next_unique_id >= 0xFFFFFFF0) next_unique_id = 1; return next_unique_id; } bool MasterItemList::IsBag(int32 item_id){ Item* item = GetItem(item_id); if(item && item->details.num_slots > 0) return true; else return false; } Item* MasterItemList::GetItem(int32 id){ Item* item = 0; if(items.count(id) > 0) item = items[id]; return item; } Item* MasterItemList::GetItemByName(const char* name) { Item* item = 0; map::iterator itr; for (itr = items.begin(); itr != items.end(); itr++) { Item* current_item = itr->second; if (::ToLower(string(current_item->name.c_str())) == ::ToLower(string(name))) { item = current_item; break; } } return item; } ItemStatsValues* MasterItemList::CalculateItemBonuses(int32 item_id, Entity* entity){ return CalculateItemBonuses(items[item_id], entity); } ItemStatsValues* MasterItemList::CalculateItemBonuses(Item* item, Entity* entity, ItemStatsValues* values){ if(item){ if(!values){ values = new ItemStatsValues; memset(values, 0, sizeof(ItemStatsValues)); } for(int32 i=0;iitem_stats.size();i++){ ItemStat* stat = item->item_stats[i]; int multiplier = 100; if(stat->stat_subtype > 99) multiplier = 1000; int32 id = 0; sint32 value = stat->value; if(stat->stat_type != 1) id = stat->stat_type*multiplier + stat->stat_subtype; else { int32 tmp_id = master_item_list.GetItemStatIDByName(::ToLower(stat->stat_name)); if(tmp_id != 0xFFFFFFFF) { id = tmp_id; value = stat->stat_subtype; } else id = stat->stat_type*multiplier + stat->stat_subtype; } world.AddBonuses(item, values, id, value, entity); } return values; } return 0; } void MasterItemList::RemoveAll(){ map::iterator iter; for(iter = items.begin();iter != items.end(); iter++){ safe_delete(iter->second); } items.clear(); if(lua_interface) lua_interface->DestroyItemScripts(); } void MasterItemList::AddItem(Item* item){ map::iterator iter; if((iter = items.find(item->details.item_id)) != items.end()) { Item* tmpItem = items[item->details.item_id]; items.erase(iter); safe_delete(tmpItem); } items[item->details.item_id] = item; } Item::Item(){ item_script = ""; sell_price = 0; sell_status = 0; max_sell_value = 0; save_needed = true; needs_deletion = false; weapon_info = 0; ranged_info = 0; adornment_info = 0; bag_info = 0; food_info = 0; bauble_info = 0; thrown_info = 0; skill_info = 0; recipebook_info = 0; itemset_info = 0; armor_info = 0; book_info = 0; book_info_pages = 0; houseitem_info = 0; housecontainer_info = 0; memset(&details, 0, sizeof(ItemCore)); memset(&generic_info, 0, sizeof(Generic_Info)); generic_info.condition = 100; no_buy_back = false; no_sale = false; created = std::time(nullptr); effect_type = NO_EFFECT_TYPE; book_language = 0; } Item::Item(Item* in_item){ needs_deletion = false; sell_price = in_item->sell_price; sell_status = in_item->sell_status; max_sell_value = in_item->max_sell_value; save_needed = true; SetItem(in_item); details.unique_id = master_item_list.NextUniqueID(); if (IsBag()) details.bag_id = details.unique_id; generic_info.condition = 100; spell_id = in_item->spell_id; spell_tier = in_item->spell_tier; no_buy_back = in_item->no_buy_back; no_sale = in_item->no_sale; created = in_item->created; grouped_char_ids.insert(in_item->grouped_char_ids.begin(), in_item->grouped_char_ids.end()); effect_type = in_item->effect_type; book_language = in_item->book_language; } Item::~Item(){ for(int32 i=0;iGetItemScript()) SetItemScript(old_item->GetItemScript()); name = old_item->name; lowername = old_item->lowername; description = old_item->description; memcpy(&generic_info, &old_item->generic_info, sizeof(Generic_Info)); weapon_info = 0; ranged_info = 0; adornment_info = 0; adorn0 = 0; adorn1 = 0; adorn2 = 0; bag_info = 0; food_info = 0; bauble_info = 0; thrown_info = 0; skill_info = 0; recipebook_info = 0; itemset_info = 0; armor_info = 0; book_info = 0; book_info_pages = 0; houseitem_info = 0; housecontainer_info = 0; stack_count = old_item->stack_count; generic_info.skill_req1 = old_item->generic_info.skill_req1; generic_info.skill_req2 = old_item->generic_info.skill_req2; memcpy(&details, &old_item->details, sizeof(ItemCore)); weapon_type = old_item->GetWeaponType(); switch(old_item->generic_info.item_type){ case ITEM_TYPE_WEAPON:{ weapon_info = new Weapon_Info; memcpy(weapon_info, old_item->weapon_info, sizeof(Weapon_Info)); break; } case ITEM_TYPE_RANGED:{ ranged_info = new Ranged_Info; memcpy(ranged_info, old_item->ranged_info, sizeof(Ranged_Info)); break; } case ITEM_TYPE_SHIELD: case ITEM_TYPE_ARMOR:{ armor_info = new Armor_Info; memcpy(armor_info, old_item->armor_info, sizeof(Armor_Info)); break; } case ITEM_TYPE_BAG:{ bag_info = new Bag_Info; memcpy(bag_info, old_item->bag_info, sizeof(Bag_Info)); break; } case ITEM_TYPE_FOOD:{ food_info = new Food_Info; memcpy(food_info, old_item->food_info, sizeof(Food_Info)); break; } case ITEM_TYPE_BAUBLE:{ bauble_info = new Bauble_Info; memcpy(bauble_info, old_item->bauble_info, sizeof(Bauble_Info)); break; } case ITEM_TYPE_SKILL:{ skill_info = new Skill_Info; memcpy(skill_info, old_item->skill_info, sizeof(Skill_Info)); break; } case ITEM_TYPE_THROWN:{ thrown_info = new Thrown_Info; memcpy(thrown_info, old_item->thrown_info, sizeof(Thrown_Info)); break; } case ITEM_TYPE_BOOK:{ book_info = new Book_Info; book_info->language = old_item->book_info->language; book_info->author.data = old_item->book_info->author.data; book_info->author.size = old_item->book_info->author.size; book_info->title.data = old_item->book_info->title.data; book_info->title.size = old_item->book_info->title.size; break; } case ITEM_TYPE_HOUSE:{ houseitem_info = new HouseItem_Info; memcpy(houseitem_info, old_item->houseitem_info, sizeof(HouseItem_Info)); break; } case ITEM_TYPE_RECIPE:{ // Recipe Book recipebook_info = new RecipeBook_Info; if (old_item->recipebook_info) { recipebook_info->recipe_id = old_item->recipebook_info->recipe_id; recipebook_info->uses = old_item->recipebook_info->uses; for (int32 i = 0; i < old_item->recipebook_info->recipes.size(); i++) recipebook_info->recipes.push_back(old_item->recipebook_info->recipes.at(i)); } break; } case ITEM_TYPE_ADORNMENT:{ adornment_info = new Adornment_Info; memcpy(adornment_info, old_item->adornment_info, sizeof(Adornment_Info)); break; } case ITEM_TYPE_HOUSE_CONTAINER:{ // House Containers housecontainer_info = new HouseContainer_Info; if (old_item->housecontainer_info) { housecontainer_info->broker_commission = old_item->housecontainer_info->broker_commission; housecontainer_info->fence_commission = old_item->housecontainer_info->fence_commission; housecontainer_info->allowed_types = old_item->housecontainer_info->allowed_types; housecontainer_info->num_slots = old_item->housecontainer_info->num_slots; } break; } } creator = old_item->creator; adornment = old_item->adornment; DeleteItemSets(); for (int32 i = 0; iitem_sets.size(); i++){ ItemSet* set = old_item->item_sets[i]; if (set){ ItemSet* set2 = new ItemSet; set2->item_id = set->item_id; set2->item_crc = set->item_crc; set2->item_icon = set->item_icon; set2->item_stack_size = set->item_stack_size; set2->item_list_color = set->item_list_color; item_sets.push_back(set2); } } item_stats.clear(); for(int32 i=0;iitem_stats.size();i++){ ItemStat* stat = old_item->item_stats[i]; if(stat){ ItemStat* stat2 = new ItemStat; stat2->stat_name = stat->stat_name; stat2->stat_type = stat->stat_type; stat2->stat_subtype = stat->stat_subtype; stat2->value = stat->value; stat2->stat_type_combined = stat->stat_type_combined; item_stats.push_back(stat2); } } item_string_stats.clear(); for(int32 i=0;iitem_string_stats.size();i++){ ItemStatString* stat = old_item->item_string_stats[i]; if(stat){ ItemStatString* stat2 = new ItemStatString; stat2->stat_string.data = stat->stat_string.data; stat2->stat_string.size = stat->stat_string.size; item_string_stats.push_back(stat2); } } item_level_overrides.clear(); for(int32 i=0;iitem_level_overrides.size();i++){ ItemLevelOverride* item_override = old_item->item_level_overrides[i]; if(item_override){ ItemLevelOverride* item_override2 = new ItemLevelOverride; memcpy(item_override2, item_override, sizeof(ItemLevelOverride)); item_level_overrides.push_back(item_override2); } } item_effects.clear(); for(int32 i=0;iitem_effects.size();i++){ ItemEffect* effect = old_item->item_effects[i]; if(effect){ ItemEffect* effect_2 = new ItemEffect; effect_2->effect = effect->effect; effect_2->percentage = effect->percentage; effect_2->subbulletflag = effect->subbulletflag; item_effects.push_back(effect_2); } } book_pages.clear(); for (int32 i = 0; i < old_item->book_pages.size(); i++) { BookPage* bookpage = old_item->book_pages[i]; if (bookpage) { BookPage* bookpage_2 = new BookPage; bookpage_2->page = bookpage->page; bookpage_2->page_text.data = bookpage->page_text.data; bookpage_2->page_text.size = bookpage->page_text.size; bookpage_2->valign = bookpage->valign; bookpage_2->halign = bookpage->halign; book_pages.push_back(bookpage_2); } } slot_data.clear(); slot_data = old_item->slot_data; spell_id = old_item->spell_id; spell_tier = old_item->spell_tier; book_language = old_item->book_language; } bool Item::CheckArchetypeAdvSubclass(int8 adventure_class, map* adv_class_levels) { if (adventure_class > FIGHTER && adventure_class < ANIMALIST) { int8 check = adventure_class % 10; if (check == 2 || check == 5 || check == 8) { int64 adv_classes = 0; int16 level = 0; for (int i = adventure_class + 1; i < adventure_class + 3; i++) { if (adv_class_levels) { //need to match levels if (level == 0) { if (adv_class_levels->count(i) > 0) level = adv_class_levels->at(i); else return false; } else{ if (adv_class_levels->count(i) > 0 && adv_class_levels->at(i) != level) return false; } } else { adv_classes = ((int64)2) << (i - 1); if (!(generic_info.adventure_classes & adv_classes)) return false; } } return true; } } return false; } bool Item::CheckArchetypeAdvClass(int8 adventure_class, map* adv_class_levels) { if (adventure_class == 1 || adventure_class == 11 || adventure_class == 21 || adventure_class == 31) { //if the class is an archetype class and the subclasses have access, then allow if (CheckArchetypeAdvSubclass(adventure_class + 1, adv_class_levels) && CheckArchetypeAdvSubclass(adventure_class + 4, adv_class_levels) && CheckArchetypeAdvSubclass(adventure_class + 7, adv_class_levels)) { if (adv_class_levels) { int16 level = 0; for (int i = adventure_class + 1; i <= adventure_class + 7; i += 3) { if (adv_class_levels->count(i+1) == 0 || adv_class_levels->count(i + 2) == 0) return false; if(level == 0) level = adv_class_levels->at(i+1); if (adv_class_levels->at(i+1) != level) //already verified the classes, just need to verify the subclasses have the same levels return false; } } return true; } } else if (CheckArchetypeAdvSubclass(adventure_class, adv_class_levels)) {//check archetype subclass return true; } return false; } bool Item::CheckClass(int8 adventure_class, int8 tradeskill_class) { int64 adv_classes = ((int64)2) << (adventure_class - 1); int64 ts_classes = ((int64)2) << (tradeskill_class - 1); if( ((generic_info.adventure_classes & adv_classes) || generic_info.adventure_classes == 0) && ((generic_info.tradeskill_classes & ts_classes) || generic_info.tradeskill_classes == 0) ) return true; //check arechtype classes as last resort return CheckArchetypeAdvClass(adventure_class); } bool Item::CheckLevel(int8 adventure_class, int8 tradeskill_class, int16 level) { if ((level >= generic_info.adventure_default_level && adventure_class < 255) && (level >= generic_info.tradeskill_default_level && tradeskill_class < 255)) return true; return false; } void Item::AddStat(ItemStat* in_stat){ item_stats.push_back(in_stat); } bool Item::HasStat(uint32 statID, std::string statNameLower) { vector::iterator itr; for (itr = item_stats.begin(); itr != item_stats.end(); itr++) { if (statID > 99 && statID < 200 && (*itr)->stat_type == 1 && ::ToLower((*itr)->stat_name) == statNameLower) { return true; break; } else if((*itr)->stat_type_combined == statID && (statNameLower.length() < 1 || (::ToLower((*itr)->stat_name) == statNameLower))) { return true; break; } } return false; } void Item::DeleteItemSets() { for (int32 i = 0; i < item_sets.size(); i++){ ItemSet* set = item_sets[i]; safe_delete(set); } item_sets.clear(); } void Item::AddSet(ItemSet* in_set){ item_sets.push_back(in_set); } void Item::AddStatString(ItemStatString* in_stat){ item_string_stats.push_back(in_stat); } bool Item::IsNormal(){ return generic_info.item_type == ITEM_TYPE_NORMAL; } bool Item::IsWeapon(){ return generic_info.item_type == ITEM_TYPE_WEAPON; } bool Item::IsArmor(){ return generic_info.item_type == ITEM_TYPE_ARMOR || generic_info.item_type == ITEM_TYPE_SHIELD; } bool Item::IsRanged(){ return generic_info.item_type == ITEM_TYPE_RANGED; } bool Item::IsBag(){ return generic_info.item_type == ITEM_TYPE_BAG; } bool Item::IsFood(){ return generic_info.item_type == ITEM_TYPE_FOOD; } bool Item::IsBauble(){ return generic_info.item_type == ITEM_TYPE_BAUBLE; } bool Item::IsSkill(){ return generic_info.item_type == ITEM_TYPE_SKILL; } bool Item::IsHouseItem(){ return generic_info.item_type == ITEM_TYPE_HOUSE; } bool Item::IsHouseContainer(){ return generic_info.item_type == ITEM_TYPE_HOUSE_CONTAINER; } bool Item::IsShield(){ return generic_info.item_type == ITEM_TYPE_SHIELD; } bool Item::IsAdornment(){ return generic_info.item_type == ITEM_TYPE_ADORNMENT && !CheckFlag2(ORNATE); } bool Item::IsAmmo(){ return HasSlot(EQ2_AMMO_SLOT); } bool Item::HasAdorn0(){ if (adorn0 > 0) return true; return false; } bool Item::HasAdorn1(){ if (adorn1 > 0) return true; return false; } bool Item::HasAdorn2(){ if (adorn2 > 0) return true; return false; } bool Item::IsBook(){ return generic_info.item_type == ITEM_TYPE_BOOK; } bool Item::IsChainArmor(){ return generic_info.item_type == ITEM_TYPE_ARMOR && (generic_info.skill_req1 == 2246237129UL || generic_info.skill_req2 == 2246237129UL); } bool Item::IsClothArmor(){ return generic_info.item_type == ITEM_TYPE_ARMOR && (generic_info.skill_req1 == 3539032716UL || generic_info.skill_req2 == 3539032716UL); } bool Item::IsCollectable(){ return generic_info.collectable == 1; } bool Item::HasSlot(int8 slot, int8 slot2){ for(int32 i=0;itype == 1; } bool Item::IsFoodDrink(){ return generic_info.item_type == ITEM_TYPE_FOOD && food_info && food_info->type == 0; } bool Item::IsJewelry(){ if(generic_info.item_type != ITEM_TYPE_ARMOR || (generic_info.skill_req1 != 2072844078 && generic_info.skill_req2 != 2072844078)) return false; for(int32 i=0;itinkered. /* bool Item::IsTinkered(){ LogWrite(MISC__TODO, 1, "TODO", "Item Is Tinkered\n\t(%s, function: %s, line #: %i)", __FILE__, __FUNCTION__, __LINE__); return false; } */ bool Item::IsThrown(){ return generic_info.item_type == ITEM_TYPE_THROWN; } bool Item::IsHarvest() { return generic_info.harvest == 1; } bool Item::IsBodyDrop() { return generic_info.body_drop == 1; } //item->crafted /*bool Item::IsTradeskill(){ LogWrite(MISC__TODO, 1, "TODO", "Item Is Crafted\n\t(%s, function: %s, line #: %i)", __FILE__, __FUNCTION__, __LINE__); return false; }*/ void Item::SetItemType(int8 in_type){ generic_info.item_type = in_type; if(IsArmor() && !armor_info){ armor_info = new Armor_Info; memset(armor_info, 0, sizeof(Armor_Info)); } else if (IsWeapon() && !weapon_info){ weapon_info = new Weapon_Info; memset(weapon_info, 0, sizeof(Weapon_Info)); } else if (IsAdornment() && !adornment_info){ adornment_info = new Adornment_Info; memset(adornment_info, 0, sizeof(Adornment_Info)); } else if(IsRanged() && !ranged_info){ ranged_info = new Ranged_Info; memset(ranged_info, 0, sizeof(Ranged_Info)); } else if(IsBag() && !bag_info){ bag_info = new Bag_Info; memset(bag_info, 0, sizeof(Bag_Info)); } else if(IsFood() && !food_info){ food_info = new Food_Info; memset(food_info, 0, sizeof(Food_Info)); } else if(IsBauble() && !bauble_info){ bauble_info = new Bauble_Info; memset(bauble_info, 0, sizeof(Bauble_Info)); } else if(IsThrown() && !thrown_info){ thrown_info = new Thrown_Info; memset(thrown_info, 0, sizeof(Thrown_Info)); } else if(IsSkill() && !skill_info){ skill_info = new Skill_Info; memset(skill_info, 0, sizeof(Skill_Info)); } else if(IsRecipeBook() && !recipebook_info){ recipebook_info = new RecipeBook_Info; recipebook_info->recipe_id = 0; recipebook_info->uses = 0; } else if(IsBook() && !book_info){ book_info = new Book_Info; book_info->language = 0; book_info->author.size = 0; book_info->title.size = 0; } else if(IsHouseItem() && !houseitem_info){ houseitem_info = new HouseItem_Info; memset(houseitem_info, 0, sizeof(HouseItem_Info)); } else if(IsHouseContainer() && !housecontainer_info){ housecontainer_info = new HouseContainer_Info; housecontainer_info->allowed_types = 0; housecontainer_info->broker_commission = 0; housecontainer_info->fence_commission = 0; housecontainer_info->num_slots = 0; } } bool Item::CheckFlag2(int32 flag){ int32 value = 0; int32 flag_val = generic_info.item_flags2; while (flag_val > 0){ if (flag_val >= FLAGS2_32768) value = FLAGS2_32768; else if (flag_val >= FREE_REFORGE) value = FREE_REFORGE; else if (flag_val >= BUILDING_BLOCK) value = BUILDING_BLOCK; else if (flag_val >= FLAGS2_4096) value = FLAGS2_4096; else if (flag_val >= HOUSE_LORE) value = HOUSE_LORE; else if (flag_val >= NO_EXPERIMENT) value = NO_EXPERIMENT; else if (flag_val >= INDESTRUCTABLE) value = INDESTRUCTABLE; else if (flag_val >= NO_SALVAGE) value = NO_SALVAGE; else if (flag_val >= REFINED) value = REFINED; else if (flag_val >= ETHERAL) value = ETHERAL; else if (flag_val >= NO_REPAIR) value = NO_REPAIR; else if (flag_val >= REFORGED) value = REFORGED; else if (flag_val >= UNLOCKED) value = UNLOCKED; else if (flag_val >= APPEARANCE_ONLY) value = APPEARANCE_ONLY; else if (flag_val >= HEIRLOOM) value = HEIRLOOM; else if (flag_val >= ORNATE) value = ORNATE; if (value == flag) return true; else flag_val -= value; } return false; } bool Item::CheckFlag(int32 flag){ int32 value = 0; int32 flag_val = generic_info.item_flags; while(flag_val>0){ if (flag_val >= CURSED) //change this value = CURSED; else if (flag_val >= NO_TRANSMUTE) //change this value = NO_TRANSMUTE; else if (flag_val >= LORE_EQUIP) //change this value = LORE_EQUIP; else if (flag_val >= STACK_LORE) //change this value = STACK_LORE; else if(flag_val >= EVIL_ONLY) value = EVIL_ONLY; else if(flag_val >= GOOD_ONLY) value = GOOD_ONLY; else if(flag_val >= CRAFTED) value = CRAFTED; else if(flag_val >= NO_DESTROY) value = NO_DESTROY; else if(flag_val >= NO_ZONE) value = NO_ZONE; else if(flag_val >= NO_VALUE) value = NO_VALUE; else if(flag_val >= NO_TRADE) value = NO_TRADE; else if(flag_val >= TEMPORARY) value = TEMPORARY; else if(flag_val >= LORE) value = LORE; else if(flag_val >= ARTIFACT) value = ARTIFACT; else if(flag_val >= ATTUNEABLE) value = ATTUNEABLE; else if(flag_val >= ATTUNED) value = ATTUNED; if(value == flag) return true; else flag_val -= value; } return false; } void Item::SetSlots(int32 slots){ if(slots & PRIMARY_SLOT) AddSlot(EQ2_PRIMARY_SLOT); if(slots & SECONDARY_SLOT) AddSlot(EQ2_SECONDARY_SLOT); if(slots & HEAD_SLOT) AddSlot(EQ2_HEAD_SLOT); if(slots & CHEST_SLOT) AddSlot(EQ2_CHEST_SLOT); if(slots & SHOULDERS_SLOT) AddSlot(EQ2_SHOULDERS_SLOT); if(slots & FOREARMS_SLOT) AddSlot(EQ2_FOREARMS_SLOT); if(slots & HANDS_SLOT) AddSlot(EQ2_HANDS_SLOT); if(slots & LEGS_SLOT) AddSlot(EQ2_LEGS_SLOT); if(slots & FEET_SLOT) AddSlot(EQ2_FEET_SLOT); if(slots & LRING_SLOT) AddSlot(EQ2_LRING_SLOT); if(slots & RRING_SLOT) AddSlot(EQ2_RRING_SLOT); if(slots & EARS_SLOT_1) AddSlot(EQ2_EARS_SLOT_1); if(slots & EARS_SLOT_2) AddSlot(EQ2_EARS_SLOT_2); if(slots & NECK_SLOT) AddSlot(EQ2_NECK_SLOT); if(slots & LWRIST_SLOT) AddSlot(EQ2_LWRIST_SLOT); if(slots & RWRIST_SLOT) AddSlot(EQ2_RWRIST_SLOT); if(slots & RANGE_SLOT) AddSlot(EQ2_RANGE_SLOT); if(slots & AMMO_SLOT) AddSlot(EQ2_AMMO_SLOT); if(slots & WAIST_SLOT) AddSlot(EQ2_WAIST_SLOT); if(slots & CLOAK_SLOT) AddSlot(EQ2_CLOAK_SLOT); if(slots & CHARM_SLOT_1) AddSlot(EQ2_CHARM_SLOT_1); if(slots & CHARM_SLOT_2) AddSlot(EQ2_CHARM_SLOT_2); if(slots & FOOD_SLOT) AddSlot(EQ2_FOOD_SLOT); if(slots & DRINK_SLOT) AddSlot(EQ2_DRINK_SLOT); if(slots & TEXTURES_SLOT) AddSlot(EQ2_TEXTURES_SLOT); } void Item::AddStat(int8 type, int16 subtype, float value, int8 level, char* name){ char item_stat_combined_string[8] = {0}; if(name && strlen(name) > 0 && type != 1){ ItemStatString* stat = new ItemStatString; stat->stat_string.data = string(name); stat->stat_string.size = stat->stat_string.data.length(); AddStatString(stat); } else{ ItemStat* stat = new ItemStat; if(name && strlen(name) > 0) stat->stat_name = string(name); stat->stat_type = type; stat->stat_subtype = subtype; stat->value = value; stat->level = level; snprintf(item_stat_combined_string, 7, "%u%02u", type, subtype); stat->stat_type_combined = atoi(item_stat_combined_string); AddStat(stat); } } void Item::AddSet(int32 item_id, int32 item_crc, int16 item_icon, int32 item_stack_size, int32 item_list_color, std::string name, int8 language){ ItemSet* set = new ItemSet; set->item_id = item_id; set->item_icon = item_icon; set->item_crc = item_crc; set->item_stack_size = item_stack_size; set->item_list_color = item_list_color; set->name = string(name); set->language = language; AddSet(set); } int16 Item::GetOverrideLevel(int8 adventure_class, int8 tradeskill_class){ int16 ret = 0; int8 tmp_class = 0; bool found_class = false; for(int32 i=0;iadventure_class; if(tmp_class == PRIEST && (adventure_class >= CLERIC && adventure_class <= DEFILER)) found_class = true; else if(tmp_class == MAGE && (adventure_class >= SORCERER && adventure_class <= NECROMANCER)) found_class = true; else if(tmp_class == SCOUT && (adventure_class >= ROGUE && adventure_class <= ASSASSIN)) found_class = true; else if(tmp_class == adventure_class || tmp_class == COMMONER || (tmp_class == FIGHTER && (adventure_class >= WARRIOR && adventure_class <= PALADIN))) found_class = true; } else if(tradeskill_class != 255){ tmp_class = item_level_overrides[i]->tradeskill_class; if(tmp_class == CRAFTSMAN && (tradeskill_class >= PROVISIONER && adventure_class <= CARPENTER)) found_class = true; else if(tmp_class == OUTFITTER && (tradeskill_class >= ARMORER && tradeskill_class <= TAILOR)) found_class = true; else if(tmp_class == SCHOLAR && (tradeskill_class >= JEWELER && tradeskill_class <= ALCHEMIST)) found_class = true; else if(tmp_class == tradeskill_class || tmp_class == ARTISAN) found_class = true; } if(found_class){ ret = item_level_overrides[i]->level; break; } } return ret; } void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16 packet_type, int8 subtype, bool loot_item){ int64 classes = 0; Client *client; int8 tmp_subtype = 0; if (!packet || !player) return; client = player->GetZone()->GetClientBySpawn(player); if (!client) return; if(creator.length() > 0){ packet->setSubstructSubstructDataByName("header", "info_header", "creator_flag", 1); packet->setSubstructSubstructDataByName("header", "info_header", "creator", creator.c_str()); } if(show_name) packet->setSubstructSubstructDataByName("header", "info_header", "show_name", show_name); if (packet_type == 20) cout << ""; if(packet_type == 0) packet->setSubstructSubstructDataByName("header", "info_header", "packettype", GetItemPacketType(packet->GetVersion())); else packet->setSubstructSubstructDataByName("header", "info_header", "packettype", packet_type); packet->setSubstructSubstructDataByName("header", "info_header", "packetsubtype", subtype); // should be substype /* 0 red 1 orange 2 yellow 3 white 4 blue 5 green 6 grey 7 purple*/ int32 color = 3; if(player) { int32 effective_level = player->GetInfoStructUInt("effective_level"); if(effective_level && effective_level < player->GetLevel() && details.recommended_level > effective_level) color = 7; } packet->setSubstructDataByName("header_info", "footer_type", color); packet->setSubstructDataByName("header_info", "item_id", details.item_id); if (!loot_item) packet->setSubstructDataByName("header_info", "broker_item_id", details.item_id); else packet->setSubstructDataByName("header_info", "broker_item_id", 0xFFFFFFFFFFFFFFFF); if(details.unique_id == 0) packet->setSubstructDataByName("header_info", "unique_id", details.item_id); else packet->setSubstructDataByName("header_info", "unique_id", details.unique_id); packet->setSubstructDataByName("header_info", "icon", details.icon); packet->setSubstructDataByName("header_info", "tier", details.tier); packet->setSubstructDataByName("header_info", "flags", generic_info.item_flags); packet->setSubstructDataByName("header_info", "flags2", generic_info.item_flags2); if(item_stats.size() > 0){ //packet->setSubstructArrayLengthByName("header_info", "stat_count", item_stats.size()); int8 dropstat = 0; int8 bluemod = 0; for (int32 i = 0; i < item_stats.size(); i++){ ItemStat* stat = item_stats[i]; if(!stat) { LogWrite(ITEM__ERROR, 0, "Item", "%s: %s (itemid: %u) Error Serializing Item: Invalid item in item_stats position %u", client->GetPlayer()->GetName(), this->name.c_str(), this->details.item_id, i); continue; } if (stat->stat_type == 9){ bluemod += 1; } if (stat->stat_type == 6 || stat->stat_type == 7){ //Convert stats to proper client //if (client->GetVersion() >= 63137){ //TEST // tmp_subtype =stat->stat_subtype; //} if(stat->stat_type == 7){ tmp_subtype = stat->stat_subtype; } else if ((client->GetVersion() >= 63119) || client->GetVersion() == 61331){ //KA tmp_subtype = world.GetItemStatKAValue(stat->stat_subtype); } else if(client->GetVersion() >= 60085 ) { tmp_subtype = world.GetItemStatAOMValue(stat->stat_subtype); } else if (client->GetVersion() >= 57107){ //TOV tmp_subtype = world.GetItemStatTOVValue(stat->stat_subtype); } else if (client->GetVersion() >= 1193){ //COE tmp_subtype = world.GetItemStatCOEValue(stat->stat_subtype); //tmp_subtype = stat->stat_subtype; } else if (client->GetVersion() >= 1096){ //DOV tmp_subtype = world.GetItemStatDOVValue(stat->stat_subtype); //tmp_subtype = stat->stat_subtype; //comment for normal use } } else tmp_subtype = stat->stat_subtype; if (tmp_subtype == 255 ){ dropstat += 1; } } packet->setSubstructArrayLengthByName("header_info", "stat_count", item_stats.size() - dropstat); dropstat = 0; for (int32 i = 0; i < item_stats.size(); i++) { ItemStat* stat = item_stats[i]; if (stat->stat_type == 6 || stat->stat_type == 7){ //Convert stats to proper client if(stat->stat_type == 7){ tmp_subtype = stat->stat_subtype; } else if ((client->GetVersion() >= 63119) || client->GetVersion() == 61331){ //KA tmp_subtype = world.GetItemStatKAValue(stat->stat_subtype); } else if(client->GetVersion() >= 60085 ) { tmp_subtype = world.GetItemStatAOMValue(stat->stat_subtype); } else if (client->GetVersion() >= 57107){ //TOV tmp_subtype = world.GetItemStatTOVValue(stat->stat_subtype); } else if (client->GetVersion() >= 1193){ //COE tmp_subtype = world.GetItemStatCOEValue(stat->stat_subtype); //tmp_subtype = stat->stat_subtype; } else if (client->GetVersion() >= 1096){ //DOV tmp_subtype = world.GetItemStatDOVValue(stat->stat_subtype); //comment out for testing //tmp_subtype = stat->stat_subtype; //comment for normal use } } else tmp_subtype = stat->stat_subtype; if (tmp_subtype == 255 ){ dropstat += 1; //packet->setSubstructArrayLengthByName("header_info", "stat_count", item_stats.size()-dropstat); } else { packet->setArrayDataByName("stat_type", stat->stat_type, i-dropstat); packet->setArrayDataByName("stat_subtype", tmp_subtype, i-dropstat); } if (stat->stat_name.length() > 0) packet->setArrayDataByName("stat_name", stat->stat_name.c_str(), i-dropstat); /* SF client */ float statValue = stat->value; if(player) { int32 effective_level = player->GetInfoStructUInt("effective_level"); if(effective_level && effective_level < player->GetLevel() && details.recommended_level > effective_level) { int32 diff = details.recommended_level - effective_level; float tmpValue = (float)statValue; statValue = (sint32)(float)(tmpValue / (1.0f + ((float)diff * rule_manager.GetGlobalRule(R_Player, MentorItemDecayRate)->GetFloat()))); } } if ((client->GetVersion() >= 63119) || client->GetVersion() == 61331) { if (stat->stat_type == 6){ packet->setArrayDataByName("value", statValue , i - dropstat);//63119 or when diety started (this is actually the modified stat packet->setArrayDataByName("value2", stat->value, i - dropstat);//63119 temp will be replace by modified value (this is the unmodified stat } else { packet->setArrayDataByName("value", (sint16)statValue , i - dropstat, 0U, true); packet->setArrayDataByName("value2", stat->value, i - dropstat);//63119 temp will be replace by modified value } } else if (client->GetVersion() >= 1028) { if (stat->stat_type == 6){ packet->setArrayDataByName("value", statValue , i - dropstat);//63119 or when diety started (this is actually the infused modified stat packet->setArrayDataByName("value2", stat->value, i - dropstat);//63119 temp will be replace by modified value (this is the unmodified stat } else { packet->setArrayDataByName("value", (sint16)statValue , i - dropstat, 0U, true); packet->setArrayDataByName("value2", stat->value, i - dropstat);//63119 temp will be replace by modified value } } else{ packet->setArrayDataByName("value", (sint16)statValue , i - dropstat); packet->setArrayDataByName("value2", stat->value, i - dropstat);//63119 temp will be replace by modified value } } } if (item_string_stats.size() > 0 && !loot_item){ if ((client->GetVersion() >= 63119) || client->GetVersion() == 61331) { packet->setSubstructArrayLengthByName("header_info", "mod_count", item_string_stats.size()); for (int32 i = 0; i < item_string_stats.size(); i++){ ItemStatString* stat = item_string_stats[i]; packet->setArrayDataByName("mod_string", &(stat->stat_string), i); packet->setArrayDataByName("mod_need", 0, i); } } else if (client->GetVersion() >= 1096) { packet->setSubstructArrayLengthByName("header_info", "stat_string_count", item_string_stats.size()); for (int32 i = 0; i < item_string_stats.size(); i++){ ItemStatString* stat = item_string_stats[i]; packet->setArrayDataByName("stat_string", &(stat->stat_string), i); } } } if (item_sets.size() > 0){ packet->setArrayLengthByName("num_pieces", item_sets.size()); for (int32 i = 0; i < item_sets.size(); i++){ ItemSet* set = item_sets[i]; packet->setArrayDataByName("item_id", set->item_id, i); packet->setArrayDataByName("item_crc", set->item_crc, i); packet->setArrayDataByName("item_icon", set->item_icon, i); packet->setArrayDataByName("item_unknown1", set->item_stack_size, i); Item* item2 = master_item_list.GetItem(set->item_id); if (item2) packet->setArrayDataByName("item_name", item2->name.c_str(), i); packet->setArrayDataByName("item_unknown2", set->item_list_color, i); } } if(!loot_item && item_effects.size() > 0){ packet->setSubstructArrayLengthByName("footer", "num_effects", item_effects.size()); for(int32 i=0;isetArrayDataByName("subbulletflag", effect->subbulletflag, i); packet->setArrayDataByName("effect", &(effect->effect), i); packet->setArrayDataByName("percentage", effect->percentage, i); } } if (packet->GetVersion() < 1096) { packet->setSubstructDataByName("header_info", "adornment_id", 0xFFFFFFFF); // Send no ID for now packet->setSubstructDataByName("header_info", "unknown3", 0xFFFFFFFF); } packet->setSubstructDataByName("header_info", "unknown21", 0x00000000); packet->setSubstructDataByName("header_info", "condition", generic_info.condition); packet->setSubstructDataByName("header_info", "weight", generic_info.weight); if (packet->GetVersion() <= 283) { //orig client only has one skill if (generic_info.skill_req1 == 0 || generic_info.skill_req1 == 0xFFFFFFFF) { if (generic_info.skill_req2 != 0 && generic_info.skill_req2 != 0xFFFFFFFF) { packet->setSubstructDataByName("header_info", "skill_req1", generic_info.skill_req2); } else { packet->setSubstructDataByName("header_info", "skill_req1", 0xFFFFFFFF); } } else { packet->setSubstructDataByName("header_info", "skill_req1", generic_info.skill_req1); } } else { if (generic_info.skill_req1 == 0) packet->setSubstructDataByName("header_info", "skill_req1", 0xFFFFFFFF); else packet->setSubstructDataByName("header_info", "skill_req1", generic_info.skill_req1); if (generic_info.skill_req2 == 0) packet->setSubstructDataByName("header_info", "skill_req2", 0xFFFFFFFF); else packet->setSubstructDataByName("header_info", "skill_req2", generic_info.skill_req2); } if(generic_info.skill_min != 0) packet->setSubstructDataByName("header_info", "skill_min", generic_info.skill_min); if (client->GetVersion() <= 283) { string flags; if (CheckFlag(NO_TRADE)) flags += "NO-TRADE "; if (CheckFlag(NO_VALUE)) flags += "NO-VALUE "; if(flags.length() > 0) packet->setSubstructDataByName("header_info", "flag_names", flags.c_str()); } if (generic_info.adventure_classes > 0 || generic_info.tradeskill_classes > 0 || item_level_overrides.size() > 0) { //int64 classes = 0; int16 tmp_level = 0; map adv_class_levels; map tradeskill_class_levels; map::iterator itr; int64 tmpVal = 0; int8 temp = ASSASSIN; // AoD + clients with beastlords if (packet->GetVersion() >= 1142) temp += 2; // Chaneler class, get a more accurate version if (packet->GetVersion() >= 60000) temp += 2; for (int32 i = 0; i <= temp; i++) { tmpVal = (int64)pow(2.0, (double)i); if ((generic_info.adventure_classes & tmpVal)) { //classes += 2 << (i - 1); classes += tmpVal; tmp_level = GetOverrideLevel(i, 255); if (tmp_level == 0) adv_class_levels[i] = generic_info.adventure_default_level; else adv_class_levels[i] = tmp_level; } if (tmpVal == 0) { if (packet->GetVersion() >= 60000) classes = 576379072454289112; else if (packet->GetVersion() >= 57048) classes = 6281081087704; else if (packet->GetVersion() >= 1142) classes = 144095080877876952; else classes = 36024082983773912; } } for (int i = ALCHEMIST + 1 - ARTISAN; i >= 0; i--) { //tmpVal = 2 << i; tmpVal = (int64)pow(2.0, (double)i); if ((generic_info.tradeskill_classes & tmpVal)) { classes += pow(2, (i + ARTISAN)); //classes += 2 << (i+ARTISAN-1); tmp_level = GetOverrideLevel(i, 255); if (tmp_level == 0) tradeskill_class_levels[i] = generic_info.tradeskill_default_level; else tradeskill_class_levels[i] = tmp_level; } } bool simplified_display = false; if (client->GetVersion() <= 546) { //simplify display (if possible) map new_adv_class_levels; for (int i = 1; i <= 31; i += 10) { bool add_archetype = CheckArchetypeAdvClass(i, &adv_class_levels); if (add_archetype) { new_adv_class_levels[i] = 0; } else { for (int x = 1; x <= 7; x += 3) { if (CheckArchetypeAdvSubclass(i+x, &adv_class_levels)) { new_adv_class_levels[i+x] = 0; } } } } if (new_adv_class_levels.size() > 0) { simplified_display = true; int8 i = 0; for (itr = new_adv_class_levels.begin(); itr != new_adv_class_levels.end(); itr++) { i = itr->first; if ((i % 10) == 1) { int16 level = 0; for (int x = i; x < i+10; x++) { if (adv_class_levels.count(x) > 0) { if(level == 0) level = adv_class_levels.at(x); adv_class_levels.erase(x); } } adv_class_levels[i] = level; } else { int16 level = 0; for (int x = i+1; x < i + 3; x++) { if (adv_class_levels.count(x) > 0) { if (level == 0) level = adv_class_levels.at(x); adv_class_levels.erase(x); } } adv_class_levels[i] = level; } } } } packet->setSubstructArrayLengthByName("header_info", "class_count", adv_class_levels.size() + tradeskill_class_levels.size()); int i = 0; for (itr = adv_class_levels.begin(); itr != adv_class_levels.end(); itr++, i++) { packet->setArrayDataByName("adventure_class", itr->first, i); packet->setArrayDataByName("tradeskill_class", 255, i); packet->setArrayDataByName("level", itr->second * 10, i); } for (itr = tradeskill_class_levels.begin(); itr != tradeskill_class_levels.end(); itr++, i++) { packet->setArrayDataByName("adventure_class", 255, i); packet->setArrayDataByName("tradeskill_class", itr->first, i); packet->setArrayDataByName("level", itr->second * 10, i); } packet->setSubstructDataByName("footer", "required_classes", classes); } else { if (packet->GetVersion() >= 60000) classes = 576379072454289112; else if (packet->GetVersion() >= 57048) classes = 6281081087704; else if (packet->GetVersion() >= 1142) classes = 144095080877876952; else classes = 36024082983773912; packet->setSubstructDataByName("footer", "required_classes", classes); } // Is this a copy and paste error??? packet->setSubstructDataByName("footer", "required_classes2", classes); { if (packet->GetVersion() >= 60000) classes = 576379072454289112; else if (packet->GetVersion() >= 57048) classes = 6281081087704; else if (packet->GetVersion() >= 1142) classes = 144095080877876952; else classes = 36024082983773912; } if (client->GetVersion() <= 283 && generic_info.adventure_default_level > 0) { packet->setSubstructDataByName("header_info", "skill_min", (generic_info.adventure_default_level-1)*5+1); packet->setSubstructDataByName("header_info", "skill_recommended", details.recommended_level * 5); } packet->setSubstructDataByName("footer", "recommended_level", details.recommended_level); if(generic_info.adventure_default_level > 0){ packet->setSubstructDataByName("footer", "required_level", generic_info.adventure_default_level); packet->setSubstructDataByName("footer", "footer_unknown2", 0);// remove defualt } else{ packet->setSubstructDataByName("footer", "required_level", generic_info.tradeskill_default_level * 10); packet->setSubstructDataByName("footer", "footer_unknown2", 0);//remove default } if(slot_data.size() > 0){ packet->setSubstructArrayLengthByName("header_info", "slot_count", slot_data.size()); for(int32 i=0;iGetVersion() <= 283) { if (slot > EQ2_EARS_SLOT_1 && slot <= EQ2_WAIST_SLOT) //they added a second ear slot later, adjust for only 1 original slot slot -= 1; else if (slot == EQ2_FOOD_SLOT) slot = EQ2_ORIG_FOOD_SLOT; else if(slot == EQ2_DRINK_SLOT) slot = EQ2_ORIG_DRINK_SLOT; } else if (client->GetVersion() <= 546) { if (slot > EQ2_EARS_SLOT_1 && slot <= EQ2_WAIST_SLOT) //they added a second ear slot later, adjust for only 1 original slot slot -= 1; else if (slot == EQ2_FOOD_SLOT) slot = EQ2_DOF_FOOD_SLOT; else if (slot == EQ2_DRINK_SLOT) slot = EQ2_DOF_DRINK_SLOT; } packet->setArrayDataByName("slot", slot, i); } } if(!loot_item){ if (adornment_info) LogWrite(ITEM__DEBUG, 0, "Items", "\ttype: %i, Duration: %i, item_types_: %i, slot_type: %i", generic_info.item_type, adornment_info->duration, adornment_info->item_types, adornment_info->slot_type); packet->setSubstructDataByName("header", "item_type", generic_info.item_type); switch(generic_info.item_type){ case ITEM_TYPE_WEAPON:{ if(weapon_info){ if (client->GetVersion() <= 283) { packet->setSubstructDataByName("details", "wield_type", weapon_info->wield_type); packet->setSubstructDataByName("details", "damage_low1", weapon_info->damage_low1); packet->setSubstructDataByName("details", "damage_high1", weapon_info->damage_high1); packet->setSubstructDataByName("details", "damage_low2", weapon_info->damage_low2); packet->setSubstructDataByName("details", "damage_high2", weapon_info->damage_high2); packet->setSubstructDataByName("details", "damage_type", weapon_type); packet->setSubstructDataByName("details", "delay", weapon_info->delay); } else { packet->setDataByName("wield_type", weapon_info->wield_type); packet->setDataByName("damage_low1", weapon_info->damage_low1); packet->setDataByName("damage_high1", weapon_info->damage_high1); packet->setDataByName("damage_low2", weapon_info->damage_low2); packet->setDataByName("damage_high2", weapon_info->damage_high2); packet->setDataByName("damage_low3", weapon_info->damage_low3); packet->setDataByName("damage_high3", weapon_info->damage_high3); packet->setDataByName("damage_type", weapon_type); packet->setDataByName("delay", weapon_info->delay); packet->setDataByName("rating", weapon_info->rating); } } break; } case ITEM_TYPE_RANGED:{ if(ranged_info){ if (client->GetVersion() <= 283) { packet->setSubstructDataByName("details", "damage_low1", ranged_info->weapon_info.damage_low1); packet->setSubstructDataByName("details", "damage_high1", ranged_info->weapon_info.damage_high1); packet->setSubstructDataByName("details", "damage_low2", ranged_info->weapon_info.damage_low2); packet->setSubstructDataByName("details", "damage_high2", ranged_info->weapon_info.damage_high2); packet->setSubstructDataByName("details", "delay", ranged_info->weapon_info.delay); packet->setSubstructDataByName("details", "range_low", ranged_info->range_low); packet->setSubstructDataByName("details", "range_high", ranged_info->range_high); } else { packet->setDataByName("damage_low1", ranged_info->weapon_info.damage_low1); packet->setDataByName("damage_high1", ranged_info->weapon_info.damage_high1); packet->setDataByName("damage_low2", ranged_info->weapon_info.damage_low2); packet->setDataByName("damage_high2", ranged_info->weapon_info.damage_high2); packet->setDataByName("damage_low3", ranged_info->weapon_info.damage_low3); packet->setDataByName("damage_high3", ranged_info->weapon_info.damage_high3); packet->setDataByName("delay", ranged_info->weapon_info.delay); packet->setDataByName("range_low", ranged_info->range_low); packet->setDataByName("range_high", ranged_info->range_high); packet->setDataByName("rating", ranged_info->weapon_info.rating); } } break; } case ITEM_TYPE_SHIELD: case ITEM_TYPE_ARMOR:{ if(armor_info){ if (client->GetVersion() <= 283) { packet->setSubstructDataByName("details", "mitigation_low", armor_info->mitigation_low); packet->setSubstructDataByName("details", "mitigation_high", armor_info->mitigation_high); } else { packet->setDataByName("mitigation_low", armor_info->mitigation_low); packet->setDataByName("mitigation_high", armor_info->mitigation_high); } } break; } case ITEM_TYPE_BAG:{ if(bag_info){ if (client->GetVersion() <= 283) { if (bag_info->num_slots > CLASSIC_EQ_MAX_BAG_SLOTS) bag_info->num_slots = CLASSIC_EQ_MAX_BAG_SLOTS; packet->setSubstructDataByName("details", "num_slots", bag_info->num_slots); packet->setSubstructDataByName("details", "weight_reduction", bag_info->weight_reduction); } else { int16 free_slots = bag_info->num_slots; if (player) { Item* bag = player->GetPlayerItemList()->GetItemFromUniqueID(details.unique_id, true); if (bag && bag->IsBag()) { vector* bag_items = player->GetPlayerItemList()->GetItemsInBag(bag); if (bag_items->size() > bag->bag_info->num_slots) { free_slots = 0; packet->setArrayLengthByName("num_names", bag->bag_info->num_slots); } else { free_slots = bag->bag_info->num_slots - bag_items->size(); packet->setArrayLengthByName("num_names", bag_items->size()); } vector::iterator itr; int16 i = 0; Item* tmp_bag_item = 0; for (itr = bag_items->begin(); itr != bag_items->end(); itr++) { tmp_bag_item = *itr; if (tmp_bag_item && tmp_bag_item->details.slot_id < bag->bag_info->num_slots) { packet->setArrayDataByName("item_name", tmp_bag_item->name.c_str(), i); i++; } } safe_delete(bag_items); } } packet->setDataByName("num_slots", bag_info->num_slots); packet->setDataByName("num_empty", free_slots); packet->setDataByName("weight_reduction", bag_info->weight_reduction); packet->setDataByName("item_score", 2); //packet->setDataByName("unknown5", 0x1e50a86f); //packet->setDataByName("unknown6", 0x2c17f61d); //1 armorer //2 weaponsmith //4 tailor //16 jeweler //32 sage //64 alchemist //120 all scholars //250 all craftsman //int8 blah[] = {0x00,0x00,0x01,0x01,0xb6,0x01,0x01}; //int8 blah[] = {0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; int8 blah[] = { 0xd8,0x66,0x9b,0x6d,0xb6,0xfb,0x7f }; for (int8 i = 0; i < sizeof(blah); i++) packet->setSubstructDataByName("footer", "footer_unknown_0", blah[i], 0, i); } } break; } case ITEM_TYPE_FOOD:{ if(food_info && client->GetVersion() >=284){ packet->setDataByName("food_type", food_info->type); packet->setDataByName("level", food_info->level); packet->setDataByName("duration", food_info->duration); } break; } case ITEM_TYPE_SKILL:{ //Spell Books if(skill_info->spell_id > 0){ Spell* spell = master_spell_list.GetSpell(skill_info->spell_id, skill_info->spell_tier); if(spell){ if(player && client->GetVersion() >= 284) { packet->setSubstructDataByName("header_info", "footer_type", 0); spell->SetPacketInformation(packet, player->GetZone()->GetClientBySpawn(player)); if (player->HasSpell(skill_info->spell_id, skill_info->spell_tier, true)) packet->setDataByName("scribed", 1); if (packet->GetVersion() >= 927){ if (player->HasSpell(skill_info->spell_id, skill_info->spell_tier, true)) packet->setAddToPacketByName("scribed_better_version", 1);// need to confirm } else packet->setAddToPacketByName("scribed_better_version", 0); //if not scribed // either don't require previous tier or check that we have the lower tier spells potentially int32 tier_up = player->GetTierUp(skill_info->spell_tier); if (!rule_manager.GetGlobalRule(R_Spells, RequirePreviousTierScribe)->GetInt8() || player->HasSpell(skill_info->spell_id, tier_up, false, true)) packet->setDataByName("require_previous", 1, 0); // membership required //packet->setDataByName("unknown_1188_2_MJ", 1, 1); } else { spell->SetPacketInformation(packet); } //packet->setDataByName("unknown26", 0); } } break; } case ITEM_TYPE_BAUBLE:{ if(bauble_info && client->GetVersion() >= 284){ packet->setDataByName("cast", bauble_info->cast); packet->setDataByName("recovery", bauble_info->recovery); packet->setDataByName("duration", bauble_info->duration); packet->setDataByName("recast", bauble_info->recast); packet->setDataByName("display_slot_optional", bauble_info->display_slot_optional); packet->setDataByName("display_cast_time", bauble_info->display_cast_time); packet->setDataByName("display_bauble_type", bauble_info->display_bauble_type); packet->setDataByName("effect_radius", bauble_info->effect_radius); packet->setDataByName("max_aoe_targets", bauble_info->max_aoe_targets); packet->setDataByName("display_until_cancelled", bauble_info->display_until_cancelled); //packet->setDataByName("item_score", 1); } break; } case ITEM_TYPE_THROWN:{ if(thrown_info && client->GetVersion() >= 284){ packet->setDataByName("range", thrown_info->range); packet->setDataByName("damage_modifier", thrown_info->damage_modifier); packet->setDataByName("hit_bonus", thrown_info->hit_bonus); packet->setDataByName("damage_type", thrown_info->damage_type); } break; } case ITEM_TYPE_HOUSE:{ if(houseitem_info && client->GetVersion() >= 284){ packet->setDataByName("status_rent_reduction", houseitem_info->status_rent_reduction); packet->setDataByName("coin_rent_reduction", houseitem_info->coin_rent_reduction); packet->setDataByName("house_only", houseitem_info->house_only); } break; } case ITEM_TYPE_BOOK:{ if(book_info && client->GetVersion() >= 284){ packet->setDataByName("language", book_info->language); packet->setMediumStringByName("author", book_info->author.data.c_str()); packet->setMediumStringByName("title", book_info->title.data.c_str()); } if (packet->GetVersion() <= 1096) packet->setDataByName("item_type", 13); break; } case ITEM_TYPE_RECIPE:{ // Recipe Books if(recipebook_info){ packet->setArrayLengthByName("num_recipes", recipebook_info->recipes.size()); for(int32 i = 0; i < recipebook_info->recipes.size(); i++){ packet->setArrayDataByName("recipe_name", recipebook_info->recipes.at(i).c_str(), i); Recipe* recipe = master_recipe_list.GetRecipeByName(recipebook_info->recipes.at(i).c_str()); if (recipe) { packet->setArrayDataByName("recipe_id", recipe->GetID(), i); packet->setArrayDataByName("recipe_icon", recipe->GetIcon(), i); } } packet->setDataByName("uses", recipebook_info->uses); if(player->GetRecipeBookList()->HasRecipeBook(recipebook_info->recipe_id)) packet->setDataByName("scribed", 1); else packet->setDataByName("scribed", 0); } break; } case ITEM_TYPE_ADORNMENT:{ //Adornements if (client->GetVersion() >= 284) { packet->setDataByName("item_types", adornment_info->item_types); packet->setDataByName("duration", adornment_info->duration); // need to calcualte for remaining duration packet->setDataByName("slot_type", adornment_info->slot_type); packet->setDataByName("footer_set_name", "test footer set name"); packet->setArrayLengthByName("footer_set_bonus_list_count", 1);// list of the bonus items packet->setArrayDataByName("footer_set_bonus_items_needed", 2, 0); //this is nember of items needed for granteing that stat //name,value,array packet->setSubArrayLengthByName("footer_set_bonus_stats_count", 2, 0);//name,value,array,subarray packet->setSubArrayDataByName("set_stat_type", 5, 0, 0); packet->setSubArrayDataByName("set_stat_subtype", 1, 0, 0); packet->setSubArrayDataByName("set_value", 25000, 0, 0); } } case ITEM_TYPE_HOUSE_CONTAINER:{ //House Containers if(housecontainer_info && client->GetVersion() >= 284){ packet->setDataByName("allowed_types", housecontainer_info->allowed_types); packet->setDataByName("num_slots", housecontainer_info->num_slots); packet->setDataByName("broker_commission", housecontainer_info->broker_commission); packet->setDataByName("fence_commission", housecontainer_info->fence_commission); } } } } LogWrite(MISC__TODO, 1, "TODO", "Item Set information\n\t(%s, function: %s, line #: %i)", __FILE__, __FUNCTION__, __LINE__); if (IsBauble()) { packet->setSubstructDataByName("footer", "stack_size", stack_count); } else { packet->setSubstructDataByName("footer", "stack_size", stack_count); } packet->setSubstructDataByName("footer", "collectable", generic_info.collectable); packet->setSubstructDataByName("footer", "status_item", sell_status); LogWrite(MISC__TODO, 1, "TODO", "Set collection_needed information properly\n\t(%s, function: %s, line #: %i)", __FILE__, __FUNCTION__, __LINE__); packet->setSubstructDataByName("footer", "collection_needed", player->GetCollectionList()->NeedsItem(this) ? 1 : 0); if(generic_info.offers_quest_id > 0){ Quest* quest = master_quest_list.GetQuest(generic_info.offers_quest_id, false); if(quest){ packet->setSubstructDataByName("footer", "offers_quest", strlen(generic_info.offers_quest_name) ? generic_info.offers_quest_name : quest->GetName()); packet->setSubstructDataByName("footer", "quest_color", player->GetArrowColor(quest->GetQuestLevel())); } } if(generic_info.part_of_quest_id > 0){ Quest* quest = master_quest_list.GetQuest(generic_info.part_of_quest_id, false); if(quest){ packet->setSubstructDataByName("footer", "part_of_quest", strlen(generic_info.required_by_quest_name) ? generic_info.required_by_quest_name : quest->GetName()); packet->setSubstructDataByName("footer", "quest_color", player->GetArrowColor(quest->GetQuestLevel())); } } if(generic_info.max_charges > 0){ packet->setSubstructDataByName("footer", "charges", 1); packet->setSubstructDataByName("footer", "total_charges", generic_info.max_charges); packet->setSubstructDataByName("footer", "charges_left", details.count); packet->setSubstructDataByName("footer", "display_charges", generic_info.display_charges); } if ((packet->GetVersion() >= 63119) || packet->GetVersion() == 61331){ if (sell_status > 0){ } } //packet->setSubstructDataByName("footer", "status_item", 0); if (IsHarvest()){ packet->setSubstructDataByName("footer", "crafting_flag", 1); } // Set these to 0 for now if(packet->GetVersion() >= 1188){ packet->setSubstructDataByName("footer", "locked_flag", 0); packet->setSubstructDataByName("footer", "account_retricted", 0); } // Adorns, set all to FF for now if (packet->GetVersion() >= 1096) {// changed to 1096 for dov from 1188 packet->setSubstructDataByName("footer", "adorn_slots", 0xFF, 0, 0); packet->setSubstructDataByName("footer", "adorn_slots", 0xFF, 0, 1); packet->setSubstructDataByName("footer", "adorn_slots", 0xFF, 0, 2); packet->setSubstructDataByName("footer", "adorn_slots", 0xFF, 0, 3); packet->setSubstructDataByName("footer", "adorn_slots", 0xFF, 0, 4); packet->setSubstructDataByName("footer", "adorn_slots", 0xFF, 0, 5); } if (packet->GetVersion() >= 1289) {// at some point after this there are 10 adornment slots all FF for now but will skip this if not needed for a version packet->setSubstructDataByName("footer", "adorn_slots", 0xFF, 0, 6); packet->setSubstructDataByName("footer", "adorn_slots", 0xFF, 0, 7); packet->setSubstructDataByName("footer", "adorn_slots", 0xFF, 0, 8); packet->setSubstructDataByName("footer", "adorn_slots", 0xFF, 0, 9); packet->setSubstructDataByName("footer", "adorn_slots", 0xFF, 0, 10); } packet->setSubstructDataByName("footer", "name", name.c_str()); packet->setSubstructDataByName("footer", "description", description.c_str()); LogWrite(ITEM__PACKET, 0, "Items", "Dump/Print Packet in func: %s, line: %i", __FUNCTION__, __LINE__); //packet->PrintPacket(); #if EQDEBUG >= 9 packet->PrintPacket(); #endif } PacketStruct* Item::PrepareItem(int16 version, bool merchant_item, bool loot_item){ PacketStruct* packet = 0; if(loot_item && version > 546) packet = configReader.getStruct("WS_LootItemGeneric", version); else{ int8 tmpType = generic_info.item_type; if (version <= 283 && generic_info.item_type > ITEM_TYPE_RECIPE) tmpType = 0; switch(tmpType){ case ITEM_TYPE_WEAPON:{ if(merchant_item) packet = configReader.getStruct("WS_MerchantItemWeapon", version); else packet = configReader.getStruct("WS_ItemWeapon", version); break; } case ITEM_TYPE_RANGED:{ if(merchant_item) packet = configReader.getStruct("WS_MerchantItemRange", version); else packet = configReader.getStruct("WS_ItemRange", version); break; } case ITEM_TYPE_SHIELD:{ if (merchant_item) packet = configReader.getStruct("WS_MerchantItemShield", version); else packet = configReader.getStruct("WS_ItemShield", version); break; } case ITEM_TYPE_ARMOR:{ if(merchant_item) packet = configReader.getStruct("WS_MerchantItemArmor", version); else packet = configReader.getStruct("WS_ItemArmor", version); break; } case ITEM_TYPE_BAG:{ if(merchant_item) packet = configReader.getStruct("WS_MerchantItemBag", version); else packet = configReader.getStruct("WS_ItemBag", version); break; } case ITEM_TYPE_BOOK:{ if(merchant_item) packet = configReader.getStruct("WS_MerchantItemBook", version); else packet = configReader.getStruct("WS_ItemBook", version); break; } case ITEM_TYPE_SKILL:{ if(merchant_item) packet = configReader.getStruct("WS_MerchantItemSkill", version); else packet = configReader.getStruct("WS_ItemSkill", version); break; } case ITEM_TYPE_RECIPE:{ if(merchant_item) packet = configReader.getStruct("WS_MerchantItemRecipeBook", version); else packet = configReader.getStruct("WS_ItemRecipeBook", version); break; } case ITEM_TYPE_FOOD:{ if(merchant_item) packet = configReader.getStruct("WS_MerchantItemFood", version); else packet = configReader.getStruct("WS_ItemFood", version); break; } case ITEM_TYPE_BAUBLE:{ if(merchant_item) packet = configReader.getStruct("WS_MerchantItemBauble", version); else packet = configReader.getStruct("WS_ItemBauble", version); break; } case ITEM_TYPE_ITEMCRATE:{ if (merchant_item) packet = configReader.getStruct("WS_MerchantItemSet", version); else packet = configReader.getStruct("WS_ItemSet", version); break; } case ITEM_TYPE_HOUSE:{ if(merchant_item) packet = configReader.getStruct("WS_MerchantItemHouse", version); else packet = configReader.getStruct("WS_ItemHouse", version); break; } case ITEM_TYPE_THROWN:{ if(merchant_item) packet = configReader.getStruct("WS_MerchantItemThrown", version); else packet = configReader.getStruct("WS_ItemThrown", version); break; } case ITEM_TYPE_HOUSE_CONTAINER:{ if(merchant_item) packet = configReader.getStruct("WS_MerchantItemHouseContainer", version); else packet = configReader.getStruct("WS_ItemHouseContainer", version); break; } case ITEM_TYPE_ADORNMENT:{ if(merchant_item) packet = configReader.getStruct("WS_MerchantAdornment", version); else packet = configReader.getStruct("WS_ItemAdornment", version); break; } default:{ if(merchant_item) packet = configReader.getStruct("WS_MerchantItemGeneric", version); else packet = configReader.getStruct("WS_ItemGeneric", version); } } if (packet && loot_item) packet->AddFlag("loot"); } if(!packet){ LogWrite(ITEM__ERROR, 0, "Item", "Unhandled Item type: %i", (int)generic_info.item_type); return 0; } return packet; } EQ2Packet* Item::serialize(int16 version, bool show_name, Player* player, bool include_twice, int16 packet_type, int8 subtype, bool merchant_item, bool loot_item){ PacketStruct* packet = PrepareItem(version, merchant_item, loot_item); if(!packet) return 0; if (version <= 546) { include_twice = false; packet_type = 0; } if(include_twice && IsBag() == false && IsBauble() == false && IsFood() == false) serialize(packet, show_name, player, packet_type, 0x80, loot_item); else serialize(packet, show_name, player, packet_type, 0, loot_item); if(merchant_item) packet->setSubstructDataByName("header_info", "unique_id", 0xFFFFFFFF); string* generic_string_data = packet->serializeString(); //packet->PrintPacket(); //LogWrite(ITEM__DEBUG, 9, "Items", "generic_string_data:"); //DumpPacket((uchar*)generic_string_data->c_str(), generic_string_data->length()); int32 size = generic_string_data->length(); if(include_twice && IsBag() == false && IsBauble() == false && IsFood() == false) size = (size*2)-13; uchar* out_data = new uchar[size+1]; uchar* out_ptr = out_data; memcpy(out_ptr, (uchar*)generic_string_data->c_str(), generic_string_data->length()); out_ptr += generic_string_data->length(); if(include_twice && IsBag() == false && IsBauble() == false && IsFood() == false){ memcpy(out_ptr, (uchar*)generic_string_data->c_str() + 13, generic_string_data->length() -13); } int32 size2 = size; if (version <= 283) { uchar* out_ptr2 = out_data; if (size2 >= 0xFF) { size2 -= 3; out_ptr2[0] = 0xFF; out_ptr2 += sizeof(int8); memcpy(out_ptr2, &size2, sizeof(int16)); } else { size2 -= 1; out_ptr2[0] = size2; } } else { size2 -= 4; memcpy(out_data, &size2, sizeof(int32)); } EQ2Packet* outapp = new EQ2Packet(OP_ClientCmdMsg, out_data, size); //DumpPacket(outapp); safe_delete(packet); safe_delete_array(out_data); return outapp; } void Item::SetAppearance(ItemAppearance* appearance){ SetAppearance(appearance->type, appearance->red, appearance->green, appearance->blue, appearance->highlight_red, appearance->highlight_green, appearance->highlight_blue); } void Item::SetAppearance(int16 type, int8 red, int8 green, int8 blue, int8 highlight_red, int8 highlight_green, int8 highlight_blue){ generic_info.appearance_id = type; generic_info.appearance_red = red; generic_info.appearance_green = green; generic_info.appearance_blue = blue; generic_info.appearance_highlight_red = highlight_red; generic_info.appearance_highlight_green = highlight_green; generic_info.appearance_highlight_blue = highlight_blue; } void Item::AddEffect(string effect, int8 percentage, int8 subbulletflag){ ItemEffect* item_effect = new ItemEffect; item_effect->subbulletflag = subbulletflag; item_effect->effect.data = effect; item_effect->effect.size = effect.length(); item_effect->percentage = percentage; item_effects.push_back(item_effect); } void Item::AddBookPage(int8 page, string page_text, int8 valign, int8 halign) { BookPage * bookpage = new BookPage; bookpage->page = page; bookpage->page_text.data = page_text; bookpage->page_text.size = page_text.length(); bookpage->valign = valign; bookpage->halign = halign; book_pages.push_back(bookpage); } void Item::AddLevelOverride(ItemLevelOverride* level_override){ AddLevelOverride(level_override->adventure_class, level_override->tradeskill_class, level_override->level); } void Item::AddLevelOverride(int8 adventure_class, int8 tradeskill_class, int16 level){ ItemLevelOverride* item_override = new ItemLevelOverride; item_override->adventure_class = adventure_class; item_override->tradeskill_class = tradeskill_class; item_override->level = level; item_level_overrides.push_back(item_override); } void Item::AddSlot(int8 slot_id){ slot_data.push_back(slot_id); } void Item::SetWeaponType(int8 type){ weapon_type = type; } int8 Item::GetWeaponType(){ return weapon_type; } int32 Item::GetMaxSellValue(){ return max_sell_value; } void Item::SetMaxSellValue(int32 val){ max_sell_value = val; } void Item::SetItemScript(string name){ item_script = name; } const char* Item::GetItemScript(){ if(item_script.length() > 0) return item_script.c_str(); return 0; } int32 Item::CalculateRepairCost() { if (generic_info.condition == 100) return 0; float repair_cost = (float)generic_info.adventure_default_level * (10.0 - ((float)generic_info.condition * 0.1)); if (details.tier == ITEM_TAG_LEGENDARY) repair_cost *= 4; else if (details.tier == ITEM_TAG_FABLED) repair_cost *= 8; else if (details.tier == ITEM_TAG_MYTHICAL) repair_cost *= 12; return (int32)repair_cost; } PlayerItemList::PlayerItemList(){ packet_count = 0; xor_packet = 0; orig_packet = 0; MPlayerItems.SetName("PlayerItemList::MPlayerItems"); } PlayerItemList::~PlayerItemList(){ safe_delete_array(xor_packet); safe_delete_array(orig_packet); map> >::iterator bag_iter; map::iterator itr; for(bag_iter = items.begin(); bag_iter != items.end(); bag_iter++){ for(itr = bag_iter->second[0].begin(); itr != bag_iter->second[0].end(); itr++){ safe_delete(itr->second); } for(itr = bag_iter->second[1].begin(); itr != bag_iter->second[1].end(); itr++){ safe_delete(itr->second); } bag_iter->second.clear(); } items.clear(); while (!overflowItems.empty()){ safe_delete(overflowItems.back()); overflowItems.pop_back(); } } map* PlayerItemList::GetAllItems(){ map* ret = new map; MPlayerItems.readlock(__FUNCTION__, __LINE__); ret->insert(indexed_items.begin(), indexed_items.end()); MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return ret; } Item* PlayerItemList::GetItemFromIndex(int32 index){ Item* ret = 0; MPlayerItems.readlock(__FUNCTION__, __LINE__); if(indexed_items.count(index) > 0) ret = indexed_items[index]; MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return ret; } Item* PlayerItemList::GetItem(sint32 bag_slot, int16 slot, int8 appearance_type){ Item* ret = 0; MPlayerItems.readlock(__FUNCTION__, __LINE__); if(items.count(bag_slot) > 0 && items[bag_slot][appearance_type].count(slot) > 0) ret = items[bag_slot][appearance_type][slot]; MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return ret; } bool PlayerItemList::AddItem(Item* item){ //is called with a slot already set //quick check to verify item if(!item) return false; else{ if(item->details.inv_slot_id != 0){ Item* bag = GetItemFromUniqueID(item->details.inv_slot_id, true); if(bag && bag->IsBag()){ if(item->details.slot_id > bag->details.num_slots){ LogWrite(ITEM__ERROR, 0, "Item", "Error Adding Item: Invalid slot for item unique id: %u (%s - %i), InvSlotID: %u, slotid: %u, numslots: %u", item->details.unique_id, item->name.c_str(), item->details.item_id, item->details.inv_slot_id, item->details.slot_id, bag->details.num_slots); safe_delete(item); return false; } } } } int32 max_index = indexed_items.size(); int32 new_index = 0; map::iterator itr; MPlayerItems.writelock(__FUNCTION__, __LINE__); for(itr = indexed_items.begin();itr != indexed_items.end(); itr++){ if(itr->first > max_index) //just grab the highest index val for next loop max_index = itr->first; } for(int32 i=0;i 0) new_index = max_index; indexed_items[new_index] = item; item->details.index = new_index; items[item->details.inv_slot_id][item->details.appearance_type][item->details.slot_id] = item; MPlayerItems.releasewritelock(__FUNCTION__, __LINE__); return true; } Item* PlayerItemList::GetBag(int8 inventory_slot, bool lock){ Item* bag = 0; if(lock) MPlayerItems.readlock(__FUNCTION__, __LINE__); if(items.count(0) > 0 && items[0][BASE_EQUIPMENT].count(inventory_slot) > 0 && items[0][BASE_EQUIPMENT][inventory_slot]->IsBag()) bag = items[0][BASE_EQUIPMENT][inventory_slot]; if(lock) MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return bag; } Item* PlayerItemList::GetBankBag(int8 inventory_slot, bool lock){ Item* bag = 0; if(lock) MPlayerItems.readlock(__FUNCTION__, __LINE__); if(items.count(-3) > 0 && items[-3][BASE_EQUIPMENT].count(inventory_slot) > 0 && items[-3][BASE_EQUIPMENT][inventory_slot]->IsBag()) bag = items[-3][BASE_EQUIPMENT][inventory_slot]; if(lock) MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return bag; } int16 PlayerItemList::GetNumberOfFreeSlots(){ int16 count = 0; MPlayerItems.readlock(__FUNCTION__, __LINE__); for(int8 i=0;idetails.num_slots > 0){ if(items.count(bag->details.bag_id) > 0){ for(int16 x=0;xdetails.num_slots;x++){ if(items[bag->details.bag_id][BASE_EQUIPMENT].count(x) == 0) count++; } } else count += bag->bag_info->num_slots; //if the bag hasnt been used yet, add all the free slots } } MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return count; } bool PlayerItemList::HasFreeBagSlot(){ bool ret = false; MPlayerItems.readlock(__FUNCTION__, __LINE__); if(items.count(0) > 0){ for(int8 i=0;i 0){ for(int8 i=0;idetails.num_slots > 0){ if(items.count(bag->details.bag_id) > 0){ for(int16 x=0;xdetails.num_slots;x++){ if(items[bag->details.bag_id][BASE_EQUIPMENT].count(x) == 0){ ret = true; break; } } } else{ //if the bag hasnt been used yet, then all slots are free ret = true; break; } } } } MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return ret; } bool PlayerItemList::GetFirstFreeBankSlot(sint32* bag_id, sint16* slot) { bool ret = false; MPlayerItems.readlock(__FUNCTION__, __LINE__); if (items.count(-3) > 0) { for (int8 i = 0; i < NUM_BANK_SLOTS; i++) { if (items[-3][BASE_EQUIPMENT].count(i) == 0) { *bag_id = -3; *slot = i; ret = true; break; } } } else { *bag_id = -3; *slot = 0; ret = true; } if(!ret) { // Inventory slots were full so check bags Item* bag = 0; for(int8 i = 0; !ret && i < NUM_BANK_SLOTS; i++) { // Check to see if the item in the inventory slot is a bag and it has slots bag = GetBankBag(i, false); if(bag && bag->details.num_slots > 0) { // Item was a bag so lets loop through the slots and try to find an empty one if(items.count(bag->details.bag_id) > 0) { for(int16 x = 0; x < bag->details.num_slots; x++) { if(items[bag->details.bag_id][BASE_EQUIPMENT].count(x) == 0) { // Found a free slot, get the bag id of this bag *bag_id = bag->details.bag_id; // Get the slot *slot = x; ret = true; break; } } } else { //if the bag hasnt been used yet, then all slots are free, so set the bag_id to this bag // and the slot to 0 (the first slot) *bag_id = bag->details.bag_id; *slot = 0; ret = true; break; } } } } MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return ret; } bool PlayerItemList::GetFirstFreeSlot(sint32* bag_id, sint16* slot) { // Mostly copy and paste from the above function bool ret = false; // Try to place the item in the normal inventory slots first MPlayerItems.readlock(__FUNCTION__, __LINE__); if(items.count(0) > 0){ for(int8 i=0; i < NUM_INV_SLOTS; i++) { if(items[0][BASE_EQUIPMENT].count(i) == 0) { // Found an empty slot, store the slot id and set the return value *bag_id = 0; *slot = i; ret = true; break; } } } else { // no items in the players inventory, set it to the first slot *bag_id = 0; *slot = 0; ret = true; } if(!ret) { // Inventory slots were full so check bags Item* bag = 0; for(int8 i = 0; !ret && i < NUM_INV_SLOTS; i++) { // Check to see if the item in the inventory slot is a bag and it has slots bag = GetBag(i, false); if(bag && bag->details.num_slots > 0) { // Item was a bag so lets loop through the slots and try to find an empty one if(items.count(bag->details.bag_id) > 0) { for(int16 x = 0; x < bag->details.num_slots; x++) { if(items[bag->details.bag_id][BASE_EQUIPMENT].count(x) == 0) { // Found a free slot, get the bag id of this bag *bag_id = bag->details.bag_id; // Get the slot *slot = x; ret = true; break; } } } else { //if the bag hasnt been used yet, then all slots are free, so set the bag_id to this bag // and the slot to 0 (the first slot) *bag_id = bag->details.bag_id; *slot = 0; ret = true; break; } } } } MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return ret; } Item* PlayerItemList::CanStack(Item* item, bool include_bank){ if(!item || item->stack_count < 2) return 0; Item* ret = 0; map> >::iterator itr; map::iterator slot_itr; MPlayerItems.readlock(__FUNCTION__, __LINE__); for(itr = items.begin(); itr != items.end(); itr++){ if(include_bank || (!include_bank && itr->first >= 0)){ for(slot_itr=itr->second[0].begin();slot_itr!=itr->second[0].end(); slot_itr++){ if(slot_itr->second && slot_itr->second->details.item_id == item->details.item_id && (((slot_itr->second->details.count ? slot_itr->second->details.count : 1) + (item->details.count > 0 ? item->details.count : 1)) <= slot_itr->second->stack_count)){ ret = slot_itr->second; break; } } for(slot_itr=itr->second[1].begin();slot_itr!=itr->second[1].end(); slot_itr++){ if(slot_itr->second && slot_itr->second->details.item_id == item->details.item_id && (((slot_itr->second->details.count ? slot_itr->second->details.count : 1) + (item->details.count > 0 ? item->details.count : 1)) <= slot_itr->second->stack_count)){ ret = slot_itr->second; break; } } } if(ret) break; } MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return ret; } void PlayerItemList::Stack(Item* orig_item, Item* item){ if(!orig_item || !item) return; orig_item->details.count += item->details.count; orig_item->save_needed = true; } bool PlayerItemList::AssignItemToFreeSlot(Item* item){ if(item){ Item* orig_item = CanStack(item); if(orig_item){ Stack(orig_item, item); return true; } bool use_bag_freeslot = false; if(item->IsBag()) use_bag_freeslot = HasFreeBagSlot(); MPlayerItems.writelock(__FUNCTION__, __LINE__); if(!use_bag_freeslot){ Item* bag = 0; for(int8 i=0;idetails.num_slots > 0){ for(int16 x=0;xdetails.num_slots;x++){ if(items[bag->details.bag_id][BASE_EQUIPMENT].count(x) == 0){ item->details.inv_slot_id = bag->details.bag_id; item->details.slot_id = x; MPlayerItems.releasewritelock(__FUNCTION__, __LINE__); bool ret = AddItem(item); return ret; } } } } } //bags full, check inventory slots for(int8 i=0;idetails.inv_slot_id = 0; item->details.slot_id = i; MPlayerItems.releasewritelock(__FUNCTION__, __LINE__); bool ret = AddItem(item); return ret; } } MPlayerItems.releasewritelock(__FUNCTION__, __LINE__); } return false; } void PlayerItemList::RemoveItem(Item* item, bool delete_item){ MPlayerItems.writelock(__FUNCTION__, __LINE__); if(items.count(item->details.inv_slot_id) > 0 && items[item->details.inv_slot_id][item->details.appearance_type].count(item->details.slot_id) > 0){ items[item->details.inv_slot_id][item->details.appearance_type].erase(item->details.slot_id); indexed_items[item->details.index] = 0; } if(item->IsBag() && item->details.inv_slot_id == 0 && item->details.slot_id < NUM_INV_SLOTS && items.count(item->details.bag_id) > 0){ map::iterator itr; for(itr = items[item->details.bag_id][item->details.appearance_type].begin(); itr != items[item->details.bag_id][item->details.appearance_type].end(); itr++){ indexed_items[itr->second->details.index] = 0; if(delete_item){ if(itr->second == item) { item = nullptr; } safe_delete(itr->second); } } items.erase(item->details.bag_id); } if(delete_item){ map::iterator itr = indexed_items.find(item->details.index); if(itr != indexed_items.end() && item == indexed_items[item->details.index]) indexed_items[item->details.index] = 0; safe_delete(item); } MPlayerItems.releasewritelock(__FUNCTION__, __LINE__); } void PlayerItemList::DestroyItem(int16 index){ MPlayerItems.writelock(__FUNCTION__, __LINE__); Item* item = indexed_items[index]; map::iterator itr; if(item && item->IsBag() && item->details.inv_slot_id == 0 && item->details.slot_id < NUM_INV_SLOTS && items.count((sint32)item->details.bag_id) > 0){ //inventory map* tmp_map = &(items[(sint32)item->details.bag_id][item->details.appearance_type]); for(itr = tmp_map->begin(); itr != tmp_map->end(); itr++){ indexed_items[itr->second->details.index] = 0; if(itr->second != item){ safe_delete(itr->second); } } items.erase(item->details.bag_id); } if(item && items.count(item->details.inv_slot_id) > 0 && items[item->details.inv_slot_id][item->details.appearance_type].count(item->details.slot_id) > 0) items[item->details.inv_slot_id][item->details.appearance_type].erase(item->details.slot_id); indexed_items[index] = 0; safe_delete(item); MPlayerItems.releasewritelock(__FUNCTION__, __LINE__); } void PlayerItemList::MoveItem(Item* item, sint32 inv_slot, int16 slot, int8 appearance_type, bool erase_old){ if(erase_old && items.count(item->details.inv_slot_id) > 0 && items[item->details.inv_slot_id][BASE_EQUIPMENT].count(item->details.slot_id)) items[item->details.inv_slot_id][BASE_EQUIPMENT].erase(item->details.slot_id); items[inv_slot][BASE_EQUIPMENT][slot] = item; item->details.inv_slot_id = inv_slot; item->details.slot_id = slot; item->details.appearance_type = 0; item->save_needed = true; } int16 PlayerItemList::GetNumberOfItems(){ int16 ret = 0; MPlayerItems.readlock(__FUNCTION__, __LINE__); if(items.size() > 0){ map> >::iterator itr; sint32 bag_id = 0; for(itr = items.begin(); itr != items.end(); itr++){ bag_id = itr->first; if(items[bag_id].count(0)) ret += items[bag_id][BASE_EQUIPMENT].size(); } } MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return ret; } bool PlayerItemList::MoveItem(sint32 to_bag_id, int16 from_index, sint8 to, int8 appearance_type, int8 charges){ MPlayerItems.writelock(__FUNCTION__, __LINE__); Item* item_from = indexed_items[from_index]; Item* item_to = 0; if(item_from){ if(to_bag_id > 0){ //bag item Item* bag = GetItemFromUniqueID(to_bag_id, true, false); if(bag && bag->details.num_slots > to) item_to = items[to_bag_id][BASE_EQUIPMENT][to]; else{ MPlayerItems.releasewritelock(__FUNCTION__, __LINE__); return false; } } else item_to = items[to_bag_id][BASE_EQUIPMENT][to]; if(charges > 0) { if (item_to && item_from->details.item_id == item_to->details.item_id){ if(item_to->details.count > 0 && item_to->details.count < item_to->stack_count){ int32 total_tmp_price = 0; if((item_to->details.count + item_from->details.count) <= item_to->stack_count){ total_tmp_price = (item_to->GetMaxSellValue()*item_to->details.count) + (item_from->GetMaxSellValue()*item_from->details.count); item_to->details.count += item_from->details.count; indexed_items[from_index] = 0; items[item_from->details.inv_slot_id][BASE_EQUIPMENT].erase(item_from->details.slot_id); item_from->needs_deletion = true; item_to->save_needed = true; } else{ int8 diff = item_to->stack_count - item_to->details.count; total_tmp_price = (item_to->GetMaxSellValue()*item_to->details.count) + (item_from->GetMaxSellValue()*diff); item_to->details.count = item_to->stack_count; item_from->details.count -= diff; item_to->save_needed = true; } item_to->SetMaxSellValue(total_tmp_price/item_to->details.count); MPlayerItems.releasewritelock(__FUNCTION__, __LINE__); return true; } } else { if (item_from->details.count == charges) { MPlayerItems.releasewritelock(__FUNCTION__, __LINE__); if (item_to) MoveItem(item_to, item_from->details.inv_slot_id, item_from->details.slot_id, BASE_EQUIPMENT, true); MoveItem(item_from, to_bag_id, to, BASE_EQUIPMENT, item_to ? false:true); } else { MPlayerItems.releasewritelock(__FUNCTION__, __LINE__); if (item_to) { MPlayerItems.releasewritelock(__FUNCTION__, __LINE__); return false; } item_from->details.count -= charges; Item* new_item = new Item(master_item_list.GetItem(item_from->details.item_id)); new_item->details.count = charges; new_item->details.slot_id = to; new_item->details.inv_slot_id = to_bag_id; new_item->details.appearance_type = 0; new_item->save_needed = true; AddItem(new_item); if (item_from->details.count == 0) RemoveItem(item_from); } return true; } } else if(item_to && item_to->IsBag() && item_to->details.num_slots > 0){ // if item we are moving is a bag if (item_from->IsBag() && item_from->details.num_slots > 0) { for (int8 i = 0; i < item_from->details.num_slots; i++) { // if there is something in the bag return, can't put bags with items into other bags if (items[item_from->details.bag_id][BASE_EQUIPMENT].count(i) != 0) { MPlayerItems.releasewritelock(__FUNCTION__, __LINE__); return false; } } } if(items.count(item_to->details.bag_id) > 0){ for(int8 i=0;idetails.num_slots;i++){ if(items[item_to->details.bag_id][BASE_EQUIPMENT].count(i) == 0){ MoveItem(item_from, item_to->details.bag_id, i, 0, true); MPlayerItems.releasewritelock(__FUNCTION__, __LINE__); return true; } } } else{ MPlayerItems.releasewritelock(__FUNCTION__, __LINE__); MoveItem(item_from, item_to->details.bag_id, 0, BASE_EQUIPMENT, true); return true; } } MPlayerItems.releasewritelock(__FUNCTION__, __LINE__); if (item_to) MoveItem(item_to, item_from->details.inv_slot_id, item_from->details.slot_id, BASE_EQUIPMENT, true); MoveItem(item_from, to_bag_id, to, BASE_EQUIPMENT, item_to ? false:true); return true; } MPlayerItems.releasewritelock(__FUNCTION__, __LINE__); return false; } EQ2Packet* PlayerItemList::serialize(Player* player, int16 version){ EQ2Packet* app = 0; PacketStruct* packet = configReader.getStruct("WS_UpdateInventory",version); Item* item = 0; MPlayerItems.readlock(__FUNCTION__, __LINE__); if(packet && indexed_items.size() > 0){ int8 packet_size = 0; int16 size = indexed_items.size(); if (overflowItems.size() > 0) size++; PacketStruct* packet2 = configReader.getStruct("Substruct_Item", version); packet_size = packet2->GetTotalPacketSize(); safe_delete(packet2); packet->setArrayLengthByName("item_count", size); if(packet_count < size){ if(!orig_packet){ xor_packet = new uchar[packet_size * size]; orig_packet = new uchar[packet_size * size]; memset(xor_packet, 0, packet_size * size); memset(orig_packet, 0, packet_size * size); } else{ uchar* tmp = new uchar[packet_size * size]; memset(tmp, 0, packet_size * size); memcpy(tmp, orig_packet, packet_size * packet_count); safe_delete_array(orig_packet); orig_packet = tmp; safe_delete_array(xor_packet); xor_packet = new uchar[packet_size * size]; } } packet_count = size; for(int16 i = 0; i < indexed_items.size(); i++){ item = indexed_items[i]; if (item && item->details.item_id > 0) AddItemToPacket(packet, player, item, i); } if (overflowItems.size() > 0) { // We have overflow items, lets get the first one item = overflowItems.at(0); // Lets make sure the item is valid if (item && item->details.item_id > 0) { // Set the slot to 6 as that is what overflow requires to work item->details.slot_id = 6; // now add it to the packet AddItemToPacket(packet, player, item, size - 1, true); } } LogWrite(ITEM__PACKET, 0, "Items", "Dump/Print Packet in func: %s, line: %i", __FUNCTION__, __LINE__); #if EQDEBUG >= 9 packet->PrintPacket(); #endif packet->setDataByName("equip_flag",0); app = packet->serializeCountPacket(version, 1, orig_packet, xor_packet); safe_delete(packet); } MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return app; } void PlayerItemList::AddItemToPacket(PacketStruct* packet, Player* player, Item* item, int16 i, bool overflow){ Client *client; int8 tmp_subtype = 0; if (!packet || !player) return; client = player->GetZone()->GetClientBySpawn(player); if (!client) return; int32 menu_data = 3; if(item->slot_data.size() > 0) menu_data -= ITEM_MENU_TYPE_GENERIC; if (item->details.num_slots > 0) { if (packet->GetVersion() <= 283 && item->details.num_slots > CLASSIC_EQ_MAX_BAG_SLOTS) item->details.num_slots = CLASSIC_EQ_MAX_BAG_SLOTS; menu_data += ITEM_MENU_TYPE_BAG; if (item->details.num_free_slots == item->details.num_slots) menu_data += ITEM_MENU_TYPE_EMPTY_BAG; } if (item->details.item_id == 21355) { //menu_data += ITEM_MENU_TYPE_GENERIC; //menu_data += ITEM_MENU_TYPE_EQUIP; menu_data += ITEM_MENU_TYPE_BOOK; //menu_data += ITEM_MENU_TYPE_BAG; //menu_data += ITEM_MENU_TYPE_HOUSE; //menu_data += ITEM_MENU_TYPE_TEST12; //menu_data += ITEM_MENU_TYPE_SCRIBE; //menu_data += ITEM_MENU_TYPE_TEST13; //menu_data += ITEM_MENU_TYPE_INVALID; //menu_data += ITEM_MENU_TYPE_TEST14; //menu_data += ITEM_MENU_TYPE_BROKEN; } if (item->details.item_id == 21356) { //menu_data += ITEM_MENU_TYPE_TEST15; menu_data += ITEM_MENU_TYPE_ATTUNED; menu_data += ITEM_MENU_TYPE_ATTUNEABLE; menu_data += ITEM_MENU_TYPE_BOOK; menu_data += ITEM_MENU_TYPE_DISPLAY_CHARGES; menu_data += ITEM_MENU_TYPE_TEST1; menu_data += ITEM_MENU_TYPE_NAMEPET; menu_data += ITEM_MENU_TYPE_MENTORED; menu_data += ITEM_MENU_TYPE_CONSUME; menu_data += ITEM_MENU_TYPE_USE; } if (item->details.item_id == 21357) { menu_data += ITEM_MENU_TYPE_CONSUME_OFF ; menu_data += ITEM_MENU_TYPE_TEST3 ; menu_data += ITEM_MENU_TYPE_TEST4 ; menu_data += ITEM_MENU_TYPE_TEST5 ; menu_data += ITEM_MENU_TYPE_TEST6 ; menu_data += ITEM_MENU_TYPE_TEST7 ; menu_data += ITEM_MENU_TYPE_TEST8 ; menu_data += ITEM_MENU_TYPE_TEST9 ; menu_data += ITEM_MENU_TYPE_DAMAGED ; menu_data += ITEM_MENU_TYPE_BROKEN2 ; menu_data += ITEM_MENU_TYPE_REDEEM ; menu_data += ITEM_MENU_TYPE_TEST10 ; menu_data += ITEM_MENU_TYPE_UNPACK ; } if(item->IsSkill()){ Spell* spell = master_spell_list.GetSpell(item->skill_info->spell_id, item->skill_info->spell_tier); if (spell && spell->ScribeAllowed(player)) menu_data += ITEM_MENU_TYPE_SCRIBE; else menu_data += ITEM_MENU_TYPE_INSUFFICIENT_KNOWLEDGE; } if(item->IsRecipeBook()){ //TODO: Add check to allow scribe menu_data += ITEM_MENU_TYPE_SCRIBE; } if (item->generic_info.item_type == 10){ menu_data += ITEM_MENU_TYPE_TEST1; menu_data += ITEM_MENU_TYPE_HOUSE; } if (item->generic_info.item_type == 18){ menu_data += ITEM_MENU_TYPE_UNPACK; packet->setSubstructArrayDataByName("items", "unknown3", ITEM_MENU_TYPE2_UNPACK, 0, i); } if(item->generic_info.condition == 0) menu_data += ITEM_MENU_TYPE_BROKEN; if (client->GetVersion() <= 283){ string flags; if (item->CheckFlag(NO_TRADE)) flags += "NO-TRADE "; if (item->CheckFlag(NO_VALUE)) flags += "NO-VALUE "; if (flags.length() > 0) packet->setSubstructArrayDataByName("items", "flag_names", flags.c_str(), 0, i); } if (item->CheckFlag(ATTUNED) || item->CheckFlag(NO_TRADE)) { if (client->GetVersion() <= 283) menu_data += ORIG_ITEM_MENU_TYPE_ATTUNED; else menu_data += ITEM_MENU_TYPE_ATTUNED; } else if (item->CheckFlag(ATTUNEABLE)) { if (client->GetVersion() <= 283) menu_data += ORIG_ITEM_MENU_TYPE_ATTUNEABLE; else menu_data += ITEM_MENU_TYPE_ATTUNEABLE; } if (item->generic_info.usable == 1) menu_data += ITEM_MENU_TYPE_USE; if (item->details.count > 0 && item->stack_count > 1) { if (client->GetVersion() <= 283) menu_data += ORIG_ITEM_MENU_TYPE_STACKABLE; else menu_data += ITEM_MENU_TYPE_DISPLAY_CHARGES; } if(item->details.item_locked) { menu_data += ITEM_MENU_TYPE_BROKEN; // broken is also used to lock item during crafting } // Added the if (overflow) so mouseover examines work properly if (overflow) packet->setSubstructArrayDataByName("items", "unique_id", item->details.item_id, 0, i); else packet->setSubstructArrayDataByName("items", "unique_id", item->details.unique_id, 0, i); packet->setSubstructArrayDataByName("items", "bag_id", item->details.bag_id, 0, i); packet->setSubstructArrayDataByName("items", "inv_slot_id", item->details.inv_slot_id, 0, i); packet->setSubstructArrayDataByName("items", "menu_type", menu_data, 0, i); if (overflow) packet->setSubstructArrayDataByName("items", "index", 0xFFFF, 0, i); else { packet->setSubstructArrayDataByName("items", "index", i, 0, i); item->details.index = i; } packet->setSubstructArrayDataByName("items", "icon", item->details.icon, 0, i); packet->setSubstructArrayDataByName("items", "slot_id", item->details.slot_id, 0, i); if (client->GetVersion() <= 1208) { packet->setSubstructArrayDataByName("items", "count", (std::min)(item->details.count, (int16)255), 0, i); } else packet->setSubstructArrayDataByName("items", "count", item->details.count, 0, i); //packet->setSubstructArrayDataByName("items", "unknown4", 5, 0, i); // need item level packet->setSubstructArrayDataByName("items", "item_level", item->details.recommended_level , 0, i); packet->setSubstructArrayDataByName("items", "tier", item->details.tier, 0, i); packet->setSubstructArrayDataByName("items", "num_slots", item->details.num_slots, 0, i); // need empty slots packet->setSubstructArrayDataByName("items", "item_id", item->details.item_id, 0, i); //need broker id packet->setSubstructArrayDataByName("items", "name", item->name.c_str(), 0, i); } bool PlayerItemList::AddOverflowItem(Item* item) { bool ret = false; MPlayerItems.writelock(__FUNCTION__, __LINE__); if (item && item->details.item_id > 0 && overflowItems.size() < 255) { item->details.slot_id = 6; item->details.inv_slot_id = -2; overflowItems.push_back(item); ret = true; } MPlayerItems.releasewritelock(__FUNCTION__, __LINE__); return ret; } Item* PlayerItemList::GetOverflowItem() { return overflowItems.at(0); } void PlayerItemList::RemoveOverflowItem(Item* item) { MPlayerItems.writelock(__FUNCTION__, __LINE__); vector::iterator itr = std::find(overflowItems.begin(), overflowItems.end(), item); overflowItems.erase(itr); MPlayerItems.releasewritelock(__FUNCTION__, __LINE__); } vector* PlayerItemList::GetOverflowItemList() { vector* ret = new vector; MPlayerItems.readlock(__FUNCTION__, __LINE__); vector::iterator itr= ret->begin(); ret->insert(itr, overflowItems.begin(), overflowItems.end()); MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return ret; } bool PlayerItemList::HasItem(int32 id, bool include_bank){ map> >::iterator itr; map::iterator slot_itr; MPlayerItems.readlock(__FUNCTION__, __LINE__); for(itr = items.begin(); itr != items.end(); itr++){ if(include_bank || (!include_bank && itr->first >= 0)){ for(slot_itr=itr->second[BASE_EQUIPMENT].begin();slot_itr!=itr->second[BASE_EQUIPMENT].end(); slot_itr++){ if(slot_itr->second && slot_itr->second->details.item_id == id){ MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return true; } } for(slot_itr=itr->second[APPEARANCE_EQUIPMENT].begin();slot_itr!=itr->second[APPEARANCE_EQUIPMENT].end(); slot_itr++){ if(slot_itr->second && slot_itr->second->details.item_id == id){ MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return true; } } } } MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return false; } bool PlayerItemList::SharedBankAddAllowed(Item* item){ if(!item || item->CheckFlag(NO_TRADE)) return false; MPlayerItems.readlock(__FUNCTION__, __LINE__); if(item->IsBag() && items.count(item->details.bag_id) > 0){ map::iterator itr; for(itr = items[item->details.bag_id][BASE_EQUIPMENT].begin(); itr != items[item->details.bag_id][BASE_EQUIPMENT].end(); itr++){ if(itr->second->CheckFlag(NO_TRADE)){ MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return false; } } } MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return true; } vector* PlayerItemList::GetItemsFromBagID(sint32 bag_id){ vector* ret = new vector; if(items.count(bag_id) > 0){ MPlayerItems.readlock(__FUNCTION__, __LINE__); map::iterator itr; map::iterator itr2; Item* item = 0; for(itr = items[bag_id][BASE_EQUIPMENT].begin(); itr != items[bag_id][BASE_EQUIPMENT].end(); itr++){ item = itr->second; if(item) ret->push_back(item); } MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); } return ret; } vector* PlayerItemList::GetItemsInBag(Item* bag){ vector* ret_items = new vector; MPlayerItems.readlock(__FUNCTION__, __LINE__); if(bag && bag->IsBag() && items.count(bag->details.bag_id) > 0){ map::iterator itr; for(itr = items[bag->details.bag_id][BASE_EQUIPMENT].begin(); itr != items[bag->details.bag_id][BASE_EQUIPMENT].end(); itr++){ ret_items->push_back(itr->second); } } MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return ret_items; } Item* PlayerItemList::GetItemFromID(int32 id, int8 count, bool include_bank, bool lock){ //first check for an exact count match map> >::iterator itr; map::iterator slot_itr; if(lock) MPlayerItems.readlock(__FUNCTION__, __LINE__); for(itr = items.begin(); itr != items.end(); itr++){ if(include_bank || (!include_bank && itr->first >= 0)){ for(int8 i=0;isecond[i].begin();slot_itr!=itr->second[i].end(); slot_itr++){ if(slot_itr->second && slot_itr->second->details.item_id == id && (count == 0 || slot_itr->second->details.count == count)){ if(lock) MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return slot_itr->second; } } } } } //couldn't find an exact match, look for closest Item* closest = 0; for(itr = items.begin(); itr != items.end(); itr++){ if(include_bank || (!include_bank && itr->first >= 0)){ for(int8 i=0;isecond[i].begin();slot_itr!=itr->second[i].end(); slot_itr++){ if(slot_itr->second && slot_itr->second->details.item_id == id && slot_itr->second->details.count > count && (closest == 0 || slot_itr->second->details.count < closest->details.count)) closest = slot_itr->second; } } } } if(lock) MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return closest; } sint32 PlayerItemList::GetAllStackCountItemFromID(int32 id, int8 count, bool include_bank, bool lock){ sint32 stack_count = 0; //first check for an exact count match map> >::iterator itr; map::iterator slot_itr; if(lock) MPlayerItems.readlock(__FUNCTION__, __LINE__); for(itr = items.begin(); itr != items.end(); itr++){ if(include_bank || (!include_bank && itr->first >= 0)){ for(int8 i=0;isecond[i].begin();slot_itr!=itr->second[i].end(); slot_itr++){ if(slot_itr->second && slot_itr->second->details.item_id == id && (count == 0 || slot_itr->second->details.count == count)){ stack_count += slot_itr->second->details.count; } } } } } //couldn't find an exact match, look for closest Item* closest = 0; for(itr = items.begin(); itr != items.end(); itr++){ if(include_bank || (!include_bank && itr->first >= 0)){ for(int8 i=0;isecond[i].begin();slot_itr!=itr->second[i].end(); slot_itr++){ if(slot_itr->second && slot_itr->second->details.item_id == id && slot_itr->second->details.count > count && (closest == 0 || slot_itr->second->details.count < closest->details.count)) stack_count += slot_itr->second->details.count; } } } } if(lock) MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return stack_count; } Item* PlayerItemList::GetItemFromUniqueID(int32 id, bool include_bank, bool lock){ map> >::iterator itr; map::iterator slot_itr; if(lock) MPlayerItems.readlock(__FUNCTION__, __LINE__); for(itr = items.begin(); itr != items.end(); itr++){ if(include_bank || (!include_bank && itr->first >= 0)){ for(slot_itr=itr->second[0].begin();slot_itr!=itr->second[0].end(); slot_itr++){ if(slot_itr->second && slot_itr->second->details.unique_id == id){ if(lock) MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return slot_itr->second; } } for(slot_itr=itr->second[1].begin();slot_itr!=itr->second[1].end(); slot_itr++){ if(slot_itr->second && slot_itr->second->details.unique_id == id){ if(lock) MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return slot_itr->second; } } } } if(lock) MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return 0; } bool PlayerItemList::HasFreeBankSlot() { bool ret = false; MPlayerItems.readlock(__FUNCTION__, __LINE__); if (items[-3][BASE_EQUIPMENT].size() < 12) //12 slots in the bank ret = true; MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return ret; } int8 PlayerItemList::FindFreeBankSlot() { int8 ret = 0; MPlayerItems.readlock(__FUNCTION__, __LINE__); for (int8 i = 0; i < 12; i++) { //12 slots in the bank if (items[-3][BASE_EQUIPMENT].count(i) == 0) { ret = i; break; } } MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return ret; } void PlayerItemList::ResetPackets() { safe_delete_array(orig_packet); safe_delete_array(xor_packet); orig_packet = 0; xor_packet = 0; packet_count = 0; } int32 PlayerItemList::CheckSlotConflict(Item* item, bool check_lore_only, bool lock, int16* lore_stack_count) { bool is_lore = false; bool is_stack_lore = false; if(!(is_lore = item->CheckFlag(LORE)) && !(is_stack_lore = item->CheckFlag(STACK_LORE)) && check_lore_only) { return 0; } if(!check_lore_only && !is_lore && !is_stack_lore && !item->CheckFlag(LORE_EQUIP)) { return 0; } int32 conflict = 0; if(lock) MPlayerItems.readlock(__FUNCTION__, __LINE__); map> >::iterator itr; map::iterator slot_itr; for(itr = items.begin(); itr != items.end(); itr++){ for(slot_itr=itr->second[0].begin();slot_itr!=itr->second[0].end(); slot_itr++){ if(slot_itr->second && slot_itr->second->details.item_id == item->details.item_id){ if(lore_stack_count) { *lore_stack_count += slot_itr->second->details.count; } if(!is_stack_lore && slot_itr->second->CheckFlag(LORE)) { conflict = LORE; break; } else if(is_stack_lore && (*lore_stack_count + item->details.count) > slot_itr->second->stack_count) { conflict = STACK_LORE; break; } else if(!check_lore_only && slot_itr->second->CheckFlag(LORE_EQUIP)) { conflict = LORE_EQUIP; break; } } } if(conflict > 0) break; for(slot_itr=itr->second[1].begin();slot_itr!=itr->second[1].end(); slot_itr++){ if(slot_itr->second && slot_itr->second->details.item_id == item->details.item_id){ if(lore_stack_count) { *lore_stack_count += slot_itr->second->details.count; } if(!is_stack_lore && slot_itr->second->CheckFlag(LORE)) { conflict = LORE; break; } else if(is_stack_lore && (*lore_stack_count + item->details.count) > slot_itr->second->stack_count) { conflict = STACK_LORE; break; } else if(!check_lore_only && slot_itr->second->CheckFlag(LORE_EQUIP)) { conflict = LORE_EQUIP; break; } } } if(conflict > 0) break; } if(lock) MPlayerItems.releasereadlock(__FUNCTION__, __LINE__); return conflict; } EquipmentItemList::EquipmentItemList(){ orig_packet = 0; xor_packet = 0; for(int8 i=0;iname.c_str(), slot, item->name.c_str()); return false; } SetItem(slot, item, true); if (item->details.unique_id == 0) { GetItem(slot)->details.unique_id = MasterItemList::NextUniqueID(); if (item->IsBag()) item->details.bag_id = item->details.unique_id; } MEquipmentItems.unlock(); return true; } return false; } int8 EquipmentItemList::GetNumberOfItems(){ int8 ret = 0; MEquipmentItems.lock(); for(int8 i=0;idetails.inv_slot_id = 0; item->details.slot_id = slot_id; item->details.index = slot_id; item->details.appearance_type = GetAppearanceType(); items[slot_id] = item; if(!locked) MEquipmentItems.unlock(); } vector* EquipmentItemList::GetAllEquippedItems(){ vector* ret = new vector; MEquipmentItems.lock(); for(int8 i=0;ipush_back(items[i]); } MEquipmentItems.unlock(); return ret; } Item* EquipmentItemList::GetItem(int8 slot_id){ return items[slot_id]; } void EquipmentItemList::SendEquippedItems(Player* player){ if(!player->GetClient()) return; for(int16 i=0;idetails.item_id > 0) player->GetClient()->QueuePacket(item->serialize(player->GetClient()->GetVersion(), false, player)); } } EQ2Packet* EquipmentItemList::serialize(int16 version, Player* player){ EQ2Packet* app = 0; Item* item = 0; PacketStruct* packet = configReader.getStruct("WS_UpdateInventory", version); if(packet){ int8 packet_size = 0; PacketStruct* packet2 = configReader.getStruct("Substruct_Item", version); packet_size = packet2->GetTotalPacketSize(); safe_delete(packet2); int8 num_slots = NUM_SLOTS; if (version <= 564) num_slots = 22; packet->setArrayLengthByName("item_count", num_slots); if(!orig_packet){ xor_packet = new uchar[packet_size* num_slots]; orig_packet = new uchar[packet_size* num_slots]; memset(xor_packet, 0, packet_size* num_slots); memset(orig_packet, 0, packet_size* num_slots); } MEquipmentItems.lock(); int32 menu_data = 3; int32 effective_level = player->GetInfoStructUInt("effective_level"); int32 levelsLowered = (effective_level > 0 && effective_level < player->GetLevel()) ? player->GetLevel() - effective_level : 0; for(int16 i=0;idetails.item_id > 0){ if(item->slot_data.size() > 0) menu_data -= ITEM_MENU_TYPE_GENERIC; if (item->details.num_slots > 0) { if (packet->GetVersion() <= 283 && item->details.num_slots > CLASSIC_EQ_MAX_BAG_SLOTS) item->details.num_slots = CLASSIC_EQ_MAX_BAG_SLOTS; menu_data += ITEM_MENU_TYPE_BAG; if (item->details.num_free_slots == item->details.num_slots) menu_data += ITEM_MENU_TYPE_EMPTY_BAG; } if(item->IsSkill()) menu_data += ITEM_MENU_TYPE_SCRIBE; if(item->generic_info.condition == 0) menu_data += ITEM_MENU_TYPE_BROKEN2; else if (item->generic_info.condition <= 20) menu_data += ITEM_MENU_TYPE_DAMAGED; if (item->CheckFlag(ATTUNED) || item->CheckFlag(NO_TRADE)) { if (version <= 283) menu_data += ORIG_ITEM_MENU_TYPE_ATTUNED; else menu_data += ITEM_MENU_TYPE_ATTUNED; } else if (item->CheckFlag(ATTUNEABLE)) { if (version <= 283) menu_data += ORIG_ITEM_MENU_TYPE_ATTUNEABLE; else menu_data += ITEM_MENU_TYPE_ATTUNEABLE; } if (item->generic_info.usable == 1) menu_data += ITEM_MENU_TYPE_USE; if (item->IsFood()) { if (version <= 283) { if (item->IsFoodDrink()) menu_data += ORIG_ITEM_MENU_TYPE_DRINK; else menu_data += ORIG_ITEM_MENU_TYPE_FOOD; } else { menu_data += ITEM_MENU_TYPE_CONSUME; if (player && ((item->IsFoodFood() && player->get_character_flag(CF_FOOD_AUTO_CONSUME)) || (item->IsFoodDrink() && player->get_character_flag(CF_DRINK_AUTO_CONSUME)))) { // needs all 3 to display 'auto consume' off option as well as set the yellowish tint in the background menu_data += ITEM_MENU_TYPE_CONSUME_OFF; menu_data += ORIG_ITEM_MENU_TYPE_DRINK; menu_data += ORIG_ITEM_MENU_TYPE_FOOD; } } } packet->setSubstructArrayDataByName("items", "unique_id", item->details.unique_id, 0, i); packet->setSubstructArrayDataByName("items", "bag_id", item->details.bag_id, 0, i); packet->setSubstructArrayDataByName("items", "inv_slot_id", item->details.inv_slot_id, 0, i); if (item->details.count > 0 && item->stack_count > 1) { if (version <= 283) menu_data += ORIG_ITEM_MENU_TYPE_STACKABLE; else menu_data += ITEM_MENU_TYPE_DISPLAY_CHARGES; } if(levelsLowered && item->details.recommended_level > effective_level) menu_data += ITEM_MENU_TYPE_MENTORED; packet->setSubstructArrayDataByName("items", "menu_type", menu_data, 0, i); packet->setSubstructArrayDataByName("items", "icon", item->details.icon, 0, i); packet->setSubstructArrayDataByName("items", "slot_id", item->details.slot_id, 0, i); packet->setSubstructArrayDataByName("items", "count", item->details.count, 0, i); // item level needed here packet->setSubstructArrayDataByName("items", "tier", item->details.tier, 0, i); packet->setSubstructArrayDataByName("items", "num_slots", item->details.num_slots, 0, i); //empty slots needed here packet->setSubstructArrayDataByName("items", "item_id", item->details.item_id, 0, i); //broker id needed here packet->setSubstructArrayDataByName("items", "name", item->name.c_str(), 0, i); //packet->setSubstructArrayDataByName("items", "unknown4", 10, 0, i); item->details.index = i; } packet->setSubstructArrayDataByName("items", "index", i, 0, i); } MEquipmentItems.unlock(); packet->setDataByName("equip_flag", GetAppearanceType() ? 2 : 1); app = packet->serializeCountPacket(version, 1, orig_packet, xor_packet); safe_delete(packet); } return app; } ItemStatsValues* EquipmentItemList::CalculateEquipmentBonuses(Entity* entity){ ItemStatsValues* stats = new ItemStatsValues; memset(stats, 0, sizeof(ItemStatsValues)); entity->GetInfoStruct()->set_mitigation_base(0); MEquipmentItems.lock(); for(int8 i=0;idetails.item_id > 0){ master_item_list.CalculateItemBonuses(items[i], entity, stats); if (items[i]->armor_info && !items[i]->IsShield()) entity->GetInfoStruct()->add_mitigation_base(items[i]->armor_info->mitigation_high); } } MEquipmentItems.unlock(); return stats; } bool EquipmentItemList::HasItem(int32 id){ MEquipmentItems.lock(); for(int8 i=0;idetails.item_id == id){ MEquipmentItems.unlock(); return true; } } MEquipmentItems.unlock(); return false; } void EquipmentItemList::RemoveItem(int8 slot, bool delete_item){ if(slot < NUM_SLOTS){ MEquipmentItems.lock(); if(items[slot] && items[slot]->details.appearance_type) items[slot]->details.appearance_type = 0; if(delete_item){ safe_delete(items[slot]); } items[slot] = 0; MEquipmentItems.unlock(); } } Item* EquipmentItemList::GetItemFromUniqueID(int32 item_id){ MEquipmentItems.lock(); for(int8 i=0;idetails.unique_id == item_id){ MEquipmentItems.unlock(); return items[i]; } } MEquipmentItems.unlock(); return 0; } Item* EquipmentItemList::GetItemFromItemID(int32 item_id) { Item* item = 0; MEquipmentItems.lock(); for(int8 i = 0; i < NUM_SLOTS; i++) { if(items[i] && items[i]->details.item_id == item_id) { item = items[i]; break; } } MEquipmentItems.unlock(); return item; } bool EquipmentItemList::CanItemBeEquippedInSlot(Item* tmp, int8 slot){ MEquipmentItems.lock(); for(int8 i=0;tmp && islot_data.size();i++){ if(tmp->slot_data[i] == slot){ MEquipmentItems.unlock(); return true; } } MEquipmentItems.unlock(); return false; } bool EquipmentItemList::CheckEquipSlot(Item* tmp, int8 slot){ MEquipmentItems.lock(); for(int8 i=0;tmp && islot_data.size();i++){ if(tmp->slot_data[i] == slot){ Item* tmp_item = GetItem(tmp->slot_data[i]); if(!tmp_item || tmp_item->details.item_id == 0){ if(slot == EQ2_SECONDARY_SLOT) { Item* primary = GetItem(EQ2_PRIMARY_SLOT); if(primary && primary->weapon_info->wield_type == ITEM_WIELD_TYPE_TWO_HAND) continue; } MEquipmentItems.unlock(); return true; } } } MEquipmentItems.unlock(); return false; } int8 EquipmentItemList::GetFreeSlot(Item* tmp, int8 slot_id){ int8 slot = 0; MEquipmentItems.lock(); for(int8 i=0;tmp && islot_data.size();i++){ slot = tmp->slot_data[i]; if(slot_id == 255 || slot == slot_id){ Item* tmp_item = GetItem(slot); if(!tmp_item || tmp_item->details.item_id == 0){ if(slot == EQ2_SECONDARY_SLOT) { Item* primary = GetItem(EQ2_PRIMARY_SLOT); if(primary && primary->weapon_info->wield_type == ITEM_WIELD_TYPE_TWO_HAND) continue; } MEquipmentItems.unlock(); return slot; } else if ( slot == EQ2_LRING_SLOT || slot == EQ2_EARS_SLOT_1 || slot == EQ2_LWRIST_SLOT || slot == EQ2_CHARM_SLOT_1) { Item* rslot = GetItem(slot+1); if(!rslot) { MEquipmentItems.unlock(); return slot+1; } } } } MEquipmentItems.unlock(); return 255; } int32 EquipmentItemList::CheckSlotConflict(Item* item, bool check_lore_only, int16* lore_stack_count) { bool is_lore = false; bool is_stack_lore = false; if(!(is_lore = item->CheckFlag(LORE)) && !(is_stack_lore = item->CheckFlag(STACK_LORE)) && check_lore_only) { return 0; } if(!check_lore_only && !is_lore && !is_stack_lore && !item->CheckFlag(LORE_EQUIP)) { return 0; } int32 conflict = 0; MEquipmentItems.lock(); for(int8 i=0;idetails.item_id == item->details.item_id) { if(lore_stack_count) *lore_stack_count += items[i]->details.count; if(!is_stack_lore && items[i]->CheckFlag(LORE)) { conflict = LORE; break; } else if(is_stack_lore && (*lore_stack_count + item->details.count) > items[i]->stack_count) { conflict = STACK_LORE; break; } else if(!check_lore_only && items[i]->CheckFlag(LORE_EQUIP)) { conflict = LORE_EQUIP; break; } } } MEquipmentItems.unlock(); return conflict; } int8 EquipmentItemList::GetSlotByItem(Item* item) { int8 slot = 255; for (int8 i = 0; i < NUM_SLOTS; i++) { if (items[i] && items[i] == item) { slot = i; break; } } return slot; } string Item::CreateItemLink(int16 client_Version, bool bUseUniqueID) { ostringstream ss; if(client_Version > 546) ss << "\\aITEM " << details.item_id << ' ' << (bUseUniqueID ? details.unique_id : 0) << ':' << name << "\\/a"; else { if(bUseUniqueID) ss << "\\aITEM " << details.item_id << ' ' << details.unique_id << ':' << name << "\\/a"; else ss << "\\aITEM " << details.item_id << ' ' << name << ':' << name << "\\/a"; } return ss.str(); } int32 MasterItemList::GetItemStatIDByName(std::string name) { boost::to_lower(name); map::iterator itr = mappedItemStatsStrings.find(name.c_str()); if(itr != mappedItemStatsStrings.end()) return itr->second; return 0xFFFFFFFF; } std::string MasterItemList::GetItemStatNameByID(int32 id) { map::iterator itr = mappedItemStatTypeIDs.find(id); if(itr != mappedItemStatTypeIDs.end()) return itr->second; return std::string(""); }