diff --git a/sql/mangos.sql b/sql/mangos.sql index d16aae93c..085827060 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -24,7 +24,7 @@ CREATE TABLE `db_version` ( `version` varchar(120) default NULL, `creature_ai_version` varchar(120) default NULL, `cache_id` int(10) default '0', - `required_11827_01_mangos_creature_linking_template` bit(1) default NULL + `required_11831_02_mangos_command` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -581,6 +581,7 @@ INSERT INTO `command` VALUES ('event stop',2,'Syntax: .event stop #event_id\r\nStop event #event_id. Set start time for event to time in past that make current moment is event stop time (change not saved in DB).'), ('explorecheat',3,'Syntax: .explorecheat #flag\r\n\r\nReveal or hide all maps for the selected player. If no player is selected, hide or reveal maps to you.\r\n\r\nUse a #flag of value 1 to reveal, use a #flag value of 0 to hide all maps.'), ('flusharenapoints','3','Syntax: .flusharenapoints\r\n\r\nUse it to distribute arena points based on arena team ratings, and start a new week.'), +('gearscore',3,'Syntax: .gearscore [#withBags] [#withBank]\r\n\r\nShow selected player\'s gear score. Check items in bags if #withBags != 0 and check items in Bank if #withBank != 0. Default: 1 for bags and 0 for bank'), ('gm',1,'Syntax: .gm [on/off]\r\n\r\nEnable or Disable in game GM MODE or show current state of on/off not provided.'), ('gm chat',1,'Syntax: .gm chat [on/off]\r\n\r\nEnable or disable chat GM MODE (show gm badge in messages) or show current state of on/off not provided.'), ('gm fly',3,'Syntax: .gm fly [on/off]\r\nEnable/disable gm fly mode.'), @@ -3965,6 +3966,7 @@ INSERT INTO `mangos_string` VALUES (1189,'Yellow',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (1190,'Amount of %s items is set to %u.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (1191,'Items ratio for %s is set to %u.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), +(1193,'Gear Score of Player %s is %u.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (1200,'You try to view cinemitic %u but it doesn\'t exist.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (1201,'You try to view movie %u but it doesn\'t exist.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), (1202,'Spell %u %s = %f (*1.88 = %f) DB = %f AP = %f',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL), diff --git a/sql/updates/11831_01_mangos_mangos_string.sql b/sql/updates/11831_01_mangos_mangos_string.sql new file mode 100644 index 000000000..591a35c38 --- /dev/null +++ b/sql/updates/11831_01_mangos_mangos_string.sql @@ -0,0 +1,4 @@ +ALTER TABLE db_version CHANGE COLUMN required_11827_01_mangos_creature_linking_template required_11831_01_mangos_mangos_string bit; + +delete from mangos_string where entry = 1193; +insert into mangos_string values (1193,'Gear Score of Player %s is %u.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); \ No newline at end of file diff --git a/sql/updates/11831_02_mangos_command.sql b/sql/updates/11831_02_mangos_command.sql new file mode 100644 index 000000000..e8b4a0a93 --- /dev/null +++ b/sql/updates/11831_02_mangos_command.sql @@ -0,0 +1,5 @@ +ALTER TABLE db_version CHANGE COLUMN required_11831_01_mangos_mangos_string required_11831_02_mangos_command bit; + +DELETE FROM command WHERE name = 'gearscore'; +INSERT INTO command (name, security, help) VALUES +('gearscore',3,'Syntax: .gearscore [#withBags] [#withBank]\r\n\r\nShow selected player\'s gear score. Check items in bags if #withBags != 0 and check items in Bank if #withBank != 0. Default: 1 for bags and 0 for bank'); \ No newline at end of file diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index 4ff6696db..81de25cbb 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -812,6 +812,7 @@ ChatCommand * ChatHandler::getCommandTable() { "stable", SEC_ADMINISTRATOR, false, &ChatHandler::HandleStableCommand, "", NULL }, { "waterwalk", SEC_GAMEMASTER, false, &ChatHandler::HandleWaterwalkCommand, "", NULL }, { "quit", SEC_CONSOLE, true, &ChatHandler::HandleQuitCommand, "", NULL }, + { "gearscore", SEC_ADMINISTRATOR, false, &ChatHandler::HandleShowGearScoreCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; diff --git a/src/game/Chat.h b/src/game/Chat.h index 87c274421..04f13dd45 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -597,6 +597,7 @@ class MANGOS_DLL_SPEC ChatHandler bool HandleStableCommand(char* args); bool HandleWaterwalkCommand(char* args); bool HandleQuitCommand(char* args); + bool HandleShowGearScoreCommand(char* args); //! Development Commands bool HandleSaveAllCommand(char* args); diff --git a/src/game/Language.h b/src/game/Language.h index 4ee1877de..d325cf4ba 100644 --- a/src/game/Language.h +++ b/src/game/Language.h @@ -938,7 +938,8 @@ enum MangosStrings LANG_AHBOT_ITEMS_AMOUNT = 1190, LANG_AHBOT_ITEMS_RATIO = 1191, LANG_MOVEGENS_EFFECT = 1192, - // Room for more level 3 1193-1199 not used + LANG_GEARSCORE = 1193, + // Room for more level 3 1194-1199 not used // Debug commands LANG_CINEMATIC_NOT_EXIST = 1200, diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index 38429e74a..bc43e0ebe 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -7074,3 +7074,31 @@ bool ChatHandler::HandleModifyGenderCommand(char *args) return true; } + +bool ChatHandler::HandleShowGearScoreCommand(char *args) +{ + Player *player = getSelectedPlayer(); + + if (!player) + { + PSendSysMessage(LANG_PLAYER_NOT_FOUND); + SetSentErrorMessage(true); + return false; + } + + uint32 withBags, withBank; + if (!ExtractOptUInt32(&args, withBags, 1)) + return false; + + if (!ExtractOptUInt32(&args, withBank, 0)) + return false; + + // always recalculate gear score for display + player->ResetCachedGearScore(); + + uint32 gearScore = player->GetEquipGearScore(withBags != 0, withBank != 0); + + PSendSysMessage(LANG_GEARSCORE, GetNameLink(player).c_str(), gearScore); + + return true; +} \ No newline at end of file diff --git a/src/game/Player.cpp b/src/game/Player.cpp index aaac2126c..2188c1a6c 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -553,6 +553,8 @@ Player::Player (WorldSession *session): Unit(), m_mover(this), m_camera(this), m m_lastFallTime = 0; m_lastFallZ = 0; + + m_cachedGS = 0; } Player::~Player () @@ -22938,3 +22940,193 @@ void Player::SetRestType( RestType n_r_type, uint32 areaTriggerId /*= 0*/) SetFFAPvP(false); } } + +uint32 Player::GetEquipGearScore(bool withBags, bool withBank) +{ + if (withBags && withBank && m_cachedGS > 0) + return m_cachedGS; + + GearScoreVec gearScore (EQUIPMENT_SLOT_END); + uint32 twoHandScore = 0; + + for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) + { + gearScore[i] = 0; + } + + for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) + { + if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + _fillGearScoreData(item, &gearScore, twoHandScore); + } + + if (withBags) + { + // check inventory + for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i) + { + if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + _fillGearScoreData(item, &gearScore, twoHandScore); + } + + // check bags + for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i) + { + if(Bag* pBag = (Bag*)GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + { + for(uint32 j = 0; j < pBag->GetBagSize(); ++j) + { + if (Item* item2 = pBag->GetItemByPos(j)) + _fillGearScoreData(item2, &gearScore, twoHandScore); + } + } + } + } + + if (withBank) + { + for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_ITEM_END; ++i) + { + if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + _fillGearScoreData(item, &gearScore, twoHandScore); + } + + for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i) + { + if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) + { + if (item->IsBag()) + { + Bag* bag = (Bag*)item; + for (uint8 j = 0; j < bag->GetBagSize(); ++j) + { + if (Item* item2 = bag->GetItemByPos(j)) + _fillGearScoreData(item2, &gearScore, twoHandScore); + } + } + } + } + } + + uint8 count = EQUIPMENT_SLOT_END - 2; // ignore body and tabard slots + uint32 sum = 0; + + // check if 2h hand is higher level than main hand + off hand + if ((gearScore[EQUIPMENT_SLOT_MAINHAND] + gearScore[EQUIPMENT_SLOT_OFFHAND]) / 2 < twoHandScore) + { + gearScore[EQUIPMENT_SLOT_OFFHAND] = 0; // off hand is ignored in calculations if 2h weapon has higher score + --count; + gearScore[EQUIPMENT_SLOT_MAINHAND] = twoHandScore; + } + + for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i) + { + sum += gearScore[i]; + } + + if (count) + { + uint32 res = uint32(sum / count); + DEBUG_LOG("Player: calculating gear score for %u. Result is %u", GetObjectGuid().GetCounter(), res); + + if (withBags && withBank) + m_cachedGS = res; + + return res; + } + else + return 0; +} + +void Player::_fillGearScoreData(Item* item, GearScoreVec* gearScore, uint32& twoHandScore) +{ + if (!item) + return; + + if (CanUseItem(item->GetProto()) != EQUIP_ERR_OK) + return; + + uint8 type = item->GetProto()->InventoryType; + uint32 level = item->GetProto()->ItemLevel; + + switch (type) + { + case INVTYPE_2HWEAPON: + twoHandScore = std::max(twoHandScore, level); + break; + case INVTYPE_WEAPON: + case INVTYPE_WEAPONMAINHAND: + (*gearScore)[SLOT_MAIN_HAND] = std::max((*gearScore)[SLOT_MAIN_HAND], level); + break; + case INVTYPE_SHIELD: + case INVTYPE_WEAPONOFFHAND: + (*gearScore)[EQUIPMENT_SLOT_OFFHAND] = std::max((*gearScore)[EQUIPMENT_SLOT_OFFHAND], level); + break; + case INVTYPE_THROWN: + case INVTYPE_RANGEDRIGHT: + case INVTYPE_RANGED: + case INVTYPE_QUIVER: + case INVTYPE_RELIC: + (*gearScore)[EQUIPMENT_SLOT_RANGED] = std::max((*gearScore)[EQUIPMENT_SLOT_RANGED], level); + break; + case INVTYPE_HEAD: + (*gearScore)[EQUIPMENT_SLOT_HEAD] = std::max((*gearScore)[EQUIPMENT_SLOT_HEAD], level); + break; + case INVTYPE_NECK: + (*gearScore)[EQUIPMENT_SLOT_NECK] = std::max((*gearScore)[EQUIPMENT_SLOT_NECK], level); + break; + case INVTYPE_SHOULDERS: + (*gearScore)[EQUIPMENT_SLOT_SHOULDERS] = std::max((*gearScore)[EQUIPMENT_SLOT_SHOULDERS], level); + break; + case INVTYPE_BODY: + (*gearScore)[EQUIPMENT_SLOT_BODY] = std::max((*gearScore)[EQUIPMENT_SLOT_BODY], level); + break; + case INVTYPE_CHEST: + (*gearScore)[EQUIPMENT_SLOT_CHEST] = std::max((*gearScore)[EQUIPMENT_SLOT_CHEST], level); + break; + case INVTYPE_WAIST: + (*gearScore)[EQUIPMENT_SLOT_WAIST] = std::max((*gearScore)[EQUIPMENT_SLOT_WAIST], level); + break; + case INVTYPE_LEGS: + (*gearScore)[EQUIPMENT_SLOT_LEGS] = std::max((*gearScore)[EQUIPMENT_SLOT_LEGS], level); + break; + case INVTYPE_FEET: + (*gearScore)[EQUIPMENT_SLOT_FEET] = std::max((*gearScore)[EQUIPMENT_SLOT_FEET], level); + break; + case INVTYPE_WRISTS: + (*gearScore)[EQUIPMENT_SLOT_WRISTS] = std::max((*gearScore)[EQUIPMENT_SLOT_WRISTS], level); + break; + case INVTYPE_HANDS: + (*gearScore)[EQUIPMENT_SLOT_HEAD] = std::max((*gearScore)[EQUIPMENT_SLOT_HEAD], level); + break; + // equipped gear score check uses both rings and trinkets for calculation, assume that for bags/banks it is the same + // with keeping second highest score at second slot + case INVTYPE_FINGER: + { + if ((*gearScore)[EQUIPMENT_SLOT_FINGER1] < level) + { + (*gearScore)[EQUIPMENT_SLOT_FINGER2] = (*gearScore)[EQUIPMENT_SLOT_FINGER1]; + (*gearScore)[EQUIPMENT_SLOT_FINGER1] = level; + } + else if ((*gearScore)[EQUIPMENT_SLOT_FINGER2] < level) + (*gearScore)[EQUIPMENT_SLOT_FINGER2] = level; + break; + } + case INVTYPE_TRINKET: + { + if ((*gearScore)[EQUIPMENT_SLOT_TRINKET1] < level) + { + (*gearScore)[EQUIPMENT_SLOT_TRINKET2] = (*gearScore)[EQUIPMENT_SLOT_TRINKET1]; + (*gearScore)[EQUIPMENT_SLOT_TRINKET1] = level; + } + else if ((*gearScore)[EQUIPMENT_SLOT_TRINKET2] < level) + (*gearScore)[EQUIPMENT_SLOT_TRINKET2] = level; + break; + } + case INVTYPE_CLOAK: + (*gearScore)[EQUIPMENT_SLOT_BACK] = std::max((*gearScore)[EQUIPMENT_SLOT_BACK], level); + break; + default: + break; + } +} \ No newline at end of file diff --git a/src/game/Player.h b/src/game/Player.h index d3bf2160a..d4ad9b21a 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1298,6 +1298,10 @@ class MANGOS_DLL_SPEC Player : public Unit uint32 m_stableSlots; + uint32 GetEquipGearScore(bool withBags = true, bool withBank = false); + void ResetCachedGearScore() { m_cachedGS = 0; } + typedef std::vector GearScoreVec; + /*********************************************************/ /*** GOSSIP SYSTEM ***/ /*********************************************************/ @@ -2590,6 +2594,8 @@ class MANGOS_DLL_SPEC Player : public Unit m_DelayedOperations |= operation; } + void _fillGearScoreData(Item* item, GearScoreVec* gearScore, uint32& twoHandScore); + Unit *m_mover; Camera m_camera; @@ -2634,6 +2640,8 @@ class MANGOS_DLL_SPEC Player : public Unit uint32 m_timeSyncTimer; uint32 m_timeSyncClient; uint32 m_timeSyncServer; + + uint32 m_cachedGS; }; void AddItemsSetItem(Player*player,Item *item); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 1a0d494ed..e73dc8083 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "11830" + #define REVISION_NR "11831" #endif // __REVISION_NR_H__ diff --git a/src/shared/revision_sql.h b/src/shared/revision_sql.h index f5c7624f5..628dbdf67 100644 --- a/src/shared/revision_sql.h +++ b/src/shared/revision_sql.h @@ -1,6 +1,6 @@ #ifndef __REVISION_SQL_H__ #define __REVISION_SQL_H__ #define REVISION_DB_CHARACTERS "required_11785_02_characters_instance" - #define REVISION_DB_MANGOS "required_11827_01_mangos_creature_linking_template" + #define REVISION_DB_MANGOS "required_11831_02_mangos_command" #define REVISION_DB_REALMD "required_10008_01_realmd_realmd_db_version" #endif // __REVISION_SQL_H__