[7168] Spell shift-link and command improvements.

* Support Htrade shift link (it created by client at click by crafting profession spell icon in spellbook)
  in spell comands.
* Support "all" second arg for .learn for learning not provided spell id but it's all ranks.
* Drop support range for .unlearn command but support instead "all" second arg for unlearn not specific spell id but it's all ranks.
* In .list auras output print spell names as shift links for better readable view.
* Add to beggining Chat.cpp lists all supported by commands shift-links (client generated and server-side)
This commit is contained in:
VladimirMangos 2009-01-25 07:08:38 +03:00
parent 7a8a1a71bf
commit 32f3331679
9 changed files with 148 additions and 83 deletions

View file

@ -22,7 +22,7 @@
DROP TABLE IF EXISTS `db_version`; DROP TABLE IF EXISTS `db_version`;
CREATE TABLE `db_version` ( CREATE TABLE `db_version` (
`version` varchar(120) default NULL, `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'; ) 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.'), ('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'), ('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.'), ('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',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_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.'), ('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 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 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.'), ('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.'), ('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.'), ('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.'), ('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.'),

View file

@ -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.');

View file

@ -150,6 +150,7 @@ pkgdata_DATA = \
7149_01_mangos_spell_proc_event.sql \ 7149_01_mangos_spell_proc_event.sql \
7150_01_mangos_playercreateinfo_spell.sql \ 7150_01_mangos_playercreateinfo_spell.sql \
7156_01_mangos_spell_proc_event.sql \ 7156_01_mangos_spell_proc_event.sql \
7168_01_mangos_command.sql \
README README
## Additional files to include when running 'make dist' ## Additional files to include when running 'make dist'
@ -280,4 +281,5 @@ EXTRA_DIST = \
7149_01_mangos_spell_proc_event.sql \ 7149_01_mangos_spell_proc_event.sql \
7150_01_mangos_playercreateinfo_spell.sql \ 7150_01_mangos_playercreateinfo_spell.sql \
7156_01_mangos_spell_proc_event.sql \ 7156_01_mangos_spell_proc_event.sql \
7168_01_mangos_command.sql \
README README

View file

@ -33,6 +33,22 @@
#include "CellImpl.h" #include "CellImpl.h"
#include "AccountMgr.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; bool ChatHandler::load_command_table = true;
ChatCommand * ChatHandler::getCommandTable() ChatCommand * ChatHandler::getCommandTable()
@ -1236,9 +1252,18 @@ GameObject* ChatHandler::GetObjectGlobalyWithGuidOrNearWithDbGuid(uint32 lowguid
return obj; return obj;
} }
static char const* const spellTalentKeys[] = { enum SpellLinkType
"Hspell", {
"Htalent", 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 0
}; };
@ -1246,24 +1271,27 @@ 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|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|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; int type = 0;
char* rankS = NULL; char* param1_str = NULL;
char* idS = extractKeyFromLink(text,spellTalentKeys,&type,&rankS); char* idS = extractKeyFromLink(text,spellKeys,&type,&param1_str);
if(!idS) if(!idS)
return 0; return 0;
uint32 id = (uint32)atol(idS); uint32 id = (uint32)atol(idS);
// spell switch(type)
if(type==0) {
case SPELL_LINK_SPELL:
return id; return id;
case SPELL_LINK_TALENT:
{
// talent // talent
TalentEntry const* talentEntry = sTalentStore.LookupEntry(id); TalentEntry const* talentEntry = sTalentStore.LookupEntry(id);
if(!talentEntry) if(!talentEntry)
return 0; return 0;
int32 rank = rankS ? (uint32)atol(rankS) : 0; int32 rank = param1_str ? (uint32)atol(param1_str) : 0;
if(rank >= 5) if(rank >= 5)
return 0; return 0;
@ -1272,6 +1300,13 @@ uint32 ChatHandler::extractSpellIdFromLink(char* text)
return talentEntry->RankID[rank]; return talentEntry->RankID[rank];
} }
case SPELL_LINK_TRADE:
return id;
}
// unknown type?
return 0;
}
GameTele const* ChatHandler::extractGameTeleFromLink(char* text) GameTele const* ChatHandler::extractGameTeleFromLink(char* text)
{ {

View file

@ -442,8 +442,10 @@ class ChatHandler
Player* getSelectedPlayer(); Player* getSelectedPlayer();
Creature* getSelectedCreature(); Creature* getSelectedCreature();
Unit* getSelectedUnit(); Unit* getSelectedUnit();
char* extractKeyFromLink(char* text, char const* linkType, char** something1 = NULL); char* extractKeyFromLink(char* text, char const* linkType, char** something1 = NULL);
char* extractKeyFromLink(char* text, char const* const* linkTypes, int* found_idx, char** something1 = NULL); char* extractKeyFromLink(char* text, char const* const* linkTypes, int* found_idx, char** something1 = NULL);
uint32 extractSpellIdFromLink(char* text); uint32 extractSpellIdFromLink(char* text);
GameTele const* extractGameTeleFromLink(char* text); GameTele const* extractGameTeleFromLink(char* text);

View file

@ -887,7 +887,6 @@ bool ChatHandler::HandleSetSkillCommand(const char* args)
char *max_p = strtok (NULL, " "); char *max_p = strtok (NULL, " ");
int32 skill = atoi(skill_p); int32 skill = atoi(skill_p);
if (skill <= 0) if (skill <= 0)
{ {
PSendSysMessage(LANG_INVALID_SKILL_ID, skill); PSendSysMessage(LANG_INVALID_SKILL_ID, skill);
@ -937,27 +936,12 @@ bool ChatHandler::HandleUnLearnCommand(const char* args)
return false; return false;
// number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r // number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r
uint32 min_id = extractSpellIdFromLink((char*)args); uint32 spell_id = extractSpellIdFromLink((char*)args);
if(!min_id) if(!spell_id)
return false; return false;
// number or [name] Shift-click form |color|Hspell:spell_id|h[name]|h|r char const* allStr = strtok(NULL," ");
char* tail = strtok(NULL,""); bool allRanks = allStr ? (strncmp(allStr, "all", strlen(allStr)) == 0) : false;
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;
}
Player* target = getSelectedPlayer(); Player* target = getSelectedPlayer();
if(!target) if(!target)
@ -967,13 +951,13 @@ bool ChatHandler::HandleUnLearnCommand(const char* args)
return false; return false;
} }
for(uint32 spell=min_id;spell<max_id;spell++) if(allRanks)
{ spell_id = spellmgr.GetFirstSpellInChain (spell_id);
if (target->HasSpell(spell))
target->removeSpell(spell); if (target->HasSpell(spell_id))
target->removeSpell(spell_id);
else else
SendSysMessage(LANG_FORGET_SPELL); SendSysMessage(LANG_FORGET_SPELL);
}
return true; return true;
} }
@ -1733,16 +1717,6 @@ bool ChatHandler::HandleLearnAllMySpellsCommand(const char* /*args*/)
return true; 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*/) bool ChatHandler::HandleLearnAllMyTalentsCommand(const char* /*args*/)
{ {
Player* player = m_session->GetPlayer(); Player* player = m_session->GetPlayer();
@ -1780,11 +1754,8 @@ bool ChatHandler::HandleLearnAllMyTalentsCommand(const char* /*args*/)
if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false)) if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false))
continue; continue;
// learn highest rank of talent // learn highest rank of talent and learn all non-talent spell ranks (recursive by tree)
player->learnSpell(spellid,false); player->learnSpellHighRank(spellid);
// and learn all non-talent spell ranks (recursive by tree)
learnAllHighRanks(player,spellid);
} }
SendSysMessage(LANG_COMMAND_LEARN_CLASS_TALENTS); SendSysMessage(LANG_COMMAND_LEARN_CLASS_TALENTS);
@ -1851,15 +1822,8 @@ bool ChatHandler::HandleLearnCommand(const char* args)
if(!spell || !sSpellStore.LookupEntry(spell)) if(!spell || !sSpellStore.LookupEntry(spell))
return false; return false;
if (targetPlayer->HasSpell(spell)) char const* allStr = strtok(NULL," ");
{ bool allRanks = allStr ? (strncmp(allStr, "all", strlen(allStr)) == 0) : false;
if(targetPlayer == m_session->GetPlayer())
SendSysMessage(LANG_YOU_KNOWN_SPELL);
else
PSendSysMessage(LANG_TARGET_KNOWN_SPELL,targetPlayer->GetName());
SetSentErrorMessage(true);
return false;
}
SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell); SpellEntry const* spellInfo = sSpellStore.LookupEntry(spell);
if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer())) if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer()))
@ -1869,6 +1833,19 @@ bool ChatHandler::HandleLearnCommand(const char* args)
return false; return 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); targetPlayer->learnSpell(spell,false);
return true; return true;
@ -4244,12 +4221,29 @@ bool ChatHandler::HandleListAurasCommand (const char * /*args*/)
for (Unit::AuraMap::const_iterator itr = uAuras.begin(); itr != uAuras.end(); ++itr) for (Unit::AuraMap::const_iterator itr = uAuras.begin(); itr != uAuras.end(); ++itr)
{ {
bool talent = GetTalentSpellCost(itr->second->GetId()) > 0; bool talent = GetTalentSpellCost(itr->second->GetId()) > 0;
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(), PSendSysMessage(LANG_COMMAND_TARGET_AURADETAIL, itr->second->GetId(), itr->second->GetEffIndex(),
itr->second->GetModifier()->m_auraname, itr->second->GetAuraDuration(), itr->second->GetAuraMaxDuration(), itr->second->GetModifier()->m_auraname, itr->second->GetAuraDuration(), itr->second->GetAuraMaxDuration(),
itr->second->GetSpellProto()->SpellName[m_session->GetSessionDbcLocale()], ss_name.str().c_str(),
(itr->second->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), (itr->second->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""),
IS_PLAYER_GUID(itr->second->GetCasterGUID()) ? "player" : "creature",GUID_LOPART(itr->second->GetCasterGUID())); 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++) for (int i = 0; i < TOTAL_AURAS; i++)
{ {
Unit::AuraList const& uAuraList = unit->GetAurasByType(AuraType(i)); Unit::AuraList const& uAuraList = unit->GetAurasByType(AuraType(i));
@ -4258,10 +4252,25 @@ bool ChatHandler::HandleListAurasCommand (const char * /*args*/)
for (Unit::AuraList::const_iterator itr = uAuraList.begin(); itr != uAuraList.end(); ++itr) for (Unit::AuraList::const_iterator itr = uAuraList.begin(); itr != uAuraList.end(); ++itr)
{ {
bool talent = GetTalentSpellCost((*itr)->GetId()) > 0; bool talent = GetTalentSpellCost((*itr)->GetId()) > 0;
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(), PSendSysMessage(LANG_COMMAND_TARGET_AURASIMPLE, (*itr)->GetId(), (*itr)->GetEffIndex(),
(*itr)->GetSpellProto()->SpellName[m_session->GetSessionDbcLocale()],((*itr)->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""), ss_name.str().c_str(),((*itr)->IsPassive() ? passiveStr : ""),(talent ? talentStr : ""),
IS_PLAYER_GUID((*itr)->GetCasterGUID()) ? "player" : "creature",GUID_LOPART((*itr)->GetCasterGUID())); 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; return true;
} }

View file

@ -19485,3 +19485,13 @@ bool Player::IsAllowUseFlyMountsHere() const
uint32 v_map = GetVirtualMapForMapAndZone(GetMapId(), GetZoneId()); uint32 v_map = GetVirtualMapForMapAndZone(GetMapId(), GetZoneId());
return v_map == 530 || v_map == 571 && HasSpell(54197); 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);
}

View file

@ -1490,6 +1490,7 @@ class MANGOS_DLL_SPEC Player : public Unit
void learnDefaultSpells(); void learnDefaultSpells();
void learnQuestRewardedSpells(); void learnQuestRewardedSpells();
void learnQuestRewardedSpells(Quest const* quest); void learnQuestRewardedSpells(Quest const* quest);
void learnSpellHighRank(uint32 spellid);
uint32 GetFreeTalentPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS1); } uint32 GetFreeTalentPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS1); }
void SetFreeTalentPoints(uint32 points) { SetUInt32Value(PLAYER_CHARACTER_POINTS1,points); } void SetFreeTalentPoints(uint32 points) { SetUInt32Value(PLAYER_CHARACTER_POINTS1,points); }

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "7167" #define REVISION_NR "7168"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__