[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 ae5b65765d
commit 4dc06d6d9e
9 changed files with 148 additions and 83 deletions

View file

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

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 \
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

View file

@ -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,&param1_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)

View file

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

View file

@ -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;spell<max_id;spell++)
{
if (target->HasSpell(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;

View file

@ -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);
}

View file

@ -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); }

View file

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