diff --git a/sql/mangos.sql b/sql/mangos.sql index 207e227d4..b2f26f539 100644 --- a/sql/mangos.sql +++ b/sql/mangos.sql @@ -22,7 +22,7 @@ DROP TABLE IF EXISTS `db_version`; CREATE TABLE `db_version` ( `version` varchar(120) default NULL, - `required_7156_01_mangos_spell_proc_event` bit(1) default NULL + `required_7168_01_mangos_command` bit(1) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; -- @@ -322,7 +322,7 @@ INSERT INTO `command` VALUES ('instance savedata',3,'Syntax: .instance savedata\r\n Save the InstanceData for the current player\'s map to the DB.'), ('itemmove',2,'Syntax: .itemmove #sourceslotid #destinationslotid\r\n\r\nMove an item from slots #sourceslotid to #destinationslotid in your inventory\r\n\r\nNot yet implemented'), ('kick',2,'Syntax: .kick [$charactername]\r\n\r\nKick the given character name from the world. If no character name is provided then the selected player (except for yourself) will be kicked.'), -('learn',3,'Syntax: .learn #parameter\r\n\r\nSelected character learn a spell of id #parameter.'), +('learn',3,'Syntax: .learn #spell [all]\r\n\r\nSelected character learn a spell of id #spell. If \'all\' provided then all ranks learned.'), ('learn all',3,'Syntax: .learn all\r\n\r\nLearn all big set different spell maybe useful for Administaror.'), ('learn all_crafts',2,'Syntax: .learn crafts\r\n\r\nLearn all professions and recipes.'), ('learn all_default',1,'Syntax: .learn all_default [$playername]\r\n\r\nLearn for selected/$playername player all default spells for his race/class and spells rewarded by completed quests.'), @@ -464,7 +464,7 @@ INSERT INTO `command` VALUES ('unban account',3,'Syntax is: unban account $Name\r\nUnban accounts for account name pattern.'), ('unban character',3,'Syntax is: unban character $Name\r\nUnban accounts for character name pattern.'), ('unban ip',3,'Syntax is: unban ip $Ip\r\nUnban accounts for IP pattern.'), -('unlearn',3,'Syntax: .unlearn #startspell #endspell\r\n\r\nUnlearn for selected player the range of spells between id #startspell and #endspell. If no #endspell is provided, just unlearn spell of id #startspell.'), +('unlearn',3,'Syntax: .unlearn #spell [all]\r\n\r\nUnlearn for selected player a spell #spell. If \'all\' provided then all ranks unlearned.'), ('unmute',1,'Syntax: .unmute $playerName\r\n\r\nRestore chat messaging for any character from account of character $playerName.'), ('waterwalk',2,'Syntax: .waterwalk on/off\r\n\r\nSet on/off waterwalk state for selected player.'), ('wchange',3,'Syntax: .wchange #weathertype #status\r\n\r\nSet current weather to #weathertype with an intensity of #status.\r\n\r\n#weathertype can be 1 for rain, 2 for snow, and 3 for sand. #status can be 0 for disabled, and 1 for enabled.'), diff --git a/sql/updates/7168_01_mangos_command.sql b/sql/updates/7168_01_mangos_command.sql new file mode 100644 index 000000000..67bbd5e31 --- /dev/null +++ b/sql/updates/7168_01_mangos_command.sql @@ -0,0 +1,6 @@ +ALTER TABLE db_version CHANGE COLUMN required_7156_01_mangos_spell_proc_event required_7168_01_mangos_command bit; + +DELETE FROM `command` WHERE `name` IN ('learn','unlearn'); +INSERT INTO `command` VALUES +('learn',3,'Syntax: .learn #spell [all]\r\n\r\nSelected character learn a spell of id #spell. If \'all\' provided then all ranks learned.'), +('unlearn',3,'Syntax: .unlearn #spell [all]\r\n\r\nUnlearn for selected player a spell #spell. If \'all\' provided then all ranks unlearned.'); diff --git a/sql/updates/Makefile.am b/sql/updates/Makefile.am index 28315cb65..4819d0cf9 100644 --- a/sql/updates/Makefile.am +++ b/sql/updates/Makefile.am @@ -150,6 +150,7 @@ pkgdata_DATA = \ 7149_01_mangos_spell_proc_event.sql \ 7150_01_mangos_playercreateinfo_spell.sql \ 7156_01_mangos_spell_proc_event.sql \ + 7168_01_mangos_command.sql \ README ## Additional files to include when running 'make dist' @@ -280,4 +281,5 @@ EXTRA_DIST = \ 7149_01_mangos_spell_proc_event.sql \ 7150_01_mangos_playercreateinfo_spell.sql \ 7156_01_mangos_spell_proc_event.sql \ + 7168_01_mangos_command.sql \ README diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp index 88522c802..8bbb8da3d 100644 --- a/src/game/Chat.cpp +++ b/src/game/Chat.cpp @@ -33,6 +33,22 @@ #include "CellImpl.h" #include "AccountMgr.h" +// Supported shift-links (client generated and server side) +// |color|Harea:area_id|h[name]|h|r +// |color|Hcreature:creature_guid|h[name]|h|r +// |color|Hcreature_entry:creature_id|h[name]|h|r +// |color|Hgameevent:id|h[name]|h|r +// |color|Hgameobject:go_guid|h[name]|h|r +// |color|Hgameobject_entry:go_id|h[name]|h|r +// |color|Hitem:item_id:perm_ench_id:0:0|h[name]|h|r +// |color|Hitemset:itemset_id|h[name]|h|r +// |color|Hquest:quest_id|h[name]|h|r +// |color|Hskill:skill_id|h[name]|h|r +// |color|Hspell:spell_id|h[name]|h|r - client, spellbook spell icon shift-click +// |color|Htalent:talent_id,rank|h[name]|h|r - client, talent icon shift-click +// |color|Htele:id|h[name]|h|r +// |color|Htrade:spell_id,cur_value,max_value,unk3int,unk3str|h[name]|h|r - client, spellbook profession icon shift-click + bool ChatHandler::load_command_table = true; ChatCommand * ChatHandler::getCommandTable() @@ -1236,9 +1252,18 @@ GameObject* ChatHandler::GetObjectGlobalyWithGuidOrNearWithDbGuid(uint32 lowguid return obj; } -static char const* const spellTalentKeys[] = { - "Hspell", - "Htalent", +enum SpellLinkType +{ + SPELL_LINK_SPELL = 0, + SPELL_LINK_TALENT = 1, + SPELL_LINK_TRADE = 2 +}; + +static char const* const spellKeys[] = +{ + "Hspell", // normal spell + "Htalent", // talent spell + "Htrade", // profession/skill spell 0 }; @@ -1246,31 +1271,41 @@ uint32 ChatHandler::extractSpellIdFromLink(char* text) { // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r // number or [name] Shift-click form |color|Htalent:talent_id,rank|h[name]|h|r + // number or [name] Shift-click form |color|Htrade:spell_id,skill_id,max_value,cur_value|h[name]|h|r int type = 0; - char* rankS = NULL; - char* idS = extractKeyFromLink(text,spellTalentKeys,&type,&rankS); + char* param1_str = NULL; + char* idS = extractKeyFromLink(text,spellKeys,&type,¶m1_str); if(!idS) return 0; uint32 id = (uint32)atol(idS); - // spell - if(type==0) - return id; + switch(type) + { + case SPELL_LINK_SPELL: + return id; + case SPELL_LINK_TALENT: + { + // talent + TalentEntry const* talentEntry = sTalentStore.LookupEntry(id); + if(!talentEntry) + return 0; - // talent - TalentEntry const* talentEntry = sTalentStore.LookupEntry(id); - if(!talentEntry) - return 0; + int32 rank = param1_str ? (uint32)atol(param1_str) : 0; + if(rank >= 5) + return 0; - int32 rank = rankS ? (uint32)atol(rankS) : 0; - if(rank >= 5) - return 0; + if(rank < 0) + rank = 0; - if(rank < 0) - rank = 0; + return talentEntry->RankID[rank]; + } + case SPELL_LINK_TRADE: + return id; + } - return talentEntry->RankID[rank]; + // unknown type? + return 0; } GameTele const* ChatHandler::extractGameTeleFromLink(char* text) diff --git a/src/game/Chat.h b/src/game/Chat.h index 13d044892..bf731cada 100644 --- a/src/game/Chat.h +++ b/src/game/Chat.h @@ -442,8 +442,10 @@ class ChatHandler Player* getSelectedPlayer(); Creature* getSelectedCreature(); Unit* getSelectedUnit(); + char* extractKeyFromLink(char* text, char const* linkType, char** something1 = NULL); char* extractKeyFromLink(char* text, char const* const* linkTypes, int* found_idx, char** something1 = NULL); + uint32 extractSpellIdFromLink(char* text); GameTele const* extractGameTeleFromLink(char* text); diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp index 8ab22b392..a24461cfa 100644 --- a/src/game/Level3.cpp +++ b/src/game/Level3.cpp @@ -876,7 +876,7 @@ bool ChatHandler::HandleSetSkillCommand(const char* args) { // number or [name] Shift-click form |color|Hskill:skill_id|h[name]|h|r char* skill_p = extractKeyFromLink((char*)args,"Hskill"); - if(!skill_p) + if(!skill_p) return false; char *level_p = strtok (NULL, " "); @@ -887,7 +887,6 @@ bool ChatHandler::HandleSetSkillCommand(const char* args) char *max_p = strtok (NULL, " "); int32 skill = atoi(skill_p); - if (skill <= 0) { PSendSysMessage(LANG_INVALID_SKILL_ID, skill); @@ -937,27 +936,12 @@ bool ChatHandler::HandleUnLearnCommand(const char* args) return false; // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r - uint32 min_id = extractSpellIdFromLink((char*)args); - if(!min_id) + uint32 spell_id = extractSpellIdFromLink((char*)args); + if(!spell_id) return false; - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r - char* tail = strtok(NULL,""); - - uint32 max_id = extractSpellIdFromLink(tail); - - if (!max_id) - { - // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r - max_id = min_id+1; - } - else - { - if (max_id < min_id) - std::swap(min_id,max_id); - - max_id=max_id+1; - } + char const* allStr = strtok(NULL," "); + bool allRanks = allStr ? (strncmp(allStr, "all", strlen(allStr)) == 0) : false; Player* target = getSelectedPlayer(); if(!target) @@ -967,13 +951,13 @@ bool ChatHandler::HandleUnLearnCommand(const char* args) return false; } - for(uint32 spell=min_id;spellHasSpell(spell)) - target->removeSpell(spell); - else - SendSysMessage(LANG_FORGET_SPELL); - } + if(allRanks) + spell_id = spellmgr.GetFirstSpellInChain (spell_id); + + if (target->HasSpell(spell_id)) + target->removeSpell(spell_id); + else + SendSysMessage(LANG_FORGET_SPELL); return true; } @@ -1733,16 +1717,6 @@ bool ChatHandler::HandleLearnAllMySpellsCommand(const char* /*args*/) return true; } -static void learnAllHighRanks(Player* player, uint32 spellid) -{ - SpellChainMapNext const& nextMap = spellmgr.GetSpellChainNext(); - for(SpellChainMapNext::const_iterator itr = nextMap.lower_bound(spellid); itr != nextMap.upper_bound(spellid); ++itr) - { - player->learnSpell(itr->second,false); - learnAllHighRanks(player,itr->second); - } -} - bool ChatHandler::HandleLearnAllMyTalentsCommand(const char* /*args*/) { Player* player = m_session->GetPlayer(); @@ -1780,11 +1754,8 @@ bool ChatHandler::HandleLearnAllMyTalentsCommand(const char* /*args*/) if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false)) continue; - // learn highest rank of talent - player->learnSpell(spellid,false); - - // and learn all non-talent spell ranks (recursive by tree) - learnAllHighRanks(player,spellid); + // learn highest rank of talent and learn all non-talent spell ranks (recursive by tree) + player->learnSpellHighRank(spellid); } SendSysMessage(LANG_COMMAND_LEARN_CLASS_TALENTS); @@ -1851,15 +1822,8 @@ bool ChatHandler::HandleLearnCommand(const char* args) if(!spell || !sSpellStore.LookupEntry(spell)) return false; - if (targetPlayer->HasSpell(spell)) - { - if(targetPlayer == m_session->GetPlayer()) - SendSysMessage(LANG_YOU_KNOWN_SPELL); - else - PSendSysMessage(LANG_TARGET_KNOWN_SPELL,targetPlayer->GetName()); - SetSentErrorMessage(true); - return false; - } + char const* allStr = strtok(NULL," "); + bool allRanks = allStr ? (strncmp(allStr, "all", strlen(allStr)) == 0) : false; SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) @@ -1869,7 +1833,20 @@ bool ChatHandler::HandleLearnCommand(const char* args) return false; } - targetPlayer->learnSpell(spell,false); + if (!allRanks && targetPlayer->HasSpell(spell)) + { + if(targetPlayer == m_session->GetPlayer()) + SendSysMessage(LANG_YOU_KNOWN_SPELL); + else + PSendSysMessage(LANG_TARGET_KNOWN_SPELL,targetPlayer->GetName()); + SetSentErrorMessage(true); + return false; + } + + if(allRanks) + targetPlayer->learnSpellHighRank(spell); + else + targetPlayer->learnSpell(spell,false); return true; } @@ -4244,11 +4221,28 @@ bool ChatHandler::HandleListAurasCommand (const char * /*args*/) for (Unit::AuraMap::const_iterator itr = uAuras.begin(); itr != uAuras.end(); ++itr) { bool talent = GetTalentSpellCost(itr->second->GetId()) > 0; - PSendSysMessage(LANG_COMMAND_TARGET_AURADETAIL, itr->second->GetId(), itr->second->GetEffIndex(), - itr->second->GetModifier()->m_auraname, itr->second->GetAuraDuration(), itr->second->GetAuraMaxDuration(), - itr->second->GetSpellProto()->SpellName[m_session->GetSessionDbcLocale()], - (itr->second->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), - IS_PLAYER_GUID(itr->second->GetCasterGUID()) ? "player" : "creature",GUID_LOPART(itr->second->GetCasterGUID())); + + char const* name = itr->second->GetSpellProto()->SpellName[m_session->GetSessionDbcLocale()]; + + if (m_session) + { + std::ostringstream ss_name; + ss_name << "|cffffffff|Hspell:" << itr->second->GetId() << "|h[" << name << "]|h|r"; + + PSendSysMessage(LANG_COMMAND_TARGET_AURADETAIL, itr->second->GetId(), itr->second->GetEffIndex(), + itr->second->GetModifier()->m_auraname, itr->second->GetAuraDuration(), itr->second->GetAuraMaxDuration(), + ss_name.str().c_str(), + (itr->second->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), + IS_PLAYER_GUID(itr->second->GetCasterGUID()) ? "player" : "creature",GUID_LOPART(itr->second->GetCasterGUID())); + } + else + { + PSendSysMessage(LANG_COMMAND_TARGET_AURADETAIL, itr->second->GetId(), itr->second->GetEffIndex(), + itr->second->GetModifier()->m_auraname, itr->second->GetAuraDuration(), itr->second->GetAuraMaxDuration(), + name, + (itr->second->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), + IS_PLAYER_GUID(itr->second->GetCasterGUID()) ? "player" : "creature",GUID_LOPART(itr->second->GetCasterGUID())); + } } for (int i = 0; i < TOTAL_AURAS; i++) { @@ -4258,9 +4252,24 @@ bool ChatHandler::HandleListAurasCommand (const char * /*args*/) for (Unit::AuraList::const_iterator itr = uAuraList.begin(); itr != uAuraList.end(); ++itr) { bool talent = GetTalentSpellCost((*itr)->GetId()) > 0; - PSendSysMessage(LANG_COMMAND_TARGET_AURASIMPLE, (*itr)->GetId(), (*itr)->GetEffIndex(), - (*itr)->GetSpellProto()->SpellName[m_session->GetSessionDbcLocale()],((*itr)->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), - IS_PLAYER_GUID((*itr)->GetCasterGUID()) ? "player" : "creature",GUID_LOPART((*itr)->GetCasterGUID())); + + char const* name = (*itr)->GetSpellProto()->SpellName[m_session->GetSessionDbcLocale()]; + + if (m_session) + { + std::ostringstream ss_name; + ss_name << "|cffffffff|Hspell:" << (*itr)->GetId() << "|h[" << name << "]|h|r"; + + PSendSysMessage(LANG_COMMAND_TARGET_AURASIMPLE, (*itr)->GetId(), (*itr)->GetEffIndex(), + ss_name.str().c_str(),((*itr)->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), + IS_PLAYER_GUID((*itr)->GetCasterGUID()) ? "player" : "creature",GUID_LOPART((*itr)->GetCasterGUID())); + } + else + { + PSendSysMessage(LANG_COMMAND_TARGET_AURASIMPLE, (*itr)->GetId(), (*itr)->GetEffIndex(), + name,((*itr)->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), + IS_PLAYER_GUID((*itr)->GetCasterGUID()) ? "player" : "creature",GUID_LOPART((*itr)->GetCasterGUID())); + } } } return true; diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 36573c593..d8ef17804 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -19485,3 +19485,13 @@ bool Player::IsAllowUseFlyMountsHere() const uint32 v_map = GetVirtualMapForMapAndZone(GetMapId(), GetZoneId()); return v_map == 530 || v_map == 571 && HasSpell(54197); } + +void Player::learnSpellHighRank(uint32 spellid) +{ + learnSpell(spellid,false); + + SpellChainMapNext const& nextMap = spellmgr.GetSpellChainNext(); + for(SpellChainMapNext::const_iterator itr = nextMap.lower_bound(spellid); itr != nextMap.upper_bound(spellid); ++itr) + learnSpellHighRank(itr->second); +} + diff --git a/src/game/Player.h b/src/game/Player.h index f613b096c..114fcf4b8 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1490,6 +1490,7 @@ class MANGOS_DLL_SPEC Player : public Unit void learnDefaultSpells(); void learnQuestRewardedSpells(); void learnQuestRewardedSpells(Quest const* quest); + void learnSpellHighRank(uint32 spellid); uint32 GetFreeTalentPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS1); } void SetFreeTalentPoints(uint32 points) { SetUInt32Value(PLAYER_CHARACTER_POINTS1,points); } diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index f2edd74cf..b97be40b7 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 "7167" + #define REVISION_NR "7168" #endif // __REVISION_NR_H__