[12774] Merged cmangos last changes, special thanks for xfurry, Dramacydal, cala, Schmoozerd,

I'm not taking any credits of this commit.

Implement spell effects 62042, 62278 and 64767
Also limit the targets for 62577 and 62603
----------
Update git_id to reflect recent sql formatting changes
----------
Update to a safer code version and also add GO caster scenarios
----------
Allow aura 62038 to stack at every 3 seconds
----------
Improve handling of TargetMMGen
This will have impact on Chase and Follow Movement.
----------
* Refactor code to check if a new position is required for the MMGen into the new function RequiresNewPosition
* Refactor code to get the current targeted distance into function GetDynamicTargetDistance
* Change ChaseMMGen (angle = 0.0f case) chase to best contact point, not zero angle.

Thanks to Cala and X-Savior for testing. Special thanks to cala for also suggesting improved values for the magic numbers
----------
Improve ObjectPosSelector
Now a spot already occupied by the searcher will be prefered
----------
Get rid of bounding radius in GetNearPoint[2D] and ObjectPosSelector
----------
This changes how ObjectPosSelector is used.
It changes the way how the functions Object::GetNearPoint and Object::GetNearPoint2d behave.
----------
So you need to check all places where these functions are used if they are still used correctly.
----------
Especially check your scripts!
----------
Remove not required duplicate indexes
----------
Implement TARGET_92 as TARGET_SUMMONER
This target is used only as TargetA and the related spells are used only by temporary summoned creatures
----------
Implement some spell effects used by Hodir in Ulduar
Dummy spells 62797, 63499, 63545 and 64543
Periodic dummy auras: 61968, 62038, 62039 and 65272
Limit targets for spells: 62797, 63545, 64543, 62476 and 62477
----------
Implement some spells used at Algalon encounter
Spell aura entries 64345, 62018 and 64412
Positive target exception for spell 64996
Aura stacking exception for spells 62169, 62168, 65250 and 64417
----------
Implement effect for spell 63633
----------
EventAI - Ingame output of script state
----------
With this the command .npc aiinfo will give more output about the current state.
Remark that this output is only given if the LogFilter for EventAIDev mode is disabled
----------
FindGit.cmake already ships with CMake
No reason for us to ship it too. Also, we had an outdated version which
had not been used anyway, because we set the include path in such a way,
that the CMake delivered version is always found first.
----------
FindOpenSSL.cmake already ships with CMake
No reason for us to ship it too. Also, we had an outdated version which
had not been used anyway, because we set the include path in such a way,
that the CMake delivered version is always found first.
----------
EventAI - Add more developing error output
----------
Fix some target-type handling for EventAI
Also increase log-output for bad target-types
----------
Fix crash due to bad compiler (author Xfurry)
----------
Add special condition id for Ulduar
Will be used to check the availability of the siege vehicles for players
----------
Update spells 62374 and 62907
* limit spell targets of spell 62374
* implement spell effect for spell 62907
----------
Remove effect for spell 64503
Will be handled in script library. For details please check 8502cdfa64
----------
Implement spells 64489 and 64673
Both are used by Auriaya (Ulduar)
----------
Implement some spells for Ignis the Furnace Master
Spell entries: 62717, 62381, 62488, 62707, 64475 and 64503
----------
Implement spells 61187 and 61190
----------
CMake: generic way to build a script library
Added new parameter INCLUDE_BINDINGS_DIR which can be set to the name of a
folder inside src/bindings/.

Includes the script library in src/bindings/ with the defined name.
The name must correspond to the name of the folder and the folder must contain
a valid CMakeLists.txt

Note: if you currently use a script library, you will probably get a merge
problem on src/bindings/CMakeLists.txt as you will have modified this file
manually. Please use the new version of this file and rerun CMake once with the
parameter -DINCLUDE_BINDINGS_DIR=ScriptDev2 (if you are not using SD2 but
another script library, replace ScriptDev2 with the name of the folder in
src/bindings/).

If you do not use a script library you should not have any merge problems
and you don't need to do anything.
----------
Add CMake source groups to target 'game'
This is the exact same grouping as it is currently in the VC 2012 files.
These groupings will have to be refactored at some point as they are not
very logical.
----------
Add CMake source groups to target 'framework'
This is the exact same grouping as it is currently in the VC 2012 files.
This is part of cmangos/issues#67
----------
Add CMake source groups to target 'shared'
This is the exact same grouping as it is currently in the VC 2012 files.
----------
Add new parameter 'expansion' to command 'account create'
----------
Update some Sunwell Plateau spells

Limit targets and allow positive effect for spell 46650
Implement effect for spells 46289 and 46637
Remove effect for spell 44845 - will be handled in script library
----------
Implement some custom use for Effect Activate Object spells
This will fix the summoning events for the Wind Stones, Ice Stones, Skettis bosses and quest 11865
----------
Sync mangos.sql with other versions
----------
Redump sql databases to unify formatting
The main reason for this was because classic/cata has updated the sql formatting and manually syncing would be a pain so redumping from master->tbc->classic->cata is easier.

Only the formatting was changed. The values were not changed at all.

mysqldump was used however manual modifications had to be done.

Dump the database:
C:/mysql/bin/mysqldump.exe mangos > sql/mangos.sql

Split insert values into multiple rows:
Replace "),(" with "),\n("
Replace "VALUES (" with "VALUES\n("

Remove the character sets by replacing them with an empty string

Custom formatting of mangos.sql:
Move db_version to the very top
Create all dbscripts_on_* tables based on dbscripts_on_creature_movement
Preserve our custom insert formatting of spell_affect (tbc/classic), spell_bonus_data, spell_chain, spell_elixir, spell_proc_event, spell_proc_item_enchant, spell_template, spell_threat
Remove autoincrement values from insert values of pet_name_generation and remove AUTO_INCREMENT=261 value from its table structure

Custom formatting of characters.sql:
Move character_db_version to the very top

Custom formatting of realmd.sql:
Move realmd_db_version to the very top
----------
Immediately remove corpses when ForcedDespawn is used
Thanks to Neotmiren for pointing, special thanks to cala for testing!
----------
Fix use of config values related to quest-status and level
This fixes use of negative value in config values Quests.LowLevelHideDiff and Quests.HighLevelHideDiff
Also add some documentation around the related code
Thanks to Neotmiren for pointing and to cala for testing.
----------
Loot-System: Fix reference loading check
This fixes a false error output for loot references that are only used with spell loot.
Thanks to X-Savior for properly reporting both error messages and use case
----------
Add missing spell 61437 to playercreate spells for bloodelves
Thanks to NeatElves for porting from TC and pointing to this
----------
Fix load bar step for alendarMgr::LoadCalendarsFromDB
----------
Cody Style Improvements
Also remove an unused variable (thanks to Den for this!)
----------
Implement the spells used in the Chess Event encounter
Combat spell entries: 37775, 37824, 39338, 39342, 39341, 39344, 45260
Melee spells: 37142, 37143, 37147, 37149, 37150, 37220, 37227, 37228, 37337, 37339, 37345, 37348
Chess movement spells: 30012, 32312, 37388, 30284, 37144, 37146, 37148, 37151, 37152, 37153
Aura stacking exception: 32261 and 39400
----------
And more hotfixes with these format strings
----------
Hotfix to recent text loading functions
----------
Use possible changed model names with vmap extraction
----------
Fix some warnings
----------
Store how many texts are loaded for validity checks. Use this with EventAI
----------
EventAI: Use generic DoDisplayText and loading of additional text data
----------
Add generic DoDisplayText function and use additional data of dbscripts table
----------
Add const-correctness to Text related functions
----------
Add database changes to support more data for DB Script texts
----------
Add stacking exception for spells 39993 and 40041
----------
Allow spell effect 86 - Activate Object to use the misc value
----------
Allow player pets to swim
----------
Enable resummoning of warlock pets
----------
Do not remove FLY auras on Evade
Also consider npcs which have SPELL_AURA_FLY as being able to fly
----------
EventAI: Improve code
* Drop rather pointless bool to check if the number of assigned events is empty
* Before the phase was resetted on death if and only if the npc has Events defined
* DoMeleeAttackIfReady could have been called even though combat state could have changed while processing events
----------
EventAI: Implement ACTION_T_SET_THROW_MASK (46)
This Action can be used to set which AIEvents should be thrown automatically, if you need more flexibility, you can always use the manual ACTION_TH_THROW_AI_EVENT version.
* Also clean some error-log output a bit.
----------
Forward original caster GUID to script library
----------
Fixup commit 12511 Thanks to Zakamurite for pointing
Also thanks to him for giving a helping hand in correcting the commit
----------
Implement some spells for Felmyst encounter
Spell entries: 45714, 45717 and 45918. Limit targets of spell 45391
Also add stacking exception for auras 45068 and 45582
----------
Fix invisible spirit healers & such on death near them
This fixes an issue that occurs if you die close to a spirit healer/guide.
----------
Fix take ammo for most ranged spells
Fix spells like Arcane Shot not taking ammo while they should
----------
Check cast spell 51690
----------
Fix SpellDamage modifier of SPELL_AURA_MOD_DAMAGE_DONE_CREATURE
This aura modifies a flat value, not a percent value.
----------
Implement proc effect of spells 67712, 67758
related to items 47316, 47477.
----------
Improve proc of spell 50421
----------
Add and implement server-side spell 23770
----------
EventAI: Improve TargetSelection related ErrorLog output
----------
DBScripts Engine: Change behaviour to search for a different npc when using buddy-search
With this an npc buddy will be interpreted as "another npc with entry"
Also toggle command 31 - TERMINATE_SCRIPT to also look only for other npcs of entry
----------
DBScripts Engine: Allow pets as buddy
Add new flag SCRIPT_FLAG_BUDDY_IS_PET (0x20) that will search not for a normal npc with buddy-search, but also for pets
----------
DBScripts Engine: Support buddy search by guid
* Add new `data_flags` flag SCRIPT_FLAG_BUDDY_BY_GUID (0x10)
If this flag is set, the content of `search_distance` is interpreted as db-guid of the requested buddy
* Also switch most error log output to DB-error log output (though this will include false positives)
----------
This commit is contained in:
Schmoozerd 2013-08-19 17:03:20 +03:00 committed by Antz
parent 8f8068714c
commit ae7348f6b0
73 changed files with 2633 additions and 1503 deletions

View file

@ -1,5 +1,5 @@
# #
# This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS. # This file is part of the MaNGOS Project. See AUTHORS file for Copyright information
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -16,11 +16,10 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# #
# CMake policies
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 2.8)
project(MaNGOS) project(MaNGOS)
set(MANGOS_VERSION 0.18) set(MANGOS_VERSION 0.17)
set(CMAKE_MODULE_PATH set(CMAKE_MODULE_PATH
${CMAKE_MODULE_PATH} ${CMAKE_MODULE_PATH}
@ -51,6 +50,10 @@ message(
CMAKE_INSTALL_PREFIX Path where the server should be installed to CMAKE_INSTALL_PREFIX Path where the server should be installed to
PCH Use precompiled headers PCH Use precompiled headers
DEBUG Debug mode DEBUG Debug mode
INCLUDE_BINDINGS_DIR Include a script library in src/bindings/ with the
defined name. the name must corespond to the name of
the folder and the folder must contain a valid
CMakeLists.txt
TBB_USE_EXTERNAL Use external TBB TBB_USE_EXTERNAL Use external TBB
USE_STD_MALLOC Use standard malloc instead of TBB USE_STD_MALLOC Use standard malloc instead of TBB
ACE_USE_EXTERNAL Use external ACE ACE_USE_EXTERNAL Use external ACE
@ -94,9 +97,6 @@ endif()
# find Git: used to get the revision number # find Git: used to get the revision number
find_package(Git) find_package(Git)
# find Git: used to get the revision number
find_package(Git)
# check if the platform supports precomiled headers # check if the platform supports precomiled headers
find_package(PCHSupport) find_package(PCHSupport)
@ -218,6 +218,20 @@ endif()
message(STATUS "MaNGOS-Core revision : ${GIT_REVISION}") message(STATUS "MaNGOS-Core revision : ${GIT_REVISION}")
message(STATUS "Install server to : ${CMAKE_INSTALL_PREFIX}") message(STATUS "Install server to : ${CMAKE_INSTALL_PREFIX}")
if(DEFINED INCLUDE_BINDINGS_DIR AND INCLUDE_BINDINGS_DIR)
# check if the directory exists
if(NOT IS_DIRECTORY ${CMAKE_SOURCE_DIR}/src/bindings/${INCLUDE_BINDINGS_DIR})
message(FATAL_ERROR "Could not find the script library which was supposed to be: " ${CMAKE_SOURCE_DIR}/src/bindings/${INCLUDE_BINDINGS_DIR})
endif()
# check if it really contains a CMakeLists.txt
if(NOT EXISTS ${CMAKE_SOURCE_DIR}/src/bindings/${INCLUDE_BINDINGS_DIR}/CMakeLists.txt)
message(FATAL_ERROR "The script library does not contain a CMakeLists.txt!")
endif()
message(STATUS "Build script library : Yes (using ${INCLUDE_BINDINGS_DIR})")
else()
message(STATUS "Build script library : No")
endif()
# if(CLI) # if(CLI)
# message(STATUS "Build with CLI : Yes (default)") # message(STATUS "Build with CLI : Yes (default)")
# add_definitions(-DENABLE_CLI) # add_definitions(-DENABLE_CLI)

View file

@ -1,46 +0,0 @@
# The module defines the following variables:
# GIT_EXECUTABLE - path to git command line client
# GIT_FOUND - true if the command line client was found
# Example usage:
# find_package(Git)
# if(GIT_FOUND)
# message("git found: ${GIT_EXECUTABLE}")
# endif()
#=============================================================================
# Copyright 2010 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distributed this file outside of CMake, substitute the full
# License text for the above reference.)
# Look for 'git' or 'eg' (easy git)
#
set(git_names git eg)
# Prefer .cmd variants on Windows unless running in a Makefile
# in the MSYS shell.
#
if(WIN32)
if(NOT CMAKE_GENERATOR MATCHES "MSYS")
set(git_names git.cmd git eg.cmd eg)
endif()
endif()
find_program(GIT_EXECUTABLE
NAMES ${git_names}
DOC "git command line client"
)
mark_as_advanced(GIT_EXECUTABLE)
# Handle the QUIETLY and REQUIRED arguments and set GIT_FOUND to TRUE if
# all listed variables are TRUE
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Git DEFAULT_MSG GIT_EXECUTABLE)

View file

@ -1,107 +0,0 @@
#
# Find the OpenSSL client includes and library
#
# This module defines
# OPENSSL_INCLUDE_DIR, where to find openssl.h
# OPENSSL_LIBRARIES, the libraries to link against to connect to MySQL
# OPENSSL_FOUND, if false, you cannot build anything that requires MySQL.
# also defined, but not for general use are
# OPENSSL_LIBRARY, where to find the MySQL library.
if( OPENSSL_INCLUDE_DIR AND OPENSSL_LIBRARIES )
# in cache already
set(OPENSSL_FOUND 1)
else( OPENSSL_INCLUDE_DIR AND OPENSSL_LIBRARIES )
set(OPENSSL_FOUND 0)
if(WIN32)
if(PLATFORM MATCHES X64)
set(TMP_OPENSSL_INCLUDE_DIR
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;InstallLocation]/include/openssl"
)
set(TMP_OPENSSL_LIBRARIES
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;InstallLocation]/lib"
)
else()
set(TMP_OPENSSL_INCLUDE_DIR
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;InstallLocation]/include/openssl"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;InstallLocation]/include/openssl"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;InstallLocation]/include/openssl"
)
set(TMP_OPENSSL_LIBRARIES
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;InstallLocation]/lib"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;InstallLocation]/lib"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;InstallLocation]/lib"
)
endif()
endif()
find_path(OPENSSL_INCLUDE_DIR
NAMES
ssl.h
PATHS
/usr/include
/usr/include/openssl
/usr/local/include
/usr/local/include/openssl
/usr/local/openssl/include
${TMP_OPENSSL_INCLUDE_DIR}
DOC
"Specify the directory containing openssl.h."
)
find_library(OPENSSL_LIBRARIES
NAMES
ssleay32
ssl
PATHS
/usr/lib
/usr/lib/ssl
/usr/local/lib
/usr/local/lib/ssl
/usr/local/ssl/lib
${TMP_OPENSSL_LIBRARIES}
DOC "Specify the OpenSSL library here."
)
if( WIN32 )
find_library(OPENSSL_EXTRA_LIBRARIES
NAMES
libeay32
PATHS
${TMP_OPENSSL_LIBRARIES}
DOC
"if more libraries are necessary to link in a OpenSSL client, specify them here."
)
endif( WIN32 )
if( UNIX )
find_library(OPENSSL_EXTRA_LIBRARIES
NAMES
crypto
PATHS
/usr/lib
/usr/lib/ssl
/usr/local/lib
/usr/local/lib/ssl
/usr/local/ssl/lib
${TMP_OPENSSL_LIBRARIES}
DOC "if more libraries are necessary to link in a OpenSSL client, specify them here."
)
endif()
if( OPENSSL_LIBRARIES )
if( OPENSSL_INCLUDE_DIR )
set( OPENSSL_FOUND 1 )
message(STATUS "Found OpenSSL library: ${OPENSSL_LIBRARIES}")
message(STATUS "Found OpenSSL headers: ${OPENSSL_INCLUDE_DIR}")
else ( OPENSSL_INCLUDE_DIR )
message(FATAL_ERROR "Could not find OpenSSL headers! Please install the development-headers")
endif( OPENSSL_INCLUDE_DIR )
else( OPENSSL_LIBRARIES )
message(FATAL_ERROR "Could not find OpenSSL libraries! Please install the library before continuing")
endif( OPENSSL_LIBRARIES )
mark_as_advanced( OPENSSL_FOUND OPENSSL_LIBRARIES OPENSSL_EXTRA_LIBRARIES OPENSSL_INCLUDE_DIR )
endif( OPENSSL_INCLUDE_DIR AND OPENSSL_LIBRARIES )

View file

@ -756,7 +756,7 @@ bool change_sql_database()
fputs(buffer, fout); fputs(buffer, fout);
} }
fprintf(fout, " `required_%s` bit(1) default NULL\n", last_sql_update[i]); fprintf(fout, " `required_%s` bit(1) DEFAULT NULL\n", last_sql_update[i]);
while (fgets(buffer, MAX_BUF, fin)) while (fgets(buffer, MAX_BUF, fin))
fputs(buffer, fout); fputs(buffer, fout);

View file

@ -73,9 +73,9 @@ void fixname2(char* name, size_t len)
} }
} }
char* GetExtension(char* FileName) char const* GetExtension(char const* FileName)
{ {
char* szTemp; char const* szTemp;
if ((szTemp = strrchr(FileName, '.')) != NULL) if ((szTemp = strrchr(FileName, '.')) != NULL)
return szTemp; return szTemp;
return NULL; return NULL;
@ -149,11 +149,11 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY, StringSet& failed
fixnamen(p, strlen(p)); fixnamen(p, strlen(p));
char* s = GetPlainName(p); char* s = GetPlainName(p);
fixname2(s, strlen(s)); fixname2(s, strlen(s));
string path(p); // Store copy after name fixed
ModelInstansName[t++] = s; std::string fixedName;
ExtractSingleModel(path, fixedName, failedPaths);
string path(p); ModelInstansName[t++] = fixedName;
ExtractSingleModel(path, failedPaths);
p = p + strlen(p) + 1; p = p + strlen(p) + 1;
} }

View file

@ -136,7 +136,7 @@ class ADTFile
const char* GetPlainName(const char* FileName); const char* GetPlainName(const char* FileName);
char* GetPlainName(char* FileName); char* GetPlainName(char* FileName);
char* GetExtension(char* FileName); char const* GetExtension(char const* FileName);
void fixnamen(char* name, size_t len); void fixnamen(char* name, size_t len);
void fixname2(char* name, size_t len); void fixname2(char* name, size_t len);
//void fixMapNamen(char *name, size_t len); //void fixMapNamen(char *name, size_t len);

View file

@ -6,28 +6,30 @@
#include <algorithm> #include <algorithm>
#include <stdio.h> #include <stdio.h>
bool ExtractSingleModel(std::string& fname, StringSet& failedPaths) bool ExtractSingleModel(std::string& origPath, std::string& fixedName, StringSet& failedPaths)
{ {
char* ext = GetExtension(GetPlainName((char*)fname.c_str())); char const* ext = GetExtension(GetPlainName(origPath.c_str()));
// < 3.1.0 ADT MMDX section store filename.mdx filenames for corresponded .m2 file // < 3.1.0 ADT MMDX section store filename.mdx filenames for corresponded .m2 file
if (!strcmp(ext, ".mdx")) if (!strcmp(ext, ".mdx"))
{ {
// replace .mdx -> .m2 // replace .mdx -> .m2
fname.erase(fname.length() - 2, 2); origPath.erase(origPath.length() - 2, 2);
fname.append("2"); origPath.append("2");
} }
// >= 3.1.0 ADT MMDX section store filename.m2 filenames for corresponded .m2 file // >= 3.1.0 ADT MMDX section store filename.m2 filenames for corresponded .m2 file
// nothing do // nothing do
fixedName = GetPlainName(origPath.c_str());
std::string output(szWorkDirWmo); // Stores output filename (possible changed) std::string output(szWorkDirWmo); // Stores output filename (possible changed)
output += "/"; output += "/";
output += GetPlainName(fname.c_str()); output += fixedName;
if (FileExists(output.c_str())) if (FileExists(output.c_str()))
return true; return true;
Model mdl(fname); Model mdl(origPath); // Possible changed fname
if (!mdl.open(failedPaths)) if (!mdl.open(failedPaths))
return false; return false;
@ -65,11 +67,11 @@ void ExtractGameobjectModels()
char* name = GetPlainName((char*)path.c_str()); char* name = GetPlainName((char*)path.c_str());
fixname2(name, strlen(name)); fixname2(name, strlen(name));
char* ch_ext = GetExtension(name); char const* ch_ext = GetExtension(name);
if (!ch_ext) if (!ch_ext)
continue; continue;
strToLower(ch_ext); //strToLower(ch_ext);
bool result = false; bool result = false;
if (!strcmp(ch_ext, ".wmo")) if (!strcmp(ch_ext, ".wmo"))
@ -83,7 +85,8 @@ void ExtractGameobjectModels()
} }
else //if (!strcmp(ch_ext, ".mdx") || !strcmp(ch_ext, ".m2")) else //if (!strcmp(ch_ext, ".mdx") || !strcmp(ch_ext, ".m2"))
{ {
result = ExtractSingleModel(path, failedPaths); std::string fixedName;
result = ExtractSingleModel(path, fixedName, failedPaths);
} }
if (result) if (result)

View file

@ -38,7 +38,12 @@ bool FileExists(const char* file);
void strToLower(char* str); void strToLower(char* str);
bool ExtractSingleWmo(std::string& fname); bool ExtractSingleWmo(std::string& fname);
bool ExtractSingleModel(std::string& fname, StringSet& failedPaths);
/* @param origPath = original path of the model, cleaned with fixnamen and fixname2
* @param fixedName = will store the translated name (if changed)
* @param failedPaths = Set to collect errors
*/
bool ExtractSingleModel(std::string& origPath, std::string& fixedName, StringSet& failedPaths);
void ExtractGameobjectModels(); void ExtractGameobjectModels();

View file

@ -1,4 +1,5 @@
# This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS. #
# This file is part of the MaNGOS Project. See AUTHORS file for Copyright information
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -13,6 +14,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
include(ExternalProject) include(ExternalProject)

View file

@ -85,7 +85,7 @@ Some events such as EVENT_T_AGGRO, EVENT_T_DEATH, EVENT_T_SPAWNED, and EVENT_T_E
18 EVENT_T_TARGET_MANA ManaMax%, ManaMin%, RepeatMin, RepeatMax Expires when current target's Mana% is between (Param1) and (Param2). Will repeat every (Param3) and (Param4) If Event Conditions Are Still Met. 18 EVENT_T_TARGET_MANA ManaMax%, ManaMin%, RepeatMin, RepeatMax Expires when current target's Mana% is between (Param1) and (Param2). Will repeat every (Param3) and (Param4) If Event Conditions Are Still Met.
21 EVENT_T_REACHED_HOME NONE Expires when a creature reaches it's home (spawn) location after evade. This is commonly used for NPC's who Stealth once reaching their Spawn Location 21 EVENT_T_REACHED_HOME NONE Expires when a creature reaches it's home (spawn) location after evade. This is commonly used for NPC's who Stealth once reaching their Spawn Location
22 EVENT_T_RECEIVE_EMOTE EmoteId, Condition, CondValue1, CondValue2 Expires when a creature receives an emote with emote text id ("enum TextEmotes" from SharedDefines.h in Mangos Source) in (Param1). Conditions can be defined (Param2) with optional values (Param3,Param4), see (enum ConditionType) in ObjectMgr.h (Mangos Source). 22 EVENT_T_RECEIVE_EMOTE EmoteId, Condition, CondValue1, CondValue2 Expires when a creature receives an emote with emote text id ("enum TextEmotes" from SharedDefines.h in Mangos Source) in (Param1). Conditions can be defined (Param2) with optional values (Param3,Param4), see (enum ConditionType) in ObjectMgr.h (Mangos Source).
23 EVENT_T_BUFFED SpellID, AmmountInStack, RepeatMin, RepeatMax Expires when a creature has spell (Param1) auras applied in a stack greater or equal to value provided in (Param2). Will repeat every (Param3) and (Param4) If Event Conditions Are Still Met. 23 EVENT_T_AURA SpellID, AmmountInStack, RepeatMin, RepeatMax Expires when a creature has spell (Param1) auras applied in a stack greater or equal to value provided in (Param2). Will repeat every (Param3) and (Param4) If Event Conditions Are Still Met.
24 EVENT_T_TARGET_BUFFED SpellID, AmmountInStack, RepeatMin, RepeatMax Expires when a target unit has spell (Param1) auras applied in a stack greater or equal to value provided in (Param2). Will repeat every (Param3) and (Param4) If Event Conditions Are Still Met. 24 EVENT_T_TARGET_BUFFED SpellID, AmmountInStack, RepeatMin, RepeatMax Expires when a target unit has spell (Param1) auras applied in a stack greater or equal to value provided in (Param2). Will repeat every (Param3) and (Param4) If Event Conditions Are Still Met.
25 EVENT_T_SUMMONED_JUST_DIED CreatureId, RepeatMin, RepeatMax Expires after creature with entry = (Param1) is die (Param1 = 0 means all spawns). Will repeat every (Param2) and (Param3). 25 EVENT_T_SUMMONED_JUST_DIED CreatureId, RepeatMin, RepeatMax Expires after creature with entry = (Param1) is die (Param1 = 0 means all spawns). Will repeat every (Param2) and (Param3).
26 EVENT_T_SUMMONED_JUST_DESPAWN CreatureId, RepeatMin, RepeatMax Expires before creature with entry = (Param1) is despawn (Param1 = 0 means all spawns). Will repeat every (Param2) and (Param3). 26 EVENT_T_SUMMONED_JUST_DESPAWN CreatureId, RepeatMin, RepeatMax Expires before creature with entry = (Param1) is despawn (Param1 = 0 means all spawns). Will repeat every (Param2) and (Param3).
@ -374,7 +374,7 @@ Expires only when creature receive emote from player. Valid text emote id's are
Event does not require any conditions to process, however many are expected to have condition. Event does not require any conditions to process, however many are expected to have condition.
--------------------------- ---------------------------
23 = EVENT_T_BUFFED : 23 = EVENT_T_AURA:
--------------------------- ---------------------------
Parameter 1: SpellId - This is the SpellID That the Aura Check will look for Parameter 1: SpellId - This is the SpellID That the Aura Check will look for
Parameter 2: Amount - This is the amount of SpellID's auras at creature required for event expire. Parameter 2: Amount - This is the amount of SpellID's auras at creature required for event expire.

View file

@ -434,7 +434,7 @@ DROP TABLE IF EXISTS `character_db_version`;
/*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */; /*!40101 SET character_set_client = utf8 */;
CREATE TABLE `character_db_version` ( CREATE TABLE `character_db_version` (
`required_12697_01_characters_characters` bit(1) default NULL `required_12774_01_characters_characters` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB'; ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Last applied sql update to DB';
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
@ -795,7 +795,6 @@ CREATE TABLE `character_queststatus_daily` (
`guid` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier', `guid` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier',
`quest` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Quest Identifier', `quest` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Quest Identifier',
PRIMARY KEY (`guid`,`quest`), PRIMARY KEY (`guid`,`quest`),
KEY `idx_guid` (`guid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
@ -819,7 +818,6 @@ CREATE TABLE `character_queststatus_monthly` (
`guid` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier', `guid` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier',
`quest` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Quest Identifier', `quest` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Quest Identifier',
PRIMARY KEY (`guid`,`quest`), PRIMARY KEY (`guid`,`quest`),
KEY `idx_guid` (`guid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
@ -843,7 +841,6 @@ CREATE TABLE `character_queststatus_weekly` (
`guid` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier', `guid` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier',
`quest` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Quest Identifier', `quest` int(11) unsigned NOT NULL DEFAULT '0' COMMENT 'Quest Identifier',
PRIMARY KEY (`guid`,`quest`), PRIMARY KEY (`guid`,`quest`),
KEY `idx_guid` (`guid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
@ -919,8 +916,6 @@ CREATE TABLE `character_social` (
`flags` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT 'Friend Flags', `flags` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT 'Friend Flags',
`note` varchar(48) NOT NULL DEFAULT '' COMMENT 'Friend Note', `note` varchar(48) NOT NULL DEFAULT '' COMMENT 'Friend Note',
PRIMARY KEY (`guid`,`friend`,`flags`), PRIMARY KEY (`guid`,`friend`,`flags`),
KEY `guid` (`guid`),
KEY `friend` (`friend`),
KEY `guid_flags` (`guid`,`flags`), KEY `guid_flags` (`guid`,`flags`),
KEY `friend_flags` (`friend`,`flags`) KEY `friend_flags` (`friend`,`flags`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
@ -1048,7 +1043,6 @@ CREATE TABLE `character_talent` (
`current_rank` tinyint(3) unsigned NOT NULL DEFAULT '0', `current_rank` tinyint(3) unsigned NOT NULL DEFAULT '0',
`spec` tinyint(3) unsigned NOT NULL DEFAULT '0', `spec` tinyint(3) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`guid`,`talent_id`,`spec`), PRIMARY KEY (`guid`,`talent_id`,`spec`),
KEY `guid_key` (`guid`),
KEY `talent_key` (`talent_id`), KEY `talent_key` (`talent_id`),
KEY `spec_key` (`spec`) KEY `spec_key` (`spec`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@ -1455,7 +1449,6 @@ CREATE TABLE `guild_bank_eventlog` (
`DestTabId` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT 'Destination Tab Id', `DestTabId` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT 'Destination Tab Id',
`TimeStamp` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'Event UNIX time', `TimeStamp` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT 'Event UNIX time',
PRIMARY KEY (`guildid`,`LogGuid`,`TabId`), PRIMARY KEY (`guildid`,`LogGuid`,`TabId`),
KEY `guildid_key` (`guildid`),
KEY `Idx_PlayerGuid` (`PlayerGuid`), KEY `Idx_PlayerGuid` (`PlayerGuid`),
KEY `Idx_LogGuid` (`LogGuid`) KEY `Idx_LogGuid` (`LogGuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@ -1484,7 +1477,6 @@ CREATE TABLE `guild_bank_item` (
`item_guid` int(11) unsigned NOT NULL DEFAULT '0', `item_guid` int(11) unsigned NOT NULL DEFAULT '0',
`item_entry` int(11) unsigned NOT NULL DEFAULT '0', `item_entry` int(11) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`guildid`,`TabId`,`SlotId`), PRIMARY KEY (`guildid`,`TabId`,`SlotId`),
KEY `guildid_key` (`guildid`),
KEY `Idx_item_guid` (`item_guid`) KEY `Idx_item_guid` (`item_guid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
@ -1511,8 +1503,7 @@ CREATE TABLE `guild_bank_right` (
`rid` int(11) unsigned NOT NULL DEFAULT '0', `rid` int(11) unsigned NOT NULL DEFAULT '0',
`gbright` tinyint(3) unsigned NOT NULL DEFAULT '0', `gbright` tinyint(3) unsigned NOT NULL DEFAULT '0',
`SlotPerDay` int(11) unsigned NOT NULL DEFAULT '0', `SlotPerDay` int(11) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`guildid`,`TabId`,`rid`), PRIMARY KEY (`guildid`,`TabId`,`rid`)
KEY `guildid_key` (`guildid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
@ -1538,8 +1529,7 @@ CREATE TABLE `guild_bank_tab` (
`TabName` varchar(100) NOT NULL DEFAULT '', `TabName` varchar(100) NOT NULL DEFAULT '',
`TabIcon` varchar(100) NOT NULL DEFAULT '', `TabIcon` varchar(100) NOT NULL DEFAULT '',
`TabText` text, `TabText` text,
PRIMARY KEY (`guildid`,`TabId`), PRIMARY KEY (`guildid`,`TabId`)
KEY `guildid_key` (`guildid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
@ -1611,7 +1601,6 @@ CREATE TABLE `guild_member` (
`BankResetTimeTab5` int(11) unsigned NOT NULL DEFAULT '0', `BankResetTimeTab5` int(11) unsigned NOT NULL DEFAULT '0',
`BankRemSlotsTab5` int(11) unsigned NOT NULL DEFAULT '0', `BankRemSlotsTab5` int(11) unsigned NOT NULL DEFAULT '0',
UNIQUE KEY `guid_key` (`guid`), UNIQUE KEY `guid_key` (`guid`),
KEY `guildid_key` (`guildid`),
KEY `guildid_rank_key` (`guildid`,`rank`) KEY `guildid_rank_key` (`guildid`,`rank`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Guild System'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Guild System';
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;

View file

@ -276,7 +276,7 @@ LOCK TABLES `command` WRITE;
INSERT INTO `command` (`name`, `security`, `help`) VALUES INSERT INTO `command` (`name`, `security`, `help`) VALUES
('account',0,'Syntax: .account\r\n\r\nDisplay the access level of your account.'), ('account',0,'Syntax: .account\r\n\r\nDisplay the access level of your account.'),
('account characters',3,'Syntax: .account characters [#accountId|$accountName]\r\n\r\nShow list all characters for account selected by provided #accountId or $accountName, or for selected player in game.'), ('account characters',3,'Syntax: .account characters [#accountId|$accountName]\r\n\r\nShow list all characters for account selected by provided #accountId or $accountName, or for selected player in game.'),
('account create',4,'Syntax: .account create $account $password\r\n\r\nCreate account and set password to it.'), ('account create',4,'Syntax: .account create $account $password [$expansion]\r\n\r\nCreate account and set password to it. Optionally, you may also set another expansion for this account than the defined default value.'),
('account delete',4,'Syntax: .account delete $account\r\n\r\nDelete account with all characters.'), ('account delete',4,'Syntax: .account delete $account\r\n\r\nDelete account with all characters.'),
('account lock',0,'Syntax: .account lock [on|off]\r\n\r\nAllow login from account only from current used IP or remove this requirement.'), ('account lock',0,'Syntax: .account lock [on|off]\r\n\r\nAllow login from account only from current used IP or remove this requirement.'),
('account onlinelist',4,'Syntax: .account onlinelist\r\n\r\nShow list of online accounts.'), ('account onlinelist',4,'Syntax: .account onlinelist\r\n\r\nShow list of online accounts.'),
@ -1002,13 +1002,13 @@ INSERT INTO `creature_model_info` (`modelid`, `bounding_radius`, `combat_reach`,
(1479,0.306,1.5,1,1478,0), (1479,0.306,1.5,1,1478,0),
(1563,0.3519,1.5,0,1564,0), (1563,0.3519,1.5,0,1564,0),
(1564,0.3519,1.5,1,1563,0), (1564,0.3519,1.5,1,1563,0),
(6894,0.389,1.5,0,6895,0),
(6895,0.389,1.5,1,6894,0),
(10045,1,1.5,2,0,0), (10045,1,1.5,2,0,0),
(15475,0.383,1.5,1,15476,0), (15475,0.383,1.5,1,15476,0),
(15476,0.383,1.5,0,15475,0), (15476,0.383,1.5,0,15475,0),
(16125,1,1.5,0,16126,0), (16125,1,1.5,0,16126,0),
(16126,1,1.5,1,16125,0), (16126,1,1.5,1,16125,0),
(6894,0.389,1.5,0,6895,0),
(6895,0.389,1.5,1,6894,0),
(29422,0.389,1.5,0,29423,0), (29422,0.389,1.5,0,29423,0),
(29423,0.389,1.5,1,29422,0); (29423,0.389,1.5,1,29422,0);
/*!40000 ALTER TABLE `creature_model_info` ENABLE KEYS */; /*!40000 ALTER TABLE `creature_model_info` ENABLE KEYS */;
@ -1355,6 +1355,11 @@ CREATE TABLE `db_script_string` (
`content_loc6` text, `content_loc6` text,
`content_loc7` text, `content_loc7` text,
`content_loc8` text, `content_loc8` text,
`sound` mediumint(8) unsigned NOT NULL DEFAULT '0',
`type` tinyint(3) unsigned NOT NULL DEFAULT '0',
`language` tinyint(3) unsigned NOT NULL DEFAULT '0',
`emote` smallint(5) unsigned NOT NULL DEFAULT '0',
`comment` text,
PRIMARY KEY (`entry`) PRIMARY KEY (`entry`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8; ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
@ -21320,6 +21325,18 @@ CREATE TABLE `spell_proc_event` (
) ENGINE=MyISAM DEFAULT CHARSET=utf8; ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */; /*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `spell_proc_event`
--
LOCK TABLES `spell_proc_event` WRITE;
/*!40000 ALTER TABLE `spell_proc_event` DISABLE KEYS */;
INSERT INTO `spell_proc_event` VALUES
(67712, 0x7F, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 2),
(67758, 0x7F, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 2);
/*!40000 ALTER TABLE `spell_proc_event` ENABLE KEYS */;
UNLOCK TABLES;
-- --
-- Table structure for table `spell_proc_item_enchant` -- Table structure for table `spell_proc_item_enchant`
-- --
@ -21341,14 +21358,14 @@ CREATE TABLE `spell_proc_item_enchant` (
LOCK TABLES `spell_proc_item_enchant` WRITE; LOCK TABLES `spell_proc_item_enchant` WRITE;
/*!40000 ALTER TABLE `spell_proc_item_enchant` DISABLE KEYS */; /*!40000 ALTER TABLE `spell_proc_item_enchant` DISABLE KEYS */;
INSERT INTO `spell_proc_item_enchant` (`entry`, `ppmRate`) VALUES INSERT INTO `spell_proc_item_enchant` (`entry`, `ppmRate`) VALUES
(8034,9), (8034, 9), -- Frostbrand Weapon
(8680,8.5714), (8680, 8.5714), -- Instant Poison
(13218,21.4286), (13218, 21.4286), -- Wound Poison
(13897,6), (13897, 6.0), -- Enchant Weapon - Fiery Weapon
(20004,6), (20004, 6.0), -- Enchant Weapon - Lifestealing
(20005,1.6), (20005, 1.6), -- Enchant Weapon - Icy Chill
(44525,3.4), (44525, 3.4), -- Enchant Weapon - Icebreaker
(44578,3.4); (44578, 3.4); -- Enchant Weapon - Lifeward
/*!40000 ALTER TABLE `spell_proc_item_enchant` ENABLE KEYS */; /*!40000 ALTER TABLE `spell_proc_item_enchant` ENABLE KEYS */;
UNLOCK TABLES; UNLOCK TABLES;
@ -21414,6 +21431,7 @@ CREATE TABLE `spell_template` (
`attr` int(11) unsigned NOT NULL DEFAULT '0', `attr` int(11) unsigned NOT NULL DEFAULT '0',
`attr_ex` int(11) unsigned NOT NULL DEFAULT '0', `attr_ex` int(11) unsigned NOT NULL DEFAULT '0',
`attr_ex2` int(11) unsigned NOT NULL DEFAULT '0', `attr_ex2` int(11) unsigned NOT NULL DEFAULT '0',
`attr_ex3` int(11) unsigned NOT NULL DEFAULT '0',
`proc_flags` int(11) unsigned NOT NULL DEFAULT '0', `proc_flags` int(11) unsigned NOT NULL DEFAULT '0',
`proc_chance` int(11) unsigned NOT NULL DEFAULT '0', `proc_chance` int(11) unsigned NOT NULL DEFAULT '0',
`duration_index` int(11) unsigned NOT NULL DEFAULT '0', `duration_index` int(11) unsigned NOT NULL DEFAULT '0',
@ -21435,40 +21453,42 @@ CREATE TABLE `spell_template` (
LOCK TABLES `spell_template` WRITE; LOCK TABLES `spell_template` WRITE;
/*!40000 ALTER TABLE `spell_template` DISABLE KEYS */; /*!40000 ALTER TABLE `spell_template` DISABLE KEYS */;
INSERT INTO `spell_template` VALUES INSERT INTO `spell_template` VALUES
-- id attr attr_ex attr_ex2 proc_flags chnce dur ef0 tarA0 tarB0 rad aur misc miscB, trigger -- id attr attr_ex attr_ex2 attr_ex3 proc_flags chnce dur ef0 tarA0 tarB0 rad aur misc miscB, trigger
(21387, 0x00000140, 0x10000000, 0x00000000, 0x00000028, 15, 21, 6, 1, 0, 0, 42, 0, 0, 21388, 'Melt-Weapon trigger aura related used by Ragnaros'), (21387, 0x00000140, 0x10000000, 0x00000000, 0x00000000, 0x00000028, 15, 21, 6, 1, 0, 0, 42, 0, 0, 21388, 'Melt-Weapon trigger aura related used by Ragnaros'),
(23363, 0x00000100, 0x00000000, 0x00000000, 0x00000000, 101, 21, 76, 18, 0, 0, 0, 179804, 0, 0, 'Summon Drakonid Corpse Trigger'), (23363, 0x00000100, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 76, 18, 0, 0, 0, 179804, 0, 0, 'Summon Drakonid Corpse Trigger'),
(25192, 0x00000100, 0x00000000, 0x00000004, 0x00000000, 101, 21, 76, 18, 0, 0, 0, 180619, 0, 0, 'Summon Ossirian Crystal'), (23770, 0x24800100, 0x10000088, 0x00000001, 0x00100000, 0x00000000, 101, 367, 6, 25, 0, 0, 4, 0, 0, 0, 'Sayge''s timer - Darkmoon Faire'),
(26133, 0x00000100, 0x00000000, 0x00000000, 0x00000000, 101, 21, 76, 18, 0, 0, 0, 180795, 0, 0, 'Summon Sandworm Base'), (25192, 0x00000100, 0x00000000, 0x00000004, 0x00000000, 0x00000000, 101, 21, 76, 18, 0, 0, 0, 180619, 0, 0, 'Summon Ossirian Crystal'),
(34810, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 28, 42, 0, 8, 0, 20083, 64, 0, 'Summon Summoned Bloodwarder Mender behind of the caster'), (26133, 0x00000100, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 76, 18, 0, 0, 0, 180795, 0, 0, 'Summon Sandworm Base'),
(34817, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 28, 44, 0, 8, 0, 20078, 64, 0, 'Summon Summoned Bloodwarder Reservist right of the caster'), (34810, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 28, 42, 0, 8, 0, 20083, 64, 0, 'Summon Summoned Bloodwarder Mender behind of the caster'),
(34818, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 28, 43, 0, 8, 0, 20078, 64, 0, 'Summon Summoned Bloodwarder Reservist left of the caster'), (34817, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 28, 44, 0, 8, 0, 20078, 64, 0, 'Summon Summoned Bloodwarder Reservist right of the caster'),
(34819, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 28, 41, 0, 8, 0, 20078, 64, 0, 'Summon Summoned Bloodwarder Reservist front of the caster'), (34818, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 28, 43, 0, 8, 0, 20078, 64, 0, 'Summon Summoned Bloodwarder Reservist left of the caster'),
(35153, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 28, 42, 0, 8, 0, 20405, 64, 0, 'Summon Nether Charge behind of the caster'), (34819, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 28, 41, 0, 8, 0, 20078, 64, 0, 'Summon Summoned Bloodwarder Reservist front of the caster'),
(35904, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 28, 44, 0, 8, 0, 20405, 64, 0, 'Summon Nether Charge right of the caster'), (35153, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 28, 42, 0, 8, 0, 20405, 64, 0, 'Summon Nether Charge behind of the caster'),
(35905, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 28, 43, 0, 8, 0, 20405, 64, 0, 'Summon Nether Charge left of the caster'), (35904, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 28, 44, 0, 8, 0, 20405, 64, 0, 'Summon Nether Charge right of the caster'),
(35906, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 28, 41, 0, 8, 0, 20405, 64, 0, 'Summon Nether Charge front of the caster'), (35905, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 28, 43, 0, 8, 0, 20405, 64, 0, 'Summon Nether Charge left of the caster'),
(37264, 0x00000180, 0x00000000, 0x00000004, 0x00000000, 101, 21, 28, 18, 0, 7, 0, 21729, 64, 0, 'Power Converters: Summon Electromental (from cata)'), (35906, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 28, 41, 0, 8, 0, 20405, 64, 0, 'Summon Nether Charge front of the caster'),
(37278, 0x00000180, 0x00000000, 0x00000004, 0x00000000, 101, 21, 28, 18, 0, 1, 0, 21737, 64, 0, 'Power Converters: Summon Mini-Electromental (from cata)'), (37264, 0x00000180, 0x00000000, 0x00000004, 0x00000000, 0x00000000, 101, 21, 28, 18, 0, 7, 0, 21729, 64, 0, 'Power Converters: Summon Electromental (from cata)'),
(37365, 0x00000180, 0x00000000, 0x00000004, 0x00000000, 101, 21, 28, 18, 0, 1, 0, 21757, 64, 0, 'Power Converters: Summon Big Flavor Electromental (from cata)'), (37278, 0x00000180, 0x00000000, 0x00000004, 0x00000000, 0x00000000, 101, 21, 28, 18, 0, 1, 0, 21737, 64, 0, 'Power Converters: Summon Mini-Electromental (from cata)'),
(44920, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 6, 1, 0, 0, 56, 24941, 0, 0, 'Model - Shattered Sun Marksman - BE Male Tier 4'), (37365, 0x00000180, 0x00000000, 0x00000004, 0x00000000, 0x00000000, 101, 21, 28, 18, 0, 1, 0, 21757, 64, 0, 'Power Converters: Summon Big Flavor Electromental (from cata)'),
(44924, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 6, 1, 0, 0, 56, 24945, 0, 0, 'Model - Shattered Sun Marksman - BE Female Tier 4'), (44920, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 6, 1, 0, 0, 56, 24941, 0, 0, 'Model - Shattered Sun Marksman - BE Male Tier 4'),
(44928, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 6, 1, 0, 0, 56, 24949, 0, 0, 'Model - Shattered Sun Marksman - Draenei Male Tier 4'), (44924, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 6, 1, 0, 0, 56, 24945, 0, 0, 'Model - Shattered Sun Marksman - BE Female Tier 4'),
(44932, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 6, 1, 0, 0, 56, 24953, 0, 0, 'Model - Shattered Sun Marksman - Draenei Female Tier 4'), (44928, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 6, 1, 0, 0, 56, 24949, 0, 0, 'Model - Shattered Sun Marksman - Draenei Male Tier 4'),
(45158, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 6, 1, 0, 0, 56, 25119, 0, 0, 'Model - Shattered Sun Warrior - BE Female Tier 4'), (44932, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 6, 1, 0, 0, 56, 24953, 0, 0, 'Model - Shattered Sun Marksman - Draenei Female Tier 4'),
(45162, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 6, 1, 0, 0, 56, 25123, 0, 0, 'Model - Shattered Sun Warrior - BE Male Tier 4'), (45158, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 6, 1, 0, 0, 56, 25119, 0, 0, 'Model - Shattered Sun Warrior - BE Female Tier 4'),
(45166, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 6, 1, 0, 0, 56, 25127, 0, 0, 'Model - Shattered Sun Warrior - Draenei Female Tier 4'), (45162, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 6, 1, 0, 0, 56, 25123, 0, 0, 'Model - Shattered Sun Warrior - BE Male Tier 4'),
(45170, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 6, 1, 0, 0, 56, 25131, 0, 0, 'Model - Shattered Sun Warrior - Draenei Male Tier 4'), (45166, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 6, 1, 0, 0, 56, 25127, 0, 0, 'Model - Shattered Sun Warrior - Draenei Female Tier 4'),
(58630, 0x00800180, 0x00000000, 0x00000005, 0x00000000, 101, 37, 6, 22, 7, 28, 4, 0, 0, 0, 'Achievement check - Mal\'Ganis'), (45170, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 6, 1, 0, 0, 56, 25131, 0, 0, 'Model - Shattered Sun Warrior - Draenei Male Tier 4'),
(59046, 0x00800180, 0x00000000, 0x00000005, 0x00000000, 101, 37, 6, 22, 7, 28, 4, 0, 0, 0, 'Achievement check - Tribunal of Ages'), (50574, 0x00000100, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 0, 90, 25, 0, 11, 0, 28042, 0, 0, 'Captain Brandon Kill Credit'),
(59450, 0x00800180, 0x00000000, 0x00000005, 0x00000000, 101, 37, 6, 22, 7, 28, 4, 0, 0, 0, 'Achievement check - The Four Horsemen'), (58630, 0x00800180, 0x00000000, 0x00000005, 0x00000000, 0x00000000, 101, 37, 6, 22, 7, 28, 4, 0, 0, 0, 'Achievement check - Mal\'Ganis'),
(62388, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 6, 1, 0, 0, 4, 0, 0, 0, 'Aura required for Demonic Circle 48020'), (59046, 0x00800180, 0x00000000, 0x00000005, 0x00000000, 0x00000000, 101, 37, 6, 22, 7, 28, 4, 0, 0, 0, 'Achievement check - Tribunal of Ages'),
(64899, 0x00800180, 0x00000000, 0x00000005, 0x00000000, 101, 37, 6, 22, 7, 28, 4, 0, 0, 0, 'Achievement check - Hodir'), (59450, 0x00800180, 0x00000000, 0x00000005, 0x00000000, 0x00000000, 101, 37, 6, 22, 7, 28, 4, 0, 0, 0, 'Achievement check - The Four Horsemen'),
(64985, 0x00800180, 0x00000000, 0x00000005, 0x00000000, 101, 37, 6, 22, 7, 28, 4, 0, 0, 0, 'Achievement check - Thorim'), (62388, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 101, 21, 6, 1, 0, 0, 4, 0, 0, 0, 'Aura required for Demonic Circle 48020'),
(65074, 0x00800180, 0x00000000, 0x00000005, 0x00000000, 101, 37, 6, 22, 7, 28, 4, 0, 0, 0, 'Achievement check - Freya'), (64899, 0x00800180, 0x00000000, 0x00000005, 0x00000000, 0x00000000, 101, 37, 6, 22, 7, 28, 4, 0, 0, 0, 'Achievement check - Hodir'),
(65195, 0x00800180, 0x00000000, 0x00000005, 0x00000000, 101, 37, 6, 22, 7, 28, 4, 0, 0, 0, 'Achievement check - Assembly of Iron'), (64985, 0x00800180, 0x00000000, 0x00000005, 0x00000000, 0x00000000, 101, 37, 6, 22, 7, 28, 4, 0, 0, 0, 'Achievement check - Thorim'),
(68184, 0x00800180, 0x00000000, 0x00000005, 0x00000000, 101, 37, 6, 22, 7, 28, 4, 0, 0, 0, 'Achievement check - Faction Champions'), (65074, 0x00800180, 0x00000000, 0x00000005, 0x00000000, 0x00000000, 101, 37, 6, 22, 7, 28, 4, 0, 0, 0, 'Achievement check - Freya'),
(72845, 0x00800180, 0x00000000, 0x00000005, 0x00000000, 101, 37, 6, 22, 7, 28, 4, 0, 0, 0, 'Achievement check - Pit of Saron - Don\'t Look Up'); (65195, 0x00800180, 0x00000000, 0x00000005, 0x00000000, 0x00000000, 101, 37, 6, 22, 7, 28, 4, 0, 0, 0, 'Achievement check - Assembly of Iron'),
(68184, 0x00800180, 0x00000000, 0x00000005, 0x00000000, 0x00000000, 101, 37, 6, 22, 7, 28, 4, 0, 0, 0, 'Achievement check - Faction Champions'),
(72845, 0x00800180, 0x00000000, 0x00000005, 0x00000000, 0x00000000, 101, 37, 6, 22, 7, 28, 4, 0, 0, 0, 'Achievement check - Pit of Saron - Don\'t Look Up');
/*!40000 ALTER TABLE `spell_template` ENABLE KEYS */; /*!40000 ALTER TABLE `spell_template` ENABLE KEYS */;
UNLOCK TABLES; UNLOCK TABLES;

View file

@ -0,0 +1,15 @@
ALTER TABLE character_db_version CHANGE COLUMN required_12697_01_characters_characters required_12774_01_characters_characters bit;
ALTER TABLE character_queststatus_daily DROP INDEX idx_guid;
ALTER TABLE character_queststatus_monthly DROP INDEX idx_guid;
ALTER TABLE character_queststatus_weekly DROP INDEX idx_guid;
ALTER TABLE character_social DROP INDEX friend;
ALTER TABLE character_social DROP INDEX guid;
ALTER TABLE character_talent DROP INDEX guid_key;
ALTER TABLE guild_bank_eventlog DROP INDEX guildid_key;
ALTER TABLE guild_bank_item DROP INDEX guildid_key;
ALTER TABLE guild_bank_right DROP INDEX guildid_key;
ALTER TABLE guild_bank_tab DROP INDEX guildid_key;
ALTER TABLE guild_member DROP INDEX guildid_key;
ALTER TABLE playercreateinfo_action DROP INDEX playercreateinfo_race_class_index;

View file

@ -0,0 +1,211 @@
ALTER TABLE db_version CHANGE COLUMN required_12662_01_mangos_hotfix_data required_12774_01_mangos bit;
ALTER TABLE spell_template ADD COLUMN attr_ex3 int(11) unsigned NOT NULL DEFAULT '0' AFTER attr_ex2;
DELETE FROM spell_template WHERE id=23770;
INSERT INTO spell_template VALUES
(23770, 0x24800100, 0x10000088, 0x00000001, 0x00100000, 0x00000000, 101, 367, 6, 25, 0, 0, 4, 0, 0, 0, 'Sayge''s timer - Darkmoon Faire');
DELETE FROM spell_proc_event WHERE entry IN (67712, 67758);
INSERT INTO spell_proc_event VALUES
(67712, 0x7F, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 2),
(67758, 0x7F, 0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0.000000, 0.000000, 2);
ALTER TABLE db_script_string ADD COLUMN sound mediumint(8) unsigned NOT NULL DEFAULT '0' AFTER content_loc8;
ALTER TABLE db_script_string ADD COLUMN type tinyint(3) unsigned NOT NULL DEFAULT '0' AFTER sound;
ALTER TABLE db_script_string ADD COLUMN language tinyint(3) unsigned NOT NULL DEFAULT '0' AFTER type;
ALTER TABLE db_script_string ADD COLUMN emote smallint(5) unsigned NOT NULL DEFAULT '0' AFTER language;
ALTER TABLE db_script_string ADD COLUMN comment text AFTER emote;
-- Update Dbscript_string with the type and language from Dbscripts_on_*
CREATE TEMPORARY TABLE IF NOT EXISTS db_script_temp AS
-- dbscripts_on_creature_death
SELECT A.entry
,A.content_default
,A.content_loc1
,A.content_loc2
,A.content_loc3
,A.content_loc4
,A.content_loc5
,A.content_loc6
,A.content_loc7
,A.content_loc8
,0 AS sound
,B.datalong AS type
,B.datalong2 AS language
,0 AS emote
,NULL AS comment
FROM db_script_string A
INNER JOIN dbscripts_on_creature_death B ON (A.entry = B.dataint OR A.entry = B.dataint2 OR A.entry = B.dataint3 OR A.entry = B.dataint4)
-- dbscripts_on_creature_movement
UNION ALL
SELECT A.entry
,A.content_default
,A.content_loc1
,A.content_loc2
,A.content_loc3
,A.content_loc4
,A.content_loc5
,A.content_loc6
,A.content_loc7
,A.content_loc8
,0 AS sound
,B.datalong AS type
,B.datalong2 AS language
,0 AS emote
,NULL AS comment
FROM db_script_string A
INNER JOIN dbscripts_on_creature_movement B ON (A.entry = B.dataint OR A.entry = B.dataint2 OR A.entry = B.dataint3 OR A.entry = B.dataint4)
-- dbscripts_on_event
UNION ALL
SELECT A.entry
,A.content_default
,A.content_loc1
,A.content_loc2
,A.content_loc3
,A.content_loc4
,A.content_loc5
,A.content_loc6
,A.content_loc7
,A.content_loc8
,0 AS sound
,B.datalong AS type
,B.datalong2 AS language
,0 AS emote
,NULL AS comment
FROM db_script_string A
INNER JOIN dbscripts_on_event B ON (A.entry = B.dataint OR A.entry = B.dataint2 OR A.entry = B.dataint3 OR A.entry = B.dataint4)
-- dbscripts_on_gossip
UNION ALL
SELECT A.entry
,A.content_default
,A.content_loc1
,A.content_loc2
,A.content_loc3
,A.content_loc4
,A.content_loc5
,A.content_loc6
,A.content_loc7
,A.content_loc8
,0 AS sound
,B.datalong AS type
,B.datalong2 AS language
,0 AS emote
,NULL AS comment
FROM db_script_string A
INNER JOIN dbscripts_on_gossip B ON (A.entry = B.dataint OR A.entry = B.dataint2 OR A.entry = B.dataint3 OR A.entry = B.dataint4)
-- dbscripts_on_go_template_use
UNION ALL
SELECT A.entry
,A.content_default
,A.content_loc1
,A.content_loc2
,A.content_loc3
,A.content_loc4
,A.content_loc5
,A.content_loc6
,A.content_loc7
,A.content_loc8
,0 AS sound
,B.datalong AS type
,B.datalong2 AS language
,0 AS emote
,NULL AS comment
FROM db_script_string A
INNER JOIN dbscripts_on_go_template_use B ON (A.entry = B.dataint OR A.entry = B.dataint2 OR A.entry = B.dataint3 OR A.entry = B.dataint4)
-- dbscripts_on_go_use
UNION ALL
SELECT A.entry
,A.content_default
,A.content_loc1
,A.content_loc2
,A.content_loc3
,A.content_loc4
,A.content_loc5
,A.content_loc6
,A.content_loc7
,A.content_loc8
,0 AS sound
,B.datalong AS type
,B.datalong2 AS language
,0 AS emote
,NULL AS comment
FROM db_script_string A
INNER JOIN dbscripts_on_go_use B ON (A.entry = B.dataint OR A.entry = B.dataint2 OR A.entry = B.dataint3 OR A.entry = B.dataint4)
-- dbscripts_on_quest_end
UNION ALL
SELECT A.entry
,A.content_default
,A.content_loc1
,A.content_loc2
,A.content_loc3
,A.content_loc4
,A.content_loc5
,A.content_loc6
,A.content_loc7
,A.content_loc8
,0 AS sound
,B.datalong AS type
,B.datalong2 AS language
,0 AS emote
,NULL AS comment
FROM db_script_string A
INNER JOIN dbscripts_on_quest_end B ON (A.entry = B.dataint OR A.entry = B.dataint2 OR A.entry = B.dataint3 OR A.entry = B.dataint4)
-- dbscripts_on_quest_start
UNION ALL
SELECT A.entry
,A.content_default
,A.content_loc1
,A.content_loc2
,A.content_loc3
,A.content_loc4
,A.content_loc5
,A.content_loc6
,A.content_loc7
,A.content_loc8
,0 AS sound
,B.datalong AS type
,B.datalong2 AS language
,0 AS emote
,NULL AS comment
FROM db_script_string A
INNER JOIN dbscripts_on_quest_start B ON (A.entry = B.dataint OR A.entry = B.dataint2 OR A.entry = B.dataint3 OR A.entry = B.dataint4)
-- dbscripts_on_spell
UNION ALL
SELECT A.entry
,A.content_default
,A.content_loc1
,A.content_loc2
,A.content_loc3
,A.content_loc4
,A.content_loc5
,A.content_loc6
,A.content_loc7
,A.content_loc8
,0 AS sound
,B.datalong AS type
,B.datalong2 AS language
,0 AS emote
,NULL AS comment
FROM db_script_string A
INNER JOIN dbscripts_on_spell B ON (A.entry = B.dataint OR A.entry = B.dataint2 OR A.entry = B.dataint3 OR A.entry = B.dataint4);
-- Clean dbscript_string and insert the new updated values
DELETE FROM db_script_string WHERE entry IN (SELECT DISTINCT entry FROM db_script_temp);
INSERT INTO db_script_string SELECT * FROM db_script_temp GROUP BY entry;
DROP TABLE IF EXISTS db_script_temp;
DELETE FROM playercreateinfo_spell WHERE race=10 AND Spell=61437;
INSERT INTO playercreateinfo_spell (race, class, Spell, Note) VALUES
(10,2,61437,'Opening'),
(10,3,61437,'Opening'),
(10,4,61437,'Opening'),
(10,5,61437,'Opening'),
(10,6,61437,'Opening'),
(10,8,61437,'Opening'),
(10,9,61437,'Opening');
UPDATE `command` SET help = 'Syntax: .account create $account $password [$expansion]\r\n\r\nCreate account and set password to it. Optionally, you may also set another expansion for this account than the defined default value.' WHERE name = 'account create';
ALTER TABLE playercreateinfo_action DROP INDEX playercreateinfo_race_class_index;

View file

@ -17,5 +17,7 @@
# Clone https://github.com/mangosthree/scripts here, and comment out # Clone https://github.com/mangosthree/scripts here, and comment out
# the next line and uncomment the last line. # the next line and uncomment the last line.
# add_subdirectory(universal) if(INCLUDE_BINDINGS_DIR)
add_subdirectory(${INCLUDE_BINDINGS_DIR})
endif()
# add_subdirectory(scripts) # add_subdirectory(scripts)

View file

@ -1,4 +1,5 @@
# This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS. #
# This file is part of the MaNGOS Project. See AUTHORS file for Copyright information
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -13,12 +14,16 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
set(LIBRARY_NAME framework) set(LIBRARY_NAME framework)
set(LIBRARY_SRCS set(SRC_GRP_DYNAMIC
Dynamic/FactoryHolder.h Dynamic/FactoryHolder.h
Dynamic/ObjectRegistry.h Dynamic/ObjectRegistry.h
)
set(SRC_GRP_GAMESYSTEM
GameSystem/Grid.h GameSystem/Grid.h
GameSystem/GridLoader.h GameSystem/GridLoader.h
GameSystem/GridReference.h GameSystem/GridReference.h
@ -27,51 +32,74 @@ set(LIBRARY_SRCS
GameSystem/TypeContainer.h GameSystem/TypeContainer.h
GameSystem/TypeContainerFunctions.h GameSystem/TypeContainerFunctions.h
GameSystem/TypeContainerVisitor.h GameSystem/TypeContainerVisitor.h
)
set(SRC_GRP_PLATFORM
Platform/CompilerDefs.h Platform/CompilerDefs.h
Platform/Define.h Platform/Define.h
)
set(SRC_GRP_POLICIES
Policies/CreationPolicy.h Policies/CreationPolicy.h
Policies/MemoryManagement.cpp Policies/MemoryManagement.cpp
Policies/ObjectLifeTime.cpp Policies/ObjectLifeTime.cpp
Policies/ObjectLifeTime.h Policies/ObjectLifeTime.h
Policies/Singleton.h Policies/Singleton.h
Policies/ThreadingModel.h Policies/ThreadingModel.h
)
set(SRC_GRP_UTIL
Utilities/ByteConverter.h Utilities/ByteConverter.h
Utilities/Callback.h Utilities/Callback.h
Utilities/EventProcessor.cpp Utilities/EventProcessor.cpp
Utilities/EventProcessor.h Utilities/EventProcessor.h
Utilities/LinkedList.h Utilities/LinkedList.h
Utilities/LinkedReference/Reference.h
Utilities/LinkedReference/RefManager.h
Utilities/TypeList.h Utilities/TypeList.h
Utilities/UnorderedMapSet.h Utilities/UnorderedMapSet.h
) )
source_group("Other" set(SRC_GRP_LINKED_REFERENCE
REGULAR_EXPRESSION .* Utilities/LinkedReference/Reference.h
Utilities/LinkedReference/RefManager.h
) )
source_group("GameSystem" set(LIBRARY_SRCS
REGULAR_EXPRESSION GameSystem ${SRC_GRP_DYNAMIC}
) ${SRC_GRP_GAMESYSTEM}
${SRC_GRP_PLATFORM}
source_group("Platform" ${SRC_GRP_POLICIES}
REGULAR_EXPRESSION Platform ${SRC_GRP_UTIL}
) ${SRC_GRP_LINKED_REFERENCE}
source_group("Policies"
REGULAR_EXPRESSION Policies
)
source_group("Utilities"
REGULAR_EXPRESSION Utilities
)
source_group("LinkedReference"
REGULAR_EXPRESSION LinkedReference
) )
source_group("Dynamic" source_group("Dynamic"
REGULAR_EXPRESSION Dynamic FILES
${SRC_GRP_DYNAMIC}
)
source_group("GameSystem"
FILES
${SRC_GRP_GAMESYSTEM}
)
source_group("Platform"
FILES
${SRC_GRP_PLATFORM}
)
source_group("Policies"
FILES
${SRC_GRP_POLICIES}
)
source_group("Utilities"
FILES
${SRC_GRP_UTIL}
)
source_group("Utilities\\LinkedReference"
FILES
${SRC_GRP_LINKED_REFERENCE}
) )
include_directories( include_directories(

View file

@ -55,6 +55,26 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass
return AOR_OK; // everything's fine return AOR_OK; // everything's fine
} }
AccountOpResult AccountMgr::CreateAccount(std::string username, std::string password, uint32 expansion)
{
if (utf8length(username) > MAX_ACCOUNT_STR)
return AOR_NAME_TOO_LONG; // username's too long
normalizeString(username);
normalizeString(password);
if (GetId(username))
{
return AOR_NAME_ALREDY_EXIST; // username does already exist
}
if (!LoginDatabase.PExecute("INSERT INTO account(username,sha_pass_hash,joindate,expansion) VALUES('%s','%s',NOW(),'%u')", username.c_str(), CalculateShaPassHash(username, password).c_str(), expansion))
return AOR_DB_INTERNAL_ERROR; // unexpected error
LoginDatabase.Execute("INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist,account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL");
return AOR_OK; // everything's fine
}
AccountOpResult AccountMgr::DeleteAccount(uint32 accid) AccountOpResult AccountMgr::DeleteAccount(uint32 accid)
{ {
QueryResult* result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%u'", accid); QueryResult* result = LoginDatabase.PQuery("SELECT 1 FROM account WHERE id='%u'", accid);

View file

@ -42,6 +42,7 @@ class AccountMgr
~AccountMgr(); ~AccountMgr();
AccountOpResult CreateAccount(std::string username, std::string password); AccountOpResult CreateAccount(std::string username, std::string password);
AccountOpResult CreateAccount(std::string username, std::string password, uint32 expansion);
AccountOpResult DeleteAccount(uint32 accid); AccountOpResult DeleteAccount(uint32 accid);
AccountOpResult ChangeUsername(uint32 accid, std::string new_uname, std::string new_passwd); AccountOpResult ChangeUsername(uint32 accid, std::string new_uname, std::string new_passwd);
AccountOpResult ChangePassword(uint32 accid, std::string new_passwd); AccountOpResult ChangePassword(uint32 accid, std::string new_passwd);

View file

@ -1,4 +1,5 @@
# This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS. #
# This file is part of the MaNGOS Project. See AUTHORS file for Copyright information
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@ -13,26 +14,34 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
set(LIBRARY_NAME game) set(LIBRARY_NAME game)
set(LIBRARY_SRCS include_directories(
AccountMgr.cpp ${CMAKE_CURRENT_SOURCE_DIR}
AccountMgr.h ${CMAKE_CURRENT_SOURCE_DIR}/vmap
AchievementMgr.cpp ${CMAKE_CURRENT_SOURCE_DIR}/AuctionHouseBot
AchievementMgr.h ${CMAKE_CURRENT_SOURCE_DIR}/BattleGround
AggressorAI.cpp ${CMAKE_CURRENT_SOURCE_DIR}/OutdoorPvP
AggressorAI.h ${CMAKE_SOURCE_DIR}/dep/include/g3dlite
ArenaTeam.cpp ${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
ArenaTeam.h ${CMAKE_SOURCE_DIR}/dep/recastnavigation/
ArenaTeamHandler.cpp ${CMAKE_SOURCE_DIR}/dep/include
${CMAKE_SOURCE_DIR}/src/shared
${CMAKE_SOURCE_DIR}/src/framework
${CMAKE_BINARY_DIR}
${CMAKE_BINARY_DIR}/src/shared
${MYSQL_INCLUDE_DIR}
${ACE_INCLUDE_DIR}
)
set(SRC_GRP_AHBOT
AuctionHouseBot/AuctionHouseBot.cpp AuctionHouseBot/AuctionHouseBot.cpp
AuctionHouseBot/AuctionHouseBot.h AuctionHouseBot/AuctionHouseBot.h
AuctionHouseHandler.cpp )
AuctionHouseMgr.cpp
AuctionHouseMgr.h set(SRC_GRP_BATTLEGROUND
Bag.cpp
Bag.h
BattleGround/BattleGround.cpp BattleGround/BattleGround.cpp
BattleGround/BattleGround.h BattleGround/BattleGround.h
BattleGround/BattleGroundAA.cpp BattleGround/BattleGroundAA.cpp
@ -64,27 +73,72 @@ set(LIBRARY_SRCS
BattleGround/BattleGroundSA.h BattleGround/BattleGroundSA.h
BattleGround/BattleGroundWS.cpp BattleGround/BattleGroundWS.cpp
BattleGround/BattleGroundWS.h BattleGround/BattleGroundWS.h
Calendar.cpp )
Calendar.h
CalendarHandler.cpp set(SRC_GRP_CHAT_COMMANDS
Camera.cpp debugcmds.cpp
Camera.h Level0.cpp
Cell.h Level1.cpp
CellImpl.h Level2.cpp
Channel.cpp Level3.cpp
Channel.h )
ChannelHandler.cpp
ChannelMgr.cpp set(SRC_GRP_MOTION_GEN
ChannelMgr.h
CharacterDatabaseCleaner.cpp
CharacterDatabaseCleaner.h
CharacterHandler.cpp
Chat.cpp
Chat.h
ChatHandler.cpp
CombatHandler.cpp
ConfusedMovementGenerator.cpp ConfusedMovementGenerator.cpp
ConfusedMovementGenerator.h ConfusedMovementGenerator.h
FleeingMovementGenerator.cpp
FleeingMovementGenerator.h
HomeMovementGenerator.cpp
HomeMovementGenerator.h
IdleMovementGenerator.cpp
IdleMovementGenerator.h
MotionMaster.cpp
MotionMaster.h
MovementGenerator.cpp
MovementGenerator.h
MovementGeneratorImpl.h # TODO: this is not in the VC files - does it belong in here?
PathFinder.cpp
PathFinder.h
PointMovementGenerator.cpp
PointMovementGenerator.h
RandomMovementGenerator.cpp
RandomMovementGenerator.h
TargetedMovementGenerator.cpp
TargetedMovementGenerator.h
WaypointMovementGenerator.cpp
WaypointMovementGenerator.h
)
set(SRC_GRP_MOVEMENT
movement/MovementStructures.h
movement/MoveSpline.cpp
movement/MoveSpline.h
movement/MoveSplineFlag.h
movement/MoveSplineInit.cpp
movement/MoveSplineInit.h
movement/MoveSplineInitArgs.h
movement/packet_builder.cpp
movement/packet_builder.h
movement/spline.cpp
movement/spline.h
movement/spline.impl.h
movement/typedefs.h
movement/util.cpp
)
set(SRC_GRP_OBJECT
AggressorAI.cpp
AggressorAI.h
ArenaTeam.cpp
ArenaTeam.h
AuctionHouseMgr.cpp
AuctionHouseMgr.h
Bag.cpp
Bag.h
Calendar.cpp
Calendar.h
Camera.cpp
Camera.h
Corpse.cpp Corpse.cpp
Corpse.h Corpse.h
Creature.cpp Creature.cpp
@ -100,136 +154,69 @@ set(LIBRARY_SRCS
CreatureEventAI.h CreatureEventAI.h
CreatureEventAIMgr.cpp CreatureEventAIMgr.cpp
CreatureEventAIMgr.h CreatureEventAIMgr.h
CreatureLinkingMgr.cpp
CreatureLinkingMgr.h
DB2fmt.h
DB2Stores.cpp
DB2Stores.h
DB2Structure.h
DBCEnums.h
DBCfmt.h
DBCStores.cpp
DBCStores.h
DBCStructure.cpp
DBCStructure.h
debugcmds.cpp
DuelHandler.cpp
DynamicObject.cpp DynamicObject.cpp
DynamicObject.h DynamicObject.h
FleeingMovementGenerator.cpp
FleeingMovementGenerator.h
FollowerReference.cpp
FollowerReference.h
FollowerRefManager.h
Formulas.h Formulas.h
GameEventMgr.cpp
GameEventMgr.h
GameObject.cpp GameObject.cpp
GameObject.h GameObject.h
GMTicketHandler.cpp
GMTicketMgr.cpp GMTicketMgr.cpp
GMTicketMgr.h GMTicketMgr.h
GossipDef.cpp
GossipDef.h
GridDefines.h
GridMap.cpp
GridMap.h
GridNotifiers.cpp
GridNotifiers.h
GridNotifiersImpl.h
GridStates.cpp
GridStates.h
Group.cpp
Group.h
GroupHandler.cpp
GroupReference.cpp
GroupReference.h
GroupRefManager.h
GuardAI.cpp GuardAI.cpp
GuardAI.h GuardAI.h
Guild.cpp Guild.cpp
Guild.h Guild.h
GuildHandler.cpp
GuildMgr.cpp
GuildMgr.h
HomeMovementGenerator.cpp
HomeMovementGenerator.h
HostileRefManager.cpp
HostileRefManager.h
IdleMovementGenerator.cpp
IdleMovementGenerator.h
InstanceData.cpp
InstanceData.h
Item.cpp Item.cpp
Item.h Item.h
ItemEnchantmentMgr.cpp ItemEnchantmentMgr.cpp
ItemEnchantmentMgr.h ItemEnchantmentMgr.h
ItemHandler.cpp
ItemPrototype.h ItemPrototype.h
Language.h
Level0.cpp
Level1.cpp
Level2.cpp
Level3.cpp
LFGHandler.cpp
LootHandler.cpp
LootMgr.cpp LootMgr.cpp
LootMgr.h LootMgr.h
Mail.cpp
Mail.h
MailHandler.cpp
Map.cpp
Map.h
MapManager.cpp
MapManager.h
MapPersistentStateMgr.cpp
MapPersistentStateMgr.h
MapReference.h
MapRefManager.h
MassMailMgr.cpp
MassMailMgr.h
MiscHandler.cpp
MotionMaster.cpp
MotionMaster.h
MoveMap.cpp
MoveMap.h
MoveMapSharedDefines.h
movement/MoveSpline.cpp
movement/MoveSpline.h
movement/MoveSplineFlag.h
movement/MoveSplineInit.cpp
movement/MoveSplineInit.h
movement/MoveSplineInitArgs.h
movement/packet_builder.cpp
movement/packet_builder.h
movement/spline.cpp
movement/spline.h
movement/spline.impl.h
movement/typedefs.h
movement/util.cpp
MovementGenerator.cpp
MovementGenerator.h
MovementGeneratorImpl.h
MovementHandler.cpp
MovementStructures.h
NPCHandler.cpp
NPCHandler.h
NullCreatureAI.cpp NullCreatureAI.cpp
NullCreatureAI.h NullCreatureAI.h
Object.cpp Object.cpp
Object.h Object.h
ObjectAccessor.cpp ObjectAccessor.cpp
ObjectAccessor.h ObjectAccessor.h
ObjectGridLoader.cpp
ObjectGridLoader.h
ObjectGuid.cpp ObjectGuid.cpp
ObjectGuid.h ObjectGuid.h
ObjectMgr.cpp ObjectMgr.cpp
ObjectMgr.h ObjectMgr.h
ObjectPosSelector.cpp ObjectPosSelector.cpp
ObjectPosSelector.h ObjectPosSelector.h
Opcodes.cpp Pet.cpp
Opcodes.h Pet.h
PetAI.cpp
PetAI.h
Player.cpp
Player.h
ReactorAI.cpp
ReactorAI.h
ReputationMgr.cpp
ReputationMgr.h
SocialMgr.cpp
SocialMgr.h
SpellMgr.cpp
SpellMgr.h
StatSystem.cpp
TemporarySummon.cpp
TemporarySummon.h
Totem.cpp
Totem.h
TotemAI.cpp
TotemAI.h
TransportSystem.cpp
TransportSystem.h
Unit.cpp
Unit.h
UnitEvents.h
UpdateFields.h
UpdateMask.h
Vehicle.cpp
Vehicle.h
)
set(SRC_GRP_OUTDOOR_PVP
OutdoorPvP/OutdoorPvP.cpp OutdoorPvP/OutdoorPvP.cpp
OutdoorPvP/OutdoorPvP.h OutdoorPvP/OutdoorPvP.h
OutdoorPvP/OutdoorPvPEP.cpp OutdoorPvP/OutdoorPvPEP.cpp
@ -248,84 +235,56 @@ set(LIBRARY_SRCS
OutdoorPvP/OutdoorPvPTF.h OutdoorPvP/OutdoorPvPTF.h
OutdoorPvP/OutdoorPvPZM.cpp OutdoorPvP/OutdoorPvPZM.cpp
OutdoorPvP/OutdoorPvPZM.h OutdoorPvP/OutdoorPvPZM.h
Path.h )
PathFinder.cpp
PathFinder.h set(SRC_GRP_REFERENCES
pchdef.cpp FollowerReference.cpp
pchdef.h FollowerReference.h
Pet.cpp FollowerRefManager.h
Pet.h GroupReference.cpp
PetAI.cpp GroupReference.h
PetAI.h GroupRefManager.h
PetHandler.cpp HostileRefManager.cpp
PetitionsHandler.cpp HostileRefManager.h
Player.cpp MapReference.h
Player.h MapRefManager.h
PlayerDump.cpp
PlayerDump.h
PointMovementGenerator.cpp
PointMovementGenerator.h
PoolManager.cpp
PoolManager.h
QueryHandler.cpp
QuestDef.cpp
QuestDef.h
QuestHandler.cpp
RandomMovementGenerator.cpp
RandomMovementGenerator.h
ReactorAI.cpp
ReactorAI.h
ReputationMgr.cpp
ReputationMgr.h
ScriptMgr.cpp
ScriptMgr.h
SharedDefines.h
SkillDiscovery.cpp
SkillDiscovery.h
SkillExtraItems.cpp
SkillExtraItems.h
SkillHandler.cpp
SocialMgr.cpp
SocialMgr.h
Spell.cpp
Spell.h
SpellAuraDefines.h
SpellAuras.cpp
SpellAuras.h
SpellEffects.cpp
SpellHandler.cpp
SpellMgr.cpp
SpellMgr.h
SQLStorages.cpp
SQLStorages.h
StatSystem.cpp
TargetedMovementGenerator.cpp
TargetedMovementGenerator.h
TaxiHandler.cpp
TemporarySummon.cpp
TemporarySummon.h
ThreatManager.cpp ThreatManager.cpp
ThreatManager.h ThreatManager.h
Totem.cpp )
Totem.h
TotemAI.cpp set(SRC_GRP_SERVER
TotemAI.h DB2fmt.h
TradeHandler.cpp DB2Stores.cpp
Transports.cpp DB2Stores.h
Transports.h DB2Structure.h
TransportSystem.cpp DBCEnums.h
TransportSystem.h DBCfmt.h
Unit.cpp DBCStores.cpp
Unit.h DBCStores.h
UnitAuraProcHandler.cpp DBCStructure.cpp
UnitEvents.h DBCStructure.h
UpdateData.cpp Opcodes.cpp
UpdateData.h Opcodes.h
UpdateFields.h SharedDefines.h
UpdateMask.h SQLStorages.cpp
Vehicle.cpp SQLStorages.h
Vehicle.h WorldSession.cpp
VehicleHandler.cpp WorldSession.h
WorldSocket.cpp
WorldSocket.h
WorldSocketMgr.cpp
WorldSocketMgr.h
)
set(SRC_GRP_TOOL
CharacterDatabaseCleaner.cpp
CharacterDatabaseCleaner.h
Language.h
PlayerDump.cpp
PlayerDump.h
)
set(SRC_GRP_VMAPS
vmap/BIH.cpp vmap/BIH.cpp
vmap/BIH.h vmap/BIH.h
vmap/BIHWrap.h vmap/BIHWrap.h
@ -349,79 +308,190 @@ set(LIBRARY_SRCS
vmap/VMapTools.h vmap/VMapTools.h
vmap/WorldModel.cpp vmap/WorldModel.cpp
vmap/WorldModel.h vmap/WorldModel.h
)
set(SRC_GRP_WORLD_HANDLERS
AccountMgr.cpp
AccountMgr.h
AchievementMgr.cpp
AchievementMgr.h
ArenaTeamHandler.cpp
AuctionHouseHandler.cpp
CalendarHandler.cpp
Cell.h
CellImpl.h
Channel.cpp
Channel.h
ChannelHandler.cpp
ChannelMgr.cpp
ChannelMgr.h
CharacterHandler.cpp
Chat.cpp
Chat.h
ChatHandler.cpp
CombatHandler.cpp
CreatureLinkingMgr.cpp
CreatureLinkingMgr.h
DuelHandler.cpp
GameEventMgr.cpp
GameEventMgr.h
GMTicketHandler.cpp
GossipDef.cpp
GossipDef.h
GridDefines.h
GridMap.cpp
GridMap.h
GridNotifiers.cpp
GridNotifiers.h
GridNotifiersImpl.h
GridStates.cpp
GridStates.h
Group.cpp
Group.h
GroupHandler.cpp
GuildHandler.cpp
GuildMgr.cpp
GuildMgr.h
InstanceData.cpp
InstanceData.h
ItemHandler.cpp
LFGHandler.cpp
LootHandler.cpp
Mail.cpp
Mail.h
MailHandler.cpp
Map.cpp
Map.h
MapManager.cpp
MapManager.h
MapPersistentStateMgr.cpp
MapPersistentStateMgr.h
MassMailMgr.cpp
MassMailMgr.h
MiscHandler.cpp
MoveMap.cpp
MoveMap.h
MoveMapSharedDefines.h
MovementHandler.cpp
NPCHandler.cpp
NPCHandler.h
ObjectGridLoader.cpp
ObjectGridLoader.h
Path.h
PetHandler.cpp
PetitionsHandler.cpp
PoolManager.cpp
PoolManager.h
QueryHandler.cpp
QuestDef.cpp
QuestDef.h
QuestHandler.cpp
ScriptMgr.cpp
ScriptMgr.h
SkillDiscovery.cpp
SkillDiscovery.h
SkillExtraItems.cpp
SkillExtraItems.h
SkillHandler.cpp
Spell.cpp
Spell.h
SpellAuraDefines.h
SpellAuras.cpp
SpellAuras.h
SpellEffects.cpp
SpellHandler.cpp
TaxiHandler.cpp
TradeHandler.cpp
Transports.cpp
Transports.h
UnitAuraProcHandler.cpp
UpdateData.cpp
UpdateData.h
VehicleHandler.cpp
VoiceChatHandler.cpp VoiceChatHandler.cpp
WaypointManager.cpp WaypointManager.cpp
WaypointManager.h WaypointManager.h
WaypointMovementGenerator.cpp
WaypointMovementGenerator.h
Weather.cpp Weather.cpp
Weather.h Weather.h
World.cpp World.cpp
World.h World.h
WorldSession.cpp
WorldSession.h
WorldSocket.cpp
WorldSocket.h
WorldSocketMgr.cpp
WorldSocketMgr.h
) )
include_directories( set(LIBRARY_SRCS
${CMAKE_CURRENT_SOURCE_DIR} ${SRC_GRP_AHBOT}
${CMAKE_CURRENT_SOURCE_DIR}/vmap ${SRC_GRP_BATTLEGROUND}
${CMAKE_CURRENT_SOURCE_DIR}/AuctionHouseBot ${SRC_GRP_CHAT_COMMANDS}
${CMAKE_CURRENT_SOURCE_DIR}/BattleGround ${SRC_GRP_MOTION_GEN}
${CMAKE_CURRENT_SOURCE_DIR}/OutdoorPvP ${SRC_GRP_MOVEMENT}
${CMAKE_SOURCE_DIR}/dep/include/g3dlite ${SRC_GRP_OBJECT}
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour ${SRC_GRP_OUTDOOR_PVP}
${CMAKE_SOURCE_DIR}/dep/recastnavigation/ ${SRC_GRP_REFERENCES}
${CMAKE_SOURCE_DIR}/dep/include ${SRC_GRP_SERVER}
${CMAKE_SOURCE_DIR}/src/shared ${SRC_GRP_TOOL}
${CMAKE_SOURCE_DIR}/src/framework ${SRC_GRP_VMAPS}
${CMAKE_BINARY_DIR} ${SRC_GRP_WORLD_HANDLERS}
${CMAKE_BINARY_DIR}/src/shared pchdef.cpp
${MYSQL_INCLUDE_DIR} pchdef.h
${ACE_INCLUDE_DIR}
) )
source_group("Object" source_group("AhBot"
REGULAR_EXPRESSION .*
)
source_group("World/Handlers"
# REGULAR_EXPRESSION Mgr|Handler|Manager|BattleGround|Cell|Channel|Chat|Gossip|Grid|Group|Instance|Mail|Map|Path|Pool|Quest|Script|Skill|Spell|Transports|Update|Weather|World
REGULAR_EXPRESSION Mgr|Handler|Manager|Cell|Channel|Chat|Gossip|Grid|Instance|Map|Path|Pool|Script|Skill|Transports|Update|Weather|World
)
source_group("Motion generators"
REGULAR_EXPRESSION MoveMap|MoveMapSharedDefines|Generator|MotionMaster
)
source_group("Server"
REGULAR_EXPRESSION Socket|Session|Opcodes|DBC
FILES FILES
SharedDefines.h ${SRC_GRP_AHBOT}
)
source_group("BattleGround"
FILES
${SRC_GRP_BATTLEGROUND}
) )
source_group("Chat Commands" source_group("Chat Commands"
REGULAR_EXPRESSION Level[0-9]
FILES FILES
debugcmds.cpp ${SRC_GRP_CHAT_COMMANDS}
) )
source_group("Tool" source_group("Motion generators"
REGULAR_EXPRESSION DatabaseCleaner|Language|PlayerDump FILES
) ${SRC_GRP_MOTION_GEN}
source_group("References"
REGULAR_EXPRESSION Reference|RefManager|ThreatManager
) )
source_group("Movement" source_group("Movement"
REGULAR_EXPRESSION spline|Spline|packet_builder
FILES FILES
movement/typedefs.h ${SRC_GRP_MOVEMENT}
movement/util.cpp )
source_group("Object"
FILES
${SRC_GRP_OBJECT}
)
source_group("Outdoor PvP"
FILES
${SRC_GRP_OUTDOOR_PVP}
)
source_group("References"
FILES
${SRC_GRP_REFERENCES}
)
source_group("Server"
FILES
${SRC_GRP_SERVER}
)
source_group("Tool"
FILES
${SRC_GRP_TOOL}
)
source_group("vmaps"
FILES
${SRC_GRP_VMAPS}
)
source_group("World/Handlers"
FILES
${SRC_GRP_WORLD_HANDLERS}
) )
if(PCH) if(PCH)

View file

@ -580,6 +580,7 @@ void CalendarMgr::LoadCalendarsFromDB()
do do
{ {
Field* field = eventsQuery->Fetch(); Field* field = eventsQuery->Fetch();
bar.step();
uint64 eventId = field[0].GetUInt64(); uint64 eventId = field[0].GetUInt64();

View file

@ -28,7 +28,9 @@
#include "ObjectMgr.h" #include "ObjectMgr.h"
Corpse::Corpse(CorpseType type) : WorldObject(), Corpse::Corpse(CorpseType type) : WorldObject(),
loot(this) loot(this),
lootRecipient(NULL),
lootForBody(false)
{ {
m_objectType |= TYPEMASK_CORPSE; m_objectType |= TYPEMASK_CORPSE;
m_objectTypeId = TYPEID_CORPSE; m_objectTypeId = TYPEID_CORPSE;
@ -40,8 +42,6 @@ Corpse::Corpse(CorpseType type) : WorldObject(),
m_type = type; m_type = type;
m_time = time(NULL); m_time = time(NULL);
lootForBody = false;
} }
Corpse::~Corpse() Corpse::~Corpse()

View file

@ -189,9 +189,18 @@ void Creature::RemoveFromWorld()
void Creature::RemoveCorpse() void Creature::RemoveCorpse()
{ {
// since pool system can fail to roll unspawned object, this one can remain spawned, so must set respawn nevertheless
if (uint16 poolid = sPoolMgr.IsPartOfAPool<Creature>(GetGUIDLow()))
sPoolMgr.UpdatePool<Creature>(*GetMap()->GetPersistentState(), poolid, GetGUIDLow());
if (!IsInWorld()) // can be despawned by update pool
return;
if ((getDeathState() != CORPSE && !m_isDeadByDefault) || (getDeathState() != ALIVE && m_isDeadByDefault)) if ((getDeathState() != CORPSE && !m_isDeadByDefault) || (getDeathState() != ALIVE && m_isDeadByDefault))
return; return;
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Removing corpse of %s ", GetGuidStr().c_str());
m_corpseDecayTimer = 0; m_corpseDecayTimer = 0;
SetDeathState(DEAD); SetDeathState(DEAD);
UpdateObjectVisibility(); UpdateObjectVisibility();
@ -515,28 +524,19 @@ void Creature::Update(uint32 update_diff, uint32 diff)
break; break;
if (m_corpseDecayTimer <= update_diff) if (m_corpseDecayTimer <= update_diff)
{
// since pool system can fail to roll unspawned object, this one can remain spawned, so must set respawn nevertheless
if (uint16 poolid = sPoolMgr.IsPartOfAPool<Creature>(GetGUIDLow()))
sPoolMgr.UpdatePool<Creature>(*GetMap()->GetPersistentState(), poolid, GetGUIDLow());
if (IsInWorld()) // can be despawned by update pool
{ {
RemoveCorpse(); RemoveCorpse();
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Removing corpse... %u ", GetEntry()); break;
}
} }
else else
{
m_corpseDecayTimer -= update_diff; m_corpseDecayTimer -= update_diff;
if (m_groupLootId) if (m_groupLootId) // Loot is stopped already if corpse got removed.
{ {
if (m_groupLootTimer <= update_diff) if (m_groupLootTimer <= update_diff)
StopGroupLoot(); StopGroupLoot();
else else
m_groupLootTimer -= update_diff; m_groupLootTimer -= update_diff;
} }
}
break; break;
} }
@ -545,24 +545,13 @@ void Creature::Update(uint32 update_diff, uint32 diff)
if (m_isDeadByDefault) if (m_isDeadByDefault)
{ {
if (m_corpseDecayTimer <= update_diff) if (m_corpseDecayTimer <= update_diff)
{
// since pool system can fail to roll unspawned object, this one can remain spawned, so must set respawn nevertheless
if (uint16 poolid = sPoolMgr.IsPartOfAPool<Creature>(GetGUIDLow()))
sPoolMgr.UpdatePool<Creature>(*GetMap()->GetPersistentState(), poolid, GetGUIDLow());
if (IsInWorld()) // can be despawned by update pool
{ {
RemoveCorpse(); RemoveCorpse();
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Removing alive corpse... %u ", GetEntry()); break;
} }
else else
return;
}
else
{
m_corpseDecayTimer -= update_diff; m_corpseDecayTimer -= update_diff;
} }
}
Unit::Update(update_diff, diff); Unit::Update(update_diff, diff);
@ -1549,6 +1538,9 @@ void Creature::SetDeathState(DeathState s)
void Creature::Respawn() void Creature::Respawn()
{ {
if (!IsInWorld()) // Could be removed as part of a pool (in which case respawn-time is handled with pool-system)
return;
RemoveCorpse(); RemoveCorpse();
if (IsDespawned()) if (IsDespawned())
@ -1568,11 +1560,14 @@ void Creature::ForcedDespawn(uint32 timeMSToDespawn)
m_Events.AddEvent(pEvent, m_Events.CalculateTime(timeMSToDespawn)); m_Events.AddEvent(pEvent, m_Events.CalculateTime(timeMSToDespawn));
return; return;
} }
if (IsDespawned())
return;
if (isAlive()) if (isAlive())
SetDeathState(JUST_DIED); SetDeathState(JUST_DIED);
m_corpseDecayTimer = 1; // Properly remove corpse on next tick (also pool system requires Creature::Update call with CORPSE state RemoveCorpse();
SetHealth(0); // just for nice GM-mode view SetHealth(0); // just for nice GM-mode view
} }
@ -1772,7 +1767,7 @@ void Creature::CallAssistance()
if (!m_AlreadyCallAssistance && getVictim() && !isCharmed()) if (!m_AlreadyCallAssistance && getVictim() && !isCharmed())
{ {
SetNoCallAssistance(true); SetNoCallAssistance(true);
AI()->SendAIEvent(AI_EVENT_CALL_ASSISTANCE, getVictim(), sWorld.getConfig(CONFIG_UINT32_CREATURE_FAMILY_ASSISTANCE_DELAY), sWorld.getConfig(CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS)); AI()->SendAIEventAround(AI_EVENT_CALL_ASSISTANCE, getVictim(), sWorld.getConfig(CONFIG_UINT32_CREATURE_FAMILY_ASSISTANCE_DELAY), sWorld.getConfig(CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS));
} }
} }

View file

@ -511,8 +511,8 @@ class MANGOS_DLL_SPEC Creature : public Unit
bool IsGuard() const { return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_GUARD; } bool IsGuard() const { return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_GUARD; }
bool CanWalk() const { return GetCreatureInfo()->InhabitType & INHABIT_GROUND; } bool CanWalk() const { return GetCreatureInfo()->InhabitType & INHABIT_GROUND; }
bool CanSwim() const { return GetCreatureInfo()->InhabitType & INHABIT_WATER; } virtual bool CanSwim() const { return GetCreatureInfo()->InhabitType & INHABIT_WATER; }
bool CanFly() const { return (GetCreatureInfo()->InhabitType & INHABIT_AIR) || (GetByteValue(UNIT_FIELD_BYTES_1, 3) & UNIT_BYTE1_FLAG_UNK_2); } bool CanFly() const { return (GetCreatureInfo()->InhabitType & INHABIT_AIR) || (GetByteValue(UNIT_FIELD_BYTES_1, 3) & UNIT_BYTE1_FLAG_UNK_2) || HasAuraType(SPELL_AURA_FLY); }
bool IsTrainerOf(Player* player, bool msg) const; bool IsTrainerOf(Player* player, bool msg) const;
bool CanInteractWithBattleMaster(Player* player, bool msg) const; bool CanInteractWithBattleMaster(Player* player, bool msg) const;

View file

@ -209,7 +209,7 @@ class AiDelayEventAround : public BasicEvent
uint32 m_miscValue; uint32 m_miscValue;
}; };
void CreatureAI::SendAIEvent(AIEventType eventType, Unit* pInvoker, uint32 uiDelay, float fRadius, uint32 miscValue /*=0*/) const void CreatureAI::SendAIEventAround(AIEventType eventType, Unit* pInvoker, uint32 uiDelay, float fRadius, uint32 miscValue /*=0*/) const
{ {
if (fRadius > 0) if (fRadius > 0)
{ {

View file

@ -63,13 +63,14 @@ enum AIEventType
{ {
// Usable with Event AI // Usable with Event AI
AI_EVENT_JUST_DIED = 0, // Sender = Killed Npc, Invoker = Killer AI_EVENT_JUST_DIED = 0, // Sender = Killed Npc, Invoker = Killer
AI_EVENT_CRITICAL_HEALTH = 1, // Sender = Hurt Npc, Invoker = DamageDealer AI_EVENT_CRITICAL_HEALTH = 1, // Sender = Hurt Npc, Invoker = DamageDealer - Expected to be sent by 10% health
AI_EVENT_LOST_HEALTH = 2, // Sender = Hurt Npc, Invoker = DamageDealer AI_EVENT_LOST_HEALTH = 2, // Sender = Hurt Npc, Invoker = DamageDealer - Expected to be sent by 50% health
AI_EVENT_GOT_CCED = 3, // Sender = CCed Npc, Invoker = Caster that CCed AI_EVENT_LOST_SOME_HEALTH = 3, // Sender = Hurt Npc, Invoker = DamageDealer - Expected to be sent by 90% health
AI_EVENT_GOT_FULL_HEALTH = 4, // Sender = Healed Npc, Invoker = Healer AI_EVENT_GOT_FULL_HEALTH = 4, // Sender = Healed Npc, Invoker = Healer
AI_EVENT_CUSTOM_EVENTAI_A = 5, // Sender = Npc that throws custom event, Invoker = TARGET_T_ACTION_INVOKER (if exists) AI_EVENT_CUSTOM_EVENTAI_A = 5, // Sender = Npc that throws custom event, Invoker = TARGET_T_ACTION_INVOKER (if exists)
AI_EVENT_CUSTOM_EVENTAI_B = 6, // Sender = Npc that throws custom event, Invoker = TARGET_T_ACTION_INVOKER (if exists) AI_EVENT_CUSTOM_EVENTAI_B = 6, // Sender = Npc that throws custom event, Invoker = TARGET_T_ACTION_INVOKER (if exists)
MAXIMAL_AI_EVENT_EVENTAI = 7, AI_EVENT_GOT_CCED = 7, // Sender = CCed Npc, Invoker = Caster that CCed
MAXIMAL_AI_EVENT_EVENTAI = 8,
// Internal Use // Internal Use
AI_EVENT_CALL_ASSISTANCE = 10, // Sender = Attacked Npc, Invoker = Enemy AI_EVENT_CALL_ASSISTANCE = 10, // Sender = Attacked Npc, Invoker = Enemy
@ -317,7 +318,7 @@ class MANGOS_DLL_SPEC CreatureAI
* @param uiDelay delay time until the Event will be triggered * @param uiDelay delay time until the Event will be triggered
* @param fRadius range in which for receiver is searched * @param fRadius range in which for receiver is searched
*/ */
void SendAIEvent(AIEventType eventType, Unit* pInvoker, uint32 uiDelay, float fRadius, uint32 miscValue = 0) const; void SendAIEventAround(AIEventType eventType, Unit* pInvoker, uint32 uiDelay, float fRadius, uint32 miscValue = 0) const;
/** /**
* Send an AI Event to a Creature * Send an AI Event to a Creature

View file

@ -59,6 +59,20 @@ void CreatureEventAI::GetAIInformation(ChatHandler& reader)
reader.PSendSysMessage(LANG_NPC_EVENTAI_PHASE, (uint32)m_Phase); reader.PSendSysMessage(LANG_NPC_EVENTAI_PHASE, (uint32)m_Phase);
reader.PSendSysMessage(LANG_NPC_EVENTAI_MOVE, reader.GetOnOffStr(m_isCombatMovement)); reader.PSendSysMessage(LANG_NPC_EVENTAI_MOVE, reader.GetOnOffStr(m_isCombatMovement));
reader.PSendSysMessage(LANG_NPC_EVENTAI_COMBAT, reader.GetOnOffStr(m_MeleeEnabled)); reader.PSendSysMessage(LANG_NPC_EVENTAI_COMBAT, reader.GetOnOffStr(m_MeleeEnabled));
if (sLog.HasLogFilter(LOG_FILTER_EVENT_AI_DEV)) // Give some more details if in EventAI Dev Mode
return;
reader.PSendSysMessage("Current events of this creature:");
for (CreatureEventAIList::const_iterator itr = m_CreatureEventAIList.begin(); itr != m_CreatureEventAIList.end(); ++itr)
{
if (itr->Event.action[2].type != ACTION_T_NONE)
reader.PSendSysMessage("%u Type%3u (%s) Timer(%3us) actions[type(param1)]: %2u(%5u) -- %2u(%u) -- %2u(%5u)", itr->Event.event_id, itr->Event.event_type, itr->Enabled ? "On" : "Off", itr->Time/1000, itr->Event.action[0].type, itr->Event.action[0].raw.param1, itr->Event.action[1].type, itr->Event.action[1].raw.param1, itr->Event.action[2].type, itr->Event.action[2].raw.param1);
else if (itr->Event.action[1].type != ACTION_T_NONE)
reader.PSendSysMessage("%u Type%3u (%s) Timer(%3us) actions[type(param1)]: %2u(%5u) -- %2u(%5u)", itr->Event.event_id, itr->Event.event_type, itr->Enabled ? "On" : "Off", itr->Time/1000, itr->Event.action[0].type, itr->Event.action[0].raw.param1, itr->Event.action[1].type, itr->Event.action[1].raw.param1);
else
reader.PSendSysMessage("%u Type%3u (%s) Timer(%3us) action[type(param1)]: %2u(%5u)", itr->Event.event_id, itr->Event.event_type, itr->Enabled ? "On" : "Off", itr->Time/1000, itr->Event.action[0].type, itr->Event.action[0].raw.param1);
}
} }
// For Non Dungeon map only allow non-difficulty flags or EFLAG_DIFFICULTY_0 mode // For Non Dungeon map only allow non-difficulty flags or EFLAG_DIFFICULTY_0 mode
@ -68,7 +82,12 @@ inline bool IsEventFlagsFitForNormalMap(uint8 eFlags)
(eFlags & EFLAG_DIFFICULTY_0); (eFlags & EFLAG_DIFFICULTY_0);
} }
CreatureEventAI::CreatureEventAI(Creature* c) : CreatureAI(c) CreatureEventAI::CreatureEventAI(Creature* c) : CreatureAI(c),
m_Phase(0),
m_MeleeEnabled(true),
m_InvinceabilityHpLevel(0),
m_throwAIEventMask(0),
m_throwAIEventStep(0)
{ {
// Need make copy for filter unneeded steps and safe in case table reload // Need make copy for filter unneeded steps and safe in case table reload
CreatureEventAI_Event_Map::const_iterator creatureEventsItr = sEventAIMgr.GetCreatureEventAIMap().find(m_creature->GetEntry()); CreatureEventAI_Event_Map::const_iterator creatureEventsItr = sEventAIMgr.GetCreatureEventAIMap().find(m_creature->GetEntry());
@ -94,7 +113,7 @@ CreatureEventAI::CreatureEventAI(Creature* c) : CreatureAI(c)
} }
// EventMap had events but they were not added because they must be for instance // EventMap had events but they were not added because they must be for instance
if (events_count == 0) if (events_count == 0)
sLog.outError("CreatureEventAI: Creature %u has events but no events added to list because of instance flags.", m_creature->GetEntry()); sLog.outErrorEventAI("Creature %u has events but no events added to list because of instance flags.", m_creature->GetEntry());
else else
{ {
m_CreatureEventAIList.reserve(events_count); m_CreatureEventAIList.reserve(events_count);
@ -121,12 +140,6 @@ CreatureEventAI::CreatureEventAI(Creature* c) : CreatureAI(c)
else else
sLog.outErrorEventAI("EventMap for Creature %u is empty but creature is using CreatureEventAI.", m_creature->GetEntry()); sLog.outErrorEventAI("EventMap for Creature %u is empty but creature is using CreatureEventAI.", m_creature->GetEntry());
m_bEmptyList = m_CreatureEventAIList.empty();
m_Phase = 0;
m_MeleeEnabled = true;
m_InvinceabilityHpLevel = 0;
// Handle Spawned Events, also calls Reset() // Handle Spawned Events, also calls Reset()
JustRespawned(); JustRespawned();
} }
@ -476,6 +489,7 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
DEBUG_FILTER_LOG(LOG_FILTER_EVENT_AI_DEV, "CreatureEventAI: Process action %u (script %u) triggered for %s (invoked by %s)", DEBUG_FILTER_LOG(LOG_FILTER_EVENT_AI_DEV, "CreatureEventAI: Process action %u (script %u) triggered for %s (invoked by %s)",
action.type, EventId, m_creature->GetGuidStr().c_str(), pActionInvoker ? pActionInvoker->GetGuidStr().c_str() : "<no invoker>"); action.type, EventId, m_creature->GetGuidStr().c_str(), pActionInvoker ? pActionInvoker->GetGuidStr().c_str() : "<no invoker>");
bool reportTargetError = false;
switch (action.type) switch (action.type)
{ {
case ACTION_T_TEXT: case ACTION_T_TEXT:
@ -484,27 +498,27 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
if (!action.text.TextId[0]) if (!action.text.TextId[0])
return; return;
int32 temp = 0; int32 textId = 0;
if (action.type == ACTION_T_TEXT) if (action.type == ACTION_T_TEXT)
{ {
if (action.text.TextId[1] && action.text.TextId[2]) if (action.text.TextId[1] && action.text.TextId[2])
temp = action.text.TextId[urand(0, 2)]; textId = action.text.TextId[urand(0, 2)];
else if (action.text.TextId[1] && urand(0, 1)) else if (action.text.TextId[1] && urand(0, 1))
temp = action.text.TextId[1]; textId = action.text.TextId[1];
else else
temp = action.text.TextId[0]; textId = action.text.TextId[0];
} }
// ACTION_T_CHANCED_TEXT, chance hits // ACTION_T_CHANCED_TEXT, chance hits
else if (urand(0, 99) < action.chanced_text.chance) else if (urand(0, 99) < action.chanced_text.chance)
{ {
if (action.chanced_text.TextId[0] && action.chanced_text.TextId[1]) if (action.chanced_text.TextId[0] && action.chanced_text.TextId[1])
temp = action.chanced_text.TextId[urand(0, 1)]; textId = action.chanced_text.TextId[urand(0, 1)];
else else
temp = action.chanced_text.TextId[0]; textId = action.chanced_text.TextId[0];
} }
if (temp) if (textId)
{ {
Unit* target = NULL; Unit* target = NULL;
@ -526,7 +540,8 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
target = owner; target = owner;
} }
DoScriptText(temp, m_creature, target); if (!DoDisplayText(m_creature, textId, target))
sLog.outErrorEventAI("Error attempting to display text %i, used by script %u", textId, EventId);
} }
break; break;
} }
@ -590,9 +605,10 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
selectFlags = SELECT_FLAG_IN_LOS; selectFlags = SELECT_FLAG_IN_LOS;
} }
Unit* target = GetTargetByType(action.cast.target, pActionInvoker, pAIEventSender, spellId, selectFlags); Unit* target = GetTargetByType(action.cast.target, pActionInvoker, pAIEventSender, reportTargetError, spellId, selectFlags);
if (!target) if (!target)
{ {
if (reportTargetError)
sLog.outErrorEventAI("NULL target for ACTION_T_CAST creature entry %u casting spell id %u", m_creature->GetEntry(), action.cast.spellId); sLog.outErrorEventAI("NULL target for ACTION_T_CAST creature entry %u casting spell id %u", m_creature->GetEntry(), action.cast.spellId);
return; return;
} }
@ -631,7 +647,9 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
} }
case ACTION_T_SUMMON: case ACTION_T_SUMMON:
{ {
Unit* target = GetTargetByType(action.summon.target, pActionInvoker, pAIEventSender); Unit* target = GetTargetByType(action.summon.target, pActionInvoker, pAIEventSender, reportTargetError);
if (!target && reportTargetError)
sLog.outErrorEventAI("Event %u - NULL target for ACTION_T_SUMMON(%u), target-type %u", EventId, action.type, action.summon.target);
Creature* pCreature = NULL; Creature* pCreature = NULL;
@ -647,8 +665,10 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
break; break;
} }
case ACTION_T_THREAT_SINGLE_PCT: case ACTION_T_THREAT_SINGLE_PCT:
if (Unit* target = GetTargetByType(action.threat_single_pct.target, pActionInvoker, pAIEventSender)) if (Unit* target = GetTargetByType(action.threat_single_pct.target, pActionInvoker, pAIEventSender, reportTargetError))
m_creature->getThreatManager().modifyThreatPercent(target, action.threat_single_pct.percent); m_creature->getThreatManager().modifyThreatPercent(target, action.threat_single_pct.percent);
else if (reportTargetError)
sLog.outErrorEventAI("Event %u - NULL target for ACTION_T_THREAT_SINGLE_PCT(%u), target-type %u", EventId, action.type, action.threat_single_pct.target);
break; break;
case ACTION_T_THREAT_ALL_PCT: case ACTION_T_THREAT_ALL_PCT:
{ {
@ -659,36 +679,48 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
break; break;
} }
case ACTION_T_QUEST_EVENT: case ACTION_T_QUEST_EVENT:
if (Unit* target = GetTargetByType(action.quest_event.target, pActionInvoker, pAIEventSender)) if (Unit* target = GetTargetByType(action.quest_event.target, pActionInvoker, pAIEventSender, reportTargetError))
{
if (target->GetTypeId() == TYPEID_PLAYER) if (target->GetTypeId() == TYPEID_PLAYER)
((Player*)target)->AreaExploredOrEventHappens(action.quest_event.questId); ((Player*)target)->AreaExploredOrEventHappens(action.quest_event.questId);
}
else if (reportTargetError)
sLog.outErrorEventAI("Event %u - NULL target for ACTION_T_QUEST_EVENT(%u), target-type %u", EventId, action.type, action.quest_event.target);
break; break;
case ACTION_T_CAST_EVENT: case ACTION_T_CAST_EVENT:
if (Unit* target = GetTargetByType(action.cast_event.target, pActionInvoker, pAIEventSender, 0, SELECT_FLAG_PLAYER)) if (Unit* target = GetTargetByType(action.cast_event.target, pActionInvoker, pAIEventSender, reportTargetError, 0, SELECT_FLAG_PLAYER))
{
if (target->GetTypeId() == TYPEID_PLAYER) if (target->GetTypeId() == TYPEID_PLAYER)
((Player*)target)->CastedCreatureOrGO(action.cast_event.creatureId, m_creature->GetObjectGuid(), action.cast_event.spellId); ((Player*)target)->CastedCreatureOrGO(action.cast_event.creatureId, m_creature->GetObjectGuid(), action.cast_event.spellId);
}
else if (reportTargetError)
sLog.outErrorEventAI("Event %u - NULL target for ACTION_T_CST_EVENT(%u), target-type %u", EventId, action.type, action.cast_event.target);
break; break;
case ACTION_T_SET_UNIT_FIELD: case ACTION_T_SET_UNIT_FIELD:
{ {
Unit* target = GetTargetByType(action.set_unit_field.target, pActionInvoker, pAIEventSender); Unit* target = GetTargetByType(action.set_unit_field.target, pActionInvoker, pAIEventSender, reportTargetError);
// not allow modify important for integrity object fields // not allow modify important for integrity object fields
if (action.set_unit_field.field < OBJECT_END || action.set_unit_field.field >= UNIT_END) if (action.set_unit_field.field < OBJECT_END || action.set_unit_field.field >= UNIT_END)
return; return;
if (target) else if (reportTargetError)
target->SetUInt32Value(action.set_unit_field.field, action.set_unit_field.value); sLog.outErrorEventAI("Event %u - NULL target for ACTION_T_SET_UNIT_FIELD(%u), target-type %u", EventId, action.type, action.set_unit_field.target);
break; break;
} }
case ACTION_T_SET_UNIT_FLAG: case ACTION_T_SET_UNIT_FLAG:
if (Unit* target = GetTargetByType(action.unit_flag.target, pActionInvoker, pAIEventSender)) if (Unit* target = GetTargetByType(action.unit_flag.target, pActionInvoker, pAIEventSender, reportTargetError))
target->SetFlag(UNIT_FIELD_FLAGS, action.unit_flag.value); target->SetFlag(UNIT_FIELD_FLAGS, action.unit_flag.value);
else if (reportTargetError)
sLog.outErrorEventAI("Event %u - NULL target for ACTION_T_SET_UNIT_FLAG(%u), target-type %u", EventId, action.type, action.unit_flag.target);
break; break;
case ACTION_T_REMOVE_UNIT_FLAG: case ACTION_T_REMOVE_UNIT_FLAG:
if (Unit* target = GetTargetByType(action.unit_flag.target, pActionInvoker, pAIEventSender)) if (Unit* target = GetTargetByType(action.unit_flag.target, pActionInvoker, pAIEventSender, reportTargetError))
target->RemoveFlag(UNIT_FIELD_FLAGS, action.unit_flag.value); target->RemoveFlag(UNIT_FIELD_FLAGS, action.unit_flag.value);
break; else if (reportTargetError)
sLog.outErrorEventAI("Event %u - NULL target for ACTION_T_REMOVE_UNIT_FLAG(%u), target-type %u", EventId, action.type, action.unit_flag.target);
case ACTION_T_AUTO_ATTACK: case ACTION_T_AUTO_ATTACK:
m_MeleeEnabled = action.auto_attack.state != 0; m_MeleeEnabled = action.auto_attack.state != 0;
break; break;
@ -746,8 +778,10 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
break; break;
} }
case ACTION_T_REMOVEAURASFROMSPELL: case ACTION_T_REMOVEAURASFROMSPELL:
if (Unit* target = GetTargetByType(action.remove_aura.target, pActionInvoker, pAIEventSender)) if (Unit* target = GetTargetByType(action.remove_aura.target, pActionInvoker, pAIEventSender, reportTargetError))
target->RemoveAurasDueToSpell(action.remove_aura.spellId); target->RemoveAurasDueToSpell(action.remove_aura.spellId);
else if (reportTargetError)
sLog.outErrorEventAI("Event %u - NULL target for ACTION_T_REMOVEAURASFROMSPELL(%u), target-type %u", EventId, action.type, action.remove_aura.target);
break; break;
case ACTION_T_RANGED_MOVEMENT: case ACTION_T_RANGED_MOVEMENT:
m_attackDistance = (float)action.ranged_movement.distance; m_attackDistance = (float)action.ranged_movement.distance;
@ -775,7 +809,9 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
break; break;
case ACTION_T_SUMMON_ID: case ACTION_T_SUMMON_ID:
{ {
Unit* target = GetTargetByType(action.summon_id.target, pActionInvoker, pAIEventSender); Unit* target = GetTargetByType(action.summon_id.target, pActionInvoker, pAIEventSender, reportTargetError);
if (!target && reportTargetError)
sLog.outErrorEventAI("Event %u - NULL target for ACTION_T_SUMMON_ID(%u), target-type %u", EventId, action.type, action.summon_id.target);
CreatureEventAI_Summon_Map::const_iterator i = sEventAIMgr.GetCreatureEventAISummonMap().find(action.summon_id.spawnId); CreatureEventAI_Summon_Map::const_iterator i = sEventAIMgr.GetCreatureEventAISummonMap().find(action.summon_id.spawnId);
if (i == sEventAIMgr.GetCreatureEventAISummonMap().end()) if (i == sEventAIMgr.GetCreatureEventAISummonMap().end())
@ -804,10 +840,14 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
else else
{ {
// if not available, use pActionInvoker // if not available, use pActionInvoker
if (Unit* pTarget = GetTargetByType(action.killed_monster.target, pActionInvoker, 0, SELECT_FLAG_PLAYER)) if (Unit* pTarget = GetTargetByType(action.killed_monster.target, pActionInvoker, pAIEventSender, reportTargetError, 0, SELECT_FLAG_PLAYER))
{
if (Player* pPlayer2 = pTarget->GetCharmerOrOwnerPlayerOrPlayerItself()) if (Player* pPlayer2 = pTarget->GetCharmerOrOwnerPlayerOrPlayerItself())
pPlayer2->RewardPlayerAndGroupAtEvent(action.killed_monster.creatureId, m_creature); pPlayer2->RewardPlayerAndGroupAtEvent(action.killed_monster.creatureId, m_creature);
} }
else if (reportTargetError)
sLog.outErrorEventAI("Event %u - NULL target for ACTION_T_KILLED_MONSTER(%u), target-type %u", EventId, action.type, action.killed_monster.target);
}
break; break;
case ACTION_T_SET_INST_DATA: case ACTION_T_SET_INST_DATA:
{ {
@ -823,9 +863,10 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
} }
case ACTION_T_SET_INST_DATA64: case ACTION_T_SET_INST_DATA64:
{ {
Unit* target = GetTargetByType(action.set_inst_data64.target, pActionInvoker, pAIEventSender); Unit* target = GetTargetByType(action.set_inst_data64.target, pActionInvoker, pAIEventSender, reportTargetError);
if (!target) if (!target)
{ {
if (reportTargetError)
sLog.outErrorEventAI("Event %d attempt to set instance data64 but Target == NULL. Creature %d", EventId, m_creature->GetEntry()); sLog.outErrorEventAI("Event %d attempt to set instance data64 but Target == NULL. Creature %d", EventId, m_creature->GetEntry());
return; return;
} }
@ -911,7 +952,12 @@ void CreatureEventAI::ProcessAction(CreatureEventAI_Action const& action, uint32
} }
case ACTION_T_THROW_AI_EVENT: case ACTION_T_THROW_AI_EVENT:
{ {
SendAIEvent(AIEventType(action.throwEvent.eventType), pActionInvoker, 0, action.throwEvent.radius); SendAIEventAround(AIEventType(action.throwEvent.eventType), pActionInvoker, 0, action.throwEvent.radius);
break;
}
case ACTION_T_SET_THROW_MASK:
{
m_throwAIEventMask = action.setThrowMask.eventTypeMask;
break; break;
} }
} }
@ -921,9 +967,6 @@ void CreatureEventAI::JustRespawned() // NOTE that this is
{ {
Reset(); Reset();
if (m_bEmptyList)
return;
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
{ {
// Reset generic timer // Reset generic timer
@ -943,8 +986,7 @@ void CreatureEventAI::Reset()
m_EventUpdateTime = EVENT_UPDATE_TIME; m_EventUpdateTime = EVENT_UPDATE_TIME;
m_EventDiff = 0; m_EventDiff = 0;
if (m_bEmptyList) m_throwAIEventStep = 0;
return;
// Reset all events to enabled // Reset all events to enabled
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
@ -969,15 +1011,12 @@ void CreatureEventAI::Reset()
} }
void CreatureEventAI::JustReachedHome() void CreatureEventAI::JustReachedHome()
{
if (!m_bEmptyList)
{ {
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
{ {
if ((*i).Event.event_type == EVENT_T_REACHED_HOME) if ((*i).Event.event_type == EVENT_T_REACHED_HOME)
ProcessEvent(*i); ProcessEvent(*i);
} }
}
Reset(); Reset();
} }
@ -1015,10 +1054,10 @@ void CreatureEventAI::JustDied(Unit* killer)
m_creature->SendZoneUnderAttackMessage(pKiller); m_creature->SendZoneUnderAttackMessage(pKiller);
} }
if (m_bEmptyList) if (m_throwAIEventMask & (1 << AI_EVENT_JUST_DIED))
return; SendAIEventAround(AI_EVENT_JUST_DIED, killer, 0, AIEVENT_DEFAULT_THROW_RADIUS);
// Handle Evade events // Handle On Death events
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
{ {
if ((*i).Event.event_type == EVENT_T_DEATH) if ((*i).Event.event_type == EVENT_T_DEATH)
@ -1031,7 +1070,7 @@ void CreatureEventAI::JustDied(Unit* killer)
void CreatureEventAI::KilledUnit(Unit* victim) void CreatureEventAI::KilledUnit(Unit* victim)
{ {
if (m_bEmptyList || victim->GetTypeId() != TYPEID_PLAYER) if (victim->GetTypeId() != TYPEID_PLAYER)
return; return;
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
@ -1043,9 +1082,6 @@ void CreatureEventAI::KilledUnit(Unit* victim)
void CreatureEventAI::JustSummoned(Creature* pUnit) void CreatureEventAI::JustSummoned(Creature* pUnit)
{ {
if (m_bEmptyList || !pUnit)
return;
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
{ {
if ((*i).Event.event_type == EVENT_T_SUMMONED_UNIT) if ((*i).Event.event_type == EVENT_T_SUMMONED_UNIT)
@ -1055,9 +1091,6 @@ void CreatureEventAI::JustSummoned(Creature* pUnit)
void CreatureEventAI::SummonedCreatureJustDied(Creature* pUnit) void CreatureEventAI::SummonedCreatureJustDied(Creature* pUnit)
{ {
if (m_bEmptyList || !pUnit)
return;
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
{ {
if ((*i).Event.event_type == EVENT_T_SUMMONED_JUST_DIED) if ((*i).Event.event_type == EVENT_T_SUMMONED_JUST_DIED)
@ -1067,9 +1100,6 @@ void CreatureEventAI::SummonedCreatureJustDied(Creature* pUnit)
void CreatureEventAI::SummonedCreatureDespawn(Creature* pUnit) void CreatureEventAI::SummonedCreatureDespawn(Creature* pUnit)
{ {
if (m_bEmptyList || !pUnit)
return;
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
{ {
if ((*i).Event.event_type == EVENT_T_SUMMONED_JUST_DESPAWN) if ((*i).Event.event_type == EVENT_T_SUMMONED_JUST_DESPAWN)
@ -1079,8 +1109,7 @@ void CreatureEventAI::SummonedCreatureDespawn(Creature* pUnit)
void CreatureEventAI::ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* pInvoker, uint32 miscValue) void CreatureEventAI::ReceiveAIEvent(AIEventType eventType, Creature* pSender, Unit* pInvoker, uint32 miscValue)
{ {
if (m_bEmptyList || !pSender) MANGOS_ASSERT(pSender);
return;
for (CreatureEventAIList::iterator itr = m_CreatureEventAIList.begin(); itr != m_CreatureEventAIList.end(); ++itr) for (CreatureEventAIList::iterator itr = m_CreatureEventAIList.begin(); itr != m_CreatureEventAIList.end(); ++itr)
{ {
@ -1093,8 +1122,6 @@ void CreatureEventAI::ReceiveAIEvent(AIEventType eventType, Creature* pSender, U
void CreatureEventAI::EnterCombat(Unit* enemy) void CreatureEventAI::EnterCombat(Unit* enemy)
{ {
// Check for on combat start events // Check for on combat start events
if (!m_bEmptyList)
{
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
{ {
CreatureEventAI_Event const& event = (*i).Event; CreatureEventAI_Event const& event = (*i).Event;
@ -1116,7 +1143,6 @@ void CreatureEventAI::EnterCombat(Unit* enemy)
break; break;
} }
} }
}
m_EventUpdateTime = EVENT_UPDATE_TIME; m_EventUpdateTime = EVENT_UPDATE_TIME;
m_EventDiff = 0; m_EventDiff = 0;
@ -1143,7 +1169,7 @@ void CreatureEventAI::MoveInLineOfSight(Unit* who)
return; return;
// Check for OOC LOS Event // Check for OOC LOS Event
if (!m_bEmptyList && !m_creature->getVictim()) if (!m_creature->getVictim())
{ {
for (CreatureEventAIList::iterator itr = m_CreatureEventAIList.begin(); itr != m_CreatureEventAIList.end(); ++itr) for (CreatureEventAIList::iterator itr = m_CreatureEventAIList.begin(); itr != m_CreatureEventAIList.end(); ++itr)
{ {
@ -1192,10 +1218,6 @@ void CreatureEventAI::MoveInLineOfSight(Unit* who)
void CreatureEventAI::SpellHit(Unit* pUnit, const SpellEntry* pSpell) void CreatureEventAI::SpellHit(Unit* pUnit, const SpellEntry* pSpell)
{ {
if (m_bEmptyList)
return;
for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i) for (CreatureEventAIList::iterator i = m_CreatureEventAIList.begin(); i != m_CreatureEventAIList.end(); ++i)
if ((*i).Event.event_type == EVENT_T_SPELLHIT) if ((*i).Event.event_type == EVENT_T_SPELLHIT)
// If spell id matches (or no spell id) & if spell school matches (or no spell school) // If spell id matches (or no spell id) & if spell school matches (or no spell school)
@ -1209,8 +1231,6 @@ void CreatureEventAI::UpdateAI(const uint32 diff)
// Check if we are in combat (also updates calls threat update code) // Check if we are in combat (also updates calls threat update code)
bool Combat = m_creature->SelectHostileTarget() && m_creature->getVictim(); bool Combat = m_creature->SelectHostileTarget() && m_creature->getVictim();
if (!m_bEmptyList)
{
// Events are only updated once every EVENT_UPDATE_TIME ms to prevent lag with large amount of events // Events are only updated once every EVENT_UPDATE_TIME ms to prevent lag with large amount of events
if (m_EventUpdateTime < diff) if (m_EventUpdateTime < diff)
{ {
@ -1263,20 +1283,19 @@ void CreatureEventAI::UpdateAI(const uint32 diff)
} }
break; break;
} }
}
m_EventDiff = 0; m_EventDiff = 0;
m_EventUpdateTime = EVENT_UPDATE_TIME; m_EventUpdateTime = EVENT_UPDATE_TIME;
} }
}
else else
{ {
m_EventDiff += diff; m_EventDiff += diff;
m_EventUpdateTime -= diff; m_EventUpdateTime -= diff;
} }
}
// Melee Auto-Attack (recheck m_creature->getVictim in case of combat state was changed while processing events) // Melee Auto-Attack (recheck m_creature->getVictim in case of combat state was changed while processing events)
if (Combat && m_MeleeEnabled) if (Combat && m_MeleeEnabled && m_creature->getVictim())
DoMeleeAttackIfReady(); DoMeleeAttackIfReady();
} }
@ -1308,33 +1327,63 @@ inline int32 CreatureEventAI::GetRandActionParam(uint32 rnd, int32 param1, int32
return 0; return 0;
} }
inline Unit* CreatureEventAI::GetTargetByType(uint32 Target, Unit* pActionInvoker, Creature* pAIEventSender, uint32 forSpellId, uint32 selectFlags) inline Unit* CreatureEventAI::GetTargetByType(uint32 Target, Unit* pActionInvoker, Creature* pAIEventSender, bool& isError, uint32 forSpellId, uint32 selectFlags)
{ {
Unit* resTarget;
switch (Target) switch (Target)
{ {
case TARGET_T_SELF: case TARGET_T_SELF:
return m_creature; return m_creature;
case TARGET_T_HOSTILE: case TARGET_T_HOSTILE:
return m_creature->getVictim(); resTarget = m_creature->getVictim();
if (!resTarget)
isError = true;
return resTarget;
case TARGET_T_HOSTILE_SECOND_AGGRO: case TARGET_T_HOSTILE_SECOND_AGGRO:
return m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 1, forSpellId, selectFlags); resTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_TOPAGGRO, 1, forSpellId, selectFlags);
if (!resTarget && ((forSpellId == 0 && selectFlags == 0 && m_creature->getThreatManager().getThreatList().size() > 1) || m_creature->getThreatManager().getThreatList().empty()))
isError = true;
return resTarget;
case TARGET_T_HOSTILE_LAST_AGGRO: case TARGET_T_HOSTILE_LAST_AGGRO:
return m_creature->SelectAttackingTarget(ATTACKING_TARGET_BOTTOMAGGRO, 0, forSpellId, selectFlags); resTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_BOTTOMAGGRO, 0, forSpellId, selectFlags);
if (!resTarget && m_creature->getThreatManager().getThreatList().empty())
isError = true;
return resTarget;
case TARGET_T_HOSTILE_RANDOM: case TARGET_T_HOSTILE_RANDOM:
return m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, forSpellId, selectFlags); resTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, forSpellId, selectFlags);
if (!resTarget && m_creature->getThreatManager().getThreatList().empty())
isError = true;
return resTarget;
case TARGET_T_HOSTILE_RANDOM_NOT_TOP: case TARGET_T_HOSTILE_RANDOM_NOT_TOP:
return m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, forSpellId, selectFlags); resTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, forSpellId, selectFlags);
if (!resTarget && ((forSpellId == 0 && selectFlags == 0 && m_creature->getThreatManager().getThreatList().size() > 1) || m_creature->getThreatManager().getThreatList().empty()))
isError = true;
return resTarget;
case TARGET_T_HOSTILE_RANDOM_PLAYER: case TARGET_T_HOSTILE_RANDOM_PLAYER:
return m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, forSpellId, SELECT_FLAG_PLAYER | selectFlags); resTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 0, forSpellId, SELECT_FLAG_PLAYER | selectFlags);
if (!resTarget)
isError = true;
return resTarget;
case TARGET_T_HOSTILE_RANDOM_NOT_TOP_PLAYER: case TARGET_T_HOSTILE_RANDOM_NOT_TOP_PLAYER:
return m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, forSpellId, SELECT_FLAG_PLAYER | selectFlags); resTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM, 1, forSpellId, SELECT_FLAG_PLAYER | selectFlags);
if (!resTarget && ((forSpellId == 0 && selectFlags == 0 && m_creature->getThreatManager().getThreatList().size() > 1) || m_creature->getThreatManager().getThreatList().empty()))
isError = true;
return resTarget;
case TARGET_T_ACTION_INVOKER: case TARGET_T_ACTION_INVOKER:
if (!pActionInvoker)
isError = true;
return pActionInvoker; return pActionInvoker;
case TARGET_T_ACTION_INVOKER_OWNER: case TARGET_T_ACTION_INVOKER_OWNER:
return pActionInvoker ? pActionInvoker->GetCharmerOrOwnerOrSelf() : NULL; resTarget = pActionInvoker ? pActionInvoker->GetCharmerOrOwnerOrSelf() : NULL;
if (!resTarget)
isError = true;
return resTarget;
case TARGET_T_EVENT_SENDER: case TARGET_T_EVENT_SENDER:
if (!pAIEventSender)
isError = true;
return pAIEventSender; return pAIEventSender;
default: default:
isError = true;
return NULL; return NULL;
}; };
} }
@ -1371,85 +1420,8 @@ void CreatureEventAI::DoFindFriendlyMissingBuff(std::list<Creature*>& _list, flo
//********************************* //*********************************
//*** Functions used globally *** //*** Functions used globally ***
void CreatureEventAI::DoScriptText(int32 textEntry, WorldObject* pSource, Unit* target)
{
if (!pSource)
{
sLog.outErrorEventAI("DoScriptText entry %i, invalid Source pointer.", textEntry);
return;
}
if (textEntry >= 0)
{
sLog.outErrorEventAI("DoScriptText with source entry %u (TypeId=%u, guid=%u) attempts to process text entry %i, but text entry must be negative.", pSource->GetEntry(), pSource->GetTypeId(), pSource->GetGUIDLow(), textEntry);
return;
}
CreatureEventAI_TextMap::const_iterator i = sEventAIMgr.GetCreatureEventAITextMap().find(textEntry);
if (i == sEventAIMgr.GetCreatureEventAITextMap().end())
{
sLog.outErrorEventAI("DoScriptText with source entry %u (TypeId=%u, guid=%u) could not find text entry %i.", pSource->GetEntry(), pSource->GetTypeId(), pSource->GetGUIDLow(), textEntry);
return;
}
DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "CreatureEventAI: DoScriptText: text entry=%i, Sound=%u, Type=%u, Language=%u, Emote=%u", textEntry, (*i).second.SoundId, (*i).second.Type, (*i).second.Language, (*i).second.Emote);
if ((*i).second.SoundId)
{
if (GetSoundEntriesStore()->LookupEntry((*i).second.SoundId))
pSource->PlayDirectSound((*i).second.SoundId);
else
sLog.outErrorEventAI("DoScriptText entry %i tried to process invalid sound id %u.", textEntry, (*i).second.SoundId);
}
if ((*i).second.Emote)
{
if (pSource->GetTypeId() == TYPEID_UNIT || pSource->GetTypeId() == TYPEID_PLAYER)
{
((Unit*)pSource)->HandleEmote((*i).second.Emote);
}
else
sLog.outErrorEventAI("DoScriptText entry %i tried to process emote for invalid TypeId (%u).", textEntry, pSource->GetTypeId());
}
switch ((*i).second.Type)
{
case CHAT_TYPE_SAY:
pSource->MonsterSay(textEntry, (*i).second.Language, target);
break;
case CHAT_TYPE_YELL:
pSource->MonsterYell(textEntry, (*i).second.Language, target);
break;
case CHAT_TYPE_TEXT_EMOTE:
pSource->MonsterTextEmote(textEntry, target);
break;
case CHAT_TYPE_BOSS_EMOTE:
pSource->MonsterTextEmote(textEntry, target, true);
break;
case CHAT_TYPE_WHISPER:
{
if (target && target->GetTypeId() == TYPEID_PLAYER)
pSource->MonsterWhisper(textEntry, target);
else sLog.outErrorEventAI("DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", textEntry);
} break;
case CHAT_TYPE_BOSS_WHISPER:
{
if (target && target->GetTypeId() == TYPEID_PLAYER)
pSource->MonsterWhisper(textEntry, target, true);
else sLog.outErrorEventAI("DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", textEntry);
} break;
case CHAT_TYPE_ZONE_YELL:
pSource->MonsterYellToZone(textEntry, (*i).second.Language, target);
break;
}
}
void CreatureEventAI::ReceiveEmote(Player* pPlayer, uint32 text_emote) void CreatureEventAI::ReceiveEmote(Player* pPlayer, uint32 text_emote)
{ {
if (m_bEmptyList)
return;
for (CreatureEventAIList::iterator itr = m_CreatureEventAIList.begin(); itr != m_CreatureEventAIList.end(); ++itr) for (CreatureEventAIList::iterator itr = m_CreatureEventAIList.begin(); itr != m_CreatureEventAIList.end(); ++itr)
{ {
if ((*itr).Event.event_type == EVENT_T_RECEIVE_EMOTE) if ((*itr).Event.event_type == EVENT_T_RECEIVE_EMOTE)
@ -1467,7 +1439,9 @@ void CreatureEventAI::ReceiveEmote(Player* pPlayer, uint32 text_emote)
} }
} }
void CreatureEventAI::DamageTaken(Unit* /*done_by*/, uint32& damage) #define HEALTH_STEPS 3
void CreatureEventAI::DamageTaken(Unit* dealer, uint32& damage)
{ {
if (m_InvinceabilityHpLevel > 0 && m_creature->GetHealth() < m_InvinceabilityHpLevel + damage) if (m_InvinceabilityHpLevel > 0 && m_creature->GetHealth() < m_InvinceabilityHpLevel + damage)
{ {
@ -1476,6 +1450,46 @@ void CreatureEventAI::DamageTaken(Unit* /*done_by*/, uint32& damage)
else else
damage = m_creature->GetHealth() - m_InvinceabilityHpLevel; damage = m_creature->GetHealth() - m_InvinceabilityHpLevel;
} }
uint32 step = m_throwAIEventStep != 100 ? m_throwAIEventStep : 0;
if (step < HEALTH_STEPS)
{
// Throw at 90%, 50% and 10% health
float healthSteps[HEALTH_STEPS] = { 90.0f, 50.0f, 10.0f };
float newHealthPercent = (m_creature->GetHealth() - damage) * 100.0f / m_creature->GetMaxHealth();
AIEventType sendEvent[HEALTH_STEPS] = { AI_EVENT_LOST_SOME_HEALTH, AI_EVENT_LOST_HEALTH, AI_EVENT_CRITICAL_HEALTH };
if (newHealthPercent > healthSteps[step])
return; // Not reached the next mark
// search for highest reached mark (with actual event attached)
for (uint32 i = HEALTH_STEPS - 1; i > step; --i)
{
if (newHealthPercent < healthSteps[i] && (m_throwAIEventMask & (1 << sendEvent[i])))
{
step = i;
break;
}
}
if (m_throwAIEventMask & (1 << sendEvent[step]))
SendAIEventAround(sendEvent[step], dealer, 0, AIEVENT_DEFAULT_THROW_RADIUS);
m_throwAIEventStep = step + 1;
}
}
void CreatureEventAI::HealedBy(Unit* healer, uint32& healedAmount)
{
if (m_throwAIEventStep == 100)
return;
if (m_creature->GetHealth() + healedAmount >= m_creature->GetMaxHealth())
{
if (m_throwAIEventMask & (1 << AI_EVENT_GOT_FULL_HEALTH))
SendAIEventAround(AI_EVENT_GOT_FULL_HEALTH, healer, 0, AIEVENT_DEFAULT_THROW_RADIUS);
m_throwAIEventStep = 100;
}
} }
bool CreatureEventAI::SpawnedEventConditionsCheck(CreatureEventAI_Event const& event) bool CreatureEventAI::SpawnedEventConditionsCheck(CreatureEventAI_Event const& event)

View file

@ -116,6 +116,7 @@ enum EventAI_ActionType
ACTION_T_MOUNT_TO_ENTRY_OR_MODEL = 43, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to unmount) ACTION_T_MOUNT_TO_ENTRY_OR_MODEL = 43, // Creature_template entry(param1) OR ModelId (param2) (or 0 for both to unmount)
ACTION_T_CHANCED_TEXT = 44, // Chance to display the text, TextId1, optionally TextId2. If more than just -TextId1 is defined, randomize. Negative values. ACTION_T_CHANCED_TEXT = 44, // Chance to display the text, TextId1, optionally TextId2. If more than just -TextId1 is defined, randomize. Negative values.
ACTION_T_THROW_AI_EVENT = 45, // EventType, Radius, unused ACTION_T_THROW_AI_EVENT = 45, // EventType, Radius, unused
ACTION_T_SET_THROW_MASK = 46, // EventTypeMask, unused, unused
ACTION_T_END, ACTION_T_END,
}; };
@ -132,15 +133,13 @@ enum Target
TARGET_T_HOSTILE_RANDOM_NOT_TOP = 5, // Any random target except top threat TARGET_T_HOSTILE_RANDOM_NOT_TOP = 5, // Any random target except top threat
// Invoker targets (if pet then returns pet owner) // Invoker targets (if pet then returns pet owner)
TARGET_T_ACTION_INVOKER = 6, // Unit who caused this Event to occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF) TARGET_T_ACTION_INVOKER = 6, // Unit who caused this Event to occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF, EVENT_T_RECEIVE_EMOTE, EVENT_T_RECEIVE_AI_EVENT)
TARGET_T_ACTION_INVOKER_OWNER = 7, // Unit who is responsible for Event to occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF) TARGET_T_ACTION_INVOKER_OWNER = 7, // Unit who is responsible for Event to occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF, EVENT_T_RECEIVE_EMOTE, EVENT_T_RECEIVE_AI_EVENT)
TARGET_T_EVENT_SENDER = 10, // Unit who sent an AIEvent that was received with EVENT_T_RECEIVE_AI_EVENT TARGET_T_EVENT_SENDER = 10, // Unit who sent an AIEvent that was received with EVENT_T_RECEIVE_AI_EVENT
// Hostile targets (including pets) // Hostile targets (including pets)
TARGET_T_HOSTILE_RANDOM_PLAYER = 8, // Just any random player on our threat list TARGET_T_HOSTILE_RANDOM_PLAYER = 8, // Just any random player on our threat list
TARGET_T_HOSTILE_RANDOM_NOT_TOP_PLAYER = 9, // Any random player from threat list except top threat TARGET_T_HOSTILE_RANDOM_NOT_TOP_PLAYER = 9 // Any random player from threat list except top threat
TARGET_T_END
}; };
enum EventFlags enum EventFlags
@ -164,17 +163,6 @@ enum SpawnedEventMode
SPAWNED_EVENT_ZONE = 2 SPAWNED_EVENT_ZONE = 2
}; };
// String text additional data, used in (CreatureEventAI)
struct StringTextData
{
uint32 SoundId;
uint8 Type;
uint32 Language;
uint32 Emote;
};
// Text Maps
typedef UNORDERED_MAP<int32, StringTextData> CreatureEventAI_TextMap;
struct CreatureEventAI_Action struct CreatureEventAI_Action
{ {
EventAI_ActionType type: 16; EventAI_ActionType type: 16;
@ -402,6 +390,13 @@ struct CreatureEventAI_Action
uint32 radius; uint32 radius;
uint32 unused; uint32 unused;
} throwEvent; } throwEvent;
// ACTION_T_SET_THROW_MASK = 46
struct
{
uint32 eventTypeMask;
uint32 unused1;
uint32 unused2;
} setThrowMask;
// RAW // RAW
struct struct
{ {
@ -412,6 +407,8 @@ struct CreatureEventAI_Action
}; };
}; };
#define AIEVENT_DEFAULT_THROW_RADIUS 30.0f
struct CreatureEventAI_Event struct CreatureEventAI_Event
{ {
uint32 event_id; uint32 event_id;
@ -620,6 +617,7 @@ class MANGOS_DLL_SPEC CreatureEventAI : public CreatureAI
void MoveInLineOfSight(Unit* who) override; void MoveInLineOfSight(Unit* who) override;
void SpellHit(Unit* pUnit, const SpellEntry* pSpell) override; void SpellHit(Unit* pUnit, const SpellEntry* pSpell) override;
void DamageTaken(Unit* done_by, uint32& damage) override; void DamageTaken(Unit* done_by, uint32& damage) override;
void HealedBy(Unit* healer, uint32& healedAmount) override;
void UpdateAI(const uint32 diff) override; void UpdateAI(const uint32 diff) override;
bool IsVisible(Unit*) const override; bool IsVisible(Unit*) const override;
void ReceiveEmote(Player* pPlayer, uint32 text_emote) override; void ReceiveEmote(Player* pPlayer, uint32 text_emote) override;
@ -633,9 +631,8 @@ class MANGOS_DLL_SPEC CreatureEventAI : public CreatureAI
void ProcessAction(CreatureEventAI_Action const& action, uint32 rnd, uint32 EventId, Unit* pActionInvoker, Creature* pAIEventSender); void ProcessAction(CreatureEventAI_Action const& action, uint32 rnd, uint32 EventId, Unit* pActionInvoker, Creature* pAIEventSender);
inline uint32 GetRandActionParam(uint32 rnd, uint32 param1, uint32 param2, uint32 param3); inline uint32 GetRandActionParam(uint32 rnd, uint32 param1, uint32 param2, uint32 param3);
inline int32 GetRandActionParam(uint32 rnd, int32 param1, int32 param2, int32 param3); inline int32 GetRandActionParam(uint32 rnd, int32 param1, int32 param2, int32 param3);
inline Unit* GetTargetByType(uint32 Target, Unit* pActionInvoker, Creature* pAIEventSender, uint32 forSpellId = 0, uint32 selectFlags = 0); /// If the bool& param is true, an error should be reported
inline Unit* GetTargetByType(uint32 Target, Unit* pActionInvoker, Creature* pAIEventSender, bool& isError, uint32 forSpellId = 0, uint32 selectFlags = 0);
void DoScriptText(int32 textEntry, WorldObject* pSource, Unit* target);
bool SpawnedEventConditionsCheck(CreatureEventAI_Event const& event); bool SpawnedEventConditionsCheck(CreatureEventAI_Event const& event);
@ -655,6 +652,11 @@ class MANGOS_DLL_SPEC CreatureEventAI : public CreatureAI
uint8 m_Phase; // Current phase, max 32 phases uint8 m_Phase; // Current phase, max 32 phases
bool m_MeleeEnabled; // If we allow melee auto attack bool m_MeleeEnabled; // If we allow melee auto attack
uint32 m_InvinceabilityHpLevel; // Minimal health level allowed at damage apply uint32 m_InvinceabilityHpLevel; // Minimal health level allowed at damage apply
uint32 m_throwAIEventMask; // Automatically throw AIEvents that are encoded into this mask
// Note that Step 100 means that AI_EVENT_GOT_FULL_HEALTH was sent
// Steps 0..2 correspond to AI_EVENT_LOST_SOME_HEALTH(90%), AI_EVENT_LOST_HEALTH(50%), AI_EVENT_CRITICAL_HEALTH(10%)
uint32 m_throwAIEventStep; // Used for damage taken/ received heal
}; };
#endif #endif

View file

@ -34,93 +34,24 @@ INSTANTIATE_SINGLETON_1(CreatureEventAIMgr);
// ------------------- // -------------------
void CreatureEventAIMgr::LoadCreatureEventAI_Texts(bool check_entry_use) void CreatureEventAIMgr::LoadCreatureEventAI_Texts(bool check_entry_use)
{ {
// Drop Existing Text Map, only done once and we are ready to add data from multiple sources.
m_CreatureEventAI_TextMap.clear();
// Load EventAI Text // Load EventAI Text
sObjectMgr.LoadMangosStrings(WorldDatabase, "creature_ai_texts", MIN_CREATURE_AI_TEXT_STRING_ID, MAX_CREATURE_AI_TEXT_STRING_ID); sObjectMgr.LoadMangosStrings(WorldDatabase, "creature_ai_texts", MIN_CREATURE_AI_TEXT_STRING_ID, MAX_CREATURE_AI_TEXT_STRING_ID, true);
// Gather Additional data from EventAI Texts
QueryResult* result = WorldDatabase.Query("SELECT entry, sound, type, language, emote FROM creature_ai_texts");
sLog.outString("Loading EventAI Texts additional data...");
if (result)
{
BarGoLink bar(result->GetRowCount());
uint32 count = 0;
do
{
bar.step();
Field* fields = result->Fetch();
StringTextData temp;
int32 i = fields[0].GetInt32();
temp.SoundId = fields[1].GetInt32();
temp.Type = fields[2].GetInt32();
temp.Language = fields[3].GetInt32();
temp.Emote = fields[4].GetInt32();
// range negative
if (i > MIN_CREATURE_AI_TEXT_STRING_ID || i <= MAX_CREATURE_AI_TEXT_STRING_ID)
{
sLog.outErrorEventAI("CreatureEventAI: Entry %i in table `creature_ai_texts` is not in valid range(%d-%d)", i, MIN_CREATURE_AI_TEXT_STRING_ID, MAX_CREATURE_AI_TEXT_STRING_ID);
continue;
}
// range negative (don't must be happen, loaded from same table)
if (!sObjectMgr.GetMangosStringLocale(i))
{
sLog.outErrorEventAI("Entry %i in table `creature_ai_texts` not found", i);
continue;
}
if (temp.SoundId)
{
if (!sSoundEntriesStore.LookupEntry(temp.SoundId))
sLog.outErrorEventAI("Entry %i in table `creature_ai_texts` has Sound %u but sound does not exist.", i, temp.SoundId);
}
if (!GetLanguageDescByID(temp.Language))
sLog.outErrorEventAI("Entry %i in table `creature_ai_texts` using Language %u but Language does not exist.", i, temp.Language);
if (temp.Type > CHAT_TYPE_ZONE_YELL)
sLog.outErrorEventAI("Entry %i in table `creature_ai_texts` has Type %u but this Chat Type does not exist.", i, temp.Type);
if (temp.Emote)
{
if (!sEmotesStore.LookupEntry(temp.Emote))
sLog.outErrorEventAI("Entry %i in table `creature_ai_texts` has Emote %u but emote does not exist.", i, temp.Emote);
}
m_CreatureEventAI_TextMap[i] = temp;
++count;
}
while (result->NextRow());
delete result;
if (check_entry_use) if (check_entry_use)
CheckUnusedAITexts(); CheckUnusedAITexts();
sLog.outString();
sLog.outString(">> Loaded %u additional CreatureEventAI Texts data.", count);
}
else
{
BarGoLink bar(1);
bar.step();
sLog.outString();
sLog.outString(">> Loaded 0 additional CreatureEventAI Texts data. DB table `creature_ai_texts` is empty.");
}
} }
void CreatureEventAIMgr::CheckUnusedAITexts() void CreatureEventAIMgr::CheckUnusedAITexts()
{ {
if (m_usedTextsAmount == sObjectMgr.GetLoadedStringsCount(MIN_CREATURE_AI_TEXT_STRING_ID))
return;
sLog.outString("Checking EventAI for unused texts, this might take a while");
std::set<int32> idx_set; std::set<int32> idx_set;
// check not used strings this is negative range // check not used strings this is negative range
for (CreatureEventAI_TextMap::const_iterator itr = m_CreatureEventAI_TextMap.begin(); itr != m_CreatureEventAI_TextMap.end(); ++itr) for (int32 i = MAX_CREATURE_AI_TEXT_STRING_ID + 1; i <= MIN_CREATURE_AI_TEXT_STRING_ID; ++i)
idx_set.insert(itr->first); if (sObjectMgr.GetMangosStringLocale(i))
idx_set.insert(i);
for (CreatureEventAI_Event_Map::const_iterator itr = m_CreatureEventAI_Event_Map.begin(); itr != m_CreatureEventAI_Event_Map.end(); ++itr) for (CreatureEventAI_Event_Map::const_iterator itr = m_CreatureEventAI_Event_Map.begin(); itr != m_CreatureEventAI_Event_Map.end(); ++itr)
{ {
@ -153,6 +84,73 @@ void CreatureEventAIMgr::CheckUnusedAITexts()
sLog.outErrorEventAI("Entry %i in table `creature_ai_texts` but not used in EventAI scripts.", *itr); sLog.outErrorEventAI("Entry %i in table `creature_ai_texts` but not used in EventAI scripts.", *itr);
} }
/// Helper function to check if a target-suite is suitable for the event-type
bool IsValidTargetType(EventAI_Type eventType, EventAI_ActionType actionType, uint32 targetType, uint32 eventId, uint8 action)
{
switch (targetType)
{
case TARGET_T_SELF:
if (actionType == ACTION_T_QUEST_EVENT || actionType == ACTION_T_CAST_EVENT || actionType == ACTION_T_QUEST_EVENT_ALL || actionType == ACTION_T_KILLED_MONSTER)
{
sLog.outErrorEventAI("Event %u Action%u uses incorrect Target type %u for event-type %u (must target player)", eventId, action, targetType, eventType);
return false;
}
return true; // Can always be used
case TARGET_T_HOSTILE_RANDOM:
case TARGET_T_HOSTILE_RANDOM_NOT_TOP:
if (actionType == ACTION_T_QUEST_EVENT || actionType == ACTION_T_CAST_EVENT || actionType == ACTION_T_QUEST_EVENT_ALL || actionType == ACTION_T_KILLED_MONSTER)
sLog.outErrorEventAI("Event %u Action%u uses LIKELY bad Target type %u for event-type %u (must target player)", eventId, action, targetType, eventType);
// no break, check if valid at all
case TARGET_T_HOSTILE:
case TARGET_T_HOSTILE_SECOND_AGGRO:
case TARGET_T_HOSTILE_LAST_AGGRO:
case TARGET_T_HOSTILE_RANDOM_PLAYER:
case TARGET_T_HOSTILE_RANDOM_NOT_TOP_PLAYER:
switch (eventType)
{
case EVENT_T_TIMER_OOC:
case EVENT_T_OOC_LOS:
case EVENT_T_REACHED_HOME:
sLog.outErrorEventAI("Event %u Action%u uses incorrect Target type %u for event-type %u (cannot be used OOC)", eventId, action, targetType, eventType);
return false;
case EVENT_T_TIMER_GENERIC:
sLog.outErrorEventAI("Event %u Action%u uses LIKELY incorrect Target type %u for event-type %u (cannot be used OOC)", eventId, action, targetType, eventType);
return true; // Does not need to be an error
default:
return true;
}
case TARGET_T_ACTION_INVOKER: // Unit who caused this Event to occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF, EVENT_T_RECEIVE_EMOTE, EVENT_T_RECEIVE_AI_EVENT)
case TARGET_T_ACTION_INVOKER_OWNER: // Unit who is responsible for Event to occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF, EVENT_T_RECEIVE_EMOTE, EVENT_T_RECEIVE_AI_EVENT)
switch (eventType)
{
case EVENT_T_AGGRO:
case EVENT_T_KILL:
case EVENT_T_DEATH:
case EVENT_T_SPELLHIT:
case EVENT_T_OOC_LOS:
case EVENT_T_FRIENDLY_HP:
case EVENT_T_FRIENDLY_IS_CC:
case EVENT_T_FRIENDLY_MISSING_BUFF:
case EVENT_T_RECEIVE_EMOTE:
case EVENT_T_RECEIVE_AI_EVENT:
return true;
default:
sLog.outErrorEventAI("Event %u Action%u uses incorrect Target type %u for event-type %u", eventId, action, targetType, eventType);
return false;
}
case TARGET_T_EVENT_SENDER: // Unit who sent an AIEvent that was received with EVENT_T_RECEIVE_AI_EVENT
if (eventType != EVENT_T_RECEIVE_AI_EVENT)
{
sLog.outErrorEventAI("Event %u Action%u uses incorrect Target type %u for event-type %u", eventId, action, targetType, eventType);
return false;
}
return true;
default:
sLog.outErrorEventAI("Event %u Action%u uses incorrect Target type", eventId, action);
return false;
}
}
// ------------------- // -------------------
void CreatureEventAIMgr::LoadCreatureEventAI_Summons(bool check_entry_use) void CreatureEventAIMgr::LoadCreatureEventAI_Summons(bool check_entry_use)
{ {
@ -248,6 +246,7 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
{ {
// Drop Existing EventAI List // Drop Existing EventAI List
m_CreatureEventAI_Event_Map.clear(); m_CreatureEventAI_Event_Map.clear();
std::set<int32> usedTextIds;
// Gather event data // Gather event data
QueryResult* result = WorldDatabase.Query("SELECT id, creature_id, event_type, event_inverse_phase_mask, event_chance, event_flags, " QueryResult* result = WorldDatabase.Query("SELECT id, creature_id, event_type, event_inverse_phase_mask, event_chance, event_flags, "
@ -492,13 +491,13 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
// Sender-Creature does not exist in database // Sender-Creature does not exist in database
if (temp.receiveAIEvent.senderEntry && !sCreatureStorage.LookupEntry<CreatureInfo>(temp.receiveAIEvent.senderEntry)) if (temp.receiveAIEvent.senderEntry && !sCreatureStorage.LookupEntry<CreatureInfo>(temp.receiveAIEvent.senderEntry))
{ {
sLog.outErrorDb("CreatureEventAI: Event %u has nonexisting creature (%u) defined for event RECEIVE_AI_EVENT, skipping.", i, temp.receiveAIEvent.senderEntry); sLog.outErrorEventAI("Event %u has nonexisting creature (%u) defined for event RECEIVE_AI_EVENT, skipping.", i, temp.receiveAIEvent.senderEntry);
continue; continue;
} }
// Event-Type is not defined // Event-Type is not defined
if (temp.receiveAIEvent.eventType >= MAXIMAL_AI_EVENT_EVENTAI) if (temp.receiveAIEvent.eventType >= MAXIMAL_AI_EVENT_EVENTAI)
{ {
sLog.outErrorDb("CreatureEventAI: Event %u has unfitting event-type (%u) defined for event RECEIVE_AI_EVENT (must be less than %u), skipping.", i, temp.receiveAIEvent.eventType, MAXIMAL_AI_EVENT_EVENTAI); sLog.outErrorEventAI("Event %u has unfitting event-type (%u) defined for event RECEIVE_AI_EVENT (must be less than %u), skipping.", i, temp.receiveAIEvent.eventType, MAXIMAL_AI_EVENT_EVENTAI);
continue; continue;
} }
break; break;
@ -556,11 +555,13 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
sLog.outErrorEventAI("Event %u Action %u param%d references out-of-range entry (%i) in texts table.", i, j + 1, k + 1, action.text.TextId[k]); sLog.outErrorEventAI("Event %u Action %u param%d references out-of-range entry (%i) in texts table.", i, j + 1, k + 1, action.text.TextId[k]);
action.text.TextId[k] = 0; action.text.TextId[k] = 0;
} }
else if (m_CreatureEventAI_TextMap.find(action.text.TextId[k]) == m_CreatureEventAI_TextMap.end()) else if (!sObjectMgr.GetMangosStringLocale(action.text.TextId[k]))
{ {
sLog.outErrorEventAI("Event %u Action %u param%d references non-existing entry (%i) in texts table.", i, j + 1, k + 1, action.text.TextId[k]); sLog.outErrorEventAI("Event %u Action %u param%d references non-existing entry (%i) in texts table.", i, j + 1, k + 1, action.text.TextId[k]);
action.text.TextId[k] = 0; action.text.TextId[k] = 0;
} }
else
usedTextIds.insert(action.text.TextId[k]);
} }
} }
break; break;
@ -641,12 +642,17 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
if (action.cast.castFlags & CAST_FORCE_TARGET_SELF) if (action.cast.castFlags & CAST_FORCE_TARGET_SELF)
action.cast.castFlags |= CAST_TRIGGERED; action.cast.castFlags |= CAST_TRIGGERED;
if (action.cast.target >= TARGET_T_END) IsValidTargetType(temp.event_type, action.type, action.cast.target, i, j + 1);
sLog.outErrorEventAI("Event %u Action %u uses incorrect Target type", i, j + 1);
// Some Advanced target type checks - Can have false positives // Some Advanced target type checks - Can have false positives
if (!sLog.HasLogFilter(LOG_FILTER_EVENT_AI_DEV) && spell) if (!sLog.HasLogFilter(LOG_FILTER_EVENT_AI_DEV) && spell)
{ {
// spell must be cast on self, but is not
if ((IsOnlySelfTargeting(spell) || spell->rangeIndex == SPELL_RANGE_IDX_SELF_ONLY) && action.cast.target != TARGET_T_SELF && !(action.cast.castFlags & CAST_FORCE_TARGET_SELF))
sLog.outErrorEventAI("Event %u Action %u uses SpellID %u that must be self cast (target is %u)", i, j + 1, action.cast.spellId, action.cast.target);
// TODO: spell must be cast on enemy, but is not
// used TARGET_T_ACTION_INVOKER, but likely should be _INVOKER_OWNER instead // used TARGET_T_ACTION_INVOKER, but likely should be _INVOKER_OWNER instead
if (action.cast.target == TARGET_T_ACTION_INVOKER && if (action.cast.target == TARGET_T_ACTION_INVOKER &&
(IsSpellHaveEffect(spell, SPELL_EFFECT_QUEST_COMPLETE) || IsSpellHaveEffect(spell, SPELL_EFFECT_CREATE_RANDOM_ITEM) || IsSpellHaveEffect(spell, SPELL_EFFECT_DUMMY) (IsSpellHaveEffect(spell, SPELL_EFFECT_QUEST_COMPLETE) || IsSpellHaveEffect(spell, SPELL_EFFECT_CREATE_RANDOM_ITEM) || IsSpellHaveEffect(spell, SPELL_EFFECT_DUMMY)
@ -664,14 +670,12 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.summon.creatureId)) if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.summon.creatureId))
sLog.outErrorEventAI("Event %u Action %u uses nonexistent creature entry %u.", i, j + 1, action.summon.creatureId); sLog.outErrorEventAI("Event %u Action %u uses nonexistent creature entry %u.", i, j + 1, action.summon.creatureId);
if (action.summon.target >= TARGET_T_END) IsValidTargetType(temp.event_type, action.type, action.summon.target, i, j + 1);
sLog.outErrorEventAI("Event %u Action %u uses incorrect Target type", i, j + 1);
break; break;
case ACTION_T_THREAT_SINGLE_PCT: case ACTION_T_THREAT_SINGLE_PCT:
if (std::abs(action.threat_single_pct.percent) > 100) if (std::abs(action.threat_single_pct.percent) > 100)
sLog.outErrorEventAI("Event %u Action %u uses invalid percent value %u.", i, j + 1, action.threat_single_pct.percent); sLog.outErrorEventAI("Event %u Action %u uses invalid percent value %u.", i, j + 1, action.threat_single_pct.percent);
if (action.threat_single_pct.target >= TARGET_T_END) IsValidTargetType(temp.event_type, action.type, action.threat_single_pct.target, i, j + 1);
sLog.outErrorEventAI("Event %u Action %u uses incorrect Target type", i, j + 1);
break; break;
case ACTION_T_THREAT_ALL_PCT: case ACTION_T_THREAT_ALL_PCT:
if (std::abs(action.threat_all_pct.percent) > 100) if (std::abs(action.threat_all_pct.percent) > 100)
@ -686,28 +690,23 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
else else
sLog.outErrorEventAI("Event %u Action %u uses nonexistent Quest entry %u.", i, j + 1, action.quest_event.questId); sLog.outErrorEventAI("Event %u Action %u uses nonexistent Quest entry %u.", i, j + 1, action.quest_event.questId);
if (action.quest_event.target >= TARGET_T_END) IsValidTargetType(temp.event_type, action.type, action.quest_event.target, i, j + 1);
sLog.outErrorEventAI("Event %u Action %u uses incorrect Target type", i, j + 1);
break; break;
case ACTION_T_CAST_EVENT: case ACTION_T_CAST_EVENT:
if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.cast_event.creatureId)) if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.cast_event.creatureId))
sLog.outErrorEventAI("Event %u Action %u uses nonexistent creature entry %u.", i, j + 1, action.cast_event.creatureId); sLog.outErrorEventAI("Event %u Action %u uses nonexistent creature entry %u.", i, j + 1, action.cast_event.creatureId);
if (!sSpellStore.LookupEntry(action.cast_event.spellId)) if (!sSpellStore.LookupEntry(action.cast_event.spellId))
sLog.outErrorEventAI("Event %u Action %u uses nonexistent SpellID %u.", i, j + 1, action.cast_event.spellId); sLog.outErrorEventAI("Event %u Action %u uses nonexistent SpellID %u.", i, j + 1, action.cast_event.spellId);
if (action.cast_event.target >= TARGET_T_END) IsValidTargetType(temp.event_type, action.type, action.cast_event.target, i, j + 1);
sLog.outErrorEventAI("Event %u Action %u uses incorrect Target type", i, j + 1);
break; break;
case ACTION_T_SET_UNIT_FIELD: case ACTION_T_SET_UNIT_FIELD:
if (action.set_unit_field.field < OBJECT_END || action.set_unit_field.field >= UNIT_END) if (action.set_unit_field.field < OBJECT_END || action.set_unit_field.field >= UNIT_END)
sLog.outErrorEventAI("Event %u Action %u param1 (UNIT_FIELD*). Index out of range for intended use.", i, j + 1); sLog.outErrorEventAI("Event %u Action %u param1 (UNIT_FIELD*). Index out of range for intended use.", i, j + 1);
if (action.set_unit_field.target >= TARGET_T_END) IsValidTargetType(temp.event_type, action.type, action.set_unit_field.target, i, j + 1);
sLog.outErrorEventAI("Event %u Action %u uses incorrect Target type", i, j + 1);
break; break;
case ACTION_T_SET_UNIT_FLAG: case ACTION_T_SET_UNIT_FLAG:
case ACTION_T_REMOVE_UNIT_FLAG: case ACTION_T_REMOVE_UNIT_FLAG:
if (action.unit_flag.target >= TARGET_T_END) IsValidTargetType(temp.event_type, action.type, action.unit_flag.target, i, j + 1);
sLog.outErrorEventAI("Event %u Action %u uses incorrect Target type", i, j + 1);
break; break;
case ACTION_T_SET_PHASE: case ACTION_T_SET_PHASE:
if (action.set_phase.phase >= MAX_PHASE) if (action.set_phase.phase >= MAX_PHASE)
@ -737,8 +736,7 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
case ACTION_T_REMOVEAURASFROMSPELL: case ACTION_T_REMOVEAURASFROMSPELL:
if (!sSpellStore.LookupEntry(action.remove_aura.spellId)) if (!sSpellStore.LookupEntry(action.remove_aura.spellId))
sLog.outErrorEventAI("Event %u Action %u uses nonexistent SpellID %u.", i, j + 1, action.remove_aura.spellId); sLog.outErrorEventAI("Event %u Action %u uses nonexistent SpellID %u.", i, j + 1, action.remove_aura.spellId);
if (action.remove_aura.target >= TARGET_T_END) IsValidTargetType(temp.event_type, action.type, action.remove_aura.target, i, j + 1);
sLog.outErrorEventAI("Event %u Action %u uses incorrect Target type", i, j + 1);
break; break;
case ACTION_T_RANDOM_PHASE: // PhaseId1, PhaseId2, PhaseId3 case ACTION_T_RANDOM_PHASE: // PhaseId1, PhaseId2, PhaseId3
if (action.random_phase.phase1 >= MAX_PHASE) if (action.random_phase.phase1 >= MAX_PHASE)
@ -763,16 +761,14 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
case ACTION_T_SUMMON_ID: case ACTION_T_SUMMON_ID:
if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.summon_id.creatureId)) if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.summon_id.creatureId))
sLog.outErrorEventAI("Event %u Action %u uses nonexistent creature entry %u.", i, j + 1, action.summon_id.creatureId); sLog.outErrorEventAI("Event %u Action %u uses nonexistent creature entry %u.", i, j + 1, action.summon_id.creatureId);
if (action.summon_id.target >= TARGET_T_END) IsValidTargetType(temp.event_type, action.type, action.summon_id.target, i, j + 1);
sLog.outErrorEventAI("Event %u Action %u uses incorrect Target type", i, j + 1);
if (m_CreatureEventAI_Summon_Map.find(action.summon_id.spawnId) == m_CreatureEventAI_Summon_Map.end()) if (m_CreatureEventAI_Summon_Map.find(action.summon_id.spawnId) == m_CreatureEventAI_Summon_Map.end())
sLog.outErrorEventAI("Event %u Action %u summons missing CreatureEventAI_Summon %u", i, j + 1, action.summon_id.spawnId); sLog.outErrorEventAI("Event %u Action %u summons missing CreatureEventAI_Summon %u", i, j + 1, action.summon_id.spawnId);
break; break;
case ACTION_T_KILLED_MONSTER: case ACTION_T_KILLED_MONSTER:
if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.killed_monster.creatureId)) if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.killed_monster.creatureId))
sLog.outErrorEventAI("Event %u Action %u uses nonexistent creature entry %u.", i, j + 1, action.killed_monster.creatureId); sLog.outErrorEventAI("Event %u Action %u uses nonexistent creature entry %u.", i, j + 1, action.killed_monster.creatureId);
if (action.killed_monster.target >= TARGET_T_END) IsValidTargetType(temp.event_type, action.type, action.killed_monster.target, i, j + 1);
sLog.outErrorEventAI("Event %u Action %u uses incorrect Target type", i, j + 1);
break; break;
case ACTION_T_SET_INST_DATA: case ACTION_T_SET_INST_DATA:
if (!(temp.event_flags & EFLAG_DIFFICULTY_ALL)) if (!(temp.event_flags & EFLAG_DIFFICULTY_ALL))
@ -783,8 +779,7 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
case ACTION_T_SET_INST_DATA64: case ACTION_T_SET_INST_DATA64:
if (!(temp.event_flags & EFLAG_DIFFICULTY_ALL)) if (!(temp.event_flags & EFLAG_DIFFICULTY_ALL))
sLog.outErrorEventAI("Event %u Action %u. Cannot set instance data without difficulty event flags.", i, j + 1); sLog.outErrorEventAI("Event %u Action %u. Cannot set instance data without difficulty event flags.", i, j + 1);
if (action.set_inst_data64.target >= TARGET_T_END) IsValidTargetType(temp.event_type, action.type, action.set_inst_data64.target, i, j + 1);
sLog.outErrorEventAI("Event %u Action %u uses incorrect Target type", i, j + 1);
break; break;
case ACTION_T_UPDATE_TEMPLATE: case ACTION_T_UPDATE_TEMPLATE:
if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.update_template.creatureId)) if (!sCreatureStorage.LookupEntry<CreatureInfo>(action.update_template.creatureId))
@ -851,20 +846,27 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
case ACTION_T_THROW_AI_EVENT: case ACTION_T_THROW_AI_EVENT:
if (action.throwEvent.eventType >= MAXIMAL_AI_EVENT_EVENTAI) if (action.throwEvent.eventType >= MAXIMAL_AI_EVENT_EVENTAI)
{ {
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses invalid event type %u (must be less than %u), skipping", i, j + 1, action.throwEvent.eventType, MAXIMAL_AI_EVENT_EVENTAI); sLog.outErrorEventAI("Event %u Action %u uses invalid event type %u (must be less than %u), skipping", i, j + 1, action.throwEvent.eventType, MAXIMAL_AI_EVENT_EVENTAI);
continue; continue;
} }
if (action.throwEvent.radius > SIZE_OF_GRIDS) if (action.throwEvent.radius > SIZE_OF_GRIDS)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses unexpectedly huge radius %u (expected to be less than %f)", i, j + 1, action.throwEvent.radius, SIZE_OF_GRIDS); sLog.outErrorEventAI("Event %u Action %u uses unexpectedly huge radius %u (expected to be less than %f)", i, j + 1, action.throwEvent.radius, SIZE_OF_GRIDS);
if (action.throwEvent.radius == 0) if (action.throwEvent.radius == 0)
{ {
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses unexpected radius 0 (set to %f of CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS)", i, j + 1, sWorld.getConfig(CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS)); sLog.outErrorEventAI("Event %u Action %u uses unexpected radius 0 (set to %f of CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS)", i, j + 1, sWorld.getConfig(CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS));
action.throwEvent.radius = uint32(sWorld.getConfig(CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS)); action.throwEvent.radius = uint32(sWorld.getConfig(CONFIG_FLOAT_CREATURE_FAMILY_ASSISTANCE_RADIUS));
} }
break; break;
case ACTION_T_SET_THROW_MASK:
if (action.setThrowMask.eventTypeMask & ~((1 << MAXIMAL_AI_EVENT_EVENTAI) - 1))
{
sLog.outErrorEventAI("Event %u Action %u uses invalid AIEvent-typemask %u (must be smaller than %u)", i, j + 1, action.setThrowMask.eventTypeMask, MAXIMAL_AI_EVENT_EVENTAI << 1);
continue;
}
break;
default: default:
sLog.outErrorEventAI("Event %u Action %u have currently not checked at load action type (%u). Need check code update?", i, j + 1, temp.action[j].type); sLog.outErrorEventAI("Event %u Action %u have currently not checked at load action type (%u). Need check code update?", i, j + 1, temp.action[j].type);
break; break;
@ -878,6 +880,7 @@ void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
while (result->NextRow()); while (result->NextRow());
delete result; delete result;
m_usedTextsAmount = usedTextIds.size();
// post check // post check
for (uint32 i = 1; i < sCreatureStorage.GetMaxEntry(); ++i) for (uint32 i = 1; i < sCreatureStorage.GetMaxEntry(); ++i)

View file

@ -25,7 +25,7 @@
class CreatureEventAIMgr class CreatureEventAIMgr
{ {
public: public:
CreatureEventAIMgr() {}; CreatureEventAIMgr() : m_usedTextsAmount(0) {};
~CreatureEventAIMgr() {}; ~CreatureEventAIMgr() {};
void LoadCreatureEventAI_Texts(bool check_entry_use); void LoadCreatureEventAI_Texts(bool check_entry_use);
@ -34,7 +34,6 @@ class CreatureEventAIMgr
CreatureEventAI_Event_Map const& GetCreatureEventAIMap() const { return m_CreatureEventAI_Event_Map; } CreatureEventAI_Event_Map const& GetCreatureEventAIMap() const { return m_CreatureEventAI_Event_Map; }
CreatureEventAI_Summon_Map const& GetCreatureEventAISummonMap() const { return m_CreatureEventAI_Summon_Map; } CreatureEventAI_Summon_Map const& GetCreatureEventAISummonMap() const { return m_CreatureEventAI_Summon_Map; }
CreatureEventAI_TextMap const& GetCreatureEventAITextMap() const { return m_CreatureEventAI_TextMap; }
private: private:
void CheckUnusedAITexts(); void CheckUnusedAITexts();
@ -42,7 +41,8 @@ class CreatureEventAIMgr
CreatureEventAI_Event_Map m_CreatureEventAI_Event_Map; CreatureEventAI_Event_Map m_CreatureEventAI_Event_Map;
CreatureEventAI_Summon_Map m_CreatureEventAI_Summon_Map; CreatureEventAI_Summon_Map m_CreatureEventAI_Summon_Map;
CreatureEventAI_TextMap m_CreatureEventAI_TextMap;
uint32 m_usedTextsAmount;
}; };
#define sEventAIMgr MaNGOS::Singleton<CreatureEventAIMgr>::Instance() #define sEventAIMgr MaNGOS::Singleton<CreatureEventAIMgr>::Instance()

View file

@ -56,10 +56,10 @@ namespace MaNGOS
struct MANGOS_DLL_DECL MessageDeliverer struct MANGOS_DLL_DECL MessageDeliverer
{ {
Player& i_player; Player const& i_player;
WorldPacket* i_message; WorldPacket* i_message;
bool i_toSelf; bool i_toSelf;
MessageDeliverer(Player& pl, WorldPacket* msg, bool to_self) : i_player(pl), i_message(msg), i_toSelf(to_self) {} MessageDeliverer(Player const& pl, WorldPacket* msg, bool to_self) : i_player(pl), i_message(msg), i_toSelf(to_self) {}
void Visit(CameraMapType& m); void Visit(CameraMapType& m);
template<class SKIP> void Visit(GridRefManager<SKIP> &) {} template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
}; };
@ -81,7 +81,7 @@ namespace MaNGOS
{ {
uint32 i_phaseMask; uint32 i_phaseMask;
WorldPacket* i_message; WorldPacket* i_message;
explicit ObjectMessageDeliverer(WorldObject& obj, WorldPacket* msg) explicit ObjectMessageDeliverer(WorldObject const& obj, WorldPacket* msg)
: i_phaseMask(obj.GetPhaseMask()), i_message(msg) {} : i_phaseMask(obj.GetPhaseMask()), i_message(msg) {}
void Visit(CameraMapType& m); void Visit(CameraMapType& m);
template<class SKIP> void Visit(GridRefManager<SKIP> &) {} template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
@ -89,13 +89,13 @@ namespace MaNGOS
struct MANGOS_DLL_DECL MessageDistDeliverer struct MANGOS_DLL_DECL MessageDistDeliverer
{ {
Player& i_player; Player const& i_player;
WorldPacket* i_message; WorldPacket* i_message;
bool i_toSelf; bool i_toSelf;
bool i_ownTeamOnly; bool i_ownTeamOnly;
float i_dist; float i_dist;
MessageDistDeliverer(Player& pl, WorldPacket* msg, float dist, bool to_self, bool ownTeamOnly) MessageDistDeliverer(Player const& pl, WorldPacket* msg, float dist, bool to_self, bool ownTeamOnly)
: i_player(pl), i_message(msg), i_toSelf(to_self), i_ownTeamOnly(ownTeamOnly), i_dist(dist) {} : i_player(pl), i_message(msg), i_toSelf(to_self), i_ownTeamOnly(ownTeamOnly), i_dist(dist) {}
void Visit(CameraMapType& m); void Visit(CameraMapType& m);
template<class SKIP> void Visit(GridRefManager<SKIP> &) {} template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
@ -103,10 +103,10 @@ namespace MaNGOS
struct MANGOS_DLL_DECL ObjectMessageDistDeliverer struct MANGOS_DLL_DECL ObjectMessageDistDeliverer
{ {
WorldObject& i_object; WorldObject const& i_object;
WorldPacket* i_message; WorldPacket* i_message;
float i_dist; float i_dist;
ObjectMessageDistDeliverer(WorldObject& obj, WorldPacket* msg, float dist) : i_object(obj), i_message(msg), i_dist(dist) {} ObjectMessageDistDeliverer(WorldObject const& obj, WorldPacket* msg, float dist) : i_object(obj), i_message(msg), i_dist(dist) {}
void Visit(CameraMapType& m); void Visit(CameraMapType& m);
template<class SKIP> void Visit(GridRefManager<SKIP> &) {} template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
}; };
@ -1127,12 +1127,13 @@ namespace MaNGOS
class NearestCreatureEntryWithLiveStateInObjectRangeCheck class NearestCreatureEntryWithLiveStateInObjectRangeCheck
{ {
public: public:
NearestCreatureEntryWithLiveStateInObjectRangeCheck(WorldObject const& obj, uint32 entry, bool onlyAlive, bool onlyDead, float range) NearestCreatureEntryWithLiveStateInObjectRangeCheck(WorldObject const& obj, uint32 entry, bool onlyAlive, bool onlyDead, float range, bool excludeSelf = false)
: i_obj(obj), i_entry(entry), i_onlyAlive(onlyAlive), i_onlyDead(onlyDead), i_range(range) {} : i_obj(obj), i_entry(entry), i_onlyAlive(onlyAlive), i_onlyDead(onlyDead), i_excludeSelf(excludeSelf), i_range(range) {}
WorldObject const& GetFocusObject() const { return i_obj; } WorldObject const& GetFocusObject() const { return i_obj; }
bool operator()(Creature* u) bool operator()(Creature* u)
{ {
if (u->GetEntry() == i_entry && ((i_onlyAlive && u->isAlive()) || (i_onlyDead && u->IsCorpse()) || (!i_onlyAlive && !i_onlyDead)) && i_obj.IsWithinDistInMap(u, i_range)) if (u->GetEntry() == i_entry && ((i_onlyAlive && u->isAlive()) || (i_onlyDead && u->IsCorpse()) || (!i_onlyAlive && !i_onlyDead))
&& (!i_excludeSelf || &i_obj != u) && i_obj.IsWithinDistInMap(u, i_range))
{ {
i_range = i_obj.GetDistance(u); // use found unit range as new range limit for next check i_range = i_obj.GetDistance(u); // use found unit range as new range limit for next check
return true; return true;
@ -1145,6 +1146,7 @@ namespace MaNGOS
uint32 i_entry; uint32 i_entry;
bool i_onlyAlive; bool i_onlyAlive;
bool i_onlyDead; bool i_onlyDead;
bool i_excludeSelf;
float i_range; float i_range;
// prevent clone this object // prevent clone this object

View file

@ -45,6 +45,8 @@ enum InstanceConditionIDs // Suggested values
// to check water event in SSC // to check water event in SSC
INSTANCE_CONDITION_ID_LURKER = 21217, INSTANCE_CONDITION_ID_LURKER = 21217,
INSTANCE_CONDITION_ID_SCALDING_WATER = 37284, INSTANCE_CONDITION_ID_SCALDING_WATER = 37284,
// to check vehicles in Ulduar
INSTANCE_CONDITION_ID_ULDUAR = 33113,
}; };
class MANGOS_DLL_SPEC InstanceData class MANGOS_DLL_SPEC InstanceData

View file

@ -1545,6 +1545,7 @@ void LoadLootTemplates_Reference()
LootTemplates_Prospecting.CheckLootRefs(&ids_set); LootTemplates_Prospecting.CheckLootRefs(&ids_set);
LootTemplates_Mail.CheckLootRefs(&ids_set); LootTemplates_Mail.CheckLootRefs(&ids_set);
LootTemplates_Reference.CheckLootRefs(&ids_set); LootTemplates_Reference.CheckLootRefs(&ids_set);
LootTemplates_Spell.CheckLootRefs(&ids_set);
// output error for any still listed ids (not referenced from any loot table) // output error for any still listed ids (not referenced from any loot table)
LootTemplates_Reference.ReportUnusedIds(ids_set); LootTemplates_Reference.ReportUnusedIds(ids_set);

View file

@ -342,7 +342,7 @@ Map::Add(T* obj)
UpdateObjectVisibility(obj, cell, p); UpdateObjectVisibility(obj, cell, p);
} }
void Map::MessageBroadcast(Player* player, WorldPacket* msg, bool to_self) void Map::MessageBroadcast(Player const* player, WorldPacket* msg, bool to_self)
{ {
CellPair p = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); CellPair p = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
@ -363,7 +363,7 @@ void Map::MessageBroadcast(Player* player, WorldPacket* msg, bool to_self)
cell.Visit(p, message, *this, *player, GetVisibilityDistance()); cell.Visit(p, message, *this, *player, GetVisibilityDistance());
} }
void Map::MessageBroadcast(WorldObject* obj, WorldPacket* msg) void Map::MessageBroadcast(WorldObject const* obj, WorldPacket* msg)
{ {
CellPair p = MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); CellPair p = MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
@ -386,7 +386,7 @@ void Map::MessageBroadcast(WorldObject* obj, WorldPacket* msg)
cell.Visit(p, message, *this, *obj, GetVisibilityDistance()); cell.Visit(p, message, *this, *obj, GetVisibilityDistance());
} }
void Map::MessageDistBroadcast(Player* player, WorldPacket* msg, float dist, bool to_self, bool own_team_only) void Map::MessageDistBroadcast(Player const* player, WorldPacket* msg, float dist, bool to_self, bool own_team_only)
{ {
CellPair p = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); CellPair p = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
@ -407,7 +407,7 @@ void Map::MessageDistBroadcast(Player* player, WorldPacket* msg, float dist, boo
cell.Visit(p, message, *this, *player, dist); cell.Visit(p, message, *this, *player, dist);
} }
void Map::MessageDistBroadcast(WorldObject* obj, WorldPacket* msg, float dist) void Map::MessageDistBroadcast(WorldObject const* obj, WorldPacket* msg, float dist)
{ {
CellPair p = MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); CellPair p = MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY());
@ -1866,7 +1866,7 @@ uint32 Map::GenerateLocalLowGuid(HighGuid guidhigh)
class StaticMonsterChatBuilder class StaticMonsterChatBuilder
{ {
public: public:
StaticMonsterChatBuilder(CreatureInfo const* cInfo, ChatMsg msgtype, int32 textId, uint32 language, Unit* target, uint32 senderLowGuid = 0) StaticMonsterChatBuilder(CreatureInfo const* cInfo, ChatMsg msgtype, int32 textId, uint32 language, Unit const* target, uint32 senderLowGuid = 0)
: i_cInfo(cInfo), i_msgtype(msgtype), i_textId(textId), i_language(language), i_target(target) : i_cInfo(cInfo), i_msgtype(msgtype), i_textId(textId), i_language(language), i_target(target)
{ {
// 0 lowguid not used in core, but accepted fine in this case by client // 0 lowguid not used in core, but accepted fine in this case by client
@ -1888,7 +1888,7 @@ class StaticMonsterChatBuilder
ChatMsg i_msgtype; ChatMsg i_msgtype;
int32 i_textId; int32 i_textId;
uint32 i_language; uint32 i_language;
Unit* i_target; Unit const* i_target;
}; };
@ -1900,7 +1900,7 @@ class StaticMonsterChatBuilder
* @param language language of the text * @param language language of the text
* @param target, can be NULL * @param target, can be NULL
*/ */
void Map::MonsterYellToMap(ObjectGuid guid, int32 textId, uint32 language, Unit* target) void Map::MonsterYellToMap(ObjectGuid guid, int32 textId, uint32 language, Unit const* target) const
{ {
if (guid.IsAnyTypeCreature()) if (guid.IsAnyTypeCreature())
{ {
@ -1931,7 +1931,7 @@ void Map::MonsterYellToMap(ObjectGuid guid, int32 textId, uint32 language, Unit*
* @param senderLowGuid provide way proper show yell for near spawned creature with known lowguid, * @param senderLowGuid provide way proper show yell for near spawned creature with known lowguid,
* 0 accepted by client else if this not important * 0 accepted by client else if this not important
*/ */
void Map::MonsterYellToMap(CreatureInfo const* cinfo, int32 textId, uint32 language, Unit* target, uint32 senderLowGuid /*= 0*/) void Map::MonsterYellToMap(CreatureInfo const* cinfo, int32 textId, uint32 language, Unit const* target, uint32 senderLowGuid /*= 0*/) const
{ {
StaticMonsterChatBuilder say_build(cinfo, CHAT_MSG_MONSTER_YELL, textId, language, target, senderLowGuid); StaticMonsterChatBuilder say_build(cinfo, CHAT_MSG_MONSTER_YELL, textId, language, target, senderLowGuid);
MaNGOS::LocalizedPacketDo<StaticMonsterChatBuilder> say_do(say_build); MaNGOS::LocalizedPacketDo<StaticMonsterChatBuilder> say_do(say_build);
@ -1947,7 +1947,7 @@ void Map::MonsterYellToMap(CreatureInfo const* cinfo, int32 textId, uint32 langu
* @param soundId Played Sound * @param soundId Played Sound
* @param zoneId Id of the Zone to which the sound should be restricted * @param zoneId Id of the Zone to which the sound should be restricted
*/ */
void Map::PlayDirectSoundToMap(uint32 soundId, uint32 zoneId /*=0*/) void Map::PlayDirectSoundToMap(uint32 soundId, uint32 zoneId /*=0*/) const
{ {
WorldPacket data(SMSG_PLAY_SOUND, 4); WorldPacket data(SMSG_PLAY_SOUND, 4);
data << uint32(soundId); data << uint32(soundId);

View file

@ -123,10 +123,10 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>
virtual void Update(const uint32&); virtual void Update(const uint32&);
void MessageBroadcast(Player*, WorldPacket*, bool to_self); void MessageBroadcast(Player const*, WorldPacket*, bool to_self);
void MessageBroadcast(WorldObject*, WorldPacket*); void MessageBroadcast(WorldObject const*, WorldPacket*);
void MessageDistBroadcast(Player*, WorldPacket*, float dist, bool to_self, bool own_team_only = false); void MessageDistBroadcast(Player const*, WorldPacket*, float dist, bool to_self, bool own_team_only = false);
void MessageDistBroadcast(WorldObject*, WorldPacket*, float dist); void MessageDistBroadcast(WorldObject const*, WorldPacket*, float dist);
float GetVisibilityDistance() const { return m_VisibleDistance; } float GetVisibilityDistance() const { return m_VisibleDistance; }
// function for setting up visibility distance for maps on per-type/per-Id basis // function for setting up visibility distance for maps on per-type/per-Id basis
@ -266,9 +266,9 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>
InstanceData* GetInstanceData() const { return i_data; } InstanceData* GetInstanceData() const { return i_data; }
uint32 GetScriptId() const { return i_script_id; } uint32 GetScriptId() const { return i_script_id; }
void MonsterYellToMap(ObjectGuid guid, int32 textId, uint32 language, Unit* target); void MonsterYellToMap(ObjectGuid guid, int32 textId, uint32 language, Unit const* target) const;
void MonsterYellToMap(CreatureInfo const* cinfo, int32 textId, uint32 language, Unit* target, uint32 senderLowGuid = 0); void MonsterYellToMap(CreatureInfo const* cinfo, int32 textId, uint32 language, Unit const* target, uint32 senderLowGuid = 0) const;
void PlayDirectSoundToMap(uint32 soundId, uint32 zoneId = 0); void PlayDirectSoundToMap(uint32 soundId, uint32 zoneId = 0) const;
// Dynamic VMaps // Dynamic VMaps
float GetHeight(uint32 phasemask, float x, float y, float z) const; float GetHeight(uint32 phasemask, float x, float y, float z) const;

View file

@ -1240,10 +1240,11 @@ bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool
bool WorldObject::IsWithinLOSInMap(const WorldObject* obj) const bool WorldObject::IsWithinLOSInMap(const WorldObject* obj) const
{ {
if (!IsInMap(obj)) return false; if (!IsInMap(obj))
return false;
float ox, oy, oz; float ox, oy, oz;
obj->GetPosition(ox, oy, oz); obj->GetPosition(ox, oy, oz);
return(IsWithinLOS(ox, oy, oz)); return IsWithinLOS(ox, oy, oz);
} }
bool WorldObject::IsWithinLOS(float ox, float oy, float oz) const bool WorldObject::IsWithinLOS(float ox, float oy, float oz) const
@ -1511,21 +1512,21 @@ bool WorldObject::IsPositionValid() const
return MaNGOS::IsValidMapCoord(m_position.x, m_position.y, m_position.z, m_position.o); return MaNGOS::IsValidMapCoord(m_position.x, m_position.y, m_position.z, m_position.o);
} }
void WorldObject::MonsterSay(const char* text, uint32 language, Unit* target) void WorldObject::MonsterSay(const char* text, uint32 language, Unit const* target) const
{ {
WorldPacket data(SMSG_MESSAGECHAT, 200); WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildMonsterChat(&data, GetObjectGuid(), CHAT_MSG_MONSTER_SAY, text, language, GetName(), target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : ""); BuildMonsterChat(&data, GetObjectGuid(), CHAT_MSG_MONSTER_SAY, text, language, GetName(), target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : "");
SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY), true); SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY), true);
} }
void WorldObject::MonsterYell(const char* text, uint32 language, Unit* target) void WorldObject::MonsterYell(const char* text, uint32 language, Unit const* target) const
{ {
WorldPacket data(SMSG_MESSAGECHAT, 200); WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildMonsterChat(&data, GetObjectGuid(), CHAT_MSG_MONSTER_YELL, text, language, GetName(), target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : ""); BuildMonsterChat(&data, GetObjectGuid(), CHAT_MSG_MONSTER_YELL, text, language, GetName(), target ? target->GetObjectGuid() : ObjectGuid(), target ? target->GetName() : "");
SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL), true); SendMessageToSetInRange(&data, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL), true);
} }
void WorldObject::MonsterTextEmote(const char* text, Unit* target, bool IsBossEmote) void WorldObject::MonsterTextEmote(const char* text, Unit const* target, bool IsBossEmote) const
{ {
WorldPacket data(SMSG_MESSAGECHAT, 200); WorldPacket data(SMSG_MESSAGECHAT, 200);
BuildMonsterChat(&data, GetObjectGuid(), IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, text, LANG_UNIVERSAL, BuildMonsterChat(&data, GetObjectGuid(), IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, text, LANG_UNIVERSAL,
@ -1533,7 +1534,7 @@ void WorldObject::MonsterTextEmote(const char* text, Unit* target, bool IsBossEm
SendMessageToSetInRange(&data, sWorld.getConfig(IsBossEmote ? CONFIG_FLOAT_LISTEN_RANGE_YELL : CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE), true); SendMessageToSetInRange(&data, sWorld.getConfig(IsBossEmote ? CONFIG_FLOAT_LISTEN_RANGE_YELL : CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE), true);
} }
void WorldObject::MonsterWhisper(const char* text, Unit* target, bool IsBossWhisper) void WorldObject::MonsterWhisper(const char* text, Unit const* target, bool IsBossWhisper) const
{ {
if (!target || target->GetTypeId() != TYPEID_PLAYER) if (!target || target->GetTypeId() != TYPEID_PLAYER)
return; return;
@ -1549,7 +1550,7 @@ namespace MaNGOS
class MonsterChatBuilder class MonsterChatBuilder
{ {
public: public:
MonsterChatBuilder(WorldObject const& obj, ChatMsg msgtype, int32 textId, uint32 language, Unit* target) MonsterChatBuilder(WorldObject const& obj, ChatMsg msgtype, int32 textId, uint32 language, Unit const* target)
: i_object(obj), i_msgtype(msgtype), i_textId(textId), i_language(language), i_target(target) {} : i_object(obj), i_msgtype(msgtype), i_textId(textId), i_language(language), i_target(target) {}
void operator()(WorldPacket& data, int32 loc_idx) void operator()(WorldPacket& data, int32 loc_idx)
{ {
@ -1563,11 +1564,11 @@ namespace MaNGOS
ChatMsg i_msgtype; ChatMsg i_msgtype;
int32 i_textId; int32 i_textId;
uint32 i_language; uint32 i_language;
Unit* i_target; Unit const* i_target;
}; };
} // namespace MaNGOS } // namespace MaNGOS
void WorldObject::MonsterSay(int32 textId, uint32 language, Unit* target) void WorldObject::MonsterSay(int32 textId, uint32 language, Unit const* target) const
{ {
float range = sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY); float range = sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY);
MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_SAY, textId, language, target); MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_SAY, textId, language, target);
@ -1576,7 +1577,7 @@ void WorldObject::MonsterSay(int32 textId, uint32 language, Unit* target)
Cell::VisitWorldObjects(this, say_worker, range); Cell::VisitWorldObjects(this, say_worker, range);
} }
void WorldObject::MonsterYell(int32 textId, uint32 language, Unit* target) void WorldObject::MonsterYell(int32 textId, uint32 language, Unit const* target) const
{ {
float range = sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL); float range = sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL);
MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textId, language, target); MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textId, language, target);
@ -1585,7 +1586,7 @@ void WorldObject::MonsterYell(int32 textId, uint32 language, Unit* target)
Cell::VisitWorldObjects(this, say_worker, range); Cell::VisitWorldObjects(this, say_worker, range);
} }
void WorldObject::MonsterYellToZone(int32 textId, uint32 language, Unit* target) void WorldObject::MonsterYellToZone(int32 textId, uint32 language, Unit const* target) const
{ {
MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textId, language, target); MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textId, language, target);
MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build); MaNGOS::LocalizedPacketDo<MaNGOS::MonsterChatBuilder> say_do(say_build);
@ -1598,7 +1599,7 @@ void WorldObject::MonsterYellToZone(int32 textId, uint32 language, Unit* target)
say_do(itr->getSource()); say_do(itr->getSource());
} }
void WorldObject::MonsterTextEmote(int32 textId, Unit* target, bool IsBossEmote) void WorldObject::MonsterTextEmote(int32 textId, Unit const* target, bool IsBossEmote) const
{ {
float range = sWorld.getConfig(IsBossEmote ? CONFIG_FLOAT_LISTEN_RANGE_YELL : CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE); float range = sWorld.getConfig(IsBossEmote ? CONFIG_FLOAT_LISTEN_RANGE_YELL : CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE);
@ -1608,7 +1609,7 @@ void WorldObject::MonsterTextEmote(int32 textId, Unit* target, bool IsBossEmote)
Cell::VisitWorldObjects(this, say_worker, range); Cell::VisitWorldObjects(this, say_worker, range);
} }
void WorldObject::MonsterWhisper(int32 textId, Unit* target, bool IsBossWhisper) void WorldObject::MonsterWhisper(int32 textId, Unit const* target, bool IsBossWhisper) const
{ {
if (!target || target->GetTypeId() != TYPEID_PLAYER) if (!target || target->GetTypeId() != TYPEID_PLAYER)
return; return;
@ -1647,21 +1648,21 @@ void WorldObject::BuildMonsterChat(WorldPacket* data, ObjectGuid senderGuid, uin
} }
} }
void WorldObject::SendMessageToSet(WorldPacket* data, bool /*bToSelf*/) void WorldObject::SendMessageToSet(WorldPacket* data, bool /*bToSelf*/) const
{ {
// if object is in world, map for it already created! // if object is in world, map for it already created!
if (IsInWorld()) if (IsInWorld())
GetMap()->MessageBroadcast(this, data); GetMap()->MessageBroadcast(this, data);
} }
void WorldObject::SendMessageToSetInRange(WorldPacket* data, float dist, bool /*bToSelf*/) void WorldObject::SendMessageToSetInRange(WorldPacket* data, float dist, bool /*bToSelf*/) const
{ {
// if object is in world, map for it already created! // if object is in world, map for it already created!
if (IsInWorld()) if (IsInWorld())
GetMap()->MessageDistBroadcast(this, data, dist); GetMap()->MessageDistBroadcast(this, data, dist);
} }
void WorldObject::SendMessageToSetExcept(WorldPacket* data, Player const* skipped_receiver) void WorldObject::SendMessageToSetExcept(WorldPacket* data, Player const* skipped_receiver) const
{ {
// if object is in world, map for it already created! // if object is in world, map for it already created!
if (IsInWorld()) if (IsInWorld())
@ -1750,6 +1751,9 @@ Creature* WorldObject::SummonCreature(uint32 id, float x, float y, float z, floa
return pCreature; return pCreature;
} }
// how much space should be left in front of/ behind a mob that already uses a space
#define OCCUPY_POS_DEPTH_FACTOR 1.8f
namespace MaNGOS namespace MaNGOS
{ {
class NearUsedPosDo class NearUsedPosDo
@ -1796,16 +1800,19 @@ namespace MaNGOS
// we must add used pos that can fill places around center // we must add used pos that can fill places around center
void add(WorldObject* u, float x, float y) const void add(WorldObject* u, float x, float y) const
{ {
// dist include size of u and i_object
float dx = i_object.GetPositionX() - x; float dx = i_object.GetPositionX() - x;
float dy = i_object.GetPositionY() - y; float dy = i_object.GetPositionY() - y;
float dist2d = sqrt((dx * dx) + (dy * dy)); float dist2d = sqrt((dx * dx) + (dy * dy));
float delta = i_selector.m_searcherSize + u->GetObjectBoundingRadius(); // It is ok for the objects to require a bit more space
float delta = u->GetObjectBoundingRadius();
if (i_selector.m_searchPosFor && i_selector.m_searchPosFor != u)
delta += i_selector.m_searchPosFor->GetObjectBoundingRadius();
// u is too nearest/far away to i_object delta *= OCCUPY_POS_DEPTH_FACTOR; // Increase by factor
if (dist2d < i_selector.m_searcherDist - delta ||
dist2d >= i_selector.m_searcherDist + delta) // u is too near/far away from i_object. Do not consider it to occupy space
if (fabs(i_selector.m_searcherDist - dist2d) > delta)
return; return;
float angle = i_object.GetAngle(u) - i_absAngle; float angle = i_object.GetAngle(u) - i_absAngle;
@ -1816,7 +1823,7 @@ namespace MaNGOS
else if (angle < -M_PI_F) else if (angle < -M_PI_F)
angle += 2.0f * M_PI_F; angle += 2.0f * M_PI_F;
i_selector.AddUsedArea(u->GetObjectBoundingRadius(), angle, dist2d); i_selector.AddUsedArea(u, angle, dist2d);
} }
private: private:
WorldObject const& i_object; WorldObject const& i_object;
@ -1830,8 +1837,8 @@ namespace MaNGOS
void WorldObject::GetNearPoint2D(float& x, float& y, float distance2d, float absAngle) const void WorldObject::GetNearPoint2D(float& x, float& y, float distance2d, float absAngle) const
{ {
x = GetPositionX() + (GetObjectBoundingRadius() + distance2d) * cos(absAngle); x = GetPositionX() + distance2d * cos(absAngle);
y = GetPositionY() + (GetObjectBoundingRadius() + distance2d) * sin(absAngle); y = GetPositionY() + distance2d * sin(absAngle);
MaNGOS::NormalizeMapCoord(x); MaNGOS::NormalizeMapCoord(x);
MaNGOS::NormalizeMapCoord(y); MaNGOS::NormalizeMapCoord(y);
@ -1839,7 +1846,7 @@ void WorldObject::GetNearPoint2D(float& x, float& y, float distance2d, float abs
void WorldObject::GetNearPoint(WorldObject const* searcher, float& x, float& y, float& z, float searcher_bounding_radius, float distance2d, float absAngle) const void WorldObject::GetNearPoint(WorldObject const* searcher, float& x, float& y, float& z, float searcher_bounding_radius, float distance2d, float absAngle) const
{ {
GetNearPoint2D(x, y, distance2d + searcher_bounding_radius, absAngle); GetNearPoint2D(x, y, distance2d, absAngle);
const float init_z = z = GetPositionZ(); const float init_z = z = GetPositionZ();
// if detection disabled, return first point // if detection disabled, return first point
@ -1860,14 +1867,14 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float& x, float& y,
const float dist = distance2d + searcher_bounding_radius + GetObjectBoundingRadius(); const float dist = distance2d + searcher_bounding_radius + GetObjectBoundingRadius();
// prepare selector for work // prepare selector for work
ObjectPosSelector selector(GetPositionX(), GetPositionY(), dist, searcher_bounding_radius); ObjectPosSelector selector(GetPositionX(), GetPositionY(), distance2d, searcher_bounding_radius, searcher);
// adding used positions around object // adding used positions around object
{ {
MaNGOS::NearUsedPosDo u_do(*this, searcher, absAngle, selector); MaNGOS::NearUsedPosDo u_do(*this, searcher, absAngle, selector);
MaNGOS::WorldObjectWorker<MaNGOS::NearUsedPosDo> worker(this, u_do); MaNGOS::WorldObjectWorker<MaNGOS::NearUsedPosDo> worker(this, u_do);
Cell::VisitAllObjects(this, worker, distance2d + searcher_bounding_radius); Cell::VisitAllObjects(this, worker, dist);
} }
// maybe can just place in primary position // maybe can just place in primary position
@ -1892,7 +1899,7 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float& x, float& y,
// select in positions after current nodes (selection one by one) // select in positions after current nodes (selection one by one)
while (selector.NextAngle(angle)) // angle for free pos while (selector.NextAngle(angle)) // angle for free pos
{ {
GetNearPoint2D(x, y, distance2d + searcher_bounding_radius, absAngle + angle); GetNearPoint2D(x, y, distance2d, absAngle + angle);
z = GetPositionZ(); z = GetPositionZ();
if (searcher) if (searcher)
@ -1924,7 +1931,7 @@ void WorldObject::GetNearPoint(WorldObject const* searcher, float& x, float& y,
// select in positions after current nodes (selection one by one) // select in positions after current nodes (selection one by one)
while (selector.NextUsedAngle(angle)) // angle for used pos but maybe without LOS problem while (selector.NextUsedAngle(angle)) // angle for used pos but maybe without LOS problem
{ {
GetNearPoint2D(x, y, distance2d + searcher_bounding_radius, absAngle + angle); GetNearPoint2D(x, y, distance2d, absAngle + angle);
z = GetPositionZ(); z = GetPositionZ();
if (searcher) if (searcher)
@ -1954,7 +1961,7 @@ void WorldObject::SetPhaseMask(uint32 newPhaseMask, bool update)
UpdateVisibilityAndView(); UpdateVisibilityAndView();
} }
void WorldObject::PlayDistanceSound(uint32 sound_id, Player* target /*= NULL*/) void WorldObject::PlayDistanceSound(uint32 sound_id, Player const* target /*= NULL*/) const
{ {
WorldPacket data(SMSG_PLAY_OBJECT_SOUND, 4 + 8); WorldPacket data(SMSG_PLAY_OBJECT_SOUND, 4 + 8);
data << uint32(sound_id); data << uint32(sound_id);
@ -1966,7 +1973,7 @@ void WorldObject::PlayDistanceSound(uint32 sound_id, Player* target /*= NULL*/)
SendMessageToSet(&data, true); SendMessageToSet(&data, true);
} }
void WorldObject::PlayDirectSound(uint32 sound_id, Player* target /*= NULL*/) void WorldObject::PlayDirectSound(uint32 sound_id, Player const* target /*= NULL*/) const
{ {
WorldPacket data(SMSG_PLAY_SOUND, 4); WorldPacket data(SMSG_PLAY_SOUND, 4);
data << uint32(sound_id); data << uint32(sound_id);

View file

@ -457,17 +457,37 @@ class MANGOS_DLL_SPEC WorldObject : public Object
void GetPosition(WorldLocation& loc) const void GetPosition(WorldLocation& loc) const
{ loc.mapid = m_mapId; GetPosition(loc.coord_x, loc.coord_y, loc.coord_z); loc.orientation = GetOrientation(); } { loc.mapid = m_mapId; GetPosition(loc.coord_x, loc.coord_y, loc.coord_z); loc.orientation = GetOrientation(); }
float GetOrientation() const { return m_position.o; } float GetOrientation() const { return m_position.o; }
void GetNearPoint2D(float& x, float& y, float distance, float absAngle) const; /// Gives a 2d-point in distance distance2d in direction absAngle around the current position (point-to-point)
void GetNearPoint2D(float& x, float& y, float distance2d, float absAngle) const;
/** Gives a "free" spot for searcher in distance distance2d in direction absAngle on "good" height
* @param searcher - for whom a spot is searched for
* @param x, y, z - position for the found spot of the searcher
* @param searcher_bounding_radius - how much space the searcher will require
* @param distance2d - distance between the middle-points
* @param absAngle - angle in which the spot is preferred
*/
void GetNearPoint(WorldObject const* searcher, float& x, float& y, float& z, float searcher_bounding_radius, float distance2d, float absAngle) const; void GetNearPoint(WorldObject const* searcher, float& x, float& y, float& z, float searcher_bounding_radius, float distance2d, float absAngle) const;
void GetClosePoint(float& x, float& y, float& z, float bounding_radius, float distance2d = 0, float angle = 0, const WorldObject* obj = NULL) const /** Gives a "free" spot for a searcher on the distance (including bounding-radius calculation)
* @param x, y, z - position for the found spot
* @param bounding_radius - radius for the searcher
* @param distance2d - range in which to find a free spot. Default = 0.0f (which usually means the units will have contact)
* @param angle - direction in which to look for a free spot. Default = 0.0f (direction in which 'this' is looking
* @param obj - for whom to look for a spot. Default = NULL
*/
void GetClosePoint(float& x, float& y, float& z, float bounding_radius, float distance2d = 0.0f, float angle = 0.0f, const WorldObject* obj = NULL) const
{ {
// angle calculated from current orientation // angle calculated from current orientation
GetNearPoint(obj, x, y, z, bounding_radius, distance2d, GetOrientation() + angle); GetNearPoint(obj, x, y, z, bounding_radius, distance2d + GetObjectBoundingRadius() + bounding_radius, GetOrientation() + angle);
} }
/** Gives a "free" spot for a searcher in contact-range of "this" (including bounding-radius calculation)
* @param x, y, z - position for the found spot
* @param obj - for whom to find a contact position. The position will be searched in direction from 'this' towards 'obj'
* @param distance2d - distance which 'obj' and 'this' should have beetween their bounding radiuses. Default = CONTACT_DISTANCE
*/
void GetContactPoint(const WorldObject* obj, float& x, float& y, float& z, float distance2d = CONTACT_DISTANCE) const void GetContactPoint(const WorldObject* obj, float& x, float& y, float& z, float distance2d = CONTACT_DISTANCE) const
{ {
// angle to face `obj` to `this` using distance includes size of `obj` // angle to face `obj` to `this` using distance includes size of `obj`
GetNearPoint(obj, x, y, z, obj->GetObjectBoundingRadius(), distance2d, GetAngle(obj)); GetNearPoint(obj, x, y, z, obj->GetObjectBoundingRadius(), distance2d + GetObjectBoundingRadius() + obj->GetObjectBoundingRadius(), GetAngle(obj));
} }
virtual float GetObjectBoundingRadius() const { return DEFAULT_WORLD_OBJECT_SIZE; } virtual float GetObjectBoundingRadius() const { return DEFAULT_WORLD_OBJECT_SIZE; }
@ -537,23 +557,23 @@ class MANGOS_DLL_SPEC WorldObject : public Object
virtual void CleanupsBeforeDelete(); // used in destructor or explicitly before mass creature delete to remove cross-references to already deleted units virtual void CleanupsBeforeDelete(); // used in destructor or explicitly before mass creature delete to remove cross-references to already deleted units
virtual void SendMessageToSet(WorldPacket* data, bool self); virtual void SendMessageToSet(WorldPacket* data, bool self) const;
virtual void SendMessageToSetInRange(WorldPacket* data, float dist, bool self); virtual void SendMessageToSetInRange(WorldPacket* data, float dist, bool self) const;
void SendMessageToSetExcept(WorldPacket* data, Player const* skipped_receiver); void SendMessageToSetExcept(WorldPacket* data, Player const* skipped_receiver) const;
void MonsterSay(const char* text, uint32 language, Unit* target = NULL); void MonsterSay(const char* text, uint32 language, Unit const* target = NULL) const;
void MonsterYell(const char* text, uint32 language, Unit* target = NULL); void MonsterYell(const char* text, uint32 language, Unit const* target = NULL) const;
void MonsterTextEmote(const char* text, Unit* target, bool IsBossEmote = false); void MonsterTextEmote(const char* text, Unit const* target, bool IsBossEmote = false) const;
void MonsterWhisper(const char* text, Unit* target, bool IsBossWhisper = false); void MonsterWhisper(const char* text, Unit const* target, bool IsBossWhisper = false) const;
void MonsterSay(int32 textId, uint32 language, Unit* target = NULL); void MonsterSay(int32 textId, uint32 language, Unit const* target = NULL) const;
void MonsterYell(int32 textId, uint32 language, Unit* target = NULL); void MonsterYell(int32 textId, uint32 language, Unit const* target = NULL) const;
void MonsterTextEmote(int32 textId, Unit* target, bool IsBossEmote = false); void MonsterTextEmote(int32 textId, Unit const* target, bool IsBossEmote = false) const;
void MonsterWhisper(int32 textId, Unit* receiver, bool IsBossWhisper = false); void MonsterWhisper(int32 textId, Unit const* receiver, bool IsBossWhisper = false) const;
void MonsterYellToZone(int32 textId, uint32 language, Unit* target); void MonsterYellToZone(int32 textId, uint32 language, Unit const* target) const;
static void BuildMonsterChat(WorldPacket* data, ObjectGuid senderGuid, uint8 msgtype, char const* text, uint32 language, char const* name, ObjectGuid targetGuid, char const* targetName); static void BuildMonsterChat(WorldPacket* data, ObjectGuid senderGuid, uint8 msgtype, char const* text, uint32 language, char const* name, ObjectGuid targetGuid, char const* targetName);
void PlayDistanceSound(uint32 sound_id, Player* target = NULL); void PlayDistanceSound(uint32 sound_id, Player const* target = NULL) const;
void PlayDirectSound(uint32 sound_id, Player* target = NULL); void PlayDirectSound(uint32 sound_id, Player const* target = NULL) const;
void SendObjectDeSpawnAnim(ObjectGuid guid); void SendObjectDeSpawnAnim(ObjectGuid guid);
void SendGameObjectCustomAnim(ObjectGuid guid, uint32 animId = 0); void SendGameObjectCustomAnim(ObjectGuid guid, uint32 animId = 0);

View file

@ -153,7 +153,8 @@ ObjectMgr::ObjectMgr() :
m_MailIds("Mail ids"), m_MailIds("Mail ids"),
m_PetNumbers("Pet numbers"), m_PetNumbers("Pet numbers"),
m_FirstTemporaryCreatureGuid(1), m_FirstTemporaryCreatureGuid(1),
m_FirstTemporaryGameObjectGuid(1) m_FirstTemporaryGameObjectGuid(1),
DBCLocaleIndex(LOCALE_enUS)
{ {
} }
@ -7655,7 +7656,27 @@ void ObjectMgr::LoadGameObjectForQuests()
sLog.outString(">> Loaded %u GameObjects for quests", count); sLog.outString(">> Loaded %u GameObjects for quests", count);
} }
bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value) inline void _DoStringError(int32 entry, char const* text, ...)
{
MANGOS_ASSERT(text);
char buf[256];
va_list ap;
va_start(ap, text);
vsnprintf(buf, 256, text, ap);
va_end(ap);
if (entry <= MAX_CREATURE_AI_TEXT_STRING_ID) // script library error
sLog.outErrorScriptLib("%s", buf);
else if (entry <= MIN_CREATURE_AI_TEXT_STRING_ID) // eventAI error
sLog.outErrorEventAI("%s", buf);
else if (entry < MIN_DB_SCRIPT_STRING_ID) // mangos string error
sLog.outError("%s", buf);
else // if (entry > MIN_DB_SCRIPT_STRING_ID) // DB script text error
sLog.outErrorDb("DB-SCRIPTS: %s", buf);
}
bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value, bool extra_content)
{ {
int32 start_value = min_value; int32 start_value = min_value;
int32 end_value = max_value; int32 end_value = max_value;
@ -7691,8 +7712,10 @@ bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, int32 min
++itr; ++itr;
} }
QueryResult* result = db.PQuery("SELECT entry,content_default,content_loc1,content_loc2,content_loc3,content_loc4,content_loc5,content_loc6,content_loc7,content_loc8 FROM %s", table); sLog.outString("Loading texts from %s%s", table, extra_content ? ", with additional data" : "");
QueryResult* result = db.PQuery("SELECT entry,content_default,content_loc1,content_loc2,content_loc3,content_loc4,content_loc5,content_loc6,content_loc7,content_loc8 %s FROM %s",
extra_content ? ",sound,type,language,emote" : "", table);
if (!result) if (!result)
{ {
BarGoLink bar(1); BarGoLink bar(1);
@ -7720,12 +7743,12 @@ bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, int32 min
if (entry == 0) if (entry == 0)
{ {
sLog.outErrorDb("Table `%s` contain reserved entry 0, ignored.", table); _DoStringError(start_value, "Table `%s` contain reserved entry 0, ignored.", table);
continue; continue;
} }
else if (entry < start_value || entry >= end_value) else if (entry < start_value || entry >= end_value)
{ {
sLog.outErrorDb("Table `%s` contain entry %i out of allowed range (%d - %d), ignored.", table, entry, min_value, max_value); _DoStringError(start_value, "Table `%s` contain entry %i out of allowed range (%d - %d), ignored.", table, entry, min_value, max_value);
continue; continue;
} }
@ -7733,7 +7756,7 @@ bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, int32 min
if (!data.Content.empty()) if (!data.Content.empty())
{ {
sLog.outErrorDb("Table `%s` contain data for already loaded entry %i (from another table?), ignored.", table, entry); _DoStringError(entry, "Table `%s` contain data for already loaded entry %i (from another table?), ignored.", table, entry);
continue; continue;
} }
@ -7759,6 +7782,39 @@ bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, int32 min
} }
} }
} }
// Load additional string content if necessary
if (extra_content)
{
data.SoundId = fields[10].GetUInt32();
data.Type = fields[11].GetUInt32();
data.Language = fields[12].GetUInt32();
data.Emote = fields[13].GetUInt32();
if (data.SoundId && !sSoundEntriesStore.LookupEntry(data.SoundId))
{
_DoStringError(entry, "Entry %i in table `%s` has soundId %u but sound does not exist.", entry, table, data.SoundId);
data.SoundId = 0;
}
if (!GetLanguageDescByID(data.Language))
{
_DoStringError(entry, "Entry %i in table `%s` using Language %u but Language does not exist.", entry, table, data.Language);
data.Language = LANG_UNIVERSAL;
}
if (data.Type > CHAT_TYPE_ZONE_YELL)
{
_DoStringError(entry, "Entry %i in table `%s` has Type %u but this Chat Type does not exist.", entry, table, data.Type);
data.Type = CHAT_TYPE_SAY;
}
if (data.Emote && !sEmotesStore.LookupEntry(data.Emote))
{
_DoStringError(entry, "Entry %i in table `%s` has Emote %u but emote does not exist.", entry, table, data.Emote);
data.Emote = EMOTE_ONESHOT_NONE;
}
}
} }
while (result->NextRow()); while (result->NextRow());
@ -7768,7 +7824,10 @@ bool ObjectMgr::LoadMangosStrings(DatabaseType& db, char const* table, int32 min
if (min_value == MIN_MANGOS_STRING_ID) if (min_value == MIN_MANGOS_STRING_ID)
sLog.outString(">> Loaded %u MaNGOS strings from table %s", count, table); sLog.outString(">> Loaded %u MaNGOS strings from table %s", count, table);
else else
sLog.outString(">> Loaded %u string templates from %s", count, table); sLog.outString(">> Loaded %u %s templates from %s", count, extra_content ? "text" : "string", table);
sLog.outString();
m_loadedStringCount[min_value] = count;
return true; return true;
} }
@ -7785,14 +7844,7 @@ const char* ObjectMgr::GetMangosString(int32 entry, int locale_idx) const
return msl->Content[0].c_str(); return msl->Content[0].c_str();
} }
if (entry > MIN_DB_SCRIPT_STRING_ID) _DoStringError(entry, "Entry %i not found but requested", entry);
sLog.outErrorDb("Entry %i not found in `db_script_string` table.", entry);
else if (entry > 0)
sLog.outErrorDb("Entry %i not found in `mangos_string` table.", entry);
else if (entry > MAX_CREATURE_AI_TEXT_STRING_ID)
sLog.outErrorEventAI("Entry %i not found in `creature_ai_texts` table.", entry);
else
sLog.outErrorScriptLib("String entry %i not found in Database.", entry);
return "<error>"; return "<error>";
} }
@ -9816,7 +9868,7 @@ void ObjectMgr::GetNpcTextLocaleStrings0(uint32 entry, int32 loc_idx, std::strin
} }
// Functions for scripting access // Functions for scripting access
bool LoadMangosStrings(DatabaseType& db, char const* table, int32 start_value, int32 end_value) bool LoadMangosStrings(DatabaseType& db, char const* table, int32 start_value, int32 end_value, bool extra_content)
{ {
// MAX_DB_SCRIPT_STRING_ID is max allowed negative value for scripts (scrpts can use only more deep negative values // MAX_DB_SCRIPT_STRING_ID is max allowed negative value for scripts (scrpts can use only more deep negative values
// start/end reversed for negative values // start/end reversed for negative values
@ -9826,7 +9878,7 @@ bool LoadMangosStrings(DatabaseType& db, char const* table, int32 start_value, i
return false; return false;
} }
return sObjectMgr.LoadMangosStrings(db, table, start_value, end_value); return sObjectMgr.LoadMangosStrings(db, table, start_value, end_value, extra_content);
} }
void ObjectMgr::LoadCreatureTemplateSpells() void ObjectMgr::LoadCreatureTemplateSpells()
@ -9854,6 +9906,11 @@ void ObjectMgr::LoadCreatureTemplateSpells()
} }
} }
MangosStringLocale const* GetMangosStringData(int32 entry)
{
return sObjectMgr.GetMangosStringLocale(entry);
}
CreatureInfo const* GetCreatureTemplateStore(uint32 entry) CreatureInfo const* GetCreatureTemplateStore(uint32 entry)
{ {
return sCreatureStorage.LookupEntry<CreatureInfo>(entry); return sCreatureStorage.LookupEntry<CreatureInfo>(entry);
@ -9903,6 +9960,87 @@ bool FindCreatureData::operator()(CreatureDataPair const& dataPair)
return false; return false;
} }
bool DoDisplayText(WorldObject* source, int32 entry, Unit const* target /*=NULL*/)
{
MangosStringLocale const* data = sObjectMgr.GetMangosStringLocale(entry);
if (!data)
{
_DoStringError(entry, "DoScriptText with source %s could not find text entry %i.", source->GetGuidStr().c_str(), entry);
return false;
}
if (data->SoundId)
{
if (data->Type == CHAT_TYPE_ZONE_YELL)
source->GetMap()->PlayDirectSoundToMap(data->SoundId, source->GetZoneId());
else if (data->Type == CHAT_TYPE_WHISPER || data->Type == CHAT_TYPE_BOSS_WHISPER)
{
// An error will be displayed for the text
if (target && target->GetTypeId() == TYPEID_PLAYER)
source->PlayDirectSound(data->SoundId, (Player const*)target);
}
else
source->PlayDirectSound(data->SoundId);
}
if (data->Emote)
{
if (source->GetTypeId() == TYPEID_UNIT || source->GetTypeId() == TYPEID_PLAYER)
{
((Unit*)source)->HandleEmote(data->Emote);
}
else
{
_DoStringError(entry, "DoDisplayText entry %i tried to process emote for invalid source %s", entry, source->GetGuidStr().c_str());
return false;
}
}
switch (data->Type)
{
case CHAT_TYPE_SAY:
source->MonsterSay(entry, data->Language, target);
break;
case CHAT_TYPE_YELL:
source->MonsterYell(entry, data->Language, target);
break;
case CHAT_TYPE_TEXT_EMOTE:
source->MonsterTextEmote(entry, target);
break;
case CHAT_TYPE_BOSS_EMOTE:
source->MonsterTextEmote(entry, target, true);
break;
case CHAT_TYPE_WHISPER:
{
if (target && target->GetTypeId() == TYPEID_PLAYER)
source->MonsterWhisper(entry, target);
else
{
_DoStringError(entry, "DoDisplayText entry %i cannot whisper without target unit (TYPEID_PLAYER).", entry);
return false;
}
break;
}
case CHAT_TYPE_BOSS_WHISPER:
{
if (target && target->GetTypeId() == TYPEID_PLAYER)
source->MonsterWhisper(entry, target, true);
else
{
_DoStringError(entry, "DoDisplayText entry %i cannot whisper without target unit (TYPEID_PLAYER).", entry);
return false;
}
break;
}
case CHAT_TYPE_ZONE_YELL:
source->MonsterYellToZone(entry, data->Language, target);
break;
}
return true;
}
CreatureDataPair const* FindCreatureData::GetResult() const CreatureDataPair const* FindCreatureData::GetResult() const
{ {
if (i_spawnedData) if (i_spawnedData)

View file

@ -128,7 +128,13 @@ static_assert(MAX_DB_SCRIPT_STRING_ID < ACE_INT32_MAX, "Must scope with int32 ra
struct MangosStringLocale struct MangosStringLocale
{ {
MangosStringLocale() : SoundId(0), Type(0), Language(0), Emote(0) { }
std::vector<std::string> Content; // 0 -> default, i -> i-1 locale index std::vector<std::string> Content; // 0 -> default, i -> i-1 locale index
uint32 SoundId;
uint8 Type;
uint32 Language;
uint32 Emote; // 0 -> default, i -> i-1 locale index
}; };
typedef UNORDERED_MAP<uint32, CreatureData> CreatureDataMap; typedef UNORDERED_MAP<uint32, CreatureData> CreatureDataMap;
@ -705,8 +711,8 @@ class ObjectMgr
void LoadCreatureQuestRelations(); void LoadCreatureQuestRelations();
void LoadCreatureInvolvedRelations(); void LoadCreatureInvolvedRelations();
bool LoadMangosStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value); bool LoadMangosStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value, bool extra_content);
bool LoadMangosStrings() { return LoadMangosStrings(WorldDatabase, "mangos_string", MIN_MANGOS_STRING_ID, MAX_MANGOS_STRING_ID); } bool LoadMangosStrings() { return LoadMangosStrings(WorldDatabase, "mangos_string", MIN_MANGOS_STRING_ID, MAX_MANGOS_STRING_ID, false); }
void LoadCreatureLocales(); void LoadCreatureLocales();
void LoadCreatureTemplates(); void LoadCreatureTemplates();
void LoadCreatures(); void LoadCreatures();
@ -956,6 +962,14 @@ class ObjectMgr
return &itr->second; return &itr->second;
} }
uint32 GetLoadedStringsCount(int32 minEntry) const
{
std::map<int32, uint32>::const_iterator itr = m_loadedStringCount.find(minEntry);
if (itr != m_loadedStringCount.end())
return itr->second;
return 0;
}
const char* GetMangosString(int32 entry, int locale_idx) const; const char* GetMangosString(int32 entry, int locale_idx) const;
const char* GetMangosStringForDBCLocale(int32 entry) const { return GetMangosString(entry, DBCLocaleIndex); } const char* GetMangosStringForDBCLocale(int32 entry) const { return GetMangosString(entry, DBCLocaleIndex); }
int32 GetDBCLocaleIndex() const { return DBCLocaleIndex; } int32 GetDBCLocaleIndex() const { return DBCLocaleIndex; }
@ -1264,6 +1278,7 @@ class ObjectMgr
NpcTextLocaleMap mNpcTextLocaleMap; NpcTextLocaleMap mNpcTextLocaleMap;
PageTextLocaleMap mPageTextLocaleMap; PageTextLocaleMap mPageTextLocaleMap;
MangosStringLocaleMap mMangosStringLocaleMap; MangosStringLocaleMap mMangosStringLocaleMap;
std::map<int32 /*minEntryOfBracket*/, uint32 /*count*/> m_loadedStringCount;
GossipMenuItemsLocaleMap mGossipMenuItemsLocaleMap; GossipMenuItemsLocaleMap mGossipMenuItemsLocaleMap;
PointOfInterestLocaleMap mPointOfInterestLocaleMap; PointOfInterestLocaleMap mPointOfInterestLocaleMap;
DungeonEncounterMap m_DungeonEncounters; DungeonEncounterMap m_DungeonEncounters;
@ -1281,9 +1296,13 @@ class ObjectMgr
#define sObjectMgr MaNGOS::Singleton<ObjectMgr>::Instance() #define sObjectMgr MaNGOS::Singleton<ObjectMgr>::Instance()
/// generic text function
MANGOS_DLL_SPEC bool DoDisplayText(WorldObject* source, int32 entry, Unit const* target = NULL);
// scripting access functions // scripting access functions
MANGOS_DLL_SPEC bool LoadMangosStrings(DatabaseType& db, char const* table, int32 start_value = MAX_CREATURE_AI_TEXT_STRING_ID, int32 end_value = std::numeric_limits<int32>::min()); MANGOS_DLL_SPEC bool LoadMangosStrings(DatabaseType& db, char const* table, int32 start_value = MAX_CREATURE_AI_TEXT_STRING_ID, int32 end_value = std::numeric_limits<int32>::min(), bool extra_content = false);
MANGOS_DLL_SPEC CreatureInfo const* GetCreatureTemplateStore(uint32 entry); MANGOS_DLL_SPEC CreatureInfo const* GetCreatureTemplateStore(uint32 entry);
MANGOS_DLL_SPEC Quest const* GetQuestTemplateStore(uint32 entry); MANGOS_DLL_SPEC Quest const* GetQuestTemplateStore(uint32 entry);
MANGOS_DLL_SPEC MangosStringLocale const* GetMangosStringData(int32 entry);
#endif #endif

View file

@ -19,20 +19,25 @@
#include "ObjectPosSelector.h" #include "ObjectPosSelector.h"
#include "Object.h" #include "Object.h"
ObjectPosSelector::ObjectPosSelector(float x, float y, float dist, float searcher_size) : // The bigger this value, the more space npcs require around their target
m_centerX(x), m_centerY(y), m_searcherDist(dist), m_searcherSize(searcher_size) #define OCCUPY_POS_ANGLE_ATAN_FACTOR 1.8f
ObjectPosSelector::ObjectPosSelector(float x, float y, float dist, float searchedForSize, WorldObject const* searchPosFor) :
m_centerX(x), m_centerY(y), m_searcherDist(dist), m_searchPosFor(searchPosFor)
{ {
// if size == 0, m_anglestep will become 0 -> freeze // if size == 0, m_anglestep will become 0 -> freeze
if (m_searcherSize == 0.0f) if (searchedForSize == 0.0f)
m_searcherSize = DEFAULT_WORLD_OBJECT_SIZE; searchedForSize = DEFAULT_WORLD_OBJECT_SIZE;
m_searcherHalfSize = asin(m_searcherSize / m_searcherDist); // undefined behaviour
if (m_searcherDist == 0.0f)
m_searcherDist = DEFAULT_WORLD_OBJECT_SIZE;
m_searchedForReqHAngle = atan(OCCUPY_POS_ANGLE_ATAN_FACTOR * searchedForSize / m_searcherDist);
// Really init in InitilizeAngle // Really init in InitilizeAngle
m_nextUsedAreaItr[USED_POS_PLUS] = m_UsedAreaLists[USED_POS_PLUS].begin(); m_nextUsedAreaItr[USED_POS_PLUS] = m_UsedAreaLists[USED_POS_PLUS].begin();
m_nextUsedAreaItr[USED_POS_MINUS] = m_UsedAreaLists[USED_POS_MINUS].begin(); m_nextUsedAreaItr[USED_POS_MINUS] = m_UsedAreaLists[USED_POS_MINUS].begin();
m_nextUsedAreaStart[USED_POS_PLUS] = 0.0f;
m_nextUsedAreaStart[USED_POS_MINUS] = 0.0f;
m_stepAngle[USED_POS_PLUS] = 0.0f; m_stepAngle[USED_POS_PLUS] = 0.0f;
m_stepAngle[USED_POS_MINUS] = 0.0f; m_stepAngle[USED_POS_MINUS] = 0.0f;
} }
@ -41,27 +46,27 @@ ObjectPosSelector::ObjectPosSelector(float x, float y, float dist, float searche
* Add used area (circle) near target object excluded from possible searcher position * Add used area (circle) near target object excluded from possible searcher position
* *
* *
* @param size Size of used circle * @param obj Object that occupies area
* @param angle Angle of used circle center point from target-searcher line * @param angle Angle of used circle center point from target-searcher line
* @param dist Distance from target object center point to used circle center point * @param dist Distance from target object center point to used circle center point
* *
* Used circles data stored as projections to searcher dist size circle as angle coordinate and half angle size * Used circles data stored as projections to searcher dist size circle as angle coordinate and half angle size
*/ */
void ObjectPosSelector::AddUsedArea(float size, float angle, float dist) void ObjectPosSelector::AddUsedArea(WorldObject const* obj, float angle, float dist)
{ {
float sr_dist = size + m_searcherSize; MANGOS_ASSERT(obj);
// by Law of cosines, angle of searcher/used centers
float sr_angle = acos((m_searcherDist * m_searcherDist + dist * dist - sr_dist * sr_dist) / (2 * m_searcherDist * dist));
// skip some unexpected results. // skip some unexpected results.
if (!finite(sr_angle) || sr_angle <= 0) if (dist == 0.0f)
return; return;
// (half) angle that obj occupies
float sr_angle = atan(OCCUPY_POS_ANGLE_ATAN_FACTOR * obj->GetObjectBoundingRadius() / dist);
if (angle >= 0) if (angle >= 0)
m_UsedAreaLists[USED_POS_PLUS].insert(UsedArea(angle, sr_angle)); m_UsedAreaLists[USED_POS_PLUS].insert(UsedArea(angle, OccupiedArea(sr_angle, obj)));
else else
m_UsedAreaLists[USED_POS_MINUS].insert(UsedArea(-angle, sr_angle)); m_UsedAreaLists[USED_POS_MINUS].insert(UsedArea(-angle, OccupiedArea(sr_angle, obj)));
} }
/** /**
@ -75,23 +80,10 @@ void ObjectPosSelector::AddUsedArea(float size, float angle, float dist)
*/ */
bool ObjectPosSelector::CheckAngle(UsedArea const& usedArea, UsedAreaSide side, float angle) const bool ObjectPosSelector::CheckAngle(UsedArea const& usedArea, UsedAreaSide side, float angle) const
{ {
float used_offset = usedArea.second.angleOffset;
float used_angle = usedArea.first * SignOf(side); float used_angle = usedArea.first * SignOf(side);
float used_offset = usedArea.second; // check first left/right used angles if exists
return fabs(used_angle - angle) > used_offset || (m_searchPosFor && usedArea.second.occupyingObj == m_searchPosFor);
return fabs(used_angle - angle) > used_offset;
}
/**
* Check searcher circle not intercepting with used circle at side (only start angle provided)
*
* @param side Side of used circle
* @param angle Checked angle at side, positive always
*
* @return true, if used circle not intercepted with searcher circle in terms projection angles
*/
bool ObjectPosSelector::CheckSideAngle(UsedAreaSide side, float angle) const
{
return angle + m_searcherHalfSize < m_nextUsedAreaStart[side];
} }
/** /**
@ -121,53 +113,17 @@ void ObjectPosSelector::InitializeAngle()
void ObjectPosSelector::InitializeAngle(UsedAreaSide side) void ObjectPosSelector::InitializeAngle(UsedAreaSide side)
{ {
m_nextUsedAreaItr[side] = m_UsedAreaLists[side].begin(); m_nextUsedAreaItr[side] = m_UsedAreaLists[side].begin();
UpdateNextAreaStart(side); // if another side not alow use 0.0f angle calculate possible value in 0..m_searchedForReqHAngle range
// if another side not alow use 0.0f angle calculate possible value in 0..m_searcherHalfSize range
if (!m_UsedAreaLists[~side].empty()) if (!m_UsedAreaLists[~side].empty())
{ {
UsedArea const& otherArea = *m_UsedAreaLists[~side].begin(); UsedArea const& otherArea = *m_UsedAreaLists[~side].begin();
m_stepAngle[side] = std::max(m_searchedForReqHAngle + otherArea.second.angleOffset - otherArea.first, 0.0f);
// if other are near start }
if (otherArea.first < otherArea.second) else // Other side empty. start from 0
m_stepAngle[side] = otherArea.second - otherArea.first;
else
m_stepAngle[side] = 0.0f; m_stepAngle[side] = 0.0f;
}
else
m_stepAngle[side] = 0.0f;
}
/** // As m_stepAngle will be incremented first in ::NextSideAngle
* Update next used area start angle for current m_nextUsedAreaItr value at side m_stepAngle[side] -= m_searchedForReqHAngle;
*/
void ObjectPosSelector::UpdateNextAreaStart(UsedAreaSide side)
{
// not last next area at side
if (m_nextUsedAreaItr[side] != m_UsedAreaLists[side].end())
{
m_nextUsedAreaStart[side] = m_nextUsedAreaItr[side]->first - m_nextUsedAreaItr[side]->second + m_searcherHalfSize;
return;
}
// last area at side and not another side areas
if (m_UsedAreaLists[~side].empty())
{
m_nextUsedAreaStart[side] = M_PI_F + m_searcherHalfSize + 0.01f;
return;
}
UsedArea const& lastArea = *m_UsedAreaLists[~side].rbegin();
// another side have used area near to end (near to PI)
if (lastArea.first + lastArea.second > M_PI_F - m_searcherHalfSize)
{
m_nextUsedAreaStart[side] = M_PI_F + (M_PI_F - lastArea.first - lastArea.second) + m_searcherHalfSize;
return;
}
// last area and fail find any used area at another side, prepare fake data as stopper
m_nextUsedAreaStart[side] = M_PI_F + m_searcherHalfSize + 0.01f;
} }
/** /**
@ -215,33 +171,34 @@ bool ObjectPosSelector::NextAngle(float& angle)
bool ObjectPosSelector::NextSideAngle(UsedAreaSide side, float& angle) bool ObjectPosSelector::NextSideAngle(UsedAreaSide side, float& angle)
{ {
// next possible angle // next possible angle
m_stepAngle[side] += (m_searcherHalfSize + 0.01); m_stepAngle[side] += (m_searchedForReqHAngle + 0.01);
// prevent jump to another side // prevent jump to another side
if (m_stepAngle[side] > M_PI_F) if (m_stepAngle[side] > M_PI_F)
return false; return false;
// update angle at attempt jump after next used area // no used area anymore on this side
while (m_stepAngle[side] <= M_PI_F && m_stepAngle[side] + m_searcherHalfSize >= m_nextUsedAreaStart[side])
{
// no used area for pass
if (m_nextUsedAreaItr[side] == m_UsedAreaLists[side].end()) if (m_nextUsedAreaItr[side] == m_UsedAreaLists[side].end())
{ {
m_stepAngle[side] = M_PI_F + m_searcherHalfSize;// prevent continue search at side angle = m_stepAngle[side] * SignOf(side);
return false; return true;
}
// Already occupied and no better found
if ((m_searchPosFor && m_nextUsedAreaItr[side]->second.occupyingObj == m_searchPosFor) ||
// Next occupied is too far away
(m_stepAngle[side] + m_searchedForReqHAngle < m_nextUsedAreaItr[side]->first - m_nextUsedAreaItr[side]->second.angleOffset))
{
angle = m_stepAngle[side] * SignOf(side);
return true;
} }
// angle set at first possible pos after passed m_nextUsedAreaItr // angle set at first possible pos after passed m_nextUsedAreaItr
m_stepAngle[side] = m_nextUsedAreaItr[side]->first + m_nextUsedAreaItr[side]->second; m_stepAngle[side] = m_nextUsedAreaItr[side]->first + m_nextUsedAreaItr[side]->second.angleOffset;
++m_nextUsedAreaItr[side]; ++m_nextUsedAreaItr[side];
UpdateNextAreaStart(side);
}
angle = m_stepAngle[side] * SignOf(side); return false;
// if next node not allow use selected angle, mark and fail
return CheckSideAngle(side, m_stepAngle[side]);
} }
/** /**

View file

@ -23,6 +23,8 @@
#include<map> #include<map>
class WorldObject;
enum UsedAreaSide { USED_POS_PLUS, USED_POS_MINUS }; enum UsedAreaSide { USED_POS_PLUS, USED_POS_MINUS };
inline UsedAreaSide operator ~(UsedAreaSide side) inline UsedAreaSide operator ~(UsedAreaSide side)
@ -37,12 +39,19 @@ inline float SignOf(UsedAreaSide side)
struct ObjectPosSelector struct ObjectPosSelector
{ {
typedef std::multimap<float, float> UsedAreaList; // angle pos -> angle offset struct OccupiedArea
{
OccupiedArea(float _angleOffset, WorldObject const* obj) : angleOffset(_angleOffset), occupyingObj(obj) {}
float angleOffset;
WorldObject const* occupyingObj;
};
// angle pos -> OccupiedArea
typedef std::multimap<float, OccupiedArea> UsedAreaList;
typedef UsedAreaList::value_type UsedArea; typedef UsedAreaList::value_type UsedArea;
ObjectPosSelector(float x, float y, float dist, float searcher_size); ObjectPosSelector(float x, float y, float dist, float searchedForSize, WorldObject const* searchPosFor);
void AddUsedArea(float size, float angle, float dist); void AddUsedArea(WorldObject const* obj, float angle, float dist);
bool CheckOriginalAngle() const; bool CheckOriginalAngle() const;
@ -52,22 +61,20 @@ struct ObjectPosSelector
bool NextUsedAngle(float& angle); bool NextUsedAngle(float& angle);
bool CheckAngle(UsedArea const& usedArea, UsedAreaSide side, float angle) const; bool CheckAngle(UsedArea const& usedArea, UsedAreaSide side, float angle) const;
bool CheckSideAngle(UsedAreaSide side, float angle) const;
void InitializeAngle(UsedAreaSide side); void InitializeAngle(UsedAreaSide side);
void UpdateNextAreaStart(UsedAreaSide side);
bool NextSideAngle(UsedAreaSide side, float& angle); bool NextSideAngle(UsedAreaSide side, float& angle);
float m_centerX; float m_centerX;
float m_centerY; float m_centerY;
float m_searcherDist; // distance for searching pos (including searcher size and target object size) float m_searcherDist; // distance for searching pos
float m_searcherSize; // searcher object radius float m_searchedForReqHAngle; // angle size/2 of searcher object (at dist distance)
float m_searcherHalfSize; // angle size/2 of searcher object (at dist distance)
UsedAreaList m_UsedAreaLists[2]; // list left/right side used angles (with angle size) UsedAreaList m_UsedAreaLists[2]; // list left/right side used angles (with angle size)
UsedAreaList::const_iterator m_nextUsedAreaItr[2]; // next used used areas for check at left/right side, possible angles selected in range m_smallStepAngle..m_nextUsedAreaItr UsedAreaList::const_iterator m_nextUsedAreaItr[2]; // next used used areas for check at left/right side, possible angles selected in range m_smallStepAngle..m_nextUsedAreaItr
float m_nextUsedAreaStart[2]; // cached angle for next used area from m_nextUsedAreaItr or another side
float m_stepAngle[2]; // current checked angle position at sides (less m_nextUsedArea), positive value float m_stepAngle[2]; // current checked angle position at sides (less m_nextUsedArea), positive value
WorldObject const* m_searchPosFor; // For whom a position is searched (can be NULL)
}; };
#endif #endif

View file

@ -162,6 +162,15 @@ class MANGOS_DLL_SPEC Pet : public Creature
return m_autospells[pos]; return m_autospells[pos];
} }
bool CanSwim() const override
{
Unit const* owner = GetOwner();
if (owner)
return owner->GetTypeId() == TYPEID_PLAYER ? true : ((Creature const*)owner)->CanSwim();
else
return Creature::CanSwim();
}
void RegenerateAll(uint32 update_diff) override; // overwrite Creature::RegenerateAll void RegenerateAll(uint32 update_diff) override; // overwrite Creature::RegenerateAll
void Regenerate(Powers power); void Regenerate(Powers power);
void GivePetXP(uint32 xp); void GivePetXP(uint32 xp);

View file

@ -5005,6 +5005,7 @@ void Player::RepopAtGraveyard()
// and don't show spirit healer location // and don't show spirit healer location
if (ClosestGrave) if (ClosestGrave)
{ {
bool updateVisibility = IsInWorld() && GetMapId() == ClosestGrave->map_id;
TeleportTo(ClosestGrave->map_id, ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, GetOrientation()); TeleportTo(ClosestGrave->map_id, ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, GetOrientation());
if (isDead()) // not send if alive, because it used in TeleportTo() if (isDead()) // not send if alive, because it used in TeleportTo()
{ {
@ -5015,6 +5016,8 @@ void Player::RepopAtGraveyard()
data << ClosestGrave->z; data << ClosestGrave->z;
GetSession()->SendPacket(&data); GetSession()->SendPacket(&data);
} }
if (updateVisibility && IsInWorld())
UpdateVisibilityAndView();
} }
} }
@ -6191,7 +6194,7 @@ void Player::SaveRecallPosition()
m_recallO = GetOrientation(); m_recallO = GetOrientation();
} }
void Player::SendMessageToSet(WorldPacket* data, bool self) void Player::SendMessageToSet(WorldPacket* data, bool self) const
{ {
if (IsInWorld()) if (IsInWorld())
GetMap()->MessageBroadcast(this, data, false); GetMap()->MessageBroadcast(this, data, false);
@ -6202,7 +6205,7 @@ void Player::SendMessageToSet(WorldPacket* data, bool self)
GetSession()->SendPacket(data); GetSession()->SendPacket(data);
} }
void Player::SendMessageToSetInRange(WorldPacket* data, float dist, bool self) void Player::SendMessageToSetInRange(WorldPacket* data, float dist, bool self) const
{ {
if (IsInWorld()) if (IsInWorld())
GetMap()->MessageDistBroadcast(this, data, dist, false); GetMap()->MessageDistBroadcast(this, data, dist, false);
@ -6211,7 +6214,7 @@ void Player::SendMessageToSetInRange(WorldPacket* data, float dist, bool self)
GetSession()->SendPacket(data); GetSession()->SendPacket(data);
} }
void Player::SendMessageToSetInRange(WorldPacket* data, float dist, bool self, bool own_team_only) void Player::SendMessageToSetInRange(WorldPacket* data, float dist, bool self, bool own_team_only) const
{ {
if (IsInWorld()) if (IsInWorld())
GetMap()->MessageDistBroadcast(this, data, dist, false, own_team_only); GetMap()->MessageDistBroadcast(this, data, dist, false, own_team_only);
@ -6220,7 +6223,7 @@ void Player::SendMessageToSetInRange(WorldPacket* data, float dist, bool self, b
GetSession()->SendPacket(data); GetSession()->SendPacket(data);
} }
void Player::SendDirectMessage(WorldPacket* data) void Player::SendDirectMessage(WorldPacket* data) const
{ {
GetSession()->SendPacket(data); GetSession()->SendPacket(data);
} }
@ -13394,6 +13397,11 @@ Quest const* Player::GetNextQuest(ObjectGuid guid, Quest const* pQuest)
return NULL; return NULL;
} }
/**
* Check if a player could see a start quest
* Basic Quest-taking requirements: Class, Race, Skill, Quest-Line, ...
* Check if the quest-level is not too high (related config value CONFIG_INT32_QUEST_HIGH_LEVEL_HIDE_DIFF)
*/
bool Player::CanSeeStartQuest(Quest const* pQuest) const bool Player::CanSeeStartQuest(Quest const* pQuest) const
{ {
if (SatisfyQuestClass(pQuest, false) && SatisfyQuestRace(pQuest, false) && SatisfyQuestSkill(pQuest, false) && if (SatisfyQuestClass(pQuest, false) && SatisfyQuestRace(pQuest, false) && SatisfyQuestSkill(pQuest, false) &&
@ -13403,7 +13411,10 @@ bool Player::CanSeeStartQuest(Quest const* pQuest) const
SatisfyQuestMonth(pQuest, false) && SatisfyQuestMonth(pQuest, false) &&
pQuest->IsActive()) pQuest->IsActive())
{ {
return int32(getLevel()) + sWorld.getConfig(CONFIG_INT32_QUEST_HIGH_LEVEL_HIDE_DIFF) >= int32(pQuest->GetMinLevel()); int32 highLevelDiff = sWorld.getConfig(CONFIG_INT32_QUEST_HIGH_LEVEL_HIDE_DIFF);
if (highLevelDiff < 0)
return true;
return getLevel() + uint32(highLevelDiff) >= pQuest->GetMinLevel();
} }
return false; return false;

View file

@ -1863,10 +1863,10 @@ class MANGOS_DLL_SPEC Player : public Unit
bool SetPosition(float x, float y, float z, float orientation, bool teleport = false); bool SetPosition(float x, float y, float z, float orientation, bool teleport = false);
void UpdateUnderwaterState(Map* m, float x, float y, float z); void UpdateUnderwaterState(Map* m, float x, float y, float z);
void SendMessageToSet(WorldPacket* data, bool self) override;// overwrite Object::SendMessageToSet void SendMessageToSet(WorldPacket* data, bool self) const override;// overwrite Object::SendMessageToSet
void SendMessageToSetInRange(WorldPacket* data, float fist, bool self) override; void SendMessageToSetInRange(WorldPacket* data, float fist, bool self) const override;
// overwrite Object::SendMessageToSetInRange // overwrite Object::SendMessageToSetInRange
void SendMessageToSetInRange(WorldPacket* data, float dist, bool self, bool own_team_only); void SendMessageToSetInRange(WorldPacket* data, float dist, bool self, bool own_team_only) const;
Corpse* GetCorpse() const; Corpse* GetCorpse() const;
void SpawnCorpseBones(); void SpawnCorpseBones();
@ -2037,7 +2037,7 @@ class MANGOS_DLL_SPEC Player : public Unit
void SendInitWorldStates(uint32 zone, uint32 area); void SendInitWorldStates(uint32 zone, uint32 area);
void SendUpdateWorldState(uint32 Field, uint32 Value); void SendUpdateWorldState(uint32 Field, uint32 Value);
void SendDirectMessage(WorldPacket* data); void SendDirectMessage(WorldPacket* data) const;
void FillBGWeekendWorldStates(WorldPacket& data, uint32& count); void FillBGWeekendWorldStates(WorldPacket& data, uint32& count);
void SendAurasForTarget(Unit* target); void SendAurasForTarget(Unit* target);

View file

@ -118,7 +118,8 @@ enum __QuestGiverStatus
DIALOG_STATUS_AVAILABLE_REP = 0x080, DIALOG_STATUS_AVAILABLE_REP = 0x080,
DIALOG_STATUS_AVAILABLE = 0x100, DIALOG_STATUS_AVAILABLE = 0x100,
DIALOG_STATUS_REWARD2 = 0x200, // no yellow dot on minimap DIALOG_STATUS_REWARD2 = 0x200, // no yellow dot on minimap
DIALOG_STATUS_REWARD = 0x400 // yellow dot on minimap DIALOG_STATUS_REWARD = 0x400, // yellow dot on minimap
DIALOG_STATUS_UNDEFINED = 0xFFFF, // Used as result for unassigned ScriptCall
}; };
// values based at QuestInfo.dbc // values based at QuestInfo.dbc

View file

@ -501,12 +501,20 @@ void WorldSession::HandleQuestPushResult(WorldPacket& recvPacket)
} }
} }
/**
* What - if any - kind of explanation mark or question-mark should a quest-giver display for a player
* @param pPlayer - for whom
* @param questgiver - from whom
* @param defstatus - initial set status (usually it will be called with DIALOG_STATUS_NONE) - must not be DIALOG_STATUS_UNDEFINED
*/
uint32 WorldSession::getDialogStatus(Player* pPlayer, Object* questgiver, uint32 defstatus) uint32 WorldSession::getDialogStatus(Player* pPlayer, Object* questgiver, uint32 defstatus)
{ {
MANGOS_ASSERT(defstatus != DIALOG_STATUS_UNDEFINED);
uint32 dialogStatus = defstatus; uint32 dialogStatus = defstatus;
QuestRelationsMapBounds rbounds; QuestRelationsMapBounds rbounds; // QuestRelations (quest-giver)
QuestRelationsMapBounds irbounds; QuestRelationsMapBounds irbounds; // InvolvedRelations (quest-finisher)
switch (questgiver->GetTypeId()) switch (questgiver->GetTypeId())
{ {
@ -528,9 +536,10 @@ uint32 WorldSession::getDialogStatus(Player* pPlayer, Object* questgiver, uint32
return DIALOG_STATUS_NONE; return DIALOG_STATUS_NONE;
} }
// Check markings for quest-finisher
for (QuestRelationsMap::const_iterator itr = irbounds.first; itr != irbounds.second; ++itr) for (QuestRelationsMap::const_iterator itr = irbounds.first; itr != irbounds.second; ++itr)
{ {
uint32 dialogStatusNew = 0; uint32 dialogStatusNew = DIALOG_STATUS_NONE;
uint32 quest_id = itr->second; uint32 quest_id = itr->second;
Quest const* pQuest = sObjectMgr.GetQuestTemplate(quest_id); Quest const* pQuest = sObjectMgr.GetQuestTemplate(quest_id);
@ -554,9 +563,10 @@ uint32 WorldSession::getDialogStatus(Player* pPlayer, Object* questgiver, uint32
dialogStatus = dialogStatusNew; dialogStatus = dialogStatusNew;
} }
// check markings for quest-giver
for (QuestRelationsMap::const_iterator itr = rbounds.first; itr != rbounds.second; ++itr) for (QuestRelationsMap::const_iterator itr = rbounds.first; itr != rbounds.second; ++itr)
{ {
uint32 dialogStatusNew = 0; uint32 dialogStatusNew = DIALOG_STATUS_NONE;
uint32 quest_id = itr->second; uint32 quest_id = itr->second;
Quest const* pQuest = sObjectMgr.GetQuestTemplate(quest_id); Quest const* pQuest = sObjectMgr.GetQuestTemplate(quest_id);
@ -565,24 +575,25 @@ uint32 WorldSession::getDialogStatus(Player* pPlayer, Object* questgiver, uint32
QuestStatus status = pPlayer->GetQuestStatus(quest_id); QuestStatus status = pPlayer->GetQuestStatus(quest_id);
if (status == QUEST_STATUS_NONE) if (status == QUEST_STATUS_NONE) // For all other cases the mark is handled either at some place else, or with involved-relations already
{ {
if (pPlayer->CanSeeStartQuest(pQuest)) if (pPlayer->CanSeeStartQuest(pQuest))
{ {
if (pPlayer->SatisfyQuestLevel(pQuest, false)) if (pPlayer->SatisfyQuestLevel(pQuest, false))
{ {
int32 lowLevelDiff = sWorld.getConfig(CONFIG_INT32_QUEST_LOW_LEVEL_HIDE_DIFF);
if (pQuest->IsAutoComplete() || (pQuest->IsRepeatable() && pPlayer->getQuestStatusMap()[quest_id].m_rewarded)) if (pQuest->IsAutoComplete() || (pQuest->IsRepeatable() && pPlayer->getQuestStatusMap()[quest_id].m_rewarded))
{ {
dialogStatusNew = DIALOG_STATUS_REWARD_REP; dialogStatusNew = DIALOG_STATUS_REWARD_REP;
} }
else if (int32(pPlayer->getLevel()) <= int32(pPlayer->GetQuestLevelForPlayer(pQuest)) + sWorld.getConfig(CONFIG_INT32_QUEST_LOW_LEVEL_HIDE_DIFF)) else if (lowLevelDiff < 0 || pPlayer->getLevel() <= pPlayer->GetQuestLevelForPlayer(pQuest) + uint32(lowLevelDiff))
{ {
if (pQuest->HasQuestFlag(QUEST_FLAGS_DAILY) || pQuest->HasQuestFlag(QUEST_FLAGS_WEEKLY)) if (pQuest->HasQuestFlag(QUEST_FLAGS_DAILY) || pQuest->HasQuestFlag(QUEST_FLAGS_WEEKLY))
dialogStatusNew = DIALOG_STATUS_AVAILABLE_REP; dialogStatusNew = DIALOG_STATUS_AVAILABLE_REP;
else else
dialogStatusNew = DIALOG_STATUS_AVAILABLE; dialogStatusNew = DIALOG_STATUS_AVAILABLE;
} }
else else // player level much higher then quest-level
dialogStatusNew = DIALOG_STATUS_LOW_LEVEL_AVAILABLE; dialogStatusNew = DIALOG_STATUS_LOW_LEVEL_AVAILABLE;
} }
else else

View file

@ -36,9 +36,9 @@ const char WorldTemplatesrcfmt[] = "is";
const char WorldTemplatedstfmt[] = "ii"; const char WorldTemplatedstfmt[] = "ii";
const char ConditionsSrcFmt[] = "iiii"; const char ConditionsSrcFmt[] = "iiii";
const char ConditionsDstFmt[] = "iiii"; const char ConditionsDstFmt[] = "iiii";
const char SpellTemplatesrcfmt[] = "iiiiiiiiiiiiiiix"; const char SpellTemplatesrcfmt[] = "iiiiiiiiiiiiiiiix";
// 0 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 185 // 0 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160 170 180 185
const char SpellTemplatedstfmt[] = "ixxxiiixxxxxxxxxxxxxxxxxxxxxxxxxiixxxxixxxxxxFxxxxxxxxxxxxxxxxxxxxxxixxxxxFFFxxxxxxixxixxixxixxxxxFFFxxxxxxixxixxixxFFFxxxxxxxxxxxxxppppppppppppppppppppppppppppppppxxxxxxxxxxxFFFxxxxxx"; const char SpellTemplatedstfmt[] = "ixxxiiiixxxxxxxxxxxxxxxxxxxxxxxxiixxxxixxxxxxFxxxxxxxxxxxxxxxxxxxxxxixxxxxFFFxxxxxxixxixxixxixxxxxFFFxxxxxxixxixxixxFFFxxxxxxxxxxxxxppppppppppppppppppppppppppppppppxxxxxxxxxxxFFFxxxxxx";
// Id attr proc DurationIndex Effect0 tarA0 effectAura0 triggerSpell0 SpellName[16] Rank[16] // Id attr proc DurationIndex Effect0 tarA0 effectAura0 triggerSpell0 SpellName[16] Rank[16]
const char VehicleAccessorySrcFmt[] = "iiix"; const char VehicleAccessorySrcFmt[] = "iiix";
const char VehicleAccessoryDstFmt[] = "iii"; const char VehicleAccessoryDstFmt[] = "iii";

View file

@ -172,7 +172,7 @@ void ScriptMgr::LoadScripts(ScriptMapMapName& scripts, const char* tablename)
tmp.raw.data[0] = fields[3].GetUInt32(); tmp.raw.data[0] = fields[3].GetUInt32();
tmp.raw.data[1] = fields[4].GetUInt32(); tmp.raw.data[1] = fields[4].GetUInt32();
tmp.buddyEntry = fields[5].GetUInt32(); tmp.buddyEntry = fields[5].GetUInt32();
tmp.searchRadius = fields[6].GetUInt32(); tmp.searchRadiusOrGuid = fields[6].GetUInt32();
tmp.data_flags = fields[7].GetUInt8(); tmp.data_flags = fields[7].GetUInt8();
tmp.textId[0] = fields[8].GetInt32(); tmp.textId[0] = fields[8].GetInt32();
tmp.textId[1] = fields[9].GetInt32(); tmp.textId[1] = fields[9].GetInt32();
@ -184,7 +184,7 @@ void ScriptMgr::LoadScripts(ScriptMapMapName& scripts, const char* tablename)
tmp.o = fields[15].GetFloat(); tmp.o = fields[15].GetFloat();
// generic command args check // generic command args check
if (tmp.buddyEntry) // Check Buddy args if (tmp.buddyEntry && !(tmp.data_flags & SCRIPT_FLAG_BUDDY_BY_GUID))
{ {
if (tmp.IsCreatureBuddy() && !ObjectMgr::GetCreatureTemplate(tmp.buddyEntry)) if (tmp.IsCreatureBuddy() && !ObjectMgr::GetCreatureTemplate(tmp.buddyEntry))
{ {
@ -196,7 +196,7 @@ void ScriptMgr::LoadScripts(ScriptMapMapName& scripts, const char* tablename)
sLog.outErrorDb("Table `%s` has buddyEntry = %u in command %u for script id %u, but this gameobject_template does not exist, skipping.", tablename, tmp.buddyEntry, tmp.command, tmp.id); sLog.outErrorDb("Table `%s` has buddyEntry = %u in command %u for script id %u, but this gameobject_template does not exist, skipping.", tablename, tmp.buddyEntry, tmp.command, tmp.id);
continue; continue;
} }
if (!tmp.searchRadius) if (!tmp.searchRadiusOrGuid)
{ {
sLog.outErrorDb("Table `%s` has searchRadius = 0 in command %u for script id %u for buddy %u, skipping.", tablename, tmp.command, tmp.id, tmp.buddyEntry); sLog.outErrorDb("Table `%s` has searchRadius = 0 in command %u for script id %u for buddy %u, skipping.", tablename, tmp.command, tmp.id, tmp.buddyEntry);
continue; continue;
@ -205,7 +205,7 @@ void ScriptMgr::LoadScripts(ScriptMapMapName& scripts, const char* tablename)
if (tmp.data_flags) // Check flags if (tmp.data_flags) // Check flags
{ {
if (tmp.data_flags & ~(SCRIPT_FLAG_COMMAND_ADDITIONAL * 2 - 1)) if (tmp.data_flags & ~MAX_SCRIPT_FLAG_VALID)
{ {
sLog.outErrorDb("Table `%s` has invalid data_flags %u in command %u for script id %u, skipping.", tablename, tmp.data_flags, tmp.command, tmp.id); sLog.outErrorDb("Table `%s` has invalid data_flags %u in command %u for script id %u, skipping.", tablename, tmp.data_flags, tmp.command, tmp.id);
continue; continue;
@ -220,24 +220,43 @@ void ScriptMgr::LoadScripts(ScriptMapMapName& scripts, const char* tablename)
sLog.outErrorDb("Table `%s` has buddy required in data_flags %u in command %u for script id %u, but no buddy defined, skipping.", tablename, tmp.data_flags, tmp.command, tmp.id); sLog.outErrorDb("Table `%s` has buddy required in data_flags %u in command %u for script id %u, but no buddy defined, skipping.", tablename, tmp.data_flags, tmp.command, tmp.id);
continue; continue;
} }
if (tmp.data_flags & SCRIPT_FLAG_BUDDY_BY_GUID) // Check guid
{
if (tmp.IsCreatureBuddy())
{
CreatureData const* data = sObjectMgr.GetCreatureData(tmp.searchRadiusOrGuid);
if (!data)
{
sLog.outErrorDb("Table `%s` has buddy defined by guid (SCRIPT_FLAG_BUDDY_BY_GUID %u set) but no npc spawned with guid %u, skipping.", tablename, SCRIPT_FLAG_BUDDY_BY_GUID, tmp.searchRadiusOrGuid);
continue;
}
if (data->id != tmp.buddyEntry)
{
sLog.outErrorDb("Table `%s` has buddy defined by guid (SCRIPT_FLAG_BUDDY_BY_GUID %u set) but spawned npc with guid %u has entry %u, expected buddy_entry is %u, skipping.", tablename, SCRIPT_FLAG_BUDDY_BY_GUID, tmp.searchRadiusOrGuid, data->id, tmp.buddyEntry);
continue;
}
}
else
{
GameObjectData const* data = sObjectMgr.GetGOData(tmp.searchRadiusOrGuid);
if (!data)
{
sLog.outErrorDb("Table `%s` has go-buddy defined by guid (SCRIPT_FLAG_BUDDY_BY_GUID %u set) but no go spawned with guid %u, skipping.", tablename, SCRIPT_FLAG_BUDDY_BY_GUID, tmp.searchRadiusOrGuid);
continue;
}
if (data->id != tmp.buddyEntry)
{
sLog.outErrorDb("Table `%s` has go-buddy defined by guid (SCRIPT_FLAG_BUDDY_BY_GUID %u set) but spawned go with guid %u has entry %u, expected buddy_entry is %u, skipping.", tablename, SCRIPT_FLAG_BUDDY_BY_GUID, tmp.searchRadiusOrGuid, data->id, tmp.buddyEntry);
continue;
}
}
}
} }
switch (tmp.command) switch (tmp.command)
{ {
case SCRIPT_COMMAND_TALK: // 0 case SCRIPT_COMMAND_TALK: // 0
{ {
if (tmp.talk.chatType > CHAT_TYPE_ZONE_YELL)
{
sLog.outErrorDb("Table `%s` has invalid CHAT_TYPE_ (datalong = %u) in SCRIPT_COMMAND_TALK for script id %u", tablename, tmp.talk.chatType, tmp.id);
continue;
}
if (!GetLanguageDescByID(tmp.talk.language))
{
sLog.outErrorDb("Table `%s` has datalong2 = %u in SCRIPT_COMMAND_TALK for script id %u, but this language does not exist.", tablename, tmp.talk.language, tmp.id);
continue;
}
if (tmp.textId[0] == 0) if (tmp.textId[0] == 0)
{ {
sLog.outErrorDb("Table `%s` has invalid talk text id (dataint = %i) in SCRIPT_COMMAND_TALK for script id %u", tablename, tmp.textId[0], tmp.id); sLog.outErrorDb("Table `%s` has invalid talk text id (dataint = %i) in SCRIPT_COMMAND_TALK for script id %u", tablename, tmp.textId[0], tmp.id);
@ -806,7 +825,7 @@ void ScriptMgr::LoadCreatureDeathScripts()
void ScriptMgr::LoadDbScriptStrings() void ScriptMgr::LoadDbScriptStrings()
{ {
sObjectMgr.LoadMangosStrings(WorldDatabase, "db_script_string", MIN_DB_SCRIPT_STRING_ID, MAX_DB_SCRIPT_STRING_ID); sObjectMgr.LoadMangosStrings(WorldDatabase, "db_script_string", MIN_DB_SCRIPT_STRING_ID, MAX_DB_SCRIPT_STRING_ID, true);
std::set<int32> ids; std::set<int32> ids;
@ -894,7 +913,7 @@ bool ScriptAction::GetScriptCommandObject(const ObjectGuid guid, bool includeIte
// else no break, but display error message // else no break, but display error message
} }
default: default:
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u with unsupported guid %s, skipping", m_table, m_script->id, m_script->command, guid.GetString().c_str()); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u with unsupported guid %s, skipping", m_table, m_script->id, m_script->command, guid.GetString().c_str());
return false; return false;
} }
@ -911,10 +930,37 @@ bool ScriptAction::GetScriptProcessTargets(WorldObject* pOrigSource, WorldObject
WorldObject* pBuddy = NULL; WorldObject* pBuddy = NULL;
if (m_script->buddyEntry) if (m_script->buddyEntry)
{
if (m_script->data_flags & SCRIPT_FLAG_BUDDY_BY_GUID)
{
if (m_script->IsCreatureBuddy())
{
CreatureInfo const* cinfo = ObjectMgr::GetCreatureTemplate(m_script->buddyEntry);
pBuddy = m_map->GetCreature(cinfo->GetObjectGuid(m_script->searchRadiusOrGuid));
if (pBuddy && !((Creature*)pBuddy)->isAlive())
{
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u has buddy %u by guid %u but buddy is dead, skipping.", m_table, m_script->id, m_script->command, m_script->buddyEntry, m_script->searchRadiusOrGuid);
return false;
}
}
else
{
// GameObjectInfo const* ginfo = ObjectMgr::GetGameObjectInfo(m_script->buddyEntry);
pBuddy = m_map->GetGameObject(ObjectGuid(HIGHGUID_GAMEOBJECT, m_script->buddyEntry, m_script->searchRadiusOrGuid));
}
// TODO Maybe load related grid if not already done? How to handle multi-map case?
if (!pBuddy)
{
sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u has buddy %u by guid %u not loaded in map %u (data-flags %u), skipping.", m_table, m_script->id, m_script->command, m_script->buddyEntry, m_script->searchRadiusOrGuid, m_map->GetId(), m_script->data_flags);
return false;
}
}
else // Buddy by entry
{ {
if (!pOrigSource && !pOrigTarget) if (!pOrigSource && !pOrigTarget)
{ {
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u called without buddy %u, but no source for search available, skipping.", m_table, m_script->id, m_script->command, m_script->buddyEntry); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u called without buddy %u, but no source for search available, skipping.", m_table, m_script->id, m_script->command, m_script->buddyEntry);
return false; return false;
} }
@ -923,33 +969,46 @@ bool ScriptAction::GetScriptProcessTargets(WorldObject* pOrigSource, WorldObject
if (pSearcher->GetTypeId() == TYPEID_PLAYER && pOrigTarget && pOrigTarget->GetTypeId() != TYPEID_PLAYER) if (pSearcher->GetTypeId() == TYPEID_PLAYER && pOrigTarget && pOrigTarget->GetTypeId() != TYPEID_PLAYER)
pSearcher = pOrigTarget; pSearcher = pOrigTarget;
if (m_script->IsCreatureBuddy()) if (m_script->IsCreatureBuddy())
{ {
Creature* pCreatureBuddy = NULL; Creature* pCreatureBuddy = NULL;
MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*pSearcher, m_script->buddyEntry, true, false, m_script->searchRadius); MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*pSearcher, m_script->buddyEntry, true, false, m_script->searchRadiusOrGuid, true);
MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(pCreatureBuddy, u_check); MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(pCreatureBuddy, u_check);
Cell::VisitGridObjects(pSearcher, searcher, m_script->searchRadius); if (m_script->data_flags & SCRIPT_FLAG_BUDDY_IS_PET)
Cell::VisitWorldObjects(pSearcher, searcher, m_script->searchRadiusOrGuid);
else // Normal Creature
Cell::VisitGridObjects(pSearcher, searcher, m_script->searchRadiusOrGuid);
pBuddy = pCreatureBuddy; pBuddy = pCreatureBuddy;
// TODO: Remove this extra check output after a while - it might have false effects
if (!pBuddy && pSearcher->GetEntry() == m_script->buddyEntry)
{
sLog.outErrorDb(" DB-SCRIPTS: WARNING: Process table `%s` id %u, command %u has no OTHER buddy %u found - maybe you need to update the script?", m_table, m_script->id, m_script->command, m_script->buddyEntry);
pBuddy = pSearcher;
}
} }
else else
{ {
GameObject* pGOBuddy = NULL; GameObject* pGOBuddy = NULL;
MaNGOS::NearestGameObjectEntryInObjectRangeCheck u_check(*pSearcher, m_script->buddyEntry, m_script->searchRadius); MaNGOS::NearestGameObjectEntryInObjectRangeCheck u_check(*pSearcher, m_script->buddyEntry, m_script->searchRadiusOrGuid);
MaNGOS::GameObjectLastSearcher<MaNGOS::NearestGameObjectEntryInObjectRangeCheck> searcher(pGOBuddy, u_check); MaNGOS::GameObjectLastSearcher<MaNGOS::NearestGameObjectEntryInObjectRangeCheck> searcher(pGOBuddy, u_check);
Cell::VisitGridObjects(pSearcher, searcher, m_script->searchRadius); Cell::VisitGridObjects(pSearcher, searcher, m_script->searchRadiusOrGuid);
pBuddy = pGOBuddy; pBuddy = pGOBuddy;
} }
if (!pBuddy) if (!pBuddy)
{ {
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u has buddy %u not found in range %u of searcher %s (data-flags %u), skipping.", m_table, m_script->id, m_script->command, m_script->buddyEntry, m_script->searchRadius, pSearcher->GetGuidStr().c_str(), m_script->data_flags); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u has buddy %u not found in range %u of searcher %s (data-flags %u), skipping.", m_table, m_script->id, m_script->command, m_script->buddyEntry, m_script->searchRadiusOrGuid, pSearcher->GetGuidStr().c_str(), m_script->data_flags);
return false; return false;
} }
} }
}
if (m_script->data_flags & SCRIPT_FLAG_BUDDY_AS_TARGET) if (m_script->data_flags & SCRIPT_FLAG_BUDDY_AS_TARGET)
{ {
@ -976,7 +1035,7 @@ bool ScriptAction::LogIfNotCreature(WorldObject* pWorldObject)
{ {
if (!pWorldObject || pWorldObject->GetTypeId() != TYPEID_UNIT) if (!pWorldObject || pWorldObject->GetTypeId() != TYPEID_UNIT)
{ {
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u call for non-creature, skipping.", m_table, m_script->id, m_script->command); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u call for non-creature, skipping.", m_table, m_script->id, m_script->command);
return true; return true;
} }
return false; return false;
@ -985,7 +1044,7 @@ bool ScriptAction::LogIfNotUnit(WorldObject* pWorldObject)
{ {
if (!pWorldObject || !pWorldObject->isType(TYPEMASK_UNIT)) if (!pWorldObject || !pWorldObject->isType(TYPEMASK_UNIT))
{ {
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u call for non-unit, skipping.", m_table, m_script->id, m_script->command); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u call for non-unit, skipping.", m_table, m_script->id, m_script->command);
return true; return true;
} }
return false; return false;
@ -994,7 +1053,7 @@ bool ScriptAction::LogIfNotGameObject(WorldObject* pWorldObject)
{ {
if (!pWorldObject || pWorldObject->GetTypeId() != TYPEID_GAMEOBJECT) if (!pWorldObject || pWorldObject->GetTypeId() != TYPEID_GAMEOBJECT)
{ {
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u call for non-gameobject, skipping.", m_table, m_script->id, m_script->command); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u call for non-gameobject, skipping.", m_table, m_script->id, m_script->command);
return true; return true;
} }
return false; return false;
@ -1005,7 +1064,7 @@ Player* ScriptAction::GetPlayerTargetOrSourceAndLog(WorldObject* pSource, WorldO
{ {
if ((!pTarget || pTarget->GetTypeId() != TYPEID_PLAYER) && (!pSource || pSource->GetTypeId() != TYPEID_PLAYER)) if ((!pTarget || pTarget->GetTypeId() != TYPEID_PLAYER) && (!pSource || pSource->GetTypeId() != TYPEID_PLAYER))
{ {
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u call for non player, skipping.", m_table, m_script->id, m_script->command); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u call for non player, skipping.", m_table, m_script->id, m_script->command);
return NULL; return NULL;
} }
@ -1046,7 +1105,7 @@ bool ScriptAction::HandleScriptStep()
{ {
if (!pSource) if (!pSource)
{ {
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u found no worldobject as source, skipping.", m_table, m_script->id, m_script->command); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u found no worldobject as source, skipping.", m_table, m_script->id, m_script->command);
break; break;
} }
@ -1067,42 +1126,9 @@ bool ScriptAction::HandleScriptStep()
textId = m_script->textId[urand(0, i - 1)]; textId = m_script->textId[urand(0, i - 1)];
} }
switch (m_script->talk.chatType) if (!DoDisplayText(pSource, textId, unitTarget))
{ sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, could not display text %i properly", m_table, m_script->id, textId);
case CHAT_TYPE_SAY:
pSource->MonsterSay(textId, m_script->talk.language, unitTarget);
break;
case CHAT_TYPE_YELL:
pSource->MonsterYell(textId, m_script->talk.language, unitTarget);
break;
case CHAT_TYPE_TEXT_EMOTE:
pSource->MonsterTextEmote(textId, unitTarget);
break;
case CHAT_TYPE_BOSS_EMOTE:
pSource->MonsterTextEmote(textId, unitTarget, true);
break;
case CHAT_TYPE_WHISPER:
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
{
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u attempt to whisper (%u) to %s, skipping.", m_table, m_script->id, m_script->command, m_script->talk.chatType, unitTarget ? unitTarget->GetGuidStr().c_str() : "<no target>");
break;
}
pSource->MonsterWhisper(textId, unitTarget);
break;
case CHAT_TYPE_BOSS_WHISPER:
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
{
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u attempt to whisper (%u) to %s, skipping.", m_table, m_script->id, m_script->command, m_script->talk.chatType, unitTarget ? unitTarget->GetGuidStr().c_str() : "<no target>");
break;
}
pSource->MonsterWhisper(textId, unitTarget, true);
break;
case CHAT_TYPE_ZONE_YELL:
pSource->MonsterYellToZone(textId, m_script->talk.language, unitTarget);
break;
default:
break; // must be already checked at load
}
break; break;
} }
case SCRIPT_COMMAND_EMOTE: // 1 case SCRIPT_COMMAND_EMOTE: // 1
@ -1116,12 +1142,12 @@ bool ScriptAction::HandleScriptStep()
case SCRIPT_COMMAND_FIELD_SET: // 2 case SCRIPT_COMMAND_FIELD_SET: // 2
if (!pSourceOrItem) if (!pSourceOrItem)
{ {
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u call for NULL object.", m_table, m_script->id, m_script->command); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u call for NULL object.", m_table, m_script->id, m_script->command);
break; break;
} }
if (m_script->setField.fieldId <= OBJECT_FIELD_ENTRY || m_script->setField.fieldId >= pSourceOrItem->GetValuesCount()) if (m_script->setField.fieldId <= OBJECT_FIELD_ENTRY || m_script->setField.fieldId >= pSourceOrItem->GetValuesCount())
{ {
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u call for wrong field %u (max count: %u) in %s.", sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u call for wrong field %u (max count: %u) in %s.",
m_table, m_script->id, m_script->command, m_script->setField.fieldId, pSourceOrItem->GetValuesCount(), pSourceOrItem->GetGuidStr().c_str()); m_table, m_script->id, m_script->command, m_script->setField.fieldId, pSourceOrItem->GetValuesCount(), pSourceOrItem->GetGuidStr().c_str());
break; break;
} }
@ -1161,12 +1187,12 @@ bool ScriptAction::HandleScriptStep()
case SCRIPT_COMMAND_FLAG_SET: // 4 case SCRIPT_COMMAND_FLAG_SET: // 4
if (!pSourceOrItem) if (!pSourceOrItem)
{ {
sLog.outError("SCRIPT_COMMAND_FLAG_SET (script id %u) call for NULL object.", m_script->id); sLog.outErrorDb("SCRIPT_COMMAND_FLAG_SET (script id %u) call for NULL object.", m_script->id);
break; break;
} }
if (m_script->setFlag.fieldId <= OBJECT_FIELD_ENTRY || m_script->setFlag.fieldId >= pSourceOrItem->GetValuesCount()) if (m_script->setFlag.fieldId <= OBJECT_FIELD_ENTRY || m_script->setFlag.fieldId >= pSourceOrItem->GetValuesCount())
{ {
sLog.outError("SCRIPT_COMMAND_FLAG_SET (script id %u) call for wrong field %u (max count: %u) in %s.", sLog.outErrorDb("SCRIPT_COMMAND_FLAG_SET (script id %u) call for wrong field %u (max count: %u) in %s.",
m_script->id, m_script->setFlag.fieldId, pSourceOrItem->GetValuesCount(), pSourceOrItem->GetGuidStr().c_str()); m_script->id, m_script->setFlag.fieldId, pSourceOrItem->GetValuesCount(), pSourceOrItem->GetGuidStr().c_str());
break; break;
} }
@ -1175,12 +1201,12 @@ bool ScriptAction::HandleScriptStep()
case SCRIPT_COMMAND_FLAG_REMOVE: // 5 case SCRIPT_COMMAND_FLAG_REMOVE: // 5
if (!pSourceOrItem) if (!pSourceOrItem)
{ {
sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE (script id %u) call for NULL object.", m_script->id); sLog.outErrorDb("SCRIPT_COMMAND_FLAG_REMOVE (script id %u) call for NULL object.", m_script->id);
break; break;
} }
if (m_script->removeFlag.fieldId <= OBJECT_FIELD_ENTRY || m_script->removeFlag.fieldId >= pSourceOrItem->GetValuesCount()) if (m_script->removeFlag.fieldId <= OBJECT_FIELD_ENTRY || m_script->removeFlag.fieldId >= pSourceOrItem->GetValuesCount())
{ {
sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE (script id %u) call for wrong field %u (max count: %u) in %s.", sLog.outErrorDb("SCRIPT_COMMAND_FLAG_REMOVE (script id %u) call for wrong field %u (max count: %u) in %s.",
m_script->id, m_script->removeFlag.fieldId, pSourceOrItem->GetValuesCount(), pSourceOrItem->GetGuidStr().c_str()); m_script->id, m_script->removeFlag.fieldId, pSourceOrItem->GetValuesCount(), pSourceOrItem->GetGuidStr().c_str());
break; break;
} }
@ -1210,7 +1236,7 @@ bool ScriptAction::HandleScriptStep()
// if we have a distance, we must have a worldobject // if we have a distance, we must have a worldobject
if (m_script->questExplored.distance != 0 && !pWorldObject) if (m_script->questExplored.distance != 0 && !pWorldObject)
{ {
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u called without source worldobject, skipping.", m_table, m_script->id, m_script->command); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u called without source worldobject, skipping.", m_table, m_script->id, m_script->command);
break; break;
} }
@ -1245,7 +1271,7 @@ bool ScriptAction::HandleScriptStep()
creatureEntry = pRewardSource->GetEntry(); creatureEntry = pRewardSource->GetEntry();
else else
{ {
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u called for dynamic killcredit without creature partner, skipping.", m_table, m_script->id, m_script->command); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u called for dynamic killcredit without creature partner, skipping.", m_table, m_script->id, m_script->command);
break; break;
} }
} }
@ -1286,7 +1312,7 @@ bool ScriptAction::HandleScriptStep()
if (!pGo) if (!pGo)
{ {
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u failed for gameobject(guid: %u, buddyEntry: %u).", m_table, m_script->id, m_script->command, m_script->respawnGo.goGuid, m_script->buddyEntry); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u failed for gameobject(guid: %u, buddyEntry: %u).", m_table, m_script->id, m_script->command, m_script->respawnGo.goGuid, m_script->buddyEntry);
break; break;
} }
@ -1295,7 +1321,7 @@ bool ScriptAction::HandleScriptStep()
pGo->GetGoType() == GAMEOBJECT_TYPE_BUTTON || pGo->GetGoType() == GAMEOBJECT_TYPE_BUTTON ||
pGo->GetGoType() == GAMEOBJECT_TYPE_TRAP) pGo->GetGoType() == GAMEOBJECT_TYPE_TRAP)
{ {
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u can not be used with gameobject of type %u (guid: %u, buddyEntry: %u).", m_table, m_script->id, m_script->command, uint32(pGo->GetGoType()), m_script->respawnGo.goGuid, m_script->buddyEntry); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u can not be used with gameobject of type %u (guid: %u, buddyEntry: %u).", m_table, m_script->id, m_script->command, uint32(pGo->GetGoType()), m_script->respawnGo.goGuid, m_script->buddyEntry);
break; break;
} }
@ -1311,7 +1337,7 @@ bool ScriptAction::HandleScriptStep()
{ {
if (!pSource) if (!pSource)
{ {
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u found no worldobject as source, skipping.", m_table, m_script->id, m_script->command); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u found no worldobject as source, skipping.", m_table, m_script->id, m_script->command);
break; break;
} }
@ -1323,7 +1349,7 @@ bool ScriptAction::HandleScriptStep()
Creature* pCreature = pSource->SummonCreature(m_script->summonCreature.creatureEntry, x, y, z, o, m_script->summonCreature.despawnDelay ? TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN : TEMPSUMMON_DEAD_DESPAWN, m_script->summonCreature.despawnDelay, (m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL) ? true : false); Creature* pCreature = pSource->SummonCreature(m_script->summonCreature.creatureEntry, x, y, z, o, m_script->summonCreature.despawnDelay ? TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN : TEMPSUMMON_DEAD_DESPAWN, m_script->summonCreature.despawnDelay, (m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL) ? true : false);
if (!pCreature) if (!pCreature)
{ {
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u failed for creature (entry: %u).", m_table, m_script->id, m_script->command, m_script->summonCreature.creatureEntry); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u failed for creature (entry: %u).", m_table, m_script->id, m_script->command, m_script->summonCreature.creatureEntry);
break; break;
} }
@ -1354,13 +1380,13 @@ bool ScriptAction::HandleScriptStep()
if (!pDoor) if (!pDoor)
{ {
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u failed for gameobject(guid: %u, buddyEntry: %u).", m_table, m_script->id, m_script->command, m_script->changeDoor.goGuid, m_script->buddyEntry); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u failed for gameobject(guid: %u, buddyEntry: %u).", m_table, m_script->id, m_script->command, m_script->changeDoor.goGuid, m_script->buddyEntry);
break; break;
} }
if (pDoor->GetGoType() != GAMEOBJECT_TYPE_DOOR) if (pDoor->GetGoType() != GAMEOBJECT_TYPE_DOOR)
{ {
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u failed for non-door(GoType: %u).", m_table, m_script->id, m_script->command, pDoor->GetGoType()); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u failed for non-door(GoType: %u).", m_table, m_script->id, m_script->command, pDoor->GetGoType());
break; break;
} }
@ -1415,7 +1441,7 @@ bool ScriptAction::HandleScriptStep()
{ {
if (!pSource) if (!pSource)
{ {
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u could not find proper source", m_table, m_script->id, m_script->command); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u could not find proper source", m_table, m_script->id, m_script->command);
break; break;
} }
@ -1584,7 +1610,7 @@ bool ScriptAction::HandleScriptStep()
if (pAttacker->IsFriendlyTo(unitTarget)) if (pAttacker->IsFriendlyTo(unitTarget))
{ {
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u attacker is friendly to target, can not attack (Attacker: %s, Target: %s)", m_table, m_script->id, m_script->command, pAttacker->GetGuidStr().c_str(), unitTarget->GetGuidStr().c_str()); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u attacker is friendly to target, can not attack (Attacker: %s, Target: %s)", m_table, m_script->id, m_script->command, pAttacker->GetGuidStr().c_str(), unitTarget->GetGuidStr().c_str());
break; break;
} }
@ -1670,18 +1696,18 @@ bool ScriptAction::HandleScriptStep()
pSearcher = pTarget; pSearcher = pTarget;
Creature* pCreatureBuddy = NULL; Creature* pCreatureBuddy = NULL;
MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*pSearcher, m_script->terminateScript.npcEntry, true, false, m_script->terminateScript.searchDist); MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*pSearcher, m_script->terminateScript.npcEntry, true, false, m_script->terminateScript.searchDist, true);
MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(pCreatureBuddy, u_check); MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(pCreatureBuddy, u_check);
Cell::VisitGridObjects(pSearcher, searcher, m_script->terminateScript.searchDist); Cell::VisitGridObjects(pSearcher, searcher, m_script->terminateScript.searchDist);
if (!(m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL) && !pCreatureBuddy) if (!(m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL) && !pCreatureBuddy)
{ {
DEBUG_LOG("DB-SCRIPTS: Process table `%s` id %u, terminate further steps of this script! (as searched npc %u was not found alive)", m_table, m_script->id, m_script->terminateScript.npcEntry); DEBUG_LOG("DB-SCRIPTS: Process table `%s` id %u, terminate further steps of this script! (as searched other npc %u was not found alive)", m_table, m_script->id, m_script->terminateScript.npcEntry);
result = true; result = true;
} }
else if (m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL && pCreatureBuddy) else if (m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL && pCreatureBuddy)
{ {
DEBUG_LOG("DB-SCRIPTS: Process table `%s` id %u, terminate further steps of this script! (as searched npc %u was found alive)", m_table, m_script->id, m_script->terminateScript.npcEntry); DEBUG_LOG("DB-SCRIPTS: Process table `%s` id %u, terminate further steps of this script! (as searched other npc %u was found alive)", m_table, m_script->id, m_script->terminateScript.npcEntry);
result = true; result = true;
} }
} }
@ -1764,7 +1790,7 @@ bool ScriptAction::HandleScriptStep()
return terminateResult; return terminateResult;
} }
default: default:
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u unknown command used.", m_table, m_script->id, m_script->command); sLog.outErrorDb(" DB-SCRIPTS: Process table `%s` id %u, command %u unknown command used.", m_table, m_script->id, m_script->command);
break; break;
} }
@ -2023,7 +2049,7 @@ bool ScriptMgr::OnQuestRewarded(Player* pPlayer, GameObject* pGameObject, Quest
uint32 ScriptMgr::GetDialogStatus(Player* pPlayer, Creature* pCreature) uint32 ScriptMgr::GetDialogStatus(Player* pPlayer, Creature* pCreature)
{ {
if (!m_pGetNPCDialogStatus) if (!m_pGetNPCDialogStatus)
return 100; return DIALOG_STATUS_UNDEFINED;
return m_pGetNPCDialogStatus(pPlayer, pCreature); return m_pGetNPCDialogStatus(pPlayer, pCreature);
} }
@ -2031,7 +2057,7 @@ uint32 ScriptMgr::GetDialogStatus(Player* pPlayer, Creature* pCreature)
uint32 ScriptMgr::GetDialogStatus(Player* pPlayer, GameObject* pGameObject) uint32 ScriptMgr::GetDialogStatus(Player* pPlayer, GameObject* pGameObject)
{ {
if (!m_pGetGODialogStatus) if (!m_pGetGODialogStatus)
return 100; return DIALOG_STATUS_UNDEFINED;
return m_pGetGODialogStatus(pPlayer, pGameObject); return m_pGetGODialogStatus(pPlayer, pGameObject);
} }
@ -2056,24 +2082,24 @@ bool ScriptMgr::OnProcessEvent(uint32 eventId, Object* pSource, Object* pTarget,
return m_pOnProcessEvent != NULL && m_pOnProcessEvent(eventId, pSource, pTarget, isStart); return m_pOnProcessEvent != NULL && m_pOnProcessEvent(eventId, pSource, pTarget, isStart);
} }
bool ScriptMgr::OnEffectDummy(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature* pTarget) bool ScriptMgr::OnEffectDummy(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature* pTarget, ObjectGuid originalCasterGuid)
{ {
return m_pOnEffectDummyCreature != NULL && m_pOnEffectDummyCreature(pCaster, spellId, effIndex, pTarget); return m_pOnEffectDummyCreature != NULL && m_pOnEffectDummyCreature(pCaster, spellId, effIndex, pTarget, originalCasterGuid);
} }
bool ScriptMgr::OnEffectDummy(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, GameObject* pTarget) bool ScriptMgr::OnEffectDummy(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, GameObject* pTarget, ObjectGuid originalCasterGuid)
{ {
return m_pOnEffectDummyGO != NULL && m_pOnEffectDummyGO(pCaster, spellId, effIndex, pTarget); return m_pOnEffectDummyGO != NULL && m_pOnEffectDummyGO(pCaster, spellId, effIndex, pTarget, originalCasterGuid);
} }
bool ScriptMgr::OnEffectDummy(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Item* pTarget) bool ScriptMgr::OnEffectDummy(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Item* pTarget, ObjectGuid originalCasterGuid)
{ {
return m_pOnEffectDummyItem != NULL && m_pOnEffectDummyItem(pCaster, spellId, effIndex, pTarget); return m_pOnEffectDummyItem != NULL && m_pOnEffectDummyItem(pCaster, spellId, effIndex, pTarget, originalCasterGuid);
} }
bool ScriptMgr::OnEffectScriptEffect(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature* pTarget) bool ScriptMgr::OnEffectScriptEffect(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature* pTarget, ObjectGuid originalCasterGuid)
{ {
return m_pOnEffectScriptEffectCreature != NULL && m_pOnEffectScriptEffectCreature(pCaster, spellId, effIndex, pTarget); return m_pOnEffectScriptEffectCreature != NULL && m_pOnEffectScriptEffectCreature(pCaster, spellId, effIndex, pTarget, originalCasterGuid);
} }
bool ScriptMgr::OnAuraDummy(Aura const* pAura, bool apply) bool ScriptMgr::OnAuraDummy(Aura const* pAura, bool apply)

View file

@ -44,7 +44,6 @@ class WorldObject;
enum ScriptCommand // resSource, resTarget are the resulting Source/ Target after buddy search is done enum ScriptCommand // resSource, resTarget are the resulting Source/ Target after buddy search is done
{ {
SCRIPT_COMMAND_TALK = 0, // resSource = WorldObject, resTarget = Unit/none SCRIPT_COMMAND_TALK = 0, // resSource = WorldObject, resTarget = Unit/none
// datalong1 (see enum ChatType for supported CHAT_TYPE_'s), datalong2 = language
// dataint = text entry from db_script_string -table. dataint2-4 optional for random selected texts. // dataint = text entry from db_script_string -table. dataint2-4 optional for random selected texts.
SCRIPT_COMMAND_EMOTE = 1, // resSource = Unit, resTarget = Unit/none SCRIPT_COMMAND_EMOTE = 1, // resSource = Unit, resTarget = Unit/none
// datalong1 = emote_id // datalong1 = emote_id
@ -112,7 +111,10 @@ enum ScriptInfoDataFlags
SCRIPT_FLAG_REVERSE_DIRECTION = 0x02, // t* -> s* (* result after previous flag is evaluated) SCRIPT_FLAG_REVERSE_DIRECTION = 0x02, // t* -> s* (* result after previous flag is evaluated)
SCRIPT_FLAG_SOURCE_TARGETS_SELF = 0x04, // s* -> s* (* result after previous flag is evaluated) SCRIPT_FLAG_SOURCE_TARGETS_SELF = 0x04, // s* -> s* (* result after previous flag is evaluated)
SCRIPT_FLAG_COMMAND_ADDITIONAL = 0x08, // command dependend SCRIPT_FLAG_COMMAND_ADDITIONAL = 0x08, // command dependend
SCRIPT_FLAG_BUDDY_BY_GUID = 0x10, // take the buddy by guid
SCRIPT_FLAG_BUDDY_IS_PET = 0x20, // buddy is a pet
}; };
#define MAX_SCRIPT_FLAG_VALID (2 * SCRIPT_FLAG_BUDDY_IS_PET - 1)
struct ScriptInfo struct ScriptInfo
{ {
@ -122,11 +124,7 @@ struct ScriptInfo
union union
{ {
struct // SCRIPT_COMMAND_TALK (0) // datalong unused // SCRIPT_COMMAND_TALK (0)
{
uint32 chatType; // datalong
uint32 language; // datalong2
} talk;
struct // SCRIPT_COMMAND_EMOTE (1) struct // SCRIPT_COMMAND_EMOTE (1)
{ {
@ -188,7 +186,8 @@ struct ScriptInfo
uint32 despawnDelay; // datalong2 uint32 despawnDelay; // datalong2
} summonCreature; } summonCreature;
// SCRIPT_COMMAND_OPEN_DOOR (11) // datalong unused // SCRIPT_COMMAND_OPEN_DOOR (11)
struct // SCRIPT_COMMAND_CLOSE_DOOR (12) struct // SCRIPT_COMMAND_CLOSE_DOOR (12)
{ {
uint32 goGuid; // datalong uint32 goGuid; // datalong
@ -273,11 +272,7 @@ struct ScriptInfo
uint32 empty; // datalong2 uint32 empty; // datalong2
} run; } run;
struct // SCRIPT_COMMAND_ATTACK_START (26) // datalong unused // SCRIPT_COMMAND_ATTACK_START (26)
{
uint32 empty1; // datalong
uint32 empty2; // datalong2
} attack;
struct // SCRIPT_COMMAND_GO_LOCK_STATE (27) struct // SCRIPT_COMMAND_GO_LOCK_STATE (27)
{ {
@ -335,8 +330,8 @@ struct ScriptInfo
}; };
// Buddy system (entry can be npc or go entry, depending on command) // Buddy system (entry can be npc or go entry, depending on command)
uint32 buddyEntry; // datalong3 -> buddy_entry uint32 buddyEntry; // buddy_entry
uint32 searchRadius; // datalong4 -> search_radius uint32 searchRadiusOrGuid; // search_radius (can also be guid in case of SCRIPT_FLAG_BUDDY_BY_GUID)
uint8 data_flags; // data_flags uint8 data_flags; // data_flags
int32 textId[MAX_TEXT_ID]; // dataint to dataint4 int32 textId[MAX_TEXT_ID]; // dataint to dataint4
@ -515,10 +510,10 @@ class ScriptMgr
bool OnItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets); bool OnItemUse(Player* pPlayer, Item* pItem, SpellCastTargets const& targets);
bool OnAreaTrigger(Player* pPlayer, AreaTriggerEntry const* atEntry); bool OnAreaTrigger(Player* pPlayer, AreaTriggerEntry const* atEntry);
bool OnProcessEvent(uint32 eventId, Object* pSource, Object* pTarget, bool isStart); bool OnProcessEvent(uint32 eventId, Object* pSource, Object* pTarget, bool isStart);
bool OnEffectDummy(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature* pTarget); bool OnEffectDummy(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature* pTarget, ObjectGuid originalCasterGuid);
bool OnEffectDummy(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, GameObject* pTarget); bool OnEffectDummy(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, GameObject* pTarget, ObjectGuid originalCasterGuid);
bool OnEffectDummy(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Item* pTarget); bool OnEffectDummy(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Item* pTarget, ObjectGuid originalCasterGuid);
bool OnEffectScriptEffect(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature* pTarget); bool OnEffectScriptEffect(Unit* pCaster, uint32 spellId, SpellEffectIndex effIndex, Creature* pTarget, ObjectGuid originalCasterGuid);
bool OnAuraDummy(Aura const* pAura, bool apply); bool OnAuraDummy(Aura const* pAura, bool apply);
private: private:
@ -569,10 +564,10 @@ class ScriptMgr
bool (MANGOS_IMPORT* m_pOnItemUse)(Player*, Item*, SpellCastTargets const&); bool (MANGOS_IMPORT* m_pOnItemUse)(Player*, Item*, SpellCastTargets const&);
bool (MANGOS_IMPORT* m_pOnAreaTrigger)(Player*, AreaTriggerEntry const*); bool (MANGOS_IMPORT* m_pOnAreaTrigger)(Player*, AreaTriggerEntry const*);
bool (MANGOS_IMPORT* m_pOnProcessEvent)(uint32, Object*, Object*, bool); bool (MANGOS_IMPORT* m_pOnProcessEvent)(uint32, Object*, Object*, bool);
bool (MANGOS_IMPORT* m_pOnEffectDummyCreature)(Unit*, uint32, SpellEffectIndex, Creature*); bool (MANGOS_IMPORT* m_pOnEffectDummyCreature)(Unit*, uint32, SpellEffectIndex, Creature*, ObjectGuid);
bool (MANGOS_IMPORT* m_pOnEffectDummyGO)(Unit*, uint32, SpellEffectIndex, GameObject*); bool (MANGOS_IMPORT* m_pOnEffectDummyGO)(Unit*, uint32, SpellEffectIndex, GameObject*, ObjectGuid);
bool (MANGOS_IMPORT* m_pOnEffectDummyItem)(Unit*, uint32, SpellEffectIndex, Item*); bool (MANGOS_IMPORT* m_pOnEffectDummyItem)(Unit*, uint32, SpellEffectIndex, Item*, ObjectGuid);
bool (MANGOS_IMPORT* m_pOnEffectScriptEffectCreature)(Unit*, uint32, SpellEffectIndex, Creature*); bool (MANGOS_IMPORT* m_pOnEffectScriptEffectCreature)(Unit*, uint32, SpellEffectIndex, Creature*, ObjectGuid);
bool (MANGOS_IMPORT* m_pOnAuraDummy)(Aura const*, bool); bool (MANGOS_IMPORT* m_pOnAuraDummy)(Aura const*, bool);
}; };

View file

@ -1467,7 +1467,7 @@ enum Targets
TARGET_DIRECTLY_FORWARD = 89, TARGET_DIRECTLY_FORWARD = 89,
TARGET_NONCOMBAT_PET = 90, TARGET_NONCOMBAT_PET = 90,
TARGET_91 = 91, TARGET_91 = 91,
TARGET_92 = 92, TARGET_SUMMONER = 92,
TARGET_CONTROLLED_VEHICLE = 94, TARGET_CONTROLLED_VEHICLE = 94,
TARGET_95 = 95, TARGET_95 = 95,
TARGET_VEHICLE_PASSENGER_0 = 96, TARGET_VEHICLE_PASSENGER_0 = 96,

View file

@ -47,6 +47,7 @@
#include "DB2Stores.h" #include "DB2Stores.h"
#include "SQLStorages.h" #include "SQLStorages.h"
#include "Vehicle.h" #include "Vehicle.h"
#include "TemporarySummon.h"
#include "SQLStorages.h" #include "SQLStorages.h"
extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS]; extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS];
@ -1749,8 +1750,9 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList&
float x, y; float x, y;
float z = m_caster->GetPositionZ(); float z = m_caster->GetPositionZ();
// Ignore the BOUNDING_RADIUS for spells with radius (add a small value to prevent < 0 rounding errors) // Do not search for a free spot. TODO: Should there be searched for a free spot. There was once a discussion that in case this space was impossible (LOS) m_caster's position should be used.
m_caster->GetNearPoint2D(x, y, radius > 0.001f ? radius - m_caster->GetObjectBoundingRadius() + 0.01f : 2.0f, angle); // TODO Bring this back to memory and search for it!
m_caster->GetNearPoint2D(x, y, radius, angle);
m_caster->UpdateAllowedPositionZ(x, y, z); m_caster->UpdateAllowedPositionZ(x, y, z);
m_targets.setDestination(x, y, z); m_targets.setDestination(x, y, z);
@ -2251,6 +2253,20 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList&
if (target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->IsPet() && ((Pet*)target)->getPetType() == MINI_PET) if (target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->IsPet() && ((Pet*)target)->getPetType() == MINI_PET)
targetUnitMap.push_back(target); targetUnitMap.push_back(target);
break; break;
case TARGET_SUMMONER:
{
WorldObject* caster = GetAffectiveCasterObject();
if (!caster)
return;
if (caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->IsTemporarySummon())
targetUnitMap.push_back(((TemporarySummon*)(Creature*)caster)->GetSummoner());
else if (caster->GetTypeId() == TYPEID_GAMEOBJECT && !((GameObject*)caster)->HasStaticDBSpawnData())
targetUnitMap.push_back(((GameObject*)caster)->GetOwner());
else
sLog.outError("SPELL: Spell ID %u with target ID %u was used by non temporary summon object %s.", m_spellInfo->Id, targetMode, caster->GetGuidStr().c_str());
break;
}
case TARGET_CONTROLLED_VEHICLE: case TARGET_CONTROLLED_VEHICLE:
if (m_caster->IsBoarded() && m_caster->GetTransportInfo()->IsOnVehicle()) if (m_caster->IsBoarded() && m_caster->GetTransportInfo()->IsOnVehicle())
targetUnitMap.push_back((Unit*)m_caster->GetTransportInfo()->GetTransport()); targetUnitMap.push_back((Unit*)m_caster->GetTransportInfo()->GetTransport());
@ -2732,7 +2748,7 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList&
} }
float x, y; float x, y;
m_caster->GetNearPoint2D(x, y, radius, angle); m_caster->GetNearPoint2D(x, y, radius + m_caster->GetObjectBoundingRadius(), angle);
m_targets.setDestination(x, y, m_caster->GetPositionZ()); m_targets.setDestination(x, y, m_caster->GetPositionZ());
} }
@ -2767,7 +2783,7 @@ void Spell::SetTargetMap(SpellEffectIndex effIndex, uint32 targetMode, UnitList&
} }
float x, y; float x, y;
currentTarget->GetNearPoint2D(x, y, radius, angle); currentTarget->GetNearPoint2D(x, y, radius + currentTarget->GetObjectBoundingRadius(), angle);
m_targets.setDestination(x, y, currentTarget->GetPositionZ()); m_targets.setDestination(x, y, currentTarget->GetPositionZ());
} }
break; break;
@ -3438,6 +3454,7 @@ void Spell::cast(bool skipCheck)
TakePower(); TakePower();
TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot
TakeAmmo();
SendCastResult(castResult); SendCastResult(castResult);
SendSpellGo(); // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()... SendSpellGo(); // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()...
@ -3484,6 +3501,34 @@ void Spell::cast(bool skipCheck)
SetExecutedCurrently(false); SetExecutedCurrently(false);
} }
void Spell::TakeAmmo()
{
// take ammo
if (m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
{
Item* pItem = ((Player*)m_caster)->GetWeaponForAttack(RANGED_ATTACK, true, false);
// wands don't have ammo
if (!pItem || pItem->GetProto()->SubClass == ITEM_SUBCLASS_WEAPON_WAND)
return;
if (pItem->GetProto()->InventoryType == INVTYPE_THROWN)
{
if (pItem->GetMaxStackCount() == 1)
{
// decrease durability for non-stackable throw weapon
((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
}
else
{
// decrease items amount for stackable throw weapon
uint32 count = 1;
((Player*)m_caster)->DestroyItemCount(pItem, count, true);
}
}
}
}
void Spell::handle_immediate() void Spell::handle_immediate()
{ {
// process immediate effects (items, ground, etc.) also initialize some variables // process immediate effects (items, ground, etc.) also initialize some variables
@ -5600,6 +5645,19 @@ SpellCastResult Spell::CheckCast(bool strict)
if (m_caster->IsInWater()) if (m_caster->IsInWater())
return SPELL_FAILED_ONLY_ABOVEWATER; return SPELL_FAILED_ONLY_ABOVEWATER;
} }
else if (m_spellInfo->Id == 51690) // Killing Spree
{
UnitList targets;
float radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex));
MaNGOS::AnyUnfriendlyVisibleUnitInObjectRangeCheck unitCheck(m_caster, m_caster, radius);
MaNGOS::UnitListSearcher<MaNGOS::AnyUnfriendlyVisibleUnitInObjectRangeCheck> checker(targets, unitCheck);
Cell::VisitAllObjects(m_caster, checker, radius);
if (targets.empty())
return SPELL_FAILED_OUT_OF_RANGE;
}
else if (m_spellInfo->Id == 68996) // Two forms else if (m_spellInfo->Id == 68996) // Two forms
{ {
if (m_caster->isInCombat()) if (m_caster->isInCombat())
@ -7884,11 +7942,16 @@ void Spell::GetSpellRangeAndRadius(SpellEffectEntry const* spellEffect, float& r
case 30769: // Pick Red Riding Hood (Karazhan, Big Bad Wolf) case 30769: // Pick Red Riding Hood (Karazhan, Big Bad Wolf)
case 30835: // Infernal Relay (Karazhan, Prince Malchezaar) case 30835: // Infernal Relay (Karazhan, Prince Malchezaar)
case 31347: // Doom (Hyjal Summit, Azgalor) case 31347: // Doom (Hyjal Summit, Azgalor)
case 32312: // Move 1 (Karazhan, Chess Event)
case 33711: // Murmur's Touch (Shadow Labyrinth, Murmur) case 33711: // Murmur's Touch (Shadow Labyrinth, Murmur)
case 37388: // Move 2 (Karazhan, Chess Event)
case 38794: // Murmur's Touch (h) (Shadow Labyrinth, Murmur) case 38794: // Murmur's Touch (h) (Shadow Labyrinth, Murmur)
case 39338: // Karazhan - Chess, Medivh CHEAT: Hand of Medivh, Target Horde
case 39342: // Karazhan - Chess, Medivh CHEAT: Hand of Medivh, Target Alliance
case 40834: // Agonizing Flames (BT, Illidan Stormrage) case 40834: // Agonizing Flames (BT, Illidan Stormrage)
case 41537: // Summon Enslaved Soul (BT, Reliquary of Souls) case 41537: // Summon Enslaved Soul (BT, Reliquary of Souls)
case 44869: // Spectral Blast (SWP, Kalecgos) case 44869: // Spectral Blast (SWP, Kalecgos)
case 45391: // Summon Demonic Vapor (SWP, Felmyst)
case 45785: // Sinister Reflection Clone (SWP, Kil'jaeden) case 45785: // Sinister Reflection Clone (SWP, Kil'jaeden)
case 45892: // Sinister Reflection (SWP, Kil'jaeden) case 45892: // Sinister Reflection (SWP, Kil'jaeden)
case 45976: // Open Portal (SWP, M'uru) case 45976: // Open Portal (SWP, M'uru)
@ -7911,16 +7974,22 @@ void Spell::GetSpellRangeAndRadius(SpellEffectEntry const* spellEffect, float& r
case 62042: // Stormhammer (Ulduar, Thorim) case 62042: // Stormhammer (Ulduar, Thorim)
case 62166: // Stone Grip (Ulduar, Kologarn) case 62166: // Stone Grip (Ulduar, Kologarn)
case 62301: // Cosmic Smash (Ulduar, Algalon) case 62301: // Cosmic Smash (Ulduar, Algalon)
case 62374: // Pursued (Ulduar, Flame Leviathan)
case 62488: // Activate Construct (Ulduar, Ignis) case 62488: // Activate Construct (Ulduar, Ignis)
case 62577: // Blizzard (Ulduar, Thorim)
case 62603: // Blizzard (h) (Ulduar, Thorim)
case 62797: // Storm Cloud (Ulduar, Hodir)
case 63018: // Searing Light (Ulduar, XT-002) case 63018: // Searing Light (Ulduar, XT-002)
case 63024: // Gravity Bomb (Ulduar, XT-002) case 63024: // Gravity Bomb (Ulduar, XT-002)
case 63387: // Rapid Burst case 63387: // Rapid Burst
case 63545: // Icicle (Ulduar, Hodir)
case 63795: // Psychosis (Ulduar, Yogg-Saron) case 63795: // Psychosis (Ulduar, Yogg-Saron)
case 63820: // Summon Scrap Bot Trigger (Ulduar, Mimiron) use for Scrap Bots, hits npc 33856 case 63820: // Summon Scrap Bot Trigger (Ulduar, Mimiron) use for Scrap Bots, hits npc 33856
case 64218: // Overcharge (VoA, Emalon) case 64218: // Overcharge (VoA, Emalon)
case 64234: // Gravity Bomb (h) (Ulduar, XT-002) case 64234: // Gravity Bomb (h) (Ulduar, XT-002)
case 64425: // Summon Scrap Bot Trigger (Ulduar, Mimiron) use for Assault Bots, hits npc 33856 case 64425: // Summon Scrap Bot Trigger (Ulduar, Mimiron) use for Assault Bots, hits npc 33856
case 64531: // Rapid Burst (h) case 64531: // Rapid Burst (h)
case 64543: // Melt Ice (Ulduar, Hodir)
case 65121: // Searing Light (h) (Ulduar, XT-002) case 65121: // Searing Light (h) (Ulduar, XT-002)
case 65301: // Psychosis (Ulduar, Yogg-Saron) case 65301: // Psychosis (Ulduar, Yogg-Saron)
case 65872: // Pursuing Spikes (ToCrusader, Anub'arak) case 65872: // Pursuing Spikes (ToCrusader, Anub'arak)
@ -7965,6 +8034,7 @@ void Spell::GetSpellRangeAndRadius(SpellEffectEntry const* spellEffect, float& r
break; break;
case 10258: // Awaken Vault Warder (Uldaman) case 10258: // Awaken Vault Warder (Uldaman)
case 28542: // Life Drain (Naxx, Sapphiron) case 28542: // Life Drain (Naxx, Sapphiron)
case 62476: // Icicle (Ulduar, Hodir)
case 66013: // Penetrating Cold (10 man) (ToCrusader, Anub'arak) case 66013: // Penetrating Cold (10 man) (ToCrusader, Anub'arak)
case 67755: // Nerubian Burrower (Mode 1) (ToCrusader, Anub'arak) case 67755: // Nerubian Burrower (Mode 1) (ToCrusader, Anub'arak)
case 67756: // Nerubian Burrower (Mode 2) (ToCrusader, Anub'arak) case 67756: // Nerubian Burrower (Mode 2) (ToCrusader, Anub'arak)
@ -7980,6 +8050,8 @@ void Spell::GetSpellRangeAndRadius(SpellEffectEntry const* spellEffect, float& r
case 29213: // Curse of the Plaguebringer (Naxx, Noth the Plaguebringer) case 29213: // Curse of the Plaguebringer (Naxx, Noth the Plaguebringer)
case 30004: // Flame Wreath (Karazhan, Shade of Aran) case 30004: // Flame Wreath (Karazhan, Shade of Aran)
case 31298: // Sleep (Hyjal Summit, Anetheron) case 31298: // Sleep (Hyjal Summit, Anetheron)
case 39341: // Karazhan - Chess, Medivh CHEAT: Fury of Medivh, Target Horde
case 39344: // Karazhan - Chess, Medivh CHEAT: Fury of Medivh, Target Alliance
case 39992: // Needle Spine Targeting (BT, Warlord Najentus) case 39992: // Needle Spine Targeting (BT, Warlord Najentus)
case 40869: // Fatal Attraction (BT, Mother Shahraz) case 40869: // Fatal Attraction (BT, Mother Shahraz)
case 41303: // Soul Drain (BT, Reliquary of Souls) case 41303: // Soul Drain (BT, Reliquary of Souls)
@ -7988,6 +8060,7 @@ void Spell::GetSpellRangeAndRadius(SpellEffectEntry const* spellEffect, float& r
case 54522: // Summon Ghouls On Scarlet Crusade case 54522: // Summon Ghouls On Scarlet Crusade
case 60936: // Surge of Power (h) (Malygos) case 60936: // Surge of Power (h) (Malygos)
case 61693: // Arcane Storm (Malygos) case 61693: // Arcane Storm (Malygos)
case 62477: // Icicle (h) (Ulduar, Hodir)
case 63981: // StoneGrip (h) (Ulduar, Kologarn) case 63981: // StoneGrip (h) (Ulduar, Kologarn)
case 64598: // Cosmic Smash (h) (Ulduar, Algalon) case 64598: // Cosmic Smash (h) (Ulduar, Algalon)
case 64620: // Summon Fire Bot Trigger (Ulduar, Mimiron) hits npc 33856 case 64620: // Summon Fire Bot Trigger (Ulduar, Mimiron) hits npc 33856
@ -8001,6 +8074,7 @@ void Spell::GetSpellRangeAndRadius(SpellEffectEntry const* spellEffect, float& r
break; break;
case 37676: // Insidious Whisper (SSC, Leotheras the Blind) case 37676: // Insidious Whisper (SSC, Leotheras the Blind)
case 38028: // Watery Grave (SSC, Morogrim Tidewalker) case 38028: // Watery Grave (SSC, Morogrim Tidewalker)
case 46650: // Open Brutallus Back Door (SWP, Felmyst)
case 67757: // Nerubian Burrower (Mode 3) (ToCrusader, Anub'arak) case 67757: // Nerubian Burrower (Mode 3) (ToCrusader, Anub'arak)
case 71221: // Gas spore (Mode 1) (ICC, Festergut) case 71221: // Gas spore (Mode 1) (ICC, Festergut)
unMaxTargets = 4; unMaxTargets = 4;

View file

@ -388,6 +388,7 @@ class Spell
void cast(bool skipCheck = false); void cast(bool skipCheck = false);
void finish(bool ok = true); void finish(bool ok = true);
void TakePower(); void TakePower();
void TakeAmmo();
void TakeReagents(); void TakeReagents();
void TakeCastItem(); void TakeCastItem();

View file

@ -1793,8 +1793,9 @@ void Aura::TriggerSpell()
// // Shield Level 3 // // Shield Level 3
// case 63132: break; // case 63132: break;
// // Food // // Food
// case 64345: break; case 64345: // Remove Player from Phase
// // Remove Player from Phase target->RemoveSpellsCausingAura(SPELL_AURA_PHASE);
return;
// case 64445: break; // case 64445: break;
// // Food // // Food
// case 65418: break; // case 65418: break;
@ -2186,7 +2187,7 @@ void Aura::TriggerSpell()
{ {
if (Unit* caster = GetCaster()) if (Unit* caster = GetCaster())
{ {
if (triggerTarget->GetTypeId() != TYPEID_UNIT || !sScriptMgr.OnEffectDummy(caster, GetId(), GetEffIndex(), (Creature*)triggerTarget)) if (triggerTarget->GetTypeId() != TYPEID_UNIT || !sScriptMgr.OnEffectDummy(caster, GetId(), GetEffIndex(), (Creature*)triggerTarget, ObjectGuid()))
sLog.outError("Aura::TriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?", GetId(), GetEffIndex()); sLog.outError("Aura::TriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?", GetId(), GetEffIndex());
} }
} }
@ -2372,6 +2373,11 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
case 58600: // Restricted Flight Area case 58600: // Restricted Flight Area
target->MonsterWhisper(LANG_NO_FLY_ZONE, target, true); target->MonsterWhisper(LANG_NO_FLY_ZONE, target, true);
return; return;
case 61187: // Twilight Shift (single target)
case 61190: // Twilight Shift (many targets)
target->RemoveAurasDueToSpell(57620);
target->CastSpell(target, 61885, true, NULL, this);
return;
case 62061: // Festive Holiday Mount case 62061: // Festive Holiday Mount
if (target->HasAuraType(SPELL_AURA_MOUNTED)) if (target->HasAuraType(SPELL_AURA_MOUNTED))
// Reindeer Transformation // Reindeer Transformation
@ -2817,6 +2823,11 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
target->CastSpell(target, 47287, true, NULL, this); target->CastSpell(target, 47287, true, NULL, this);
return; return;
} }
case 46637: // Break Ice
{
target->CastSpell(target, 46638, true);
return;
}
case 48385: // Create Spirit Fount Beam case 48385: // Create Spirit Fount Beam
{ {
target->CastSpell(target, target->GetMap()->IsRegularDifficulty() ? 48380 : 59320, true); target->CastSpell(target, target->GetMap()->IsRegularDifficulty() ? 48380 : 59320, true);
@ -8014,6 +8025,19 @@ void Aura::PeriodicDummyTick()
return; return;
// // Panda // // Panda
// case 19230: break; // case 19230: break;
case 30019: // Control Piece
{
if (target->GetTypeId() != TYPEID_PLAYER)
return;
Unit* chessPiece = target->GetCharm();
if (!chessPiece)
{
target->CastSpell(target, 30529, true);
target->RemoveAurasDueToSpell(30019);
}
return;
}
// // Gossip NPC Periodic - Talk // // Gossip NPC Periodic - Talk
// case 33208: break; // case 33208: break;
// // Gossip NPC Periodic - Despawn // // Gossip NPC Periodic - Despawn
@ -8259,11 +8283,41 @@ void Aura::PeriodicDummyTick()
case 2: target->CastSpell(target, 55739, true); break; case 2: target->CastSpell(target, 55739, true); break;
} }
return; return;
case 61968: // Flash Freeze
{
if (GetAuraTicks() == 1 && !target->HasAura(62464))
target->CastSpell(target, 61970, true, NULL, this);
return;
}
case 62018: // Collapse
{
// lose 1% of health every second
target->DealDamage(target, target->GetMaxHealth() * .01, NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NONE, NULL, false);
return;
}
case 62019: // Rune of Summoning case 62019: // Rune of Summoning
{ {
target->CastSpell(target, 62020, true, NULL, this); target->CastSpell(target, 62020, true, NULL, this);
return; return;
} }
case 62038: // Biting Cold
{
if (target->GetTypeId() != TYPEID_PLAYER)
return;
// if player is moving remove one aura stack
if (((Player*)target)->isMoving())
target->RemoveAuraHolderFromStack(62039);
// otherwise add one aura stack each 3 seconds
else if (GetAuraTicks() % 3 && !target->HasAura(62821))
target->CastSpell(target, 62039, true, NULL, this);
return;
}
case 62039: // Biting Cold
{
target->CastSpell(target, 62188, true);
return;
}
case 62566: // Healthy Spore Summon Periodic case 62566: // Healthy Spore Summon Periodic
{ {
target->CastSpell(target, 62582, true); target->CastSpell(target, 62582, true);
@ -8272,6 +8326,15 @@ void Aura::PeriodicDummyTick()
target->CastSpell(target, 62593, true); target->CastSpell(target, 62593, true);
return; return;
} }
case 62717: // Slag Pot
{
target->CastSpell(target, target->GetMap()->IsRegularDifficulty() ? 65722 : 65723, true, NULL, this);
// cast Slag Imbued if the target survives up to the last tick
if (GetAuraTicks() == 10)
target->CastSpell(target, 63536, true, NULL, this);
return;
}
case 64217: // Overcharged case 64217: // Overcharged
{ {
if (GetHolder()->GetStackAmount() >= 10) if (GetHolder()->GetStackAmount() >= 10)
@ -8281,6 +8344,39 @@ void Aura::PeriodicDummyTick()
} }
return; return;
} }
case 64412: // Phase Punch
{
if (SpellAuraHolder* phaseAura = target->GetSpellAuraHolder(64412))
{
uint32 uiAuraId = 0;
switch (phaseAura->GetStackAmount())
{
case 1: uiAuraId = 64435; break;
case 2: uiAuraId = 64434; break;
case 3: uiAuraId = 64428; break;
case 4: uiAuraId = 64421; break;
case 5: uiAuraId = 64417; break;
}
if (uiAuraId && !target->HasAura(uiAuraId))
{
target->CastSpell(target, uiAuraId, true, NULL, this);
// remove original aura if phased
if (uiAuraId == 64417)
{
target->RemoveAurasDueToSpell(64412);
target->CastSpell(target, 62169, true, NULL, this);
}
}
}
return;
}
case 65272: // Shatter Chest
{
target->CastSpell(target, 62501, true, NULL, this);
return;
}
case 66118: // Leeching Swarm case 66118: // Leeching Swarm
case 67630: // Leeching Swarm case 67630: // Leeching Swarm
case 68646: // Leeching Swarm case 68646: // Leeching Swarm
@ -8537,7 +8633,7 @@ void Aura::PeriodicDummyTick()
if (Unit* caster = GetCaster()) if (Unit* caster = GetCaster())
{ {
if (target && target->GetTypeId() == TYPEID_UNIT) if (target && target->GetTypeId() == TYPEID_UNIT)
sScriptMgr.OnEffectDummy(caster, GetId(), GetEffIndex(), (Creature*)target); sScriptMgr.OnEffectDummy(caster, GetId(), GetEffIndex(), (Creature*)target, ObjectGuid());
} }
} }

View file

@ -1365,6 +1365,16 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
unitTarget->CastSpell(unitTarget, unitTarget->GetMap()->IsRegularDifficulty() ? 32302 : 38382, true); unitTarget->CastSpell(unitTarget, unitTarget->GetMap()->IsRegularDifficulty() ? 32302 : 38382, true);
return; return;
} }
case 32312: // Move 1 (Chess event AI short distance move)
case 37388: // Move 2 (Chess event AI long distance move)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
// cast generic move spell
m_caster->CastSpell(unitTarget, 30012, true);
return;
}
case 33060: // Make a Wish case 33060: // Make a Wish
{ {
if (m_caster->GetTypeId() != TYPEID_PLAYER) if (m_caster->GetTypeId() != TYPEID_PLAYER)
@ -1700,21 +1710,6 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
m_caster->CastSpell(unitTarget, 44455, true, m_CastItem); m_caster->CastSpell(unitTarget, 44455, true, m_CastItem);
return; return;
} }
case 44845: // Spectral Realm
{
if (!unitTarget)
return;
// teleport all targets which have the spectral realm aura
if (unitTarget->HasAura(46021))
{
unitTarget->RemoveAurasDueToSpell(46021);
unitTarget->CastSpell(unitTarget, 46020, true);
unitTarget->CastSpell(unitTarget, 44867, true);
}
return;
}
case 44869: // Spectral Blast case 44869: // Spectral Blast
{ {
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
@ -1961,6 +1956,14 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
m_caster->CastSpell(unitTarget, 46359, true); m_caster->CastSpell(unitTarget, 46359, true);
return; return;
} }
case 46289: // Negative Energy
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 46285, true);
return;
}
case 46430: // Synch Health case 46430: // Synch Health
{ {
if (!unitTarget) if (!unitTarget)
@ -2728,6 +2731,47 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
unitTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); unitTarget->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE);
return; return;
} }
case 62278: // Lightning Orb Charger
{
if (!unitTarget)
return;
unitTarget->CastSpell(m_caster, 62466, true);
unitTarget->CastSpell(unitTarget, 62279, true);
return;
}
case 62797: // Storm Cloud
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, m_caster->GetMap()->IsRegularDifficulty() ? 65123 : 65133, true);
return;
}
case 62907: // Freya's Ward
{
if (!unitTarget)
return;
for (uint8 i = 0; i < 5; ++i)
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 63499: // Dispel Magic
{
if (!unitTarget)
return;
unitTarget->RemoveAurasDueToSpell(effect->CalculateSimpleValue());
return;
}
case 63545: // Icicle
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
}
case 63820: // Summon Scrap Bot Trigger (Ulduar - Mimiron) for Scrap Bots case 63820: // Summon Scrap Bot Trigger (Ulduar - Mimiron) for Scrap Bots
case 64425: // Summon Scrap Bot Trigger (Ulduar - Mimiron) for Assault Bots case 64425: // Summon Scrap Bot Trigger (Ulduar - Mimiron) for Assault Bots
case 64620: // Summon Fire Bot Trigger (Ulduar - Mimiron) for Fire Bots case 64620: // Summon Fire Bot Trigger (Ulduar - Mimiron) for Fire Bots
@ -2750,6 +2794,31 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
m_caster->SetFacingTo(frand(0, M_PI_F * 2)); m_caster->SetFacingTo(frand(0, M_PI_F * 2));
return; return;
} }
case 64489: // Feral Rush
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, 64496, true);
return;
}
case 64543: // Melt Ice
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
m_caster->CastSpell(m_caster, 64540, true);
return;
}
case 64673: // Feral Rush (h)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
m_caster->CastSpell(unitTarget, 64674, true);
return;
}
case 64981: // Summon Random Vanquished Tentacle case 64981: // Summon Random Vanquished Tentacle
{ {
uint32 spell_id = 0; uint32 spell_id = 0;
@ -3055,6 +3124,35 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
m_caster->CastCustomSpell(unitTarget, 23885, &damage, NULL, NULL, true, NULL); m_caster->CastCustomSpell(unitTarget, 23885, &damage, NULL, NULL, true, NULL);
return; return;
} }
case 30012: // Move
{
if (!unitTarget || unitTarget->HasAura(39400))
return;
unitTarget->CastSpell(m_caster, 30253, true);
}
case 30284: // Change Facing
{
if (!unitTarget)
return;
unitTarget->CastSpell(m_caster, 30270, true);
return;
}
case 37144: // Move (Chess event player knight move)
case 37146: // Move (Chess event player pawn move)
case 37148: // Move (Chess event player queen move)
case 37151: // Move (Chess event player rook move)
case 37152: // Move (Chess event player bishop move)
case 37153: // Move (Chess event player king move)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
// cast generic move spell
m_caster->CastSpell(unitTarget, 30012, true);
return;
}
} }
break; break;
} }
@ -3678,11 +3776,11 @@ void Spell::EffectDummy(SpellEffectEntry const* effect)
// So called only for not processed cases // So called only for not processed cases
bool libraryResult = false; bool libraryResult = false;
if (gameObjTarget) if (gameObjTarget)
libraryResult = sScriptMgr.OnEffectDummy(m_caster, m_spellInfo->Id, SpellEffectIndex(effect->EffectIndex), gameObjTarget); libraryResult = sScriptMgr.OnEffectDummy(m_caster, m_spellInfo->Id, SpellEffectIndex(effect->EffectIndex), gameObjTarget, m_originalCasterGUID);
else if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT) else if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT)
libraryResult = sScriptMgr.OnEffectDummy(m_caster, m_spellInfo->Id, SpellEffectIndex(effect->EffectIndex), (Creature*)unitTarget); libraryResult = sScriptMgr.OnEffectDummy(m_caster, m_spellInfo->Id, SpellEffectIndex(effect->EffectIndex), (Creature*)unitTarget, m_originalCasterGUID);
else if (itemTarget) else if (itemTarget)
libraryResult = sScriptMgr.OnEffectDummy(m_caster, m_spellInfo->Id, SpellEffectIndex(effect->EffectIndex), itemTarget); libraryResult = sScriptMgr.OnEffectDummy(m_caster, m_spellInfo->Id, SpellEffectIndex(effect->EffectIndex), itemTarget, m_originalCasterGUID);
if (libraryResult || !unitTarget) if (libraryResult || !unitTarget)
return; return;
@ -3812,10 +3910,6 @@ void Spell::EffectTriggerSpell(SpellEffectEntry const* effect)
m_caster->CastSpell(unitTarget, spellId, true); m_caster->CastSpell(unitTarget, spellId, true);
return; return;
} }
// just skip
case 23770: // Sayge's Dark Fortune of *
// not exist, common cooldown can be implemented in scripts if need.
return;
case 29284: // Brittle Armor - (need add max stack of 24575 Brittle Armor) case 29284: // Brittle Armor - (need add max stack of 24575 Brittle Armor)
m_caster->CastSpell(unitTarget, 24575, true, m_CastItem, NULL, m_originalCasterGUID); m_caster->CastSpell(unitTarget, 24575, true, m_CastItem, NULL, m_originalCasterGUID);
return; return;
@ -6284,7 +6378,7 @@ void Spell::EffectSummonPet(SpellEffectEntry const* effect)
// if pet requested type already exist // if pet requested type already exist
if (OldSummon) if (OldSummon)
{ {
if (petentry == 0 || OldSummon->GetEntry() == petentry) if ((petentry == 0 || OldSummon->GetEntry() == petentry) && OldSummon->getPetType() != SUMMON_PET)
{ {
// pet in corpse state can't be summoned // pet in corpse state can't be summoned
if (OldSummon->isDead()) if (OldSummon->isDead())
@ -6759,31 +6853,6 @@ void Spell::EffectWeaponDmg(SpellEffectEntry const* effect)
if (m_caster->GetTypeId() == TYPEID_PLAYER) if (m_caster->GetTypeId() == TYPEID_PLAYER)
((Player*)m_caster)->AddComboPoints(unitTarget, 1); ((Player*)m_caster)->AddComboPoints(unitTarget, 1);
} }
// take ammo
if (m_attackType == RANGED_ATTACK && m_caster->GetTypeId() == TYPEID_PLAYER)
{
Item* pItem = ((Player*)m_caster)->GetWeaponForAttack(RANGED_ATTACK, true, false);
// wands don't have ammo
if (!pItem || pItem->GetProto()->SubClass == ITEM_SUBCLASS_WEAPON_WAND)
return;
if (pItem->GetProto()->InventoryType == INVTYPE_THROWN)
{
if (pItem->GetMaxStackCount() == 1)
{
// decrease durability for non-stackable throw weapon
((Player*)m_caster)->DurabilityPointLossForEquipSlot(EQUIPMENT_SLOT_RANGED);
}
else
{
// decrease items amount for stackable throw weapon
uint32 count = 1;
((Player*)m_caster)->DestroyItemCount(pItem, count, true);
}
}
}
} }
void Spell::EffectThreat(SpellEffectEntry const* /*effect*/) void Spell::EffectThreat(SpellEffectEntry const* /*effect*/)
@ -7217,7 +7286,7 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
float angle = unitTarget->GetOrientation(); float angle = unitTarget->GetOrientation();
for (uint8 i = 0; i < 4; ++i) for (uint8 i = 0; i < 4; ++i)
{ {
unitTarget->GetNearPoint(unitTarget, x, y, z, unitTarget->GetObjectBoundingRadius(), 5.0f, angle + i * M_PI_F / 2); unitTarget->GetNearPoint(unitTarget, x, y, z, unitTarget->GetObjectBoundingRadius(), INTERACTION_DISTANCE, angle + i * M_PI_F / 2);
unitTarget->SummonCreature(16119, x, y, z, angle, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 10 * MINUTE * IN_MILLISECONDS); unitTarget->SummonCreature(16119, x, y, z, angle, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 10 * MINUTE * IN_MILLISECONDS);
} }
return; return;
@ -7347,6 +7416,25 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
unitTarget->RemoveAurasAtMechanicImmunity(IMMUNE_TO_ROOT_AND_SNARE_MASK, 30918, true); unitTarget->RemoveAurasAtMechanicImmunity(IMMUNE_TO_ROOT_AND_SNARE_MASK, 30918, true);
break; break;
} }
case 37142: // Karazhan - Chess NPC Action: Melee Attack: Conjured Water Elemental
case 37143: // Karazhan - Chess NPC Action: Melee Attack: Charger
case 37147: // Karazhan - Chess NPC Action: Melee Attack: Human Cleric
case 37149: // Karazhan - Chess NPC Action: Melee Attack: Human Conjurer
case 37150: // Karazhan - Chess NPC Action: Melee Attack: King Llane
case 37220: // Karazhan - Chess NPC Action: Melee Attack: Summoned Daemon
case 32227: // Karazhan - Chess NPC Action: Melee Attack: Footman
case 32228: // Karazhan - Chess NPC Action: Melee Attack: Grunt
case 37337: // Karazhan - Chess NPC Action: Melee Attack: Orc Necrolyte
case 37339: // Karazhan - Chess NPC Action: Melee Attack: Orc Wolf
case 37345: // Karazhan - Chess NPC Action: Melee Attack: Orc Warlock
case 37348: // Karazhan - Chess NPC Action: Melee Attack: Warchief Blackhand
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 32247, true);
return;
}
case 32301: // Ping Shirrak case 32301: // Ping Shirrak
{ {
if (!unitTarget) if (!unitTarget)
@ -7372,7 +7460,7 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
float x, y, z; float x, y, z;
for (uint8 i = 0; i < 4; ++i) for (uint8 i = 0; i < 4; ++i)
{ {
m_caster->GetNearPoint(m_caster, x, y, z, 0, 5.0f, M_PI_F * .5f * i + M_PI_F * .25f); m_caster->GetNearPoint(m_caster, x, y, z, 0.0f, INTERACTION_DISTANCE, M_PI_F * .5f * i + M_PI_F * .25f);
m_caster->SummonCreature(21002, x, y, z, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000); m_caster->SummonCreature(21002, x, y, z, 0, TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 30000);
} }
return; return;
@ -7385,6 +7473,22 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
unitTarget->CastSpell(unitTarget, urand(0, 1) ? 37429 : 37430, true); unitTarget->CastSpell(unitTarget, urand(0, 1) ? 37429 : 37430, true);
return; return;
} }
case 37775: // Karazhan - Chess NPC Action - Poison Cloud
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 37469, true);
return;
}
case 37824: // Karazhan - Chess NPC Action - Shadow Mend
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 37456, true);
return;
}
case 38358: // Tidal Surge case 38358: // Tidal Surge
{ {
if (!unitTarget) if (!unitTarget)
@ -7393,6 +7497,24 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
unitTarget->CastSpell(unitTarget, 38353, true, NULL, NULL, m_caster->GetObjectGuid()); unitTarget->CastSpell(unitTarget, 38353, true, NULL, NULL, m_caster->GetObjectGuid());
return; return;
} }
case 39338: // Karazhan - Chess, Medivh CHEAT: Hand of Medivh, Target Horde
case 39342: // Karazhan - Chess, Medivh CHEAT: Hand of Medivh, Target Alliance
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, 39339, true);
return;
}
case 39341: // Karazhan - Chess, Medivh CHEAT: Fury of Medivh, Target Horde
case 39344: // Karazhan - Chess, Medivh CHEAT: Fury of Medivh, Target Alliance
{
if (!unitTarget)
return;
m_caster->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 41055: // Copy Weapon case 41055: // Copy Weapon
{ {
if (m_caster->GetTypeId() != TYPEID_UNIT || !unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER) if (m_caster->GetTypeId() != TYPEID_UNIT || !unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
@ -7538,9 +7660,10 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
} }
// Teleport target to the spectral realm, add debuff and force faction // Teleport target to the spectral realm, add debuff and force faction
unitTarget->CastSpell(unitTarget, 44852, true);
unitTarget->CastSpell(unitTarget, 46019, true); unitTarget->CastSpell(unitTarget, 46019, true);
unitTarget->CastSpell(unitTarget, 46021, true); unitTarget->CastSpell(unitTarget, 46021, true);
unitTarget->CastSpell(unitTarget, 44845, true);
unitTarget->CastSpell(unitTarget, 44852, true);
return; return;
} }
case 45141: // Burn case 45141: // Burn
@ -7600,6 +7723,14 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
unitTarget->CastSpell(unitTarget, 45236, true, NULL, NULL, m_caster->GetObjectGuid()); unitTarget->CastSpell(unitTarget, 45236, true, NULL, NULL, m_caster->GetObjectGuid());
return; return;
} }
case 45260: // Karazhan - Chess - Force Player to Kill Bunny
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->CastSpell(unitTarget, 45259, true);
return;
}
case 45668: // Ultra-Advanced Proto-Typical Shortening Blaster case 45668: // Ultra-Advanced Proto-Typical Shortening Blaster
{ {
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT) if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
@ -7704,6 +7835,22 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
m_caster->SetDisplayId(display_id); m_caster->SetDisplayId(display_id);
return; return;
} }
case 45714: // Fog of Corruption (caster inform)
{
if (!unitTarget || m_caster->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->CastSpell(m_caster, effect->CalculateSimpleValue(), true);
return;
}
case 45717: // Fog of Corruption (player buff)
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->CastSpell(unitTarget, 45726, true);
return;
}
case 45785: // Sinister Reflection Clone case 45785: // Sinister Reflection Clone
{ {
if (!unitTarget) if (!unitTarget)
@ -7730,6 +7877,15 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
unitTarget->CastSpell(unitTarget, 45891, true, NULL, NULL, m_caster->GetObjectGuid()); unitTarget->CastSpell(unitTarget, 45891, true, NULL, NULL, m_caster->GetObjectGuid());
return; return;
} }
case 45918: // Soul Sever
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER || !unitTarget->HasAura(45717))
return;
// kill all charmed targets
unitTarget->CastSpell(unitTarget, 45917, true);
return;
}
case 45958: // Signal Alliance case 45958: // Signal Alliance
{ {
// "escort" aura not present, so let nothing happen // "escort" aura not present, so let nothing happen
@ -8438,6 +8594,37 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
return; return;
} }
case 62042: // Stormhammer
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->CastSpell(unitTarget, 62470, true);
unitTarget->CastSpell(m_caster, 64909, true);
return;
}
case 62381: // Chill
{
if (!unitTarget)
return;
unitTarget->RemoveAurasDueToSpell(62373);
unitTarget->CastSpell(unitTarget, 62382, true);
return;
}
case 62488: // Activate Construct
{
if (!unitTarget || !unitTarget->HasAura(62468))
return;
unitTarget->RemoveAurasDueToSpell(62468);
unitTarget->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
unitTarget->CastSpell(unitTarget, 64474, true);
if (m_caster->getVictim())
((Creature*)unitTarget)->AI()->AttackStart(m_caster->getVictim());
return;
}
case 62524: // Attuned to Nature 2 Dose Reduction case 62524: // Attuned to Nature 2 Dose Reduction
case 62525: // Attuned to Nature 10 Dose Reduction case 62525: // Attuned to Nature 10 Dose Reduction
case 62521: // Attuned to Nature 25 Dose Reduction case 62521: // Attuned to Nature 25 Dose Reduction
@ -8479,6 +8666,23 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
return; return;
} }
case 62707: // Grab
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
return;
unitTarget->CastSpell(unitTarget, 62708, true);
return;
}
case 63633: // Summon Rubble
{
if (!unitTarget)
return;
for (uint8 i = 0; i < 5; ++i)
unitTarget->CastSpell(unitTarget, effect->CalculateSimpleValue(), true);
return;
}
case 64456: // Feral Essence Application Removal case 64456: // Feral Essence Application Removal
{ {
if (!unitTarget) if (!unitTarget)
@ -8488,6 +8692,29 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
unitTarget->RemoveAuraHolderFromStack(spellId); unitTarget->RemoveAuraHolderFromStack(spellId);
return; return;
} }
case 64475: // Strength of the Creator
{
if (!unitTarget)
return;
unitTarget->RemoveAuraHolderFromStack(64473);
return;
}
case 64767: // Stormhammer
{
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
return;
if (Creature* target = (Creature*)unitTarget)
{
target->AI()->EnterEvadeMode();
target->CastSpell(target, 62470, true);
target->CastSpell(m_caster, 64909, true);
target->CastSpell(target, 64778, true);
target->ForcedDespawn(10000);
}
return;
}
case 66477: // Bountiful Feast case 66477: // Bountiful Feast
{ {
if (!unitTarget) if (!unitTarget)
@ -9057,7 +9284,7 @@ void Spell::EffectScriptEffect(SpellEffectEntry const* effect)
// So called only for not processed cases // So called only for not processed cases
if (unitTarget->GetTypeId() == TYPEID_UNIT) if (unitTarget->GetTypeId() == TYPEID_UNIT)
{ {
if (sScriptMgr.OnEffectScriptEffect(m_caster, m_spellInfo->Id, SpellEffectIndex(effect->EffectIndex), (Creature*)unitTarget)) if (sScriptMgr.OnEffectScriptEffect(m_caster, m_spellInfo->Id, SpellEffectIndex(effect->EffectIndex), (Creature*)unitTarget, m_originalCasterGUID))
return; return;
} }
@ -9230,7 +9457,7 @@ static ScriptInfo generateActivateCommand()
si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT; si.command = SCRIPT_COMMAND_ACTIVATE_OBJECT;
si.id = 0; si.id = 0;
si.buddyEntry = 0; si.buddyEntry = 0;
si.searchRadius = 0; si.searchRadiusOrGuid = 0;
si.data_flags = 0x00; si.data_flags = 0x00;
return si; return si;
} }
@ -9240,11 +9467,145 @@ void Spell::EffectActivateObject(SpellEffectEntry const* effect)
if (!gameObjTarget) if (!gameObjTarget)
return; return;
uint32 misc_value = uint32(effect->EffectMiscValue);
switch (misc_value)
{
case 1: // GO simple use
case 2: // unk - 2 spells
case 4: // unk - 1 spell
case 5: // GO trap usage
case 7: // unk - 2 spells
case 8: // GO usage with TargetB = none or random
case 10: // GO explosions
case 11: // unk - 1 spell
case 19: // unk - 1 spell
case 20: // unk - 2 spells
{
static ScriptInfo activateCommand = generateActivateCommand(); static ScriptInfo activateCommand = generateActivateCommand();
int32 delay_secs = effect->CalculateSimpleValue(); int32 delay_secs = effect->CalculateSimpleValue();
gameObjTarget->GetMap()->ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget); gameObjTarget->GetMap()->ScriptCommandStart(activateCommand, delay_secs, m_caster, gameObjTarget);
break;
}
case 3: // GO custom anim - found mostly in Lunar Fireworks spells
gameObjTarget->SendGameObjectCustomAnim(gameObjTarget->GetObjectGuid());
break;
case 12: // GO state active alternative - found mostly in Simon Game spells
gameObjTarget->UseDoorOrButton(0, true);
break;
case 13: // GO state ready - found only in Simon Game spells
gameObjTarget->ResetDoorOrButton();
break;
case 15: // GO destroy
gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
break;
case 16: // GO custom use - found mostly in Wind Stones spells, Simon Game spells and other GO target summoning spells
{
switch (m_spellInfo->Id)
{
case 24734: // Summon Templar Random
case 24744: // Summon Templar (fire)
case 24756: // Summon Templar (air)
case 24758: // Summon Templar (earth)
case 24760: // Summon Templar (water)
case 24763: // Summon Duke Random
case 24765: // Summon Duke (fire)
case 24768: // Summon Duke (air)
case 24770: // Summon Duke (earth)
case 24772: // Summon Duke (water)
case 24784: // Summon Royal Random
case 24786: // Summon Royal (fire)
case 24788: // Summon Royal (air)
case 24789: // Summon Royal (earth)
case 24790: // Summon Royal (water)
{
uint32 npcEntry = 0;
uint32 templars[] = {15209, 15211, 15212, 15307};
uint32 dukes[] = {15206, 15207, 15208, 15220};
uint32 royals[] = {15203, 15204, 15205, 15305};
switch (m_spellInfo->Id)
{
case 24734: npcEntry = templars[urand(0, 3)]; break;
case 24763: npcEntry = dukes[urand(0, 3)]; break;
case 24784: npcEntry = royals[urand(0, 3)]; break;
case 24744: npcEntry = 15209; break;
case 24756: npcEntry = 15212; break;
case 24758: npcEntry = 15307; break;
case 24760: npcEntry = 15211; break;
case 24765: npcEntry = 15206; break;
case 24768: npcEntry = 15220; break;
case 24770: npcEntry = 15208; break;
case 24772: npcEntry = 15207; break;
case 24786: npcEntry = 15203; break;
case 24788: npcEntry = 15204; break;
case 24789: npcEntry = 15205; break;
case 24790: npcEntry = 15305; break;
}
gameObjTarget->SummonCreature(npcEntry, gameObjTarget->GetPositionX(), gameObjTarget->GetPositionY(), gameObjTarget->GetPositionZ(), gameObjTarget->GetAngle(m_caster), TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, MINUTE * IN_MILLISECONDS);
gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
break;
}
case 40176: // Simon Game pre-game Begin, blue
case 40177: // Simon Game pre-game Begin, green
case 40178: // Simon Game pre-game Begin, red
case 40179: // Simon Game pre-game Begin, yellow
case 40283: // Simon Game END, blue
case 40284: // Simon Game END, green
case 40285: // Simon Game END, red
case 40286: // Simon Game END, yellow
case 40494: // Simon Game, switched ON
case 40495: // Simon Game, switched OFF
case 40512: // Simon Game, switch...disable Off switch
gameObjTarget->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT);
break;
case 40632: // Summon Gezzarak the Huntress
case 40640: // Summon Karrog
case 40642: // Summon Darkscreecher Akkarai
case 40644: // Summon Vakkiz the Windrager
case 41004: // Summon Terokk
gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
break;
case 46085: // Place Fake Fur
{
float x, y, z;
gameObjTarget->GetClosePoint(x, y, z, gameObjTarget->GetObjectBoundingRadius(), 2 * INTERACTION_DISTANCE, frand(0, M_PI_F * 2));
// Note: event script is implemented in script library
gameObjTarget->SummonCreature(25835, x, y, z, gameObjTarget->GetOrientation(), TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, 15000);
gameObjTarget->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE);
break;
}
case 46592: // Summon Ahune Lieutenant
{
uint32 npcEntry = 0;
switch (gameObjTarget->GetEntry())
{
case 188049: npcEntry = 26116; break; // Frostwave Lieutenant (Ashenvale)
case 188137: npcEntry = 26178; break; // Hailstone Lieutenant (Desolace)
case 188138: npcEntry = 26204; break; // Chillwind Lieutenant (Stranglethorn)
case 188148: npcEntry = 26214; break; // Frigid Lieutenant (Searing Gorge)
case 188149: npcEntry = 26215; break; // Glacial Lieutenant (Silithus)
case 188150: npcEntry = 26216; break; // Glacial Templar (Hellfire Peninsula)
}
gameObjTarget->SummonCreature(npcEntry, gameObjTarget->GetPositionX(), gameObjTarget->GetPositionY(), gameObjTarget->GetPositionZ(), gameObjTarget->GetAngle(m_caster), TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN, MINUTE * IN_MILLISECONDS);
gameObjTarget->SetLootState(GO_JUST_DEACTIVATED);
break;
}
}
break;
}
case 17: // GO unlock - found mostly in Simon Game spells
gameObjTarget->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NO_INTERACT);
break;
default:
sLog.outError("Spell::EffectActivateObject called with unknown misc value. Spell Id %u", m_spellInfo->Id);
break;
}
} }
void Spell::EffectApplyGlyph(SpellEffectEntry const* effect) void Spell::EffectApplyGlyph(SpellEffectEntry const* effect)
@ -9540,7 +9901,7 @@ void Spell::EffectLeapForward(SpellEffectEntry const* effect)
if (unitTarget->IsTaxiFlying()) if (unitTarget->IsTaxiFlying())
return; return;
if (m_spellInfo->rangeIndex == 1) // self range if (m_spellInfo->rangeIndex == SPELL_RANGE_IDX_SELF_ONLY)
{ {
float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(effect->GetRadiusIndex())); float dis = GetSpellRadius(sSpellRadiusStore.LookupEntry(effect->GetRadiusIndex()));
@ -9935,7 +10296,7 @@ void Spell::EffectTransmitted(SpellEffectEntry const* effect)
// calculate angle variation for roughly equal dimensions of target area // calculate angle variation for roughly equal dimensions of target area
float max_angle = (max_dis - min_dis) / (max_dis + m_caster->GetObjectBoundingRadius()); float max_angle = (max_dis - min_dis) / (max_dis + m_caster->GetObjectBoundingRadius());
float angle_offset = max_angle * (rand_norm_f() - 0.5f); float angle_offset = max_angle * (rand_norm_f() - 0.5f);
m_caster->GetNearPoint2D(fx, fy, dis, m_caster->GetOrientation() + angle_offset); m_caster->GetNearPoint2D(fx, fy, dis + m_caster->GetObjectBoundingRadius(), m_caster->GetOrientation() + angle_offset);
GridMapLiquidData liqData; GridMapLiquidData liqData;
if (!m_caster->GetTerrain()->IsInWater(fx, fy, m_caster->GetPositionZ() + 1.f, &liqData)) if (!m_caster->GetTerrain()->IsInWater(fx, fy, m_caster->GetPositionZ() + 1.f, &liqData))

View file

@ -749,6 +749,8 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex)
return false; return false;
case 10258: // Awaken Vault Warder case 10258: // Awaken Vault Warder
case 18153: // Kodo Kombobulator case 18153: // Kodo Kombobulator
case 32312: // Move 1
case 37388: // Move 2
case 49634: // Sergeant's Flare case 49634: // Sergeant's Flare
case 54530: // Opening case 54530: // Opening
case 62105: // To'kini's Blowgun case 62105: // To'kini's Blowgun
@ -757,6 +759,18 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex)
break; break;
} }
break; break;
case SPELL_EFFECT_SCRIPT_EFFECT:
// some explicitly required script effect sets
switch (spellproto->Id)
{
case 46650: // Open Brutallus Back Door
case 62488: // Activate Construct
case 64503: // Water
return true;
default:
break;
}
break;
// always positive effects (check before target checks that provided non-positive result in some case for positive effects) // always positive effects (check before target checks that provided non-positive result in some case for positive effects)
case SPELL_EFFECT_HEAL: case SPELL_EFFECT_HEAL:
case SPELL_EFFECT_LEARN_SPELL: case SPELL_EFFECT_LEARN_SPELL:
@ -797,6 +811,7 @@ bool IsPositiveEffect(SpellEntry const* spellproto, SpellEffectIndex effIndex)
case 27202: case 27202:
case 27203: case 27203:
case 47669: case 47669:
case 64996: // Reorigination
return true; return true;
default: default:
break; break;
@ -2164,6 +2179,40 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons
(spellInfo_2->Id == 57598 && spellInfo_1->Id == 57560)) (spellInfo_2->Id == 57598 && spellInfo_1->Id == 57560))
return false; return false;
// Shard of Flame and Mote of Flame
if ((spellInfo_1->SpellIconID == 2302 && spellInfo_1->SpellVisual[0] == 0) ||
(spellInfo_2->SpellIconID == 2302 && spellInfo_2->SpellVisual[0] == 0))
return false;
// Felblaze Visual and Fog of Corruption
if ((spellInfo_1->Id == 45068 && spellInfo_2->Id == 45582) ||
(spellInfo_2->Id == 45068 && spellInfo_1->Id == 45582))
return false;
// Simon Game START timer, (DND) and Simon Game Pre-game timer
if ((spellInfo_1->Id == 39993 && spellInfo_2->Id == 40041) ||
(spellInfo_2->Id == 39993 && spellInfo_1->Id == 40041))
return false;
// Karazhan - Chess: Is Square OCCUPIED aura Karazhan - Chess: Create Move Marker
if ((spellInfo_1->Id == 39400 && spellInfo_2->Id == 32261) ||
(spellInfo_2->Id == 39400 && spellInfo_1->Id == 32261))
return false;
// Black Hole (damage) and Black Hole (phase)
if ((spellInfo_1->Id == 62169 && spellInfo_2->Id == 62168) ||
(spellInfo_2->Id == 62169 && spellInfo_1->Id == 62168))
return false;
// Black Hole (damage) and Worm Hole (phase)
if ((spellInfo_1->Id == 62169 && spellInfo_2->Id == 65250) ||
(spellInfo_2->Id == 62169 && spellInfo_1->Id == 65250))
return false;
// Black Hole (damage) and Phase Punch (phase)
if ((spellInfo_1->Id == 62169 && spellInfo_2->Id == 64417) ||
(spellInfo_2->Id == 62169 && spellInfo_1->Id == 64417))
return false;
break; break;
} }
case SPELLFAMILY_MAGE: case SPELLFAMILY_MAGE:

View file

@ -43,23 +43,23 @@ void TargetedMovementGeneratorMedium<T, D>::_setTargetLocation(T& owner, bool up
// Can happen for example if no path was created on MMGen-Initialize because of the owner being stunned // Can happen for example if no path was created on MMGen-Initialize because of the owner being stunned
if (updateDestination || !i_path) if (updateDestination || !i_path)
{ {
owner.GetPosition(x, y, z);
// prevent redundant micro-movement for pets, other followers. // prevent redundant micro-movement for pets, other followers.
if (i_offset && i_target->IsWithinDistInMap(&owner, 2 * i_offset)) if (!RequiresNewPosition(owner, x, y, z))
{ {
if (!owner.movespline->Finalized()) if (!owner.movespline->Finalized())
return; return;
owner.GetPosition(x, y, z);
} }
else if (!i_offset) // Chase Movement and angle == 0 case: Chase to current angle
else if (this->GetMovementGeneratorType() == CHASE_MOTION_TYPE && i_angle == 0.0f)
{ {
// to nearest contact position i_target->GetNearPoint(&owner, x, y, z, owner.GetObjectBoundingRadius(), this->GetDynamicTargetDistance(owner, false), i_target->GetAngle(&owner));
i_target->GetContactPoint(&owner, x, y, z);
} }
// Targeted movement to at i_offset distance from target and i_angle from target facing
else else
{ {
// to at i_offset distance from target and i_angle from target facing i_target->GetNearPoint(&owner, x, y, z, owner.GetObjectBoundingRadius(), this->GetDynamicTargetDistance(owner, false), i_target->GetOrientation() + i_angle);
i_target->GetClosePoint(x, y, z, owner.GetObjectBoundingRadius(), i_offset, i_angle, &owner);
} }
} }
else else
@ -131,16 +131,10 @@ bool TargetedMovementGeneratorMedium<T, D>::Update(T& owner, const uint32& time_
i_recheckDistance.Update(time_diff); i_recheckDistance.Update(time_diff);
if (i_recheckDistance.Passed()) if (i_recheckDistance.Passed())
{ {
i_recheckDistance.Reset(100); i_recheckDistance.Reset(this->GetMovementGeneratorType() == FOLLOW_MOTION_TYPE ? 50 : 100);
// More distance let have better performance, less distance let have more sensitive reaction at target move.
float allowed_dist = owner.GetObjectBoundingRadius() + sWorld.getConfig(CONFIG_FLOAT_RATE_TARGET_POS_RECALCULATION_RANGE);
G3D::Vector3 dest = owner.movespline->FinalDestination(); G3D::Vector3 dest = owner.movespline->FinalDestination();
if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->CanFly()) targetMoved = RequiresNewPosition(owner, dest.x, dest.y, dest.z);
targetMoved = !i_target->IsWithinDist3d(dest.x, dest.y, dest.z, allowed_dist);
else
targetMoved = !i_target->IsWithinDist2d(dest.x, dest.y, allowed_dist);
} }
if (m_speedChanged || targetMoved) if (m_speedChanged || targetMoved)
@ -166,6 +160,15 @@ bool TargetedMovementGeneratorMedium<T, D>::IsReachable() const
return (i_path) ? (i_path->getPathType() & PATHFIND_NORMAL) : true; return (i_path) ? (i_path->getPathType() & PATHFIND_NORMAL) : true;
} }
template<class T, typename D>
bool TargetedMovementGeneratorMedium<T, D>::RequiresNewPosition(T& owner, float x, float y, float z) const
{
// More distance let have better performance, less distance let have more sensitive reaction at target move.
if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->CanFly())
return !i_target->IsWithinDist3d(x, y, z, this->GetDynamicTargetDistance(owner, true));
else
return !i_target->IsWithinDist2d(x, y, this->GetDynamicTargetDistance(owner, true));
}
//-----------------------------------------------// //-----------------------------------------------//
template<class T> template<class T>
@ -220,6 +223,19 @@ void ChaseMovementGenerator<T>::Reset(T& owner)
Initialize(owner); Initialize(owner);
} }
// Chase-Movement: These factors depend on combat-reach distance
#define CHASE_DEFAULT_RANGE_FACTOR 0.5f
#define CHASE_RECHASE_RANGE_FACTOR 0.75f
template<class T>
float ChaseMovementGenerator<T>::GetDynamicTargetDistance(T& owner, bool forRangeCheck) const
{
if (!forRangeCheck)
return this->i_offset + CHASE_DEFAULT_RANGE_FACTOR * this->i_target->GetCombatReach(&owner);
return CHASE_RECHASE_RANGE_FACTOR * this->i_target->GetCombatReach(&owner) - this->i_target->GetObjectBoundingRadius();
}
//-----------------------------------------------// //-----------------------------------------------//
template<class T> template<class T>
void FollowMovementGenerator<T>::_clearUnitStateMove(T& u) { u.clearUnitState(UNIT_STAT_FOLLOW_MOVE); } void FollowMovementGenerator<T>::_clearUnitStateMove(T& u) { u.clearUnitState(UNIT_STAT_FOLLOW_MOVE); }
@ -293,6 +309,28 @@ void FollowMovementGenerator<T>::Reset(T& owner)
Initialize(owner); Initialize(owner);
} }
// This factor defines how much of the bounding-radius (as measurement of size) will be used for recalculating a new following position
// The smaller, the more micro movement, the bigger, possibly no proper movement updates
#define FOLLOW_RECALCULATE_FACTOR 0.1f
// This factor defines when the distance of a follower will have impact onto following-position updates
#define FOLLOW_DIST_GAP_FOR_DIST_FACTOR 3.0f
// This factor defines how much of the follow-distance will be used as sloppyness value (if the above distance is exceeded)
#define FOLLOW_DIST_RECALCULATE_FACTOR 0.1f
template<class T>
float FollowMovementGenerator<T>::GetDynamicTargetDistance(T& owner, bool forRangeCheck) const
{
if (!forRangeCheck)
return this->i_offset + owner.GetObjectBoundingRadius() + this->i_target->GetObjectBoundingRadius();
float allowed_dist = sWorld.getConfig(CONFIG_FLOAT_RATE_TARGET_POS_RECALCULATION_RANGE) - this->i_target->GetObjectBoundingRadius();
allowed_dist += FOLLOW_RECALCULATE_FACTOR * (owner.GetObjectBoundingRadius() + this->i_target->GetObjectBoundingRadius());
if (this->i_offset > FOLLOW_DIST_GAP_FOR_DIST_FACTOR)
allowed_dist += FOLLOW_DIST_RECALCULATE_FACTOR * this->i_offset;
return allowed_dist;
}
//-----------------------------------------------// //-----------------------------------------------//
template void TargetedMovementGeneratorMedium<Player, ChaseMovementGenerator<Player> >::_setTargetLocation(Player&, bool); template void TargetedMovementGeneratorMedium<Player, ChaseMovementGenerator<Player> >::_setTargetLocation(Player&, bool);
template void TargetedMovementGeneratorMedium<Player, FollowMovementGenerator<Player> >::_setTargetLocation(Player&, bool); template void TargetedMovementGeneratorMedium<Player, FollowMovementGenerator<Player> >::_setTargetLocation(Player&, bool);
@ -319,6 +357,8 @@ template void ChaseMovementGenerator<Player>::Interrupt(Player&);
template void ChaseMovementGenerator<Creature>::Interrupt(Creature&); template void ChaseMovementGenerator<Creature>::Interrupt(Creature&);
template void ChaseMovementGenerator<Player>::Reset(Player&); template void ChaseMovementGenerator<Player>::Reset(Player&);
template void ChaseMovementGenerator<Creature>::Reset(Creature&); template void ChaseMovementGenerator<Creature>::Reset(Creature&);
template float ChaseMovementGenerator<Creature>::GetDynamicTargetDistance(Creature&, bool) const;
template float ChaseMovementGenerator<Player>::GetDynamicTargetDistance(Player&, bool) const;
template void FollowMovementGenerator<Player>::_clearUnitStateMove(Player& u); template void FollowMovementGenerator<Player>::_clearUnitStateMove(Player& u);
template void FollowMovementGenerator<Creature>::_addUnitStateMove(Creature& u); template void FollowMovementGenerator<Creature>::_addUnitStateMove(Creature& u);
@ -328,3 +368,5 @@ template void FollowMovementGenerator<Player>::Interrupt(Player&);
template void FollowMovementGenerator<Creature>::Interrupt(Creature&); template void FollowMovementGenerator<Creature>::Interrupt(Creature&);
template void FollowMovementGenerator<Player>::Reset(Player&); template void FollowMovementGenerator<Player>::Reset(Player&);
template void FollowMovementGenerator<Creature>::Reset(Creature&); template void FollowMovementGenerator<Creature>::Reset(Creature&);
template float FollowMovementGenerator<Creature>::GetDynamicTargetDistance(Creature&, bool) const;
template float FollowMovementGenerator<Player>::GetDynamicTargetDistance(Player&, bool) const;

View file

@ -59,6 +59,8 @@ class MANGOS_DLL_SPEC TargetedMovementGeneratorMedium
protected: protected:
void _setTargetLocation(T&, bool updateDestination); void _setTargetLocation(T&, bool updateDestination);
bool RequiresNewPosition(T& owner, float x, float y, float z) const;
virtual float GetDynamicTargetDistance(T& owner, bool forRangeCheck) const { return i_offset; }
ShortTimeTracker i_recheckDistance; ShortTimeTracker i_recheckDistance;
float i_offset; float i_offset;
@ -73,8 +75,6 @@ template<class T>
class MANGOS_DLL_SPEC ChaseMovementGenerator : public TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> > class MANGOS_DLL_SPEC ChaseMovementGenerator : public TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >
{ {
public: public:
ChaseMovementGenerator(Unit& target)
: TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >(target) {}
ChaseMovementGenerator(Unit& target, float offset, float angle) ChaseMovementGenerator(Unit& target, float offset, float angle)
: TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >(target, offset, angle) {} : TargetedMovementGeneratorMedium<T, ChaseMovementGenerator<T> >(target, offset, angle) {}
~ChaseMovementGenerator() {} ~ChaseMovementGenerator() {}
@ -91,6 +91,9 @@ class MANGOS_DLL_SPEC ChaseMovementGenerator : public TargetedMovementGeneratorM
bool EnableWalking() const { return false;} bool EnableWalking() const { return false;}
bool _lostTarget(T& u) const; bool _lostTarget(T& u) const;
void _reachTarget(T&); void _reachTarget(T&);
protected:
float GetDynamicTargetDistance(T& owner, bool forRangeCheck) const override;
}; };
template<class T> template<class T>
@ -115,8 +118,12 @@ class MANGOS_DLL_SPEC FollowMovementGenerator : public TargetedMovementGenerator
bool EnableWalking() const; bool EnableWalking() const;
bool _lostTarget(T&) const { return false; } bool _lostTarget(T&) const { return false; }
void _reachTarget(T&) {} void _reachTarget(T&) {}
private: private:
void _updateSpeed(T& u); void _updateSpeed(T& u);
protected:
float GetDynamicTargetDistance(T& owner, bool forRangeCheck) const override;
}; };
#endif #endif

View file

@ -163,7 +163,7 @@ class MANGOS_DLL_SPEC ThreatContainer
bool isDirty() const { return iDirty; } bool isDirty() const { return iDirty; }
bool empty() const { return(iThreatList.empty()); } bool empty() const { return iThreatList.empty(); }
HostileReference* getMostHated() { return iThreatList.empty() ? NULL : iThreatList.front(); } HostileReference* getMostHated() { return iThreatList.empty() ? NULL : iThreatList.front(); }

View file

@ -51,7 +51,7 @@
#include "movement/MoveSplineInit.h" #include "movement/MoveSplineInit.h"
#include "movement/MoveSpline.h" #include "movement/MoveSpline.h"
#include "CreatureLinkingMgr.h" #include "CreatureLinkingMgr.h"
#include "MovementStructures.h" #include "movement/MovementStructures.h"
#include <math.h> #include <math.h>
#include <stdarg.h> #include <stdarg.h>
@ -5170,7 +5170,7 @@ void Unit::RemoveAllAurasOnEvade()
for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();) for (SpellAuraHolderMap::iterator iter = m_spellAuraHolders.begin(); iter != m_spellAuraHolders.end();)
{ {
SpellEntry const* proto = iter->second->GetSpellProto(); SpellEntry const* proto = iter->second->GetSpellProto();
if (!IsSpellHaveAura(proto, SPELL_AURA_CONTROL_VEHICLE)) if (!IsSpellHaveAura(proto, SPELL_AURA_CONTROL_VEHICLE) && !IsSpellHaveAura(proto, SPELL_AURA_FLY))
{ {
RemoveSpellAuraHolder(iter->second, AURA_REMOVE_BY_DEFAULT); RemoveSpellAuraHolder(iter->second, AURA_REMOVE_BY_DEFAULT);
iter = m_spellAuraHolders.begin(); iter = m_spellAuraHolders.begin();
@ -6620,6 +6620,7 @@ uint32 Unit::SpellDamageBonusDone(Unit* pVictim, SpellEntry const* spellProto, u
return owner->SpellDamageBonusDone(pVictim, spellProto, pdamage, damagetype); return owner->SpellDamageBonusDone(pVictim, spellProto, pdamage, damagetype);
} }
uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
float DoneTotalMod = 1.0f; float DoneTotalMod = 1.0f;
int32 DoneTotal = 0; int32 DoneTotal = 0;
@ -6641,20 +6642,14 @@ uint32 Unit::SpellDamageBonusDone(Unit* pVictim, SpellEntry const* spellProto, u
} }
} }
uint32 creatureTypeMask = pVictim->GetCreatureTypeMask();
// Add flat bonus from spell damage versus // Add flat bonus from spell damage versus
DoneTotal += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS, creatureTypeMask); DoneTotal += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS, creatureTypeMask);
AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS);
for (AuraList::const_iterator i = mDamageDoneVersus.begin(); i != mDamageDoneVersus.end(); ++i)
if (creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
DoneTotalMod *= ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f;
AuraList const& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE); // Add pct bonus from spell damage versus
for (AuraList::const_iterator i = mDamageDoneCreature.begin(); i != mDamageDoneCreature.end(); ++i) DoneTotalMod *= GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE_VERSUS, creatureTypeMask);
{
if (creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue)) // Add flat bonus from spell damage creature
DoneTotalMod += ((*i)->GetModifier()->m_amount + 100.0f) / 100.0f; DoneTotal += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE, creatureTypeMask);
}
if (getPowerType() == POWER_MANA) if (getPowerType() == POWER_MANA)
{ {
@ -6672,7 +6667,9 @@ uint32 Unit::SpellDamageBonusDone(Unit* pVictim, SpellEntry const* spellProto, u
// done scripted mod (take it from owner) // done scripted mod (take it from owner)
Unit* owner = GetOwner(); Unit* owner = GetOwner();
if (!owner) owner = this; if (!owner)
owner = this;
AuraList const& mOverrideClassScript = owner->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS); AuraList const& mOverrideClassScript = owner->GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
for (AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i) for (AuraList::const_iterator i = mOverrideClassScript.begin(); i != mOverrideClassScript.end(); ++i)
{ {

View file

@ -518,8 +518,6 @@ enum UnitMoveType
#define MAX_MOVE_TYPE 9 #define MAX_MOVE_TYPE 9
extern float baseMoveSpeed[MAX_MOVE_TYPE];
enum CombatRating enum CombatRating
{ {
CR_WEAPON_SKILL = 0, CR_WEAPON_SKILL = 0,

View file

@ -2883,6 +2883,7 @@ SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit* pVictim, uint32 d
switch (auraSpellInfo->GetSpellFamilyName()) switch (auraSpellInfo->GetSpellFamilyName())
{ {
case SPELLFAMILY_GENERIC: case SPELLFAMILY_GENERIC:
{
switch (auraSpellInfo->Id) switch (auraSpellInfo->Id)
{ {
// case 191: // Elemental Response // case 191: // Elemental Response
@ -3067,7 +3068,9 @@ SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit* pVictim, uint32 d
} }
} }
break; break;
}
case SPELLFAMILY_MAGE: case SPELLFAMILY_MAGE:
{
if (auraSpellInfo->SpellIconID == 2127) // Blazing Speed if (auraSpellInfo->SpellIconID == 2127) // Blazing Speed
{ {
switch (auraSpellInfo->Id) switch (auraSpellInfo->Id)
@ -3096,7 +3099,9 @@ SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit* pVictim, uint32 d
return SPELL_AURA_PROC_FAILED; return SPELL_AURA_PROC_FAILED;
} }
break; break;
}
case SPELLFAMILY_WARRIOR: case SPELLFAMILY_WARRIOR:
{
// Deep Wounds (replace triggered spells to directly apply DoT), dot spell have familyflags // Deep Wounds (replace triggered spells to directly apply DoT), dot spell have familyflags
if (auraClassOptions && auraClassOptions->SpellFamilyFlags == UI64LIT(0x0) && auraSpellInfo->SpellIconID == 243) if (auraClassOptions && auraClassOptions->SpellFamilyFlags == UI64LIT(0x0) && auraSpellInfo->SpellIconID == 243)
{ {
@ -3110,9 +3115,9 @@ SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit* pVictim, uint32 d
switch (auraSpellInfo->Id) switch (auraSpellInfo->Id)
{ {
case 12834: basepoints[0] = int32(weaponDamage * 16 / 100); break; case 12834: basepoints[EFFECT_INDEX_0] = int32(weaponDamage * 16 / 100); break;
case 12849: basepoints[0] = int32(weaponDamage * 32 / 100); break; case 12849: basepoints[EFFECT_INDEX_0] = int32(weaponDamage * 32 / 100); break;
case 12867: basepoints[0] = int32(weaponDamage * 48 / 100); break; case 12867: basepoints[EFFECT_INDEX_0] = int32(weaponDamage * 48 / 100); break;
// Impossible case // Impossible case
default: default:
sLog.outError("Unit::HandleProcTriggerSpellAuraProc: DW unknown spell rank %u", auraSpellInfo->Id); sLog.outError("Unit::HandleProcTriggerSpellAuraProc: DW unknown spell rank %u", auraSpellInfo->Id);
@ -3120,7 +3125,7 @@ SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit* pVictim, uint32 d
} }
// 1 tick/sec * 6 sec = 6 ticks // 1 tick/sec * 6 sec = 6 ticks
basepoints[0] /= 6; basepoints[EFFECT_INDEX_0] /= 6;
trigger_spell_id = 12721; trigger_spell_id = 12721;
break; break;
@ -3132,8 +3137,14 @@ SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit* pVictim, uint32 d
return SPELL_AURA_PROC_FAILED; return SPELL_AURA_PROC_FAILED;
} }
else if (auraSpellInfo->Id == 50421) // Scent of Blood else if (auraSpellInfo->Id == 50421) // Scent of Blood
{
RemoveAuraHolderFromStack(50421);
trigger_spell_id = 50422; trigger_spell_id = 50422;
target = this;
break; break;
}
break;
}
case SPELLFAMILY_WARLOCK: case SPELLFAMILY_WARLOCK:
{ {
// Drain Soul // Drain Soul
@ -3169,14 +3180,13 @@ SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit* pVictim, uint32 d
return SPELL_AURA_PROC_FAILED; return SPELL_AURA_PROC_FAILED;
switch (GetFirstSchoolInMask(GetSpellSchoolMask(procSpell))) switch (GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
{ {
case SPELL_SCHOOL_NORMAL:
return SPELL_AURA_PROC_FAILED; // ignore
case SPELL_SCHOOL_HOLY: trigger_spell_id = 54370; break; case SPELL_SCHOOL_HOLY: trigger_spell_id = 54370; break;
case SPELL_SCHOOL_FIRE: trigger_spell_id = 54371; break; case SPELL_SCHOOL_FIRE: trigger_spell_id = 54371; break;
case SPELL_SCHOOL_NATURE: trigger_spell_id = 54375; break; case SPELL_SCHOOL_NATURE: trigger_spell_id = 54375; break;
case SPELL_SCHOOL_FROST: trigger_spell_id = 54372; break; case SPELL_SCHOOL_FROST: trigger_spell_id = 54372; break;
case SPELL_SCHOOL_SHADOW: trigger_spell_id = 54374; break; case SPELL_SCHOOL_SHADOW: trigger_spell_id = 54374; break;
case SPELL_SCHOOL_ARCANE: trigger_spell_id = 54373; break; case SPELL_SCHOOL_ARCANE: trigger_spell_id = 54373; break;
case SPELL_SCHOOL_NORMAL: // ignore
default: default:
return SPELL_AURA_PROC_FAILED; return SPELL_AURA_PROC_FAILED;
} }
@ -3417,6 +3427,29 @@ SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit* pVictim, uint32 d
trigger_spell_id = 54843; trigger_spell_id = 54843;
target = pVictim; target = pVictim;
} }
// Item - Coliseum 25 Normal and Heroic Caster Trinket
else if (auraSpellInfo->Id == 67712 || auraSpellInfo->Id == 67758)
{
if (!pVictim || !pVictim->isAlive())
return SPELL_AURA_PROC_FAILED;
uint32 castSpell = auraSpellInfo->Id == 67758 ? 67759 : 67713;
// stacking
CastSpell(this, castSpell, true, NULL, triggeredByAura);
// counting
Aura* dummy = GetDummyAura(castSpell);
// release at 3 aura in stack (count contained in basepoint of trigger aura)
if (!dummy || dummy->GetStackAmount() < uint32(triggerAmount))
return SPELL_AURA_PROC_FAILED;
RemoveAurasDueToSpell(castSpell);
trigger_spell_id = castSpell + 1;
target = pVictim;
break;
}
break; break;
} }
case SPELLFAMILY_SHAMAN: case SPELLFAMILY_SHAMAN:
@ -3530,6 +3563,7 @@ SpellAuraProcResult Unit::HandleProcTriggerSpellAuraProc(Unit* pVictim, uint32 d
break; break;
} }
// All ok. Check current trigger spell // All ok. Check current trigger spell
SpellEntry const* triggerEntry = sSpellStore.LookupEntry(trigger_spell_id); SpellEntry const* triggerEntry = sSpellStore.LookupEntry(trigger_spell_id);
if (!triggerEntry) if (!triggerEntry)

View file

@ -718,7 +718,6 @@ void World::LoadConfigSettings(bool reload)
setConfig(CONFIG_UINT32_WORLD_BOSS_LEVEL_DIFF, "WorldBossLevelDiff", 3); setConfig(CONFIG_UINT32_WORLD_BOSS_LEVEL_DIFF, "WorldBossLevelDiff", 3);
// note: disable value (-1) will assigned as 0xFFFFFFF, to prevent overflow at calculations limit it to max possible player level MAX_LEVEL(100)
setConfigMinMax(CONFIG_INT32_QUEST_LOW_LEVEL_HIDE_DIFF, "Quests.LowLevelHideDiff", 4, -1, MAX_LEVEL); setConfigMinMax(CONFIG_INT32_QUEST_LOW_LEVEL_HIDE_DIFF, "Quests.LowLevelHideDiff", 4, -1, MAX_LEVEL);
setConfigMinMax(CONFIG_INT32_QUEST_HIGH_LEVEL_HIDE_DIFF, "Quests.HighLevelHideDiff", 7, -1, MAX_LEVEL); setConfigMinMax(CONFIG_INT32_QUEST_HIGH_LEVEL_HIDE_DIFF, "Quests.HighLevelHideDiff", 7, -1, MAX_LEVEL);

View file

@ -1,5 +1,5 @@
/* /*
* This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS. * This file is part of the MaNGOS Project. See AUTHORS file for Copyright information
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by

View file

@ -82,9 +82,9 @@ namespace VMAP
*/ */
void setEnableHeightCalc(bool pVal) { iEnableHeightCalc = pVal; } void setEnableHeightCalc(bool pVal) { iEnableHeightCalc = pVal; }
bool isLineOfSightCalcEnabled() const { return(iEnableLineOfSightCalc); } bool isLineOfSightCalcEnabled() const { return iEnableLineOfSightCalc; }
bool isHeightCalcEnabled() const { return(iEnableHeightCalc); } bool isHeightCalcEnabled() const { return iEnableHeightCalc; }
bool isMapLoadingEnabled() const { return(iEnableLineOfSightCalc || iEnableHeightCalc); } bool isMapLoadingEnabled() const { return iEnableLineOfSightCalc || iEnableHeightCalc; }
virtual std::string getDirFileName(unsigned int pMapId, int x, int y) const = 0; virtual std::string getDirFileName(unsigned int pMapId, int x, int y) const = 0;
/** /**

View file

@ -224,7 +224,7 @@ namespace VMAP
{ {
height = pPos.z - maxDist; height = pPos.z - maxDist;
} }
return(height); return height;
} }
//========================================================= //=========================================================

View file

@ -48,7 +48,7 @@ namespace VMAP
{ {
Vector3 out = pIn * iScale; Vector3 out = pIn * iScale;
out = iRotation * out; out = iRotation * out;
return(out); return out;
} }
//================================================================= //=================================================================

View file

@ -77,7 +77,7 @@ namespace VMAP
pId = atoi(idString.c_str()); pId = atoi(idString.c_str());
result = true; result = true;
} }
return(result); return result;
} }
//=============================================== //===============================================
@ -106,7 +106,7 @@ namespace VMAP
bool VMapFactory::checkSpellForLoS(unsigned int pSpellId) bool VMapFactory::checkSpellForLoS(unsigned int pSpellId)
{ {
return(!iIgnoreSpellIds->containsKey(pSpellId)); return !iIgnoreSpellIds->containsKey(pSpellId);
} }
//=============================================== //===============================================

View file

@ -480,7 +480,12 @@ bool ChatHandler::HandleAccountCreateCommand(char* args)
std::string account_name = szAcc; std::string account_name = szAcc;
std::string password = szPassword; std::string password = szPassword;
AccountOpResult result = sAccountMgr.CreateAccount(account_name, password); AccountOpResult result;
uint32 expansion = 0;
if(ExtractUInt32(&args, expansion))
result = sAccountMgr.CreateAccount(account_name, password, expansion);
else
result = sAccountMgr.CreateAccount(account_name, password);
switch (result) switch (result)
{ {
case AOR_OK: case AOR_OK:

View file

@ -1,22 +1,6 @@
# This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS.
#
# 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
set(LIBRARY_NAME shared) set(LIBRARY_NAME shared)
set(LIBRARY_SRCS set(SRC_GRP_AUTH
Auth/AuthCrypt.cpp Auth/AuthCrypt.cpp
Auth/AuthCrypt.h Auth/AuthCrypt.h
Auth/BigNumber.cpp Auth/BigNumber.cpp
@ -28,12 +12,14 @@ set(LIBRARY_SRCS
Auth/SARC4.h Auth/SARC4.h
Auth/Sha1.cpp Auth/Sha1.cpp
Auth/Sha1.h Auth/Sha1.h
ByteBuffer.cpp )
ByteBuffer.h
Common.cpp set(SRC_GRP_CONFIG
Common.h
Config/Config.cpp Config/Config.cpp
Config/Config.h Config/Config.h
)
set(SRC_GRP_DATABASE
Database/Database.cpp Database/Database.cpp
Database/Database.h Database/Database.h
Database/DatabaseEnv.h Database/DatabaseEnv.h
@ -42,12 +28,6 @@ set(LIBRARY_SRCS
Database/DatabaseMysql.h Database/DatabaseMysql.h
Database/DatabasePostgre.cpp Database/DatabasePostgre.cpp
Database/DatabasePostgre.h Database/DatabasePostgre.h
Database/DB2FileLoader.cpp
Database/DB2FileLoader.h
Database/DB2Store.h
Database/DBCFileLoader.cpp
Database/DBCFileLoader.h
Database/DBCStore.h
Database/Field.cpp Database/Field.cpp
Database/Field.h Database/Field.h
Database/PGSQLDelayThread.h Database/PGSQLDelayThread.h
@ -65,21 +45,82 @@ set(LIBRARY_SRCS
Database/SQLStorage.cpp Database/SQLStorage.cpp
Database/SQLStorage.h Database/SQLStorage.h
Database/SQLStorageImpl.h Database/SQLStorageImpl.h
Errors.h )
LockedQueue.h
set(SRC_GRP_DATABASE_DBC
Database/DB2FileLoader.cpp
Database/DB2FileLoader.h
Database/DB2Store.h
Database/DBCFileLoader.cpp
Database/DBCFileLoader.h
Database/DBCStore.h
)
set(SRC_GRP_LOG
Log.cpp Log.cpp
Log.h Log.h
)
set(SRC_GRP_UTIL
ByteBuffer.cpp
ByteBuffer.h
Errors.h
# dep/include/mersennetwister/MersenneTwister.h is part of this group in the VC 2012 file but it is not part of src/shared, so it is omitted here
ProgressBar.cpp ProgressBar.cpp
ProgressBar.h ProgressBar.h
Timer.h
Util.cpp
Util.h
WorldPacket.h
)
set(LIBRARY_SRCS
${SRC_GRP_AUTH}
${SRC_GRP_CONFIG}
${SRC_GRP_DATABASE}
${SRC_GRP_DATABASE_DBC}
${SRC_GRP_LOG}
${SRC_GRP_UTIL}
Common.cpp
Common.h
LockedQueue.h
revision_nr.h revision_nr.h
revision_sql.h revision_sql.h
SystemConfig.h SystemConfig.h
Threading.cpp Threading.cpp
Threading.h Threading.h
Timer.h )
Util.cpp
Util.h
WorldPacket.h source_group("Auth"
FILES
${SRC_GRP_AUTH}
)
source_group("Config"
FILES
${SRC_GRP_CONFIG}
)
source_group("Database"
FILES
${SRC_GRP_DATABASE}
)
source_group("Database\\DataStores"
FILES
${SRC_GRP_DATABASE_DBC}
)
source_group("Log"
FILES
${SRC_GRP_LOG}
)
source_group("Util"
FILES
${SRC_GRP_UTIL}
) )
# OS specific files # OS specific files
@ -99,29 +140,6 @@ else()
) )
endif() endif()
source_group("Util"
REGULAR_EXPRESSION .*
)
# TODO: really needed?
foreach(SRC ${LIBRARY_SRCS})
get_filename_component(PTH ${SRC} PATH)
if(PTH)
if(NOT XCODE) # FIXME: Xcode Generator has bug with nested dirs
string(REPLACE "/" "\\\\" PTH ${PTH})
endif()
source_group(${PTH} FILES ${SRC})
endif()
endforeach(SRC)
source_group("DataStores"
REGULAR_EXPRESSION DBC
)
source_group("Log"
REGULAR_EXPRESSION Log
)
include_directories( include_directories(
${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/dep/include ${CMAKE_SOURCE_DIR}/dep/include

View file

@ -1,6 +1,6 @@
#ifndef __REVISION_SQL_H__ #ifndef __REVISION_SQL_H__
#define __REVISION_SQL_H__ #define __REVISION_SQL_H__
#define REVISION_DB_CHARACTERS "required_12697_01_characters_characters" #define REVISION_DB_CHARACTERS "required_12774_01_characters_characters"
#define REVISION_DB_MANGOS "required_12662_01_mangos_hotfix_data" #define REVISION_DB_MANGOS "required_12774_01_mangos"
#define REVISION_DB_REALMD "required_c12484_02_realmd_account_access" #define REVISION_DB_REALMD "required_c12484_02_realmd_account_access"
#endif // __REVISION_SQL_H__ #endif // __REVISION_SQL_H__