Merge commit 'origin/master' into 320

This commit is contained in:
tomrus88 2009-08-28 17:26:09 +04:00
commit 2d65ce8b87
30 changed files with 1149 additions and 355 deletions

View file

@ -53,3 +53,5 @@ EXTRA_DIST += \
win/VC100/zlib.vcxproj \
win/VC100/g3dlite.vcxproj
ACLOCAL_AMFLAGS = -I m4

View file

@ -48,7 +48,7 @@ if test "$srcdir" = "." && test "$enable_maintainer_mode" != "yes"; then
../configure
make
This will create a build space in the directory `objdir' and
This will create a build space in the directory 'objdir' and
start a build in that directory.
If however you realy want to disable this error,

155
m4/pkg.m4 Normal file
View file

@ -0,0 +1,155 @@
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
#
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
#
# This program 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 2 of the License, or
# (at your option) any later version.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# PKG_PROG_PKG_CONFIG([MIN-VERSION])
# ----------------------------------
AC_DEFUN([PKG_PROG_PKG_CONFIG],
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
fi
if test -n "$PKG_CONFIG"; then
_pkg_min_version=m4_default([$1], [0.9.0])
AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
PKG_CONFIG=""
fi
fi[]dnl
])# PKG_PROG_PKG_CONFIG
# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
#
# Check to see whether a particular set of modules exists. Similar
# to PKG_CHECK_MODULES(), but does not set variables or print errors.
#
#
# Similar to PKG_CHECK_MODULES, make sure that the first instance of
# this or PKG_CHECK_MODULES is called, or make sure to call
# PKG_CHECK_EXISTS manually
# --------------------------------------------------------------
AC_DEFUN([PKG_CHECK_EXISTS],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
if test -n "$PKG_CONFIG" && \
AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
m4_ifval([$2], [$2], [:])
m4_ifvaln([$3], [else
$3])dnl
fi])
# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
# ---------------------------------------------
m4_define([_PKG_CONFIG],
[if test -n "$$1"; then
pkg_cv_[]$1="$$1"
elif test -n "$PKG_CONFIG"; then
PKG_CHECK_EXISTS([$3],
[pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
[pkg_failed=yes])
else
pkg_failed=untried
fi[]dnl
])# _PKG_CONFIG
# _PKG_SHORT_ERRORS_SUPPORTED
# -----------------------------
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
_pkg_short_errors_supported=yes
else
_pkg_short_errors_supported=no
fi[]dnl
])# _PKG_SHORT_ERRORS_SUPPORTED
# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
# [ACTION-IF-NOT-FOUND])
#
#
# Note that if there is a possibility the first call to
# PKG_CHECK_MODULES might not happen, you should be sure to include an
# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
#
#
# --------------------------------------------------------------
AC_DEFUN([PKG_CHECK_MODULES],
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
pkg_failed=no
AC_MSG_CHECKING([for $1])
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
_PKG_CONFIG([$1][_LIBS], [libs], [$2])
m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
and $1[]_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.])
if test $pkg_failed = yes; then
_PKG_SHORT_ERRORS_SUPPORTED
if test $_pkg_short_errors_supported = yes; then
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "$2" 2>&1`
else
$1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors "$2" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
ifelse([$4], , [AC_MSG_ERROR(dnl
[Package requirements ($2) were not met:
$$1_PKG_ERRORS
Consider adjusting the PKG_CONFIG_PATH environment variable if you
installed software in a non-standard prefix.
_PKG_TEXT
])],
[AC_MSG_RESULT([no])
$4])
elif test $pkg_failed = untried; then
ifelse([$4], , [AC_MSG_FAILURE(dnl
[The pkg-config script could not be found or is too old. Make sure it
is in your PATH or set the PKG_CONFIG environment variable to the full
path to pkg-config.
_PKG_TEXT
To get pkg-config, see <http://pkg-config.freedesktop.org/>.])],
[$4])
else
$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
AC_MSG_RESULT([yes])
ifelse([$3], , :, [$3])
fi[]dnl
])# PKG_CHECK_MODULES

View file

@ -38,6 +38,7 @@ CREATE TABLE `spell_check` (
INSERT INTO spell_check (spellid,SpellFamilyName,SpellFamilyMaskA,SpellFamilyMaskB,SpellIcon,SpellVisual,SpellCategory,EffectType,EffectAura,EffectIdx,Name,Code) VALUES
/* sorted by spell ids */
/*id fm familyMaskA fmMaskB icon vis cat eff aur ef name code */
(781, 9, -1, -1, -1, -1, -1, 3, -1,-1,'Disengage', 'Spell::EffectDummy'),
(1454, 5,0x0000000000040000,0x00000000, -1, -1, -1, 3, -1,-1,'Life Tap', 'Spell::EffectDummy'),
(1455, 5,0x0000000000040000,0x00000000, -1, -1, -1, 3, -1,-1,'Life Tap', 'Spell::EffectDummy'),
(1456, 5,0x0000000000040000,0x00000000, -1, -1, -1, 3, -1,-1,'Life Tap', 'Spell::EffectDummy'),
@ -315,7 +316,10 @@ INSERT INTO spell_check (spellid,SpellFamilyName,SpellFamilyMaskA,SpellFamilyMas
(55004, 0, -1, -1, -1, -1, -1, 3, -1,-1,'Nitro Boosts', 'Spell::EffectDummy'),
(55441,11, -1, -1, -1, -1, -1, -1, 4,-1,'Glyph of Mana Tide', 'Spell::EffectDummy'),
(56235,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Glyph of Conflagrate', 'Spell::EffectSchoolDMG'),
(56446,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Disengage', 'Spell::EffectDummy'),
(57627,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Charge', 'Spell::EffectSchoolDMG'),
(57635, 9, -1, -1, -1, -1, -1, 3, -1,-1,'Disengage', 'Spell::EffectDummy'),
(57636,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Disengage', 'Spell::EffectDummy'),
(57946, 5,0x0000000000040000,0x00000000, -1, -1, -1, 3, -1,-1,'Life Tap', 'Spell::EffectDummy'),
(58367,-1, -1, -1, -1, -1, -1, -1, 4,-1,'Glyph of Execution', 'Spell::EffectDummy'),
(58418, 0, -1, -1, -1, -1, -1, 3, -1,-1,'Portal to Orgrimmar', 'Spell::EffectDummy'),
@ -324,9 +328,13 @@ INSERT INTO spell_check (spellid,SpellFamilyName,SpellFamilyMaskA,SpellFamilyMas
(59645,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Underbelly Elixir', 'Spell::EffectDummy'),
(59831,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Underbelly Elixir', 'Spell::EffectDummy'),
(59843,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Underbelly Elixir', 'Spell::EffectDummy'),
(60932, 0, -1, -1, -1, -1, -1, 3, -1,-1,'Disengage', 'Spell::EffectDummy'),
(60934,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Disengage', 'Spell::EffectDummy'),
(61290, 5,0x0001000000000000,0x00000000, -1, -1, -1, 2, -1,-1,'Shadowflame', 'Spell::EffectSchoolDMG'),
(61291,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Shadowflame', 'Spell::EffectSchoolDMG'),
(61491, 0, -1, -1, -1, -1, -1, 2, -1,-1,'Intercept', 'Spell::EffectSchoolDMG'),
(61507, 9, -1, -1, -1, -1, -1, 3, -1,-1,'Disengage', 'Spell::EffectDummy'),
(61508,-1, -1, -1, -1, -1, -1, -1, -1,-1,'Disengage', 'Spell::EffectDummy'),
(63375,-1, -1, -1, -1, -1, -1, 30, -1,-1,'Improved Stormstrike', 'Spell::EffectEnergize'),
/* sorted by spell names */
@ -344,6 +352,7 @@ INSERT INTO spell_check (spellid,SpellFamilyName,SpellFamilyMaskA,SpellFamilyMas
( 0,15,0x0000000000002000,0x00000000, -1, -1, -1, 3, -1,-1,'Death Coil', 'Spell::EffectDummy'),
( 0,15,0x0000000000000010,0x00000000, -1, -1, -1, 3, -1,-1,'Death Strike', 'Spell::EffectDummy'),
( 0, 5, -1, -1, -1, -1, 12, 38, -1,-1,'Devour Magic', 'Spell::EffectDispel'),
( 0, 9,0x0000400000000000,0x00000000, -1, -1, -1, 3, -1,-1,'Disengage', 'Spell::EffectDummy'),
( 0, 8,0x0000000800000000,0x00000000, -1, -1, -1, 2, -1,-1,'Envenom', 'Spell::EffectSchoolDMG'),
( 0, 8,0x0000000000020000,0x00000000, -1, -1, -1, 2, -1,-1,'Eviscerate', 'Spell::EffectSchoolDMG'),
(0, 4,0x0000000020000000,0x00000000, -1, -1, -1, 3, -1,-1,'Execute', 'Spell::EffectDummy'),

View file

@ -1208,18 +1208,18 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
}
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM:
// miscvalue1 = item_id
if(!miscvalue1)
if (!miscvalue1)
continue;
if(miscvalue1 != achievementCriteria->equip_item.itemID)
if (miscvalue1 != achievementCriteria->equip_item.itemID)
continue;
SetCriteriaProgress(achievementCriteria, 1);
break;
case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT:
// miscvalue1 = go entry
if(!miscvalue1)
if (!miscvalue1)
continue;
if(miscvalue1 != achievementCriteria->use_gameobject.goEntry)
if (miscvalue1 != achievementCriteria->use_gameobject.goEntry)
continue;
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
@ -1234,7 +1234,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
break;
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS:
{
if(miscvalue1 && miscvalue1 != achievementCriteria->learn_skillline_spell.skillLine)
if (miscvalue1 && miscvalue1 != achievementCriteria->learn_skillline_spell.skillLine)
continue;
uint32 spellCount = 0;
@ -1242,9 +1242,8 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
spellIter != GetPlayer()->GetSpellMap().end();
++spellIter)
{
for(SkillLineAbilityMap::const_iterator skillIter = spellmgr.GetBeginSkillLineAbilityMap(spellIter->first);
skillIter != spellmgr.GetEndSkillLineAbilityMap(spellIter->first);
++skillIter)
SkillLineAbilityMapBounds bounds = spellmgr.GetSkillLineAbilityMapBounds(spellIter->first);
for(SkillLineAbilityMap::const_iterator skillIter = bounds.first; skillIter != bounds.second; ++skillIter)
{
if(skillIter->second->skillId == achievementCriteria->learn_skillline_spell.skillLine)
spellCount++;
@ -1255,17 +1254,17 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
}
case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL:
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
if(!miscvalue1)
if (!miscvalue1)
continue;
if(achievementCriteria->win_duel.duelCount)
if (achievementCriteria->win_duel.duelCount)
{
// those requirements couldn't be found in the dbc
AchievementCriteriaDataSet const* data = achievementmgr.GetCriteriaDataSet(achievementCriteria);
if(!data)
if (!data)
continue;
if(!data->Meets(GetPlayer(),unit))
if (!data->Meets(GetPlayer(),unit))
continue;
}
@ -1301,7 +1300,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
}
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE:
{
if(miscvalue1 && miscvalue1 != achievementCriteria->learn_skill_line.skillLine)
if (miscvalue1 && miscvalue1 != achievementCriteria->learn_skill_line.skillLine)
continue;
uint32 spellCount = 0;
@ -1309,13 +1308,10 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
spellIter != GetPlayer()->GetSpellMap().end();
++spellIter)
{
for(SkillLineAbilityMap::const_iterator skillIter = spellmgr.GetBeginSkillLineAbilityMap(spellIter->first);
skillIter != spellmgr.GetEndSkillLineAbilityMap(spellIter->first);
++skillIter)
{
if(skillIter->second->skillId == achievementCriteria->learn_skill_line.skillLine)
SkillLineAbilityMapBounds bounds = spellmgr.GetSkillLineAbilityMapBounds(spellIter->first);
for(SkillLineAbilityMap::const_iterator skillIter = bounds.first; skillIter != bounds.second; ++skillIter)
if (skillIter->second->skillId == achievementCriteria->learn_skill_line.skillLine)
spellCount++;
}
}
SetCriteriaProgress(achievementCriteria, spellCount);
break;

View file

@ -1099,6 +1099,10 @@ void BattleGround::StartBattleGround()
void BattleGround::AddPlayer(Player *plr)
{
// remove afk from player
if (plr->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK))
plr->ToggleAFK();
// score struct must be created in inherited class
uint64 guid = plr->GetGUID();

View file

@ -31,6 +31,7 @@
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
#include "AccountMgr.h"
#include "SpellMgr.h"
// Supported shift-links (client generated and server side)
// |color|Hachievement:achievement_id:player_guid:0:0:0:0:0:0:0:0|h[name]|h|r
@ -980,6 +981,540 @@ int ChatHandler::ParseCommands(const char* text)
return 1;
}
bool ChatHandler::isValidChatMessage(const char* message)
{
/*
valid examples:
|cffa335ee|Hitem:812:0:0:0:0:0:0:0:70|h[Glowing Brightwood Staff]|h|r
|cff808080|Hquest:2278:47|h[The Platinum Discs]|h|r
|cffffd000|Htrade:4037:1:150:1:6AAAAAAAAAAAAAAAAAAAAAAOAADAAAAAAAAAAAAAAAAIAAAAAAAAA|h[Engineering]|h|r
|cff4e96f7|Htalent:2232:-1|h[Taste for Blood]|h|r
|cff71d5ff|Hspell:21563|h[Command]|h|r
|cffffd000|Henchant:3919|h[Engineering: Rough Dynamite]|h|r
|cffffff00|Hachievement:546:0000000000000001:0:0:0:-1:0:0:0:0|h[Safe Deposit]|h|r
|cff66bbff|Hglyph:21:762|h[Glyph of Bladestorm]|h|r
| will be escaped to ||
*/
if(strlen(message) > 255)
return false;
const char validSequence[6] = "cHhhr";
const char* validSequenceIterator = validSequence;
// more simple checks
if (sWorld.getConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY) < 3)
{
const std::string validCommands = "cHhr|";
while(*message)
{
// find next pipe command
message = strchr(message, '|');
if(!message)
return true;
++message;
char commandChar = *message;
if(validCommands.find(commandChar) == std::string::npos)
return false;
++message;
// validate sequence
if(sWorld.getConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY) == 2)
{
if(commandChar == *validSequenceIterator)
{
if (validSequenceIterator == validSequence+4)
validSequenceIterator = validSequence;
else
++validSequenceIterator;
}
else
return false;
}
}
return true;
}
std::istringstream reader(message);
char buffer[256];
uint32 color;
ItemPrototype const* linkedItem;
Quest const* linkedQuest;
SpellEntry const *linkedSpell;
AchievementEntry const* linkedAchievement;
while(!reader.eof())
{
if (validSequence == validSequenceIterator)
{
linkedItem = NULL;
linkedQuest = NULL;
linkedSpell = NULL;
linkedAchievement = NULL;
reader.ignore(255, '|');
}
else if(reader.get() != '|')
{
#ifdef MANGOS_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage sequence aborted unexpectedly");
#endif
return false;
}
// pipe has always to be followed by at least one char
if ( reader.peek() == '\0')
{
#ifdef MANGOS_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage pipe followed by \\0");
#endif
return false;
}
// no further pipe commands
if (reader.eof())
break;
char commandChar;
reader >> commandChar;
// | in normal messages is escaped by ||
if (commandChar != '|')
{
if(commandChar == *validSequenceIterator)
{
if (validSequenceIterator == validSequence+4)
validSequenceIterator = validSequence;
else
++validSequenceIterator;
}
else
{
#ifdef MANGOS_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage invalid sequence, expected %c but got %c", *validSequenceIterator, commandChar);
#endif
return false;
}
}
else if(validSequence != validSequenceIterator)
{
// no escaped pipes in sequences
#ifdef MANGOS_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage got escaped pipe in sequence");
#endif
return false;
}
switch (commandChar)
{
case 'c':
color = 0;
// validate color, expect 8 hex chars
for(int i=0; i<8; i++)
{
char c;
reader >> c;
if(!c)
{
#ifdef MANGOS_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage got \\0 while reading color in |c command");
#endif
return false;
}
color <<= 4;
// check for hex char
if(c >= '0' && c <='9')
{
color |= c-'0';
continue;
}
if(c >= 'a' && c <='f')
{
color |= 10+c-'a';
continue;
}
#ifdef MANGOS_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage got non hex char '%c' while reading color", c);
#endif
return false;
}
break;
case 'H':
// read chars up to colon = link type
reader.getline(buffer, 256, ':');
if (strcmp(buffer, "item") == 0)
{
// read item entry
reader.getline(buffer, 256, ':');
linkedItem= objmgr.GetItemPrototype(atoi(buffer));
if(!linkedItem)
{
#ifdef MANGOS_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage got invalid itemID %u in |item command", atoi(buffer));
#endif
return false;
}
if (color != ItemQualityColors[linkedItem->Quality])
{
#ifdef MANGOS_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage linked item has color %u, but user claims %u", ItemQualityColors[linkedItem->Quality],
color);
#endif
return false;
}
char c = reader.peek();
// ignore enchants etc.
while(c >='0' && c <='9' || c==':')
{
reader.ignore(1);
c = reader.peek();
}
}
else if(strcmp(buffer, "quest") == 0)
{
// no color check for questlinks, each client will adapt it anyway
uint32 questid= 0;
// read questid
char c = reader.peek();
while(c >='0' && c<='9')
{
reader.ignore(1);
questid *= 10;
questid += c-'0';
c = reader.peek();
}
linkedQuest = objmgr.GetQuestTemplate(questid);
if(!linkedQuest)
{
#ifdef MANOGS_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage Questtemplate %u not found", questid);
#endif
return false;
}
c = reader.peek();
// level
while(c !='|' && c!='\0')
{
reader.ignore(1);
c = reader.peek();
}
}
else if(strcmp(buffer, "trade") == 0)
{
if(color != CHAT_LINK_COLOR_TRADE)
return false;
// read spell entry
reader.getline(buffer, 256, ':');
linkedSpell = sSpellStore.LookupEntry(atoi(buffer));
if(!linkedSpell)
return false;
char c = reader.peek();
// base64 encoded stuff
while(c !='|' && c!='\0')
{
reader.ignore(1);
c = reader.peek();
}
}
else if(strcmp(buffer, "talent") == 0)
{
// talent links are always supposed to be blue
if(color != CHAT_LINK_COLOR_TALENT)
return false;
// read talent entry
reader.getline(buffer, 256, ':');
TalentEntry const *talentInfo = sTalentStore.LookupEntry(atoi(buffer));
if(!talentInfo)
return false;
linkedSpell = sSpellStore.LookupEntry(talentInfo->RankID[0]);
if(!linkedSpell)
return false;
char c = reader.peek();
// skillpoints? whatever, drop it
while(c !='|' && c!='\0')
{
reader.ignore(1);
c = reader.peek();
}
}
else if(strcmp(buffer, "spell") == 0)
{
if(color != CHAT_LINK_COLOR_SPELL)
return false;
uint32 spellid = 0;
// read spell entry
char c = reader.peek();
while(c >='0' && c<='9')
{
reader.ignore(1);
spellid *= 10;
spellid += c-'0';
c = reader.peek();
}
linkedSpell = sSpellStore.LookupEntry(spellid);
if(!linkedSpell)
return false;
}
else if(strcmp(buffer, "enchant") == 0)
{
if(color != CHAT_LINK_COLOR_ENCHANT)
return false;
uint32 spellid = 0;
// read spell entry
char c = reader.peek();
while(c >='0' && c<='9')
{
reader.ignore(1);
spellid *= 10;
spellid += c-'0';
c = reader.peek();
}
linkedSpell = sSpellStore.LookupEntry(spellid);
if(!linkedSpell)
return false;
}
else if(strcmp(buffer, "achievement") == 0)
{
if(color != CHAT_LINK_COLOR_ACHIEVEMENT)
return false;
reader.getline(buffer, 256, ':');
uint32 achievementId = atoi(buffer);
linkedAchievement = sAchievementStore.LookupEntry(achievementId);
if(!linkedAchievement)
return false;
char c = reader.peek();
// skip progress
while(c !='|' && c!='\0')
{
reader.ignore(1);
c = reader.peek();
}
}
else if(strcmp(buffer, "glyph") == 0)
{
if(color != CHAT_LINK_COLOR_GLYPH)
return false;
// first id is slot, drop it
reader.getline(buffer, 256, ':');
uint32 glyphId = 0;
char c = reader.peek();
while(c>='0' && c <='9')
{
glyphId *= 10;
glyphId += c-'0';
reader.ignore(1);
c = reader.peek();
}
GlyphPropertiesEntry const* glyph = sGlyphPropertiesStore.LookupEntry(glyphId);
if (!glyph)
return false;
linkedSpell = sSpellStore.LookupEntry(glyph->SpellId);
if (!linkedSpell)
return false;
}
else
{
#ifdef MANGOS_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage user sent unsupported link type '%s'", buffer);
#endif
return false;
}
break;
case 'h':
// if h is next element in sequence, this one must contain the linked text :)
if (*validSequenceIterator == 'h')
{
// links start with '['
if (reader.get() != '[')
{
#ifdef MANGOS_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage link caption doesn't start with '['");
#endif
return false;
}
reader.getline(buffer, 256, ']');
// verify the link name
if (linkedSpell)
{
// spells with that flag have a prefix of "$PROFESSION: "
if (linkedSpell->Attributes & SPELL_ATTR_TRADESPELL)
{
// lookup skillid
SkillLineAbilityMapBounds bounds = spellmgr.GetSkillLineAbilityMapBounds(linkedSpell->Id);
if (bounds.first == bounds.second)
{
return false;
}
SkillLineAbilityEntry const *skillInfo = bounds.first->second;
if (!skillInfo)
{
return false;
}
SkillLineEntry const *skillLine = sSkillLineStore.LookupEntry(skillInfo->skillId);
if (!skillLine)
{
return false;
}
for(uint8 i=0; i<MAX_LOCALE; ++i)
{
uint32 skillLineNameLength = strlen(skillLine->name[i]);
if (skillLineNameLength > 0 && strncmp(skillLine->name[i], buffer, skillLineNameLength) == 0)
{
// found the prefix, remove it to perform spellname validation below
// -2 = strlen(": ")
uint32 spellNameLength = strlen(buffer)-skillLineNameLength-2;
memmove(buffer, buffer+skillLineNameLength+2, spellNameLength+1);
}
}
}
bool foundName = false;
for(uint8 i=0; i<MAX_LOCALE; ++i)
{
if (*linkedSpell->SpellName[i] && strcmp(linkedSpell->SpellName[i], buffer) == 0)
{
foundName = true;
break;
}
}
if (!foundName)
return false;
}
else if (linkedQuest)
{
if (linkedQuest->GetTitle() != buffer)
{
QuestLocale const *ql = objmgr.GetQuestLocale(linkedQuest->GetQuestId());
if (!ql)
{
#ifdef MANOGS_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage default questname didn't match and there is no locale");
#endif
return false;
}
bool foundName = false;
for(uint8 i=0; i<ql->Title.size(); i++)
{
if (ql->Title[i] == buffer)
{
foundName = true;
break;
}
}
if (!foundName)
{
#ifdef MANOGS_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage no quest locale title matched")
#endif
return false;
}
}
}
else if(linkedItem)
{
if (strcmp(linkedItem->Name1, buffer) != 0)
{
ItemLocale const *il = objmgr.GetItemLocale(linkedItem->ItemId);
if (!il)
{
#ifdef MANGOS_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage linked item name doesn't is wrong and there is no localization");
#endif
return false;
}
bool foundName = false;
for(uint8 i=0; i<il->Name.size(); ++i)
{
if (il->Name[i] == buffer)
{
foundName = true;
break;
}
}
if (!foundName)
{
#ifdef MANGOS_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage linked item name wasn't found in any localization");
#endif
return false;
}
}
}
else if (linkedAchievement)
{
bool foundName = false;
for(uint8 i=0; i<MAX_LOCALE; ++i)
{
if (*linkedAchievement->name[i], strcmp(linkedAchievement->name[i], buffer) == 0)
{
foundName = true;
break;
}
}
if (!foundName)
return false;
}
// that place should never be reached - if nothing linked has been set in |H
// it will return false before
else
return false;
}
break;
case 'r':
case '|':
// no further payload
break;
default:
#ifdef MANGOS_DEBUG
sLog.outBasic("ChatHandler::isValidChatMessage got invalid command |%c", commandChar);
#endif
return false;
}
}
// check if every opened sequence was also closed properly
#ifdef MANGOS_DEBUG
if(validSequence != validSequenceIterator)
sLog.outBasic("ChatHandler::isValidChatMessage EOF in active sequence");
#endif
return validSequence == validSequenceIterator;
}
bool ChatHandler::ShowHelpForSubCommands(ChatCommand *table, char const* cmd, char const* subcmd)
{
std::string list;
@ -1666,4 +2201,4 @@ LocaleConstant CliHandler::GetSessionDbcLocale() const
int CliHandler::GetSessionDbLocaleIndex() const
{
return objmgr.GetDBCLocaleIndex();
}
}

View file

@ -69,6 +69,8 @@ class ChatHandler
void PSendSysMessage( int32 entry, ... );
int ParseCommands(const char* text);
bool isValidChatMessage(const char* msg);
protected:
explicit ChatHandler() : m_session(NULL) {} // for CLI subclass

View file

@ -37,6 +37,28 @@
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
bool WorldSession::processChatmessageFurtherAfterSecurityChecks(std::string& msg, uint32 lang)
{
if (lang != LANG_ADDON)
{
// strip invisible characters for non-addon messages
if(sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
stripLineInvisibleChars(msg);
if (sWorld.getConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY) && GetSecurity() < SEC_MODERATOR
&& !ChatHandler(this).isValidChatMessage(msg.c_str()))
{
sLog.outError("Player %s (GUID: %u) sent a chatmessage with an invalid link: %s", GetPlayer()->GetName(),
GetPlayer()->GetGUIDLow(), msg.c_str());
if (sWorld.getConfig(CONFIG_CHAT_STRICT_LINK_CHECKING_KICK))
KickPlayer();
return false;
}
}
return true;
}
void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
{
uint32 type;
@ -150,9 +172,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
break;
// strip invisible characters for non-addon messages
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
stripLineInvisibleChars(msg);
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
return;
if(msg.empty())
break;
@ -171,9 +192,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
recv_data >> to;
recv_data >> msg;
// strip invisible characters for non-addon messages
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
stripLineInvisibleChars(msg);
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
return;
if(msg.empty())
break;
@ -224,9 +244,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
break;
// strip invisible characters for non-addon messages
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
stripLineInvisibleChars(msg);
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
return;
if(msg.empty())
break;
@ -253,9 +272,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
break;
// strip invisible characters for non-addon messages
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
stripLineInvisibleChars(msg);
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
return;
if(msg.empty())
break;
@ -280,9 +298,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
break;
// strip invisible characters for non-addon messages
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
stripLineInvisibleChars(msg);
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
return;
if(msg.empty())
break;
@ -306,9 +323,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
break;
// strip invisible characters for non-addon messages
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
stripLineInvisibleChars(msg);
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
return;
if(msg.empty())
break;
@ -334,9 +350,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
break;
// strip invisible characters for non-addon messages
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
stripLineInvisibleChars(msg);
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
return;
if(msg.empty())
break;
@ -355,9 +370,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
std::string msg="";
recv_data >> msg;
// strip invisible characters for non-addon messages
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
stripLineInvisibleChars(msg);
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
return;
if(msg.empty())
break;
@ -377,9 +391,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
std::string msg="";
recv_data >> msg;
// strip invisible characters for non-addon messages
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
stripLineInvisibleChars(msg);
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
return;
if(msg.empty())
break;
@ -399,9 +412,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
std::string msg="";
recv_data >> msg;
// strip invisible characters for non-addon messages
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
stripLineInvisibleChars(msg);
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
return;
if(msg.empty())
break;
@ -423,9 +435,8 @@ void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
recv_data >> msg;
// strip invisible characters for non-addon messages
if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
stripLineInvisibleChars(msg);
if (!processChatmessageFurtherAfterSecurityChecks(msg, lang))
return;
if(msg.empty())
break;

View file

@ -41,7 +41,7 @@ struct AchievementEntry
uint32 factionFlag; // 1 -1=all, 0=horde, 1=alliance
uint32 mapID; // 2 -1=none
//uint32 parentAchievement; // 3 its Achievement parent (can`t start while parent uncomplete, use its Criteria if don`t have own, use its progress on begin)
//char *name[16]; // 4-19
char *name[16]; // 4-19
//uint32 name_flags; // 20
//char *description[16]; // 21-36
//uint32 desc_flags; // 37

View file

@ -19,7 +19,7 @@
#ifndef MANGOS_DBCSFRM_H
#define MANGOS_DBCSFRM_H
const char Achievementfmt[]="niixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxii";
const char Achievementfmt[]="niixssssssssssssssssxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxii";
const char AchievementCriteriafmt[]="niiiiiiiixxxxxxxxxxxxxxxxxiixix";
const char AreaTableEntryfmt[]="iiinixxxxxissssssssssssssssxixxxxxxx";
const char AreaGroupEntryfmt[]="niiiiiii";

View file

@ -1322,7 +1322,7 @@ void LoadLootTemplates_Spell()
{
// not report about not trainable spells (optionally supported by DB)
// ignore 61756 (Northrend Inscription Research (FAST QA VERSION) for example
if (!(spellInfo->Attributes & SPELL_ATTR_NOT_SHAPESHIFT) || (spellInfo->Attributes & SPELL_ATTR_UNK5))
if (!(spellInfo->Attributes & SPELL_ATTR_NOT_SHAPESHIFT) || (spellInfo->Attributes & SPELL_ATTR_TRADESPELL))
{
LootTemplates_Spell.ReportNotExistedId(spell_id);
}

View file

@ -511,43 +511,41 @@ void WorldSession::HandleMountSpecialAnimOpcode(WorldPacket& /*recvdata*/)
GetPlayer()->SendMessageToSet(&data, false);
}
void WorldSession::HandleMoveKnockBackAck( WorldPacket & /*recv_data*/ )
void WorldSession::HandleMoveKnockBackAck( WorldPacket & recv_data )
{
sLog.outDebug("CMSG_MOVE_KNOCK_BACK_ACK");
// Currently not used but maybe use later for recheck final player position
// (must be at call same as into "recv_data >> x >> y >> z >> orientation;"
/*
uint32 flags, time;
float x, y, z, orientation;
uint64 guid;
uint32 sequence;
uint32 ukn1;
float xdirection,ydirection,hspeed,vspeed;
recv_data.read_skip<uint64>(); // guid
recv_data.read_skip<uint32>(); // unk
recv_data >> guid;
recv_data >> sequence;
recv_data >> flags >> time;
recv_data >> x >> y >> z >> orientation;
recv_data >> ukn1; //unknown
recv_data >> vspeed >> xdirection >> ydirection >> hspeed;
// skip not personal message;
if(GetPlayer()->GetGUID()!=guid)
return;
// check code
*/
MovementInfo movementInfo;
ReadMovementInfo(recv_data, &movementInfo);
}
void WorldSession::HandleMoveHoverAck( WorldPacket& /*recv_data*/ )
void WorldSession::HandleMoveHoverAck( WorldPacket& recv_data )
{
sLog.outDebug("CMSG_MOVE_HOVER_ACK");
recv_data.read_skip<uint64>(); // guid
recv_data.read_skip<uint32>(); // unk
MovementInfo movementInfo;
ReadMovementInfo(recv_data, &movementInfo);
recv_data.read_skip<uint32>(); // unk2
}
void WorldSession::HandleMoveWaterWalkAck(WorldPacket& /*recv_data*/)
void WorldSession::HandleMoveWaterWalkAck(WorldPacket& recv_data)
{
sLog.outDebug("CMSG_MOVE_WATER_WALK_ACK");
recv_data.read_skip<uint64>(); // guid
recv_data.read_skip<uint32>(); // unk
MovementInfo movementInfo;
ReadMovementInfo(recv_data, &movementInfo);
recv_data.read_skip<uint32>(); // unk2
}
void WorldSession::HandleSummonResponseOpcode(WorldPacket& recv_data)

View file

@ -2034,10 +2034,8 @@ void ObjectMgr::LoadItemRequiredTarget()
if (pItemProto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_USE ||
pItemProto->Spells[i].SpellTrigger == ITEM_SPELLTRIGGER_ON_NO_DELAY_USE)
{
SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(pSpellInfo->Id);
SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(pSpellInfo->Id);
if (lower != upper)
SpellScriptTargetBounds bounds = spellmgr.GetSpellScriptTargetBounds(pSpellInfo->Id);
if (bounds.first != bounds.second)
break;
for (int j = 0; j < 3; ++j)

View file

@ -3001,7 +3001,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen
// cast talents with SPELL_EFFECT_LEARN_SPELL (other dependent spells will learned later as not auto-learned)
// note: all spells with SPELL_EFFECT_LEARN_SPELL isn't passive
if( talentCost > 0 && IsSpellHaveEffect(spellInfo,SPELL_EFFECT_LEARN_SPELL) )
if (talentCost > 0 && IsSpellHaveEffect(spellInfo,SPELL_EFFECT_LEARN_SPELL))
{
// ignore stance requirement for talent learn spell (stance set for spell only for client spell description show)
CastSpell(this, spell_id, true);
@ -3009,10 +3009,10 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen
// also cast passive spells (including all talents without SPELL_EFFECT_LEARN_SPELL) with additional checks
else if (IsPassiveSpell(spell_id))
{
if(IsNeedCastPassiveSpellAtLearn(spellInfo))
if (IsNeedCastPassiveSpellAtLearn(spellInfo))
CastSpell(this, spell_id, true);
}
else if( IsSpellHaveEffect(spellInfo,SPELL_EFFECT_SKILL_STEP) )
else if (IsSpellHaveEffect(spellInfo,SPELL_EFFECT_SKILL_STEP))
{
CastSpell(this, spell_id, true);
return false;
@ -3022,7 +3022,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen
m_usedTalentCount += talentCost;
// update free primary prof.points (if any, can be none in case GM .learn prof. learning)
if(uint32 freeProfs = GetFreePrimaryProfessionPoints())
if (uint32 freeProfs = GetFreePrimaryProfessionPoints())
{
if(spellmgr.IsPrimaryProfessionFirstRankSpell(spell_id))
SetFreePrimaryProfessions(freeProfs-1);
@ -3033,20 +3033,19 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen
SpellLearnSkillNode const* spellLearnSkill = spellmgr.GetSpellLearnSkill(spell_id);
SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spell_id);
SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spell_id);
SkillLineAbilityMapBounds skill_bounds = spellmgr.GetSkillLineAbilityMapBounds(spell_id);
if(spellLearnSkill)
if (spellLearnSkill)
{
uint32 skill_value = GetPureSkillValue(spellLearnSkill->skill);
uint32 skill_max_value = GetPureMaxSkillValue(spellLearnSkill->skill);
if(skill_value < spellLearnSkill->value)
if (skill_value < spellLearnSkill->value)
skill_value = spellLearnSkill->value;
uint32 new_skill_max_value = spellLearnSkill->maxvalue == 0 ? maxskill : spellLearnSkill->maxvalue;
if(skill_max_value < new_skill_max_value)
if (skill_max_value < new_skill_max_value)
skill_max_value = new_skill_max_value;
SetSkill(spellLearnSkill->skill,skill_value,skill_max_value);
@ -3054,16 +3053,16 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen
else
{
// not ranked skills
for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
for(SkillLineAbilityMap::const_iterator _spell_idx = skill_bounds.first; _spell_idx != skill_bounds.second; ++_spell_idx)
{
SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->skillId);
if(!pSkill)
if (!pSkill)
continue;
if(HasSkill(pSkill->id))
if (HasSkill(pSkill->id))
continue;
if(_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL ||
if (_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL ||
// lockpicking/runeforging special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL
(pSkill->id==SKILL_LOCKPICKING || pSkill->id==SKILL_RUNEFORGING) && _spell_idx->second->max_value==0 )
{
@ -3086,24 +3085,23 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen
}
// learn dependent spells
SpellLearnSpellMap::const_iterator spell_begin = spellmgr.GetBeginSpellLearnSpell(spell_id);
SpellLearnSpellMap::const_iterator spell_end = spellmgr.GetEndSpellLearnSpell(spell_id);
SpellLearnSpellMapBounds spell_bounds = spellmgr.GetSpellLearnSpellMapBounds(spell_id);
for(SpellLearnSpellMap::const_iterator itr2 = spell_begin; itr2 != spell_end; ++itr2)
for(SpellLearnSpellMap::const_iterator itr2 = spell_bounds.first; itr2 != spell_bounds.second; ++itr2)
{
if(!itr2->second.autoLearned)
if (!itr2->second.autoLearned)
{
if(!IsInWorld() || !itr2->second.active) // at spells loading, no output, but allow save
if (!IsInWorld() || !itr2->second.active) // at spells loading, no output, but allow save
addSpell(itr2->second.spell,itr2->second.active,true,true,false);
else // at normal learning
learnSpell(itr2->second.spell,true);
}
}
if(!GetSession()->PlayerLoading())
if (!GetSession()->PlayerLoading())
{
// not ranked skills
for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
for(SkillLineAbilityMap::const_iterator _spell_idx = skill_bounds.first; _spell_idx != skill_bounds.second; ++_spell_idx)
{
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE,_spell_idx->second->skillId);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS,_spell_idx->second->skillId);
@ -3238,19 +3236,19 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
prevSkill = spellmgr.GetSpellLearnSkill(spellmgr.GetFirstSpellInChain(prev_spell));
}
if(!prevSkill) // not found prev skill setting, remove skill
if (!prevSkill) // not found prev skill setting, remove skill
SetSkill(spellLearnSkill->skill,0,0);
else // set to prev. skill setting values
{
uint32 skill_value = GetPureSkillValue(prevSkill->skill);
uint32 skill_max_value = GetPureMaxSkillValue(prevSkill->skill);
if(skill_value > prevSkill->value)
if (skill_value > prevSkill->value)
skill_value = prevSkill->value;
uint32 new_skill_max_value = prevSkill->maxvalue == 0 ? GetMaxSkillValueForLevel() : prevSkill->maxvalue;
if(skill_max_value > new_skill_max_value)
if (skill_max_value > new_skill_max_value)
skill_max_value = new_skill_max_value;
SetSkill(prevSkill->skill,skill_value,skill_max_value);
@ -3261,22 +3259,22 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
else
{
// not ranked skills
SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spell_id);
SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spell_id);
SkillLineAbilityMapBounds bounds = spellmgr.GetSkillLineAbilityMapBounds(spell_id);
for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
for(SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
{
SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->skillId);
if(!pSkill)
if (!pSkill)
continue;
if(_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL ||
if(_spell_idx->second->learnOnGetSkill == ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL &&
pSkill->categoryId != SKILL_CATEGORY_CLASS ||// not unlearn class skills (spellbook/talent pages)
// lockpicking/runeforging special case, not have ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL
(pSkill->id==SKILL_LOCKPICKING || pSkill->id==SKILL_RUNEFORGING) && _spell_idx->second->max_value==0 )
{
// not reset skills for professions and racial abilities
if( (pSkill->categoryId==SKILL_CATEGORY_SECONDARY || pSkill->categoryId==SKILL_CATEGORY_PROFESSION) &&
(IsProfessionSkill(pSkill->id) || _spell_idx->second->racemask!=0) )
if ((pSkill->categoryId==SKILL_CATEGORY_SECONDARY || pSkill->categoryId==SKILL_CATEGORY_PROFESSION) &&
(IsProfessionSkill(pSkill->id) || _spell_idx->second->racemask!=0))
continue;
SetSkill(pSkill->id, 0, 0 );
@ -3285,43 +3283,42 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
}
// remove dependent spells
SpellLearnSpellMap::const_iterator spell_begin = spellmgr.GetBeginSpellLearnSpell(spell_id);
SpellLearnSpellMap::const_iterator spell_end = spellmgr.GetEndSpellLearnSpell(spell_id);
SpellLearnSpellMapBounds spell_bounds = spellmgr.GetSpellLearnSpellMapBounds(spell_id);
for(SpellLearnSpellMap::const_iterator itr2 = spell_begin; itr2 != spell_end; ++itr2)
for(SpellLearnSpellMap::const_iterator itr2 = spell_bounds.first; itr2 != spell_bounds.second; ++itr2)
removeSpell(itr2->second.spell, disabled);
// activate lesser rank in spellbook/action bar, and cast it if need
bool prev_activate = false;
if(uint32 prev_id = spellmgr.GetPrevSpellInChain (spell_id))
if (uint32 prev_id = spellmgr.GetPrevSpellInChain (spell_id))
{
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
// if talent then lesser rank also talent and need learn
if(talentCosts)
if (talentCosts)
{
if(learn_low_rank)
learnSpell (prev_id,false);
}
// if ranked non-stackable spell: need activate lesser rank and update dendence state
else if(cur_active && !SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0)
else if (cur_active && !SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0)
{
// need manually update dependence state (learn spell ignore like attempts)
PlayerSpellMap::iterator prev_itr = m_spells.find(prev_id);
if (prev_itr != m_spells.end())
{
if(prev_itr->second->dependent != cur_dependent)
if (prev_itr->second->dependent != cur_dependent)
{
prev_itr->second->dependent = cur_dependent;
if(prev_itr->second->state != PLAYERSPELL_NEW)
if (prev_itr->second->state != PLAYERSPELL_NEW)
prev_itr->second->state = PLAYERSPELL_CHANGED;
}
// now re-learn if need re-activate
if(cur_active && !prev_itr->second->active && learn_low_rank)
if (cur_active && !prev_itr->second->active && learn_low_rank)
{
if(addSpell(prev_id,true,false,prev_itr->second->dependent,prev_itr->second->disabled))
if (addSpell(prev_id,true,false,prev_itr->second->dependent,prev_itr->second->disabled))
{
// downgrade spell ranks in spellbook and action bar
WorldPacket data(SMSG_SUPERCEDED_SPELL, 4 + 4);
@ -5045,20 +5042,19 @@ bool Player::UpdateCraftSkill(uint32 spellid)
{
sLog.outDebug("UpdateCraftSkill spellid %d", spellid);
SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spellid);
SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spellid);
SkillLineAbilityMapBounds bounds = spellmgr.GetSkillLineAbilityMapBounds(spellid);
for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
for(SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
{
if(_spell_idx->second->skillId)
if (_spell_idx->second->skillId)
{
uint32 SkillValue = GetPureSkillValue(_spell_idx->second->skillId);
// Alchemy Discoveries here
SpellEntry const* spellEntry = sSpellStore.LookupEntry(spellid);
if(spellEntry && spellEntry->Mechanic==MECHANIC_DISCOVERY)
if (spellEntry && spellEntry->Mechanic==MECHANIC_DISCOVERY)
{
if(uint32 discoveredSpell = GetSkillDiscoverySpell(_spell_idx->second->skillId, spellid, this))
if (uint32 discoveredSpell = GetSkillDiscoverySpell(_spell_idx->second->skillId, spellid, this))
learnSpell(discoveredSpell,false);
}
@ -18596,19 +18592,18 @@ bool Player::IsSpellFitByClassAndRace( uint32 spell_id ) const
uint32 racemask = getRaceMask();
uint32 classmask = getClassMask();
SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spell_id);
SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spell_id);
if(lower==upper)
SkillLineAbilityMapBounds bounds = spellmgr.GetSkillLineAbilityMapBounds(spell_id);
if (bounds.first==bounds.second)
return true;
for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
for(SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
{
// skip wrong race skills
if( _spell_idx->second->racemask && (_spell_idx->second->racemask & racemask) == 0)
if (_spell_idx->second->racemask && (_spell_idx->second->racemask & racemask) == 0)
continue;
// skip wrong class skills
if( _spell_idx->second->classmask && (_spell_idx->second->classmask & classmask) == 0)
if (_spell_idx->second->classmask && (_spell_idx->second->classmask & classmask) == 0)
continue;
return true;

View file

@ -207,6 +207,18 @@ enum ItemQualities
#define MAX_ITEM_QUALITY 8
const uint32 ItemQualityColors[MAX_ITEM_QUALITY] = {
0xff9d9d9d, //GREY
0xffffffff, //WHITE
0xff1eff00, //GREEN
0xff0070dd, //BLUE
0xffa335ee, //PURPLE
0xffff8000, //ORANGE
0xffe6cc80, //LIGHT YELLOW
0xffe6cc80 //LIGHT YELLOW
};
// ***********************************
// Spell Attributes definitions
// ***********************************
@ -216,7 +228,7 @@ enum ItemQualities
#define SPELL_ATTR_ON_NEXT_SWING_1 0x00000004 // 2 on next swing
#define SPELL_ATTR_UNK3 0x00000008 // 3 not set in 3.0.3
#define SPELL_ATTR_UNK4 0x00000010 // 4
#define SPELL_ATTR_UNK5 0x00000020 // 5 trade spells?
#define SPELL_ATTR_TRADESPELL 0x00000020 // 5 trade spells, will be added by client to a sublist of profession spell
#define SPELL_ATTR_PASSIVE 0x00000040 // 6 Passive spell
#define SPELL_ATTR_UNK7 0x00000080 // 7 visible?
#define SPELL_ATTR_UNK8 0x00000100 // 8
@ -658,7 +670,7 @@ enum SpellEffects
SPELL_EFFECT_CALL_PET = 135,
SPELL_EFFECT_HEAL_PCT = 136,
SPELL_EFFECT_ENERGIZE_PCT = 137,
SPELL_EFFECT_138 = 138,
SPELL_EFFECT_LEAP_BACK = 138,
SPELL_EFFECT_CLEAR_QUEST = 139,
SPELL_EFFECT_FORCE_CAST = 140,
SPELL_EFFECT_141 = 141,
@ -2309,6 +2321,16 @@ enum ChatMsg
#define MAX_CHAT_MSG_TYPE 0x32
enum ChatLinkColors
{
CHAT_LINK_COLOR_TRADE = 0xffffd000, // orange
CHAT_LINK_COLOR_TALENT = 0xff4e96f7, // blue
CHAT_LINK_COLOR_SPELL = 0xff71d5ff, // bright blue
CHAT_LINK_COLOR_ENCHANT = 0xffffd000, // orange
CHAT_LINK_COLOR_ACHIEVEMENT = 0xffffff00,
CHAT_LINK_COLOR_GLYPH = 0xff66bbff
};
// Values from ItemPetFood (power of (value-1) used for compare with CreatureFamilyEntry.petDietMask
enum PetDiet
{

View file

@ -114,21 +114,18 @@ void LoadSkillDiscoveryTable()
SkillDiscoveryStore[reqSkillOrSpell].push_back( SkillDiscoveryEntry(spellId, reqSkillValue, chance) );
}
else if( reqSkillOrSpell == 0 ) // skill case
else if (reqSkillOrSpell == 0) // skill case
{
SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spellId);
SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spellId);
SkillLineAbilityMapBounds bounds = spellmgr.GetSkillLineAbilityMapBounds(spellId);
if(lower==upper)
if (bounds.first==bounds.second)
{
sLog.outErrorDb("Spell (ID: %u) not listed in `SkillLineAbility.dbc` but listed with `reqSpell`=0 in `skill_discovery_template` table",spellId);
continue;
}
for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
{
for(SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
SkillDiscoveryStore[-int32(_spell_idx->second->skillId)].push_back( SkillDiscoveryEntry(spellId, reqSkillValue, chance) );
}
}
else
{
@ -143,21 +140,21 @@ void LoadSkillDiscoveryTable()
sLog.outString();
sLog.outString( ">> Loaded %u skill discovery definitions", count );
if(!ssNonDiscoverableEntries.str().empty())
if (!ssNonDiscoverableEntries.str().empty())
sLog.outErrorDb("Some items can't be successfully discovered: have in chance field value < 0.000001 in `skill_discovery_template` DB table . List:\n%s",ssNonDiscoverableEntries.str().c_str());
// report about empty data for explicit discovery spells
for(uint32 spell_id = 1; spell_id < sSpellStore.GetNumRows(); ++spell_id)
{
SpellEntry const* spellEntry = sSpellStore.LookupEntry(spell_id);
if(!spellEntry)
if (!spellEntry)
continue;
// skip not explicit discovery spells
if (!IsExplicitDiscoverySpell(spellEntry))
continue;
if(SkillDiscoveryStore.find(spell_id)==SkillDiscoveryStore.end())
if (SkillDiscoveryStore.find(spell_id)==SkillDiscoveryStore.end())
sLog.outErrorDb("Spell (ID: %u) is 100%% chance random discovery ability but not have data in `skill_discovery_template` table",spell_id);
}
}
@ -170,9 +167,8 @@ uint32 GetExplicitDiscoverySpell(uint32 spellId, Player* player)
if (tab == SkillDiscoveryStore.end())
return 0;
SkillLineAbilityMap::const_iterator lower = spellmgr.GetBeginSkillLineAbilityMap(spellId);
SkillLineAbilityMap::const_iterator upper = spellmgr.GetEndSkillLineAbilityMap(spellId);
uint32 skillvalue = lower != upper ? player->GetSkillValue(lower->second->skillId) : 0;
SkillLineAbilityMapBounds bounds = spellmgr.GetSkillLineAbilityMapBounds(spellId);
uint32 skillvalue = bounds.first != bounds.second ? player->GetSkillValue(bounds.first->second->skillId) : 0;
float full_chance = 0;
for(SkillDiscoveryList::const_iterator item_iter = tab->second.begin(); item_iter != tab->second.end(); ++item_iter)

View file

@ -3966,15 +3966,15 @@ SpellCastResult Spell::CheckCast(bool strict)
}
// Spell casted only on battleground
if((m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_BATTLEGROUND) && m_caster->GetTypeId() == TYPEID_PLAYER)
if ((m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_BATTLEGROUND) && m_caster->GetTypeId() == TYPEID_PLAYER)
if(!((Player*)m_caster)->InBattleGround())
return SPELL_FAILED_ONLY_BATTLEGROUNDS;
// do not allow spells to be cast in arenas
// - with greater than 15 min CD without SPELL_ATTR_EX4_USABLE_IN_ARENA flag
// - with SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA flag
if( (m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA) ||
GetSpellRecoveryTime(m_spellInfo) > 15 * MINUTE * IN_MILISECONDS && !(m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_USABLE_IN_ARENA) )
if ((m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_NOT_USABLE_IN_ARENA) ||
GetSpellRecoveryTime(m_spellInfo) > 15 * MINUTE * IN_MILISECONDS && !(m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_USABLE_IN_ARENA))
if(MapEntry const* mapEntry = sMapStore.LookupEntry(m_caster->GetMapId()))
if(mapEntry->IsBattleArena())
return SPELL_FAILED_NOT_IN_ARENA;
@ -3985,21 +3985,21 @@ SpellCastResult Spell::CheckCast(bool strict)
SpellCastResult locRes= spellmgr.GetSpellAllowedInLocationError(m_spellInfo,m_caster->GetMapId(),zone,area,
m_caster->GetTypeId() == TYPEID_PLAYER ? ((Player*)m_caster) : NULL);
if(locRes != SPELL_CAST_OK)
if (locRes != SPELL_CAST_OK)
return locRes;
// not let players cast spells at mount (and let do it to creatures)
if( m_caster->IsMounted() && m_caster->GetTypeId()==TYPEID_PLAYER && !m_IsTriggeredSpell &&
!IsPassiveSpell(m_spellInfo->Id) && !(m_spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_MOUNTED) )
if (m_caster->IsMounted() && m_caster->GetTypeId()==TYPEID_PLAYER && !m_IsTriggeredSpell &&
!IsPassiveSpell(m_spellInfo->Id) && !(m_spellInfo->Attributes & SPELL_ATTR_CASTABLE_WHILE_MOUNTED))
{
if(m_caster->isInFlight())
if (m_caster->isInFlight())
return SPELL_FAILED_NOT_FLYING;
else
return SPELL_FAILED_NOT_MOUNTED;
}
// always (except passive spells) check items (focus object can be required for any type casts)
if(!IsPassiveSpell(m_spellInfo->Id))
if (!IsPassiveSpell(m_spellInfo->Id))
{
SpellCastResult castResult = CheckItems();
if(castResult != SPELL_CAST_OK)
@ -4007,7 +4007,7 @@ SpellCastResult Spell::CheckCast(bool strict)
}
//ImpliciteTargetA-B = 38, If fact there is 0 Spell with ImpliciteTargetB=38
if(m_UniqueTargetInfo.empty()) // skip second CheckCast apply (for delayed spells for example)
if (m_UniqueTargetInfo.empty()) // skip second CheckCast apply (for delayed spells for example)
{
for(uint8 j = 0; j < 3; ++j)
{
@ -4016,9 +4016,8 @@ SpellCastResult Spell::CheckCast(bool strict)
m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES ||
m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES )
{
SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(m_spellInfo->Id);
SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id);
if(lower==upper)
SpellScriptTargetBounds bounds = spellmgr.GetSpellScriptTargetBounds(m_spellInfo->Id);
if(bounds.first==bounds.second)
sLog.outErrorDb("Spell (ID: %u) has effect EffectImplicitTargetA/EffectImplicitTargetB = TARGET_SCRIPT or TARGET_SCRIPT_COORDINATES, but does not have record in `spell_script_target`",m_spellInfo->Id);
SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex);
@ -4027,7 +4026,7 @@ SpellCastResult Spell::CheckCast(bool strict)
Creature* creatureScriptTarget = NULL;
GameObject* goScriptTarget = NULL;
for(SpellScriptTarget::const_iterator i_spellST = lower; i_spellST != upper; ++i_spellST)
for(SpellScriptTarget::const_iterator i_spellST = bounds.first; i_spellST != bounds.second; ++i_spellST)
{
switch(i_spellST->second.type)
{
@ -4035,7 +4034,7 @@ SpellCastResult Spell::CheckCast(bool strict)
{
GameObject* p_GameObject = NULL;
if(i_spellST->second.targetEntry)
if (i_spellST->second.targetEntry)
{
CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
Cell cell(p);
@ -4048,7 +4047,7 @@ SpellCastResult Spell::CheckCast(bool strict)
CellLock<GridReadGuard> cell_lock(cell, p);
cell_lock->Visit(cell_lock, object_checker, *m_caster->GetMap());
if(p_GameObject)
if (p_GameObject)
{
// remember found target and range, next attempt will find more near target with another entry
creatureScriptTarget = NULL;
@ -4056,10 +4055,10 @@ SpellCastResult Spell::CheckCast(bool strict)
range = go_check.GetLastRange();
}
}
else if( focusObject ) // Focus Object
else if (focusObject) // Focus Object
{
float frange = m_caster->GetDistance(focusObject);
if(range >= frange)
if (range >= frange)
{
creatureScriptTarget = NULL;
goScriptTarget = focusObject;
@ -5952,4 +5951,4 @@ void Spell::FillRaidOrPartyHealthPriorityTargets( UnitList &TagUnitMap, Unit* me
TagUnitMap.push_back(healthQueue.top().getUnit());
healthQueue.pop();
}
}
}

View file

@ -280,7 +280,8 @@ class Spell
void EffectResurrect(uint32 i);
void EffectParry(uint32 i);
void EffectBlock(uint32 i);
void EffectMomentMove(uint32 i);
void EffectLeapForward(uint32 i);
void EffectLeapBack(uint32 i);
void EffectTransmitted(uint32 i);
void EffectDisEnchant(uint32 i);
void EffectInebriate(uint32 i);

View file

@ -1317,13 +1317,18 @@ void Aura::HandleAddModifier(bool apply, bool Real)
((Player*)m_target)->AddSpellMod(m_spellmod, apply);
// reapply some passive spells after add/remove related spellmods
if(m_spellProto->SpellFamilyName==SPELLFAMILY_WARRIOR && (spellFamilyMask & UI64LIT(0x0000100000000000)))
{
m_target->RemoveAurasDueToSpell(45471);
// reaplly talents to own passive persistent auras
std::set<uint32> affectedPassives;
if(apply)
m_target->CastSpell(m_target, 45471, true);
for(Unit::AuraMap::const_iterator itr = m_target->GetAuras().begin(); itr != m_target->GetAuras().end(); ++itr)
if (itr->second->IsPassive() && itr->second->IsPermanent() &&
itr->second->GetCasterGUID() == m_target->GetGUID() && isAffectedOnSpell(itr->second->GetSpellProto()))
affectedPassives.insert(itr->second->GetId());
for(std::set<uint32>::const_iterator set_itr = affectedPassives.begin(); set_itr != affectedPassives.end(); ++set_itr)
{
m_target->RemoveAurasDueToSpell(*set_itr);
m_target->CastSpell(m_target, *set_itr, true);
}
}
void Aura::HandleAddTargetTrigger(bool apply, bool /*Real*/)
@ -5993,93 +5998,102 @@ void Aura::HandleSchoolAbsorb(bool apply, bool Real)
if(!caster)
return;
// prevent double apply bonuses
if(apply && (m_target->GetTypeId()!=TYPEID_PLAYER || !((Player*)m_target)->GetSession()->PlayerLoading()))
if (apply)
{
float DoneActualBenefit = 0.0f;
switch(m_spellProto->SpellFamilyName)
// prevent double apply bonuses
if (m_target->GetTypeId()!=TYPEID_PLAYER || !((Player*)m_target)->GetSession()->PlayerLoading())
{
case SPELLFAMILY_PRIEST:
// Power Word: Shield
if (m_spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000001))
//+80.68% from +spell bonus
DoneActualBenefit = caster->SpellBaseHealingBonus(GetSpellSchoolMask(m_spellProto)) * 0.8068f;
break;
case SPELLFAMILY_MAGE:
// Frost Ward, Fire Ward
if (m_spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000108))
//+10% from +spell bonus
DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.1f;
// Ice Barrier
else if (m_spellProto->SpellFamilyFlags & UI64LIT(0x0000000100000000))
//+80.67% from +spell bonus
DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.8067f;
break;
case SPELLFAMILY_WARLOCK:
// Shadow Ward
if (m_spellProto->SpellFamilyFlags2 & 0x00000040)
//+30% from +spell bonus
DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.30f;
break;
default:
break;
}
DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellProto());
m_modifier.m_amount += (int32)DoneActualBenefit;
}
// Ice Barrier (remove effect from Shattered Barrier)
if(!apply && m_spellProto->SpellIconID == 32 && m_spellProto->SpellFamilyName == SPELLFAMILY_MAGE)
{
if (!((m_removeMode == AURA_REMOVE_BY_DEFAULT && !m_modifier.m_amount) || m_removeMode == AURA_REMOVE_BY_DISPEL))
return;
if (m_target->HasAura(44745,0)) // Shattered Barrier, rank 1
{
if(roll_chance_i(50))
m_target->CastSpell(m_target, 55080, true, NULL, this);
}
else if (m_target->HasAura(54787,0)) // Shattered Barrier, rank 2
{
m_target->CastSpell(m_target, 55080, true, NULL, this);
}
}
if (!apply && caster &&
// Power Word: Shield
m_spellProto->SpellFamilyName == SPELLFAMILY_PRIEST && m_spellProto->Mechanic == MECHANIC_SHIELD &&
(m_spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000001)) &&
// completely absorbed or dispelled
((m_removeMode == AURA_REMOVE_BY_DEFAULT && !m_modifier.m_amount) || m_removeMode == AURA_REMOVE_BY_DISPEL))
{
Unit::AuraList const& vDummyAuras = caster->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); itr++)
{
SpellEntry const* vSpell = (*itr)->GetSpellProto();
// Rapture (main spell)
if(vSpell->SpellFamilyName == SPELLFAMILY_PRIEST && vSpell->SpellIconID == 2894 && vSpell->Effect[1])
float DoneActualBenefit = 0.0f;
switch(m_spellProto->SpellFamilyName)
{
switch((*itr)->GetEffIndex())
{
case 0:
{
// energize caster
int32 manapct1000 = 5 * ((*itr)->GetModifier()->m_amount + spellmgr.GetSpellRank(vSpell->Id));
int32 basepoints0 = caster->GetMaxPower(POWER_MANA) * manapct1000 / 1000;
caster->CastCustomSpell(caster, 47755, &basepoints0, NULL, NULL, true);
break;
}
case 1:
{
// energize target
if (!roll_chance_i((*itr)->GetModifier()->m_amount) || caster->HasAura(63853))
break;
case SPELLFAMILY_PRIEST:
// Power Word: Shield
if (m_spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000001))
//+80.68% from +spell bonus
DoneActualBenefit = caster->SpellBaseHealingBonus(GetSpellSchoolMask(m_spellProto)) * 0.8068f;
break;
case SPELLFAMILY_MAGE:
// Frost Ward, Fire Ward
if (m_spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000108))
//+10% from +spell bonus
DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.1f;
// Ice Barrier
else if (m_spellProto->SpellFamilyFlags & UI64LIT(0x0000000100000000))
//+80.67% from +spell bonus
DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.8067f;
break;
case SPELLFAMILY_WARLOCK:
// Shadow Ward
if (m_spellProto->SpellFamilyFlags2 & 0x00000040)
//+30% from +spell bonus
DoneActualBenefit = caster->SpellBaseDamageBonus(GetSpellSchoolMask(m_spellProto)) * 0.30f;
break;
case SPELLFAMILY_DRUID:
// Savage Defense (amount store original percent of attack power applied)
if (m_spellProto->SpellIconID == 50) // only spell with this aura fit
m_modifier.m_amount = int32(m_modifier.m_amount * m_target->GetTotalAttackPowerValue(BASE_ATTACK) / 100);
break;
default:
break;
}
switch(m_target->getPowerType())
DoneActualBenefit *= caster->CalculateLevelPenalty(GetSpellProto());
m_modifier.m_amount += (int32)DoneActualBenefit;
}
}
else
{
// Ice Barrier (remove effect from Shattered Barrier)
if (m_spellProto->SpellIconID == 32 && m_spellProto->SpellFamilyName == SPELLFAMILY_MAGE)
{
if (!((m_removeMode == AURA_REMOVE_BY_DEFAULT && !m_modifier.m_amount) || m_removeMode == AURA_REMOVE_BY_DISPEL))
return;
if (m_target->HasAura(44745,0)) // Shattered Barrier, rank 1
{
if(roll_chance_i(50))
m_target->CastSpell(m_target, 55080, true, NULL, this);
}
else if (m_target->HasAura(54787,0)) // Shattered Barrier, rank 2
{
m_target->CastSpell(m_target, 55080, true, NULL, this);
}
}
if (caster &&
// Power Word: Shield
m_spellProto->SpellFamilyName == SPELLFAMILY_PRIEST && m_spellProto->Mechanic == MECHANIC_SHIELD &&
(m_spellProto->SpellFamilyFlags & UI64LIT(0x0000000000000001)) &&
// completely absorbed or dispelled
((m_removeMode == AURA_REMOVE_BY_DEFAULT && !m_modifier.m_amount) || m_removeMode == AURA_REMOVE_BY_DISPEL))
{
Unit::AuraList const& vDummyAuras = caster->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator itr = vDummyAuras.begin(); itr != vDummyAuras.end(); itr++)
{
SpellEntry const* vSpell = (*itr)->GetSpellProto();
// Rapture (main spell)
if(vSpell->SpellFamilyName == SPELLFAMILY_PRIEST && vSpell->SpellIconID == 2894 && vSpell->Effect[1])
{
switch((*itr)->GetEffIndex())
{
case 0:
{
// energize caster
int32 manapct1000 = 5 * ((*itr)->GetModifier()->m_amount + spellmgr.GetSpellRank(vSpell->Id));
int32 basepoints0 = caster->GetMaxPower(POWER_MANA) * manapct1000 / 1000;
caster->CastCustomSpell(caster, 47755, &basepoints0, NULL, NULL, true);
break;
}
case 1:
{
// energize target
if (!roll_chance_i((*itr)->GetModifier()->m_amount) || caster->HasAura(63853))
break;
switch(m_target->getPowerType())
{
case POWER_RUNIC_POWER:
m_target->CastSpell(m_target, 63652, true, NULL, NULL, m_caster_guid);
break;
@ -6087,25 +6101,26 @@ void Aura::HandleSchoolAbsorb(bool apply, bool Real)
m_target->CastSpell(m_target, 63653, true, NULL, NULL, m_caster_guid);
break;
case POWER_MANA:
{
int32 basepoints0 = m_target->GetMaxPower(POWER_MANA) * 2 / 100;
m_target->CastCustomSpell(m_target, 63654, &basepoints0, NULL, NULL, true);
break;
}
{
int32 basepoints0 = m_target->GetMaxPower(POWER_MANA) * 2 / 100;
m_target->CastCustomSpell(m_target, 63654, &basepoints0, NULL, NULL, true);
break;
}
case POWER_ENERGY:
m_target->CastSpell(m_target, 63655, true, NULL, NULL, m_caster_guid);
break;
default:
break;
}
}
//cooldwon aura
caster->CastSpell(caster, 63853, true);
break;
//cooldwon aura
caster->CastSpell(caster, 63853, true);
break;
}
default:
sLog.outError("Changes in R-dummy spell???: effect 3");
break;
}
default:
sLog.outError("Changes in R-dummy spell???: effect 3");
break;
}
}
}

View file

@ -86,7 +86,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectUnused, // 26 SPELL_EFFECT_DEFENSE one spell: Defense
&Spell::EffectPersistentAA, // 27 SPELL_EFFECT_PERSISTENT_AREA_AURA
&Spell::EffectSummonType, // 28 SPELL_EFFECT_SUMMON
&Spell::EffectMomentMove, // 29 SPELL_EFFECT_LEAP
&Spell::EffectLeapForward, // 29 SPELL_EFFECT_LEAP
&Spell::EffectEnergize, // 30 SPELL_EFFECT_ENERGIZE
&Spell::EffectWeaponDmg, // 31 SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
&Spell::EffectTriggerMissileSpell, // 32 SPELL_EFFECT_TRIGGER_MISSILE
@ -195,7 +195,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectNULL, //135 SPELL_EFFECT_CALL_PET
&Spell::EffectHealPct, //136 SPELL_EFFECT_HEAL_PCT
&Spell::EffectEnergisePct, //137 SPELL_EFFECT_ENERGIZE_PCT
&Spell::EffectNULL, //138 SPELL_EFFECT_138 Leap
&Spell::EffectLeapBack, //138 SPELL_EFFECT_LEAP_BACK Leap back
&Spell::EffectUnused, //139 SPELL_EFFECT_CLEAR_QUEST (misc - is quest ID)
&Spell::EffectForceCast, //140 SPELL_EFFECT_FORCE_CAST
&Spell::EffectNULL, //141 SPELL_EFFECT_141 damage and reduce speed?
@ -1234,6 +1234,11 @@ void Spell::EffectDummy(uint32 i)
m_caster->CastSpell(m_caster,spell_id,true,NULL);
return;
}
case 60932: // Disengage (one from creature versions)
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget,60934,true,NULL);
return;
}
//All IconID Check in there
@ -1568,6 +1573,28 @@ void Spell::EffectDummy(uint32 i)
return;
}
// Disengage
if (m_spellInfo->SpellFamilyFlags & UI64LIT(0x0000400000000000))
{
Unit* target = unitTarget;
uint32 spellid;
switch(m_spellInfo->Id)
{
case 781: // player case
target = m_caster;
spellid = 56446;
break;
case 57635: spellid = 57636; break; // one from creature cases
case 61507: spellid = 61508; break; // one from creature cases
default:
sLog.outError("Spell %u not handled propertly in EffectDummy(Disengage)",m_spellInfo->Id);
return;
}
if (!target || !target->isAlive())
return;
m_caster->CastSpell(target,spellid,true,NULL);
}
switch(m_spellInfo->Id)
{
case 23989: // Readiness talent
@ -5985,7 +6012,7 @@ void Spell::EffectBlock(uint32 /*i*/)
((Player*)unitTarget)->SetCanBlock(true);
}
void Spell::EffectMomentMove(uint32 i)
void Spell::EffectLeapForward(uint32 i)
{
if(unitTarget->isInFlight())
return;
@ -6013,6 +6040,14 @@ void Spell::EffectMomentMove(uint32 i)
}
}
void Spell::EffectLeapBack(uint32 i)
{
if(unitTarget->isInFlight())
return;
m_caster->KnockBackFrom(unitTarget,float(m_spellInfo->EffectMiscValue[i])/10,float(damage)/10);
}
void Spell::EffectReputation(uint32 i)
{
if(!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
@ -6242,25 +6277,10 @@ void Spell::EffectSummonCritter(uint32 i)
void Spell::EffectKnockBack(uint32 i)
{
if(!unitTarget || !m_caster)
if(!unitTarget)
return;
// Effect only works on players
if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
return;
float vsin = sin(m_caster->GetAngle(unitTarget));
float vcos = cos(m_caster->GetAngle(unitTarget));
WorldPacket data(SMSG_MOVE_KNOCK_BACK, 8+4+4+4+4+4);
data.append(unitTarget->GetPackGUID());
data << uint32(0); // Sequence
data << float(vcos); // x direction
data << float(vsin); // y direction
data << float(m_spellInfo->EffectMiscValue[i])/10; // Horizontal speed
data << float(damage/-10); // Z Movement speed (vertical)
((Player*)unitTarget)->GetSession()->SendPacket(&data);
unitTarget->KnockBackFrom(m_caster,float(m_spellInfo->EffectMiscValue[i])/10,float(damage)/10);
}
void Spell::EffectSendTaxi(uint32 i)
@ -6273,26 +6293,10 @@ void Spell::EffectSendTaxi(uint32 i)
void Spell::EffectPlayerPull(uint32 i)
{
if(!unitTarget || !m_caster)
if(!unitTarget)
return;
// Effect only works on players
if(unitTarget->GetTypeId()!=TYPEID_PLAYER)
return;
float vsin = sin(unitTarget->GetAngle(m_caster));
float vcos = cos(unitTarget->GetAngle(m_caster));
WorldPacket data(SMSG_MOVE_KNOCK_BACK, 8+4+4+4+4+4);
data.append(unitTarget->GetPackGUID());
data << uint32(0); // Sequence
data << float(vcos); // x direction
data << float(vsin); // y direction
// Horizontal speed
data << float(damage ? damage : unitTarget->GetDistance2d(m_caster));
data << float(m_spellInfo->EffectMiscValue[i])/-10; // Z Movement speed
((Player*)unitTarget)->GetSession()->SendPacket(&data);
unitTarget->KnockBackFrom(m_caster,float(damage ? damage : unitTarget->GetDistance2d(m_caster)),float(m_spellInfo->EffectMiscValue[i])/10);
}
void Spell::EffectDispelMechanic(uint32 i)

View file

@ -75,7 +75,7 @@ uint32 GetSpellCastTime(SpellEntry const* spellInfo, Spell const* spell)
if(Player* modOwner = spell->GetCaster()->GetSpellModOwner())
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CASTING_TIME, castTime, spell);
if( !(spellInfo->Attributes & (SPELL_ATTR_UNK4|SPELL_ATTR_UNK5)) )
if( !(spellInfo->Attributes & (SPELL_ATTR_UNK4|SPELL_ATTR_TRADESPELL)) )
castTime = int32(castTime * spell->GetCaster()->GetFloatValue(UNIT_MOD_CAST_SPEED));
else
{
@ -1693,16 +1693,15 @@ bool SpellMgr::IsPrimaryProfessionFirstRankSpell(uint32 spellId) const
bool SpellMgr::IsSkillBonusSpell(uint32 spellId) const
{
SkillLineAbilityMap::const_iterator lower = GetBeginSkillLineAbilityMap(spellId);
SkillLineAbilityMap::const_iterator upper = GetEndSkillLineAbilityMap(spellId);
SkillLineAbilityMapBounds bounds = GetSkillLineAbilityMapBounds(spellId);
for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
for(SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
{
SkillLineAbilityEntry const *pAbility = _spell_idx->second;
if (!pAbility || pAbility->learnOnGetSkill != ABILITY_LEARNED_ON_GET_PROFESSION_SKILL)
continue;
if(pAbility->req_skill_value > 0)
if (pAbility->req_skill_value > 0)
return true;
}
@ -1964,7 +1963,7 @@ void SpellMgr::LoadSpellLearnSpells()
// 0 1 2
QueryResult *result = WorldDatabase.Query("SELECT entry, SpellID, Active FROM spell_learn_spell");
if(!result)
if (!result)
{
barGoLink bar( 1 );
bar.step();
@ -1990,19 +1989,19 @@ void SpellMgr::LoadSpellLearnSpells()
node.active = fields[2].GetBool();
node.autoLearned= false;
if(!sSpellStore.LookupEntry(spell_id))
if (!sSpellStore.LookupEntry(spell_id))
{
sLog.outErrorDb("Spell %u listed in `spell_learn_spell` does not exist",spell_id);
continue;
}
if(!sSpellStore.LookupEntry(node.spell))
if (!sSpellStore.LookupEntry(node.spell))
{
sLog.outErrorDb("Spell %u listed in `spell_learn_spell` learning not existed spell %u",spell_id,node.spell);
continue;
}
if(GetTalentSpellCost(node.spell))
if (GetTalentSpellCost(node.spell))
{
sLog.outErrorDb("Spell %u listed in `spell_learn_spell` attempt learning talent spell %u, skipped",spell_id,node.spell);
continue;
@ -2021,7 +2020,7 @@ void SpellMgr::LoadSpellLearnSpells()
{
SpellEntry const* entry = sSpellStore.LookupEntry(spell);
if(!entry)
if (!entry)
continue;
for(int i = 0; i < 3; ++i)
@ -2033,7 +2032,7 @@ void SpellMgr::LoadSpellLearnSpells()
dbc_node.active = true; // all dbc based learned spells is active (show in spell book or hide by client itself)
// ignore learning not existed spells (broken/outdated/or generic learnig spell 483
if(!sSpellStore.LookupEntry(dbc_node.spell))
if (!sSpellStore.LookupEntry(dbc_node.spell))
continue;
// talent or passive spells or skill-step spells auto-casted and not need dependent learning,
@ -2041,13 +2040,12 @@ void SpellMgr::LoadSpellLearnSpells()
// other required explicit dependent learning
dbc_node.autoLearned = entry->EffectImplicitTargetA[i]==TARGET_PET || GetTalentSpellCost(spell) > 0 || IsPassiveSpell(spell) || IsSpellHaveEffect(entry,SPELL_EFFECT_SKILL_STEP);
SpellLearnSpellMap::const_iterator db_node_begin = GetBeginSpellLearnSpell(spell);
SpellLearnSpellMap::const_iterator db_node_end = GetEndSpellLearnSpell(spell);
SpellLearnSpellMapBounds db_node_bounds = GetSpellLearnSpellMapBounds(spell);
bool found = false;
for(SpellLearnSpellMap::const_iterator itr = db_node_begin; itr != db_node_end; ++itr)
for(SpellLearnSpellMap::const_iterator itr = db_node_bounds.first; itr != db_node_bounds.second; ++itr)
{
if(itr->second.spell == dbc_node.spell)
if (itr->second.spell == dbc_node.spell)
{
sLog.outErrorDb("Spell %u auto-learn spell %u in spell.dbc then the record in `spell_learn_spell` is redundant, please fix DB.",
spell,dbc_node.spell);
@ -2056,7 +2054,7 @@ void SpellMgr::LoadSpellLearnSpells()
}
}
if(!found) // add new spell-spell pair if not found
if (!found) // add new spell-spell pair if not found
{
mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(spell,dbc_node));
++dbc_count;

View file

@ -545,6 +545,7 @@ struct SpellTargetEntry
};
typedef std::multimap<uint32,SpellTargetEntry> SpellScriptTarget;
typedef std::pair<SpellScriptTarget::const_iterator,SpellScriptTarget::const_iterator> SpellScriptTargetBounds;
// coordinates for spells (accessed using SpellMgr functions)
struct SpellTargetPosition
@ -666,8 +667,10 @@ struct SpellLearnSpellNode
};
typedef std::multimap<uint32, SpellLearnSpellNode> SpellLearnSpellMap;
typedef std::pair<SpellLearnSpellMap::const_iterator,SpellLearnSpellMap::const_iterator> SpellLearnSpellMapBounds;
typedef std::multimap<uint32, SkillLineAbilityEntry const*> SkillLineAbilityMap;
typedef std::pair<SkillLineAbilityMap::const_iterator,SkillLineAbilityMap::const_iterator> SkillLineAbilityMapBounds;
typedef std::multimap<uint32, uint32> PetLevelupSpellSet;
typedef std::map<uint32, PetLevelupSpellSet> PetLevelupSpellMap;
@ -883,22 +886,16 @@ class SpellMgr
return mSpellLearnSpells.find(spell_id) != mSpellLearnSpells.end();
}
SpellLearnSpellMap::const_iterator GetBeginSpellLearnSpell(uint32 spell_id) const
SpellLearnSpellMapBounds GetSpellLearnSpellMapBounds(uint32 spell_id) const
{
return mSpellLearnSpells.lower_bound(spell_id);
}
SpellLearnSpellMap::const_iterator GetEndSpellLearnSpell(uint32 spell_id) const
{
return mSpellLearnSpells.upper_bound(spell_id);
return SpellLearnSpellMapBounds(mSpellLearnSpells.lower_bound(spell_id),mSpellLearnSpells.upper_bound(spell_id));
}
bool IsSpellLearnToSpell(uint32 spell_id1,uint32 spell_id2) const
{
SpellLearnSpellMap::const_iterator b = GetBeginSpellLearnSpell(spell_id1);
SpellLearnSpellMap::const_iterator e = GetEndSpellLearnSpell(spell_id1);
for(SpellLearnSpellMap::const_iterator i = b; i != e; ++i)
if(i->second.spell==spell_id2)
SpellLearnSpellMapBounds bounds = GetSpellLearnSpellMapBounds(spell_id1);
for(SpellLearnSpellMap::const_iterator i = bounds.first; i != bounds.second; ++i)
if (i->second.spell==spell_id2)
return true;
return false;
}
@ -912,27 +909,17 @@ class SpellMgr
// Spell script targets
SpellScriptTarget::const_iterator GetBeginSpellScriptTarget(uint32 spell_id) const
SpellScriptTargetBounds GetSpellScriptTargetBounds(uint32 spell_id) const
{
return mSpellScriptTarget.lower_bound(spell_id);
}
SpellScriptTarget::const_iterator GetEndSpellScriptTarget(uint32 spell_id) const
{
return mSpellScriptTarget.upper_bound(spell_id);
return SpellScriptTargetBounds(mSpellScriptTarget.lower_bound(spell_id),mSpellScriptTarget.upper_bound(spell_id));
}
// Spell correctess for client using
static bool IsSpellValid(SpellEntry const * spellInfo, Player* pl = NULL, bool msg = true);
SkillLineAbilityMap::const_iterator GetBeginSkillLineAbilityMap(uint32 spell_id) const
SkillLineAbilityMapBounds GetSkillLineAbilityMapBounds(uint32 spell_id) const
{
return mSkillLineAbilityMap.lower_bound(spell_id);
}
SkillLineAbilityMap::const_iterator GetEndSkillLineAbilityMap(uint32 spell_id) const
{
return mSkillLineAbilityMap.upper_bound(spell_id);
return SkillLineAbilityMapBounds(mSkillLineAbilityMap.lower_bound(spell_id),mSkillLineAbilityMap.upper_bound(spell_id));
}
PetAura const* GetPetAura(uint32 spell_id, uint8 eff)

View file

@ -44,6 +44,7 @@
#include "CellImpl.h"
#include "Path.h"
#include "Traveller.h"
#include "VMapFactory.h"
#include <math.h>
@ -3436,17 +3437,17 @@ bool Unit::AddAura(Aura *Aur)
switch(aurName)
{
// DoT/HoT/etc
case SPELL_AURA_PERIODIC_DAMAGE: // allow stack
case SPELL_AURA_PERIODIC_DAMAGE: // allow stack
case SPELL_AURA_PERIODIC_DAMAGE_PERCENT:
case SPELL_AURA_PERIODIC_LEECH:
case SPELL_AURA_PERIODIC_HEAL:
case SPELL_AURA_OBS_MOD_HEALTH:
case SPELL_AURA_PERIODIC_MANA_LEECH:
case SPELL_AURA_PERIODIC_ENERGIZE:
case SPELL_AURA_OBS_MOD_MANA:
case SPELL_AURA_POWER_BURN_MANA:
break;
default: // not allow
case SPELL_AURA_PERIODIC_ENERGIZE: // all or self or clear non-stackable
default: // not allow
// can be only single (this check done at _each_ aura add
RemoveAura(i2,AURA_REMOVE_BY_STACK);
stop = true;
@ -12051,3 +12052,47 @@ void Unit::SetPvP( bool state )
if(Creature *totem = GetMap()->GetCreature(m_TotemSlot[i]))
totem->SetPvP(state);
}
void Unit::KnockBackFrom(Unit* target, float horizintalSpeed, float verticalSpeed)
{
float angle = this == target ? GetOrientation() + M_PI : target->GetAngle(this);
float vsin = sin(angle);
float vcos = cos(angle);
// Effect propertly implemented only for players
if(GetTypeId()==TYPEID_PLAYER)
{
WorldPacket data(SMSG_MOVE_KNOCK_BACK, 8+4+4+4+4+4);
data.append(GetPackGUID());
data << uint32(0); // Sequence
data << float(vcos); // x direction
data << float(vsin); // y direction
data << float(horizintalSpeed); // Horizontal speed
data << float(-verticalSpeed); // Z Movement speed (vertical)
((Player*)this)->GetSession()->SendPacket(&data);
}
else
{
float dis = horizintalSpeed;
float ox, oy, oz;
GetPosition(ox, oy, oz);
float fx = ox + dis * vcos;
float fy = oy + dis * vsin;
float fz = oz;
float fx2, fy2, fz2; // getObjectHitPos overwrite last args in any result case
if(VMAP::VMapFactory::createOrGetVMapManager()->getObjectHitPos(GetMapId(), ox,oy,oz+0.5, fx,fy,oz+0.5,fx2,fy2,fz2, -0.5))
{
fx = fx2;
fy = fy2;
fz = fz2;
UpdateGroundPositionZ(fx, fy, fz);
}
//FIXME: this mostly hack, must exist some packet for proper creature move at client side
// with CreatureRelocation at server side
NearTeleportTo(fx, fy, fz, GetOrientation(), this == target);
}
}

View file

@ -1450,6 +1450,8 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
void SetHover(bool on);
bool isHover() const { return HasAuraType(SPELL_AURA_HOVER); }
void KnockBackFrom(Unit* target, float horizintalSpeed, float verticalSpeed);
void _RemoveAllAuraMods();
void _ApplyAllAuraMods();

View file

@ -922,6 +922,8 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_TALENTS_INSPECTING] = sConfig.GetBoolDefault("TalentsInspecting", true);
m_configs[CONFIG_CHAT_FAKE_MESSAGE_PREVENTING] = sConfig.GetBoolDefault("ChatFakeMessagePreventing", false);
m_configs[CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY] = sConfig.GetIntDefault("ChatStrictLinkChecking.Severity", 0);
m_configs[CONFIG_CHAT_STRICT_LINK_CHECKING_KICK] = sConfig.GetIntDefault("ChatStrictLinkChecking.Kick", 0);
m_configs[CONFIG_CORPSE_DECAY_NORMAL] = sConfig.GetIntDefault("Corpse.Decay.NORMAL", 60);
m_configs[CONFIG_CORPSE_DECAY_RARE] = sConfig.GetIntDefault("Corpse.Decay.RARE", 300);

View file

@ -178,6 +178,8 @@ enum WorldConfigs
CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL,
CONFIG_TALENTS_INSPECTING,
CONFIG_CHAT_FAKE_MESSAGE_PREVENTING,
CONFIG_CHAT_STRICT_LINK_CHECKING_SEVERITY,
CONFIG_CHAT_STRICT_LINK_CHECKING_KICK,
CONFIG_CORPSE_DECAY_NORMAL,
CONFIG_CORPSE_DECAY_RARE,
CONFIG_CORPSE_DECAY_ELITE,

View file

@ -563,6 +563,7 @@ class MANGOS_DLL_SPEC WorldSession
void HandlePushQuestToParty(WorldPacket& recvPacket);
void HandleQuestPushResult(WorldPacket& recvPacket);
bool processChatmessageFurtherAfterSecurityChecks(std::string&, uint32);
void HandleMessagechatOpcode(WorldPacket& recvPacket);
void HandleTextEmoteOpcode(WorldPacket& recvPacket);
void HandleChatIgnoredOpcode(WorldPacket& recvPacket);

View file

@ -826,6 +826,19 @@ ListenRange.Yell = 300
# Default: 0 (disible fake messages preventing)
# 1 (enabled fake messages preventing)
#
# ChatStrictLinkChecking.Severity
# Check chat messages for ingame links to spells, items, quests, achievements etc.
# Default: 0 (disable link checking)
# 1 (check if only valid pipe commands are used. This prevents posting pictures for example)
# 2 (verifiy that pipe commands are used in a correct order)
# 3 (check if color, entry and name don't contradict each other. For correct work, please assure
# that you have extracted locale DBCs of every language specific client playing on this server.)
#
# ChatStrictLinkChecking.Kick
# Defines, what should be done if a message is considered to contain invalid pipe commands.
# Default: 0 (silently ignore message)
# 1 (kick players who sent invalid formed messages)
#
# ChatFlood.MessageCount
# Chat anti-flood protection, haste message count to activate protection
# Default: 10
@ -852,6 +865,8 @@ ListenRange.Yell = 300
###################################################################################################################
ChatFakeMessagePreventing = 0
ChatStrictLinkChecking.Severity = 0
ChatStrictLinkChecking.Kick = 0
ChatFlood.MessageCount = 10
ChatFlood.MessageDelay = 1
ChatFlood.MuteTime = 10

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "8423"
#define REVISION_NR "8432"
#endif // __REVISION_NR_H__