aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/updates/262_characters.sql8
-rw-r--r--sql/updates/262_realmd.sql2
-rw-r--r--sql/updates/262_world.sql138
-rw-r--r--sql/updates/262_world_runthisonlyonce.sql60
-rw-r--r--sql/updates/273_world_scripts.sql2
-rw-r--r--sql/updates/285_world.sql470
-rw-r--r--sql/updates/285_world.sql.disabled110
-rw-r--r--sql/updates/287_world_scripts.sql2
-rw-r--r--sql/updates/329_world_spell_proc_event.sql605
-rw-r--r--sql/updates/332_world_spell_script_target.sql2
-rw-r--r--sql/updates/333_world_spell_proc_event.sql618
-rw-r--r--sql/updates/334_world_trinity_string.sql20
-rw-r--r--sql/updates/341_world.sql1
-rw-r--r--sql/updates/356_world.sql2
-rw-r--r--sql/updates/360_characters.sql4
-rw-r--r--sql/updates/373_world_scripts.sql3
-rw-r--r--sql/updates/377_world_scripts.sql10
-rw-r--r--sql/updates/381_world.sql82
-rw-r--r--src/bindings/interface/ScriptMgr.cpp145
-rw-r--r--src/bindings/scripts/Makefile.am2
-rw-r--r--src/bindings/scripts/ScriptMgr.cpp6
-rw-r--r--src/bindings/scripts/VC71/71ScriptDev2.vcproj8
-rw-r--r--src/bindings/scripts/VC80/80ScriptDev2.vcproj8
-rw-r--r--src/bindings/scripts/VC90/90ScriptDev2.vcproj8
-rw-r--r--src/bindings/scripts/include/sc_creature.cpp59
-rw-r--r--src/bindings/scripts/include/sc_creature.h2
-rw-r--r--src/bindings/scripts/include/sc_instance.h4
-rw-r--r--src/bindings/scripts/scripts/creature/mob_event_ai.cpp54
-rw-r--r--src/bindings/scripts/scripts/creature/mob_event_ai.h8
-rw-r--r--src/bindings/scripts/scripts/npc/npc_escortAI.cpp41
-rw-r--r--src/bindings/scripts/scripts/npc/npcs_special.cpp75
-rw-r--r--src/bindings/scripts/scripts/zone/aunchindoun/auchenai_crypts/boss_exarch_maladaar.cpp2
-rw-r--r--src/bindings/scripts/scripts/zone/aunchindoun/mana_tombs/boss_nexusprince_shaffar.cpp2
-rw-r--r--src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/boss_tailonking_ikiss.cpp2
-rw-r--r--src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp4
-rw-r--r--src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp2
-rw-r--r--src/bindings/scripts/scripts/zone/black_temple/boss_reliquary_of_souls.cpp22
-rw-r--r--src/bindings/scripts/scripts/zone/black_temple/boss_teron_gorefiend.cpp8
-rw-r--r--src/bindings/scripts/scripts/zone/blades_edge_mountains/blades_edge_mountains.cpp13
-rw-r--r--src/bindings/scripts/scripts/zone/burning_steppes/burning_steppes.cpp13
-rw-r--r--src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_temporus.cpp13
-rw-r--r--src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjalAI.cpp2
-rw-r--r--src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/instance_hyjal.cpp2
-rw-r--r--src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lady_vashj.cpp4
-rw-r--r--src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_leotheras_the_blind.cpp6
-rw-r--r--src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_morogrim_tidewalker.cpp2
-rw-r--r--src/bindings/scripts/scripts/zone/deadmines/deadmines.cpp206
-rw-r--r--src/bindings/scripts/scripts/zone/deadmines/def_deadmines.h13
-rw-r--r--src/bindings/scripts/scripts/zone/eversong_woods/eversong_woods.cpp419
-rw-r--r--src/bindings/scripts/scripts/zone/gruuls_lair/boss_high_king_maulgar.cpp80
-rw-r--r--src/bindings/scripts/scripts/zone/hellfire_citadel/hellfire_ramparts/boss_watchkeeper_gargolmar.cpp2
-rw-r--r--src/bindings/scripts/scripts/zone/hellfire_citadel/magtheridons_lair/boss_magtheridon.cpp2
-rw-r--r--src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_nethekurse.cpp4
-rw-r--r--src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_warchief_kargath_bladefist.cpp298
-rw-r--r--src/bindings/scripts/scripts/zone/hellfire_peninsula/hellfire_peninsula.cpp157
-rw-r--r--src/bindings/scripts/scripts/zone/naxxramas/boss_anubrekhan.cpp2
-rw-r--r--src/bindings/scripts/scripts/zone/naxxramas/boss_faerlina.cpp2
-rw-r--r--src/bindings/scripts/scripts/zone/netherstorm/netherstorm.cpp98
-rw-r--r--src/bindings/scripts/scripts/zone/shadowfang_keep/instance_shadowfang_keep.cpp72
-rw-r--r--src/bindings/scripts/scripts/zone/shadowmoon_valley/boss_doomwalker.cpp2
-rw-r--r--src/bindings/scripts/scripts/zone/stratholme/boss_timmy_the_cruel.cpp17
-rw-r--r--src/bindings/scripts/scripts/zone/sunwell_plateau/boss_eredar_twins.cpp3
-rw-r--r--src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/arcatraz.cpp5
-rw-r--r--src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/boss_harbinger_skyriss.cpp41
-rw-r--r--src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/def_arcatraz.h2
-rw-r--r--src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/instance_arcatraz.cpp12
-rw-r--r--src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_kaelthas.cpp32
-rw-r--r--src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_pathaleon_the_calculator.cpp612
-rw-r--r--src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/instance_mechanar.cpp180
-rw-r--r--src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_cthun.cpp2
-rw-r--r--src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_twinemperors.cpp4
-rw-r--r--src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp2
-rw-r--r--src/bindings/scripts/scripts/zone/westfall/westfall.cpp358
-rw-r--r--src/bindings/scripts/scripts/zone/zulaman/boss_akilzon.cpp2
-rw-r--r--src/bindings/scripts/scripts/zone/zulaman/boss_hexlord.cpp3
-rw-r--r--src/bindings/scripts/scripts/zone/zulaman/boss_janalai.cpp7
-rw-r--r--src/bindings/scripts/scripts/zone/zulaman/instance_zulaman.cpp2
-rw-r--r--src/bindings/scripts/scripts/zone/zulaman/zulaman.cpp18
-rw-r--r--src/framework/Platform/Define.h2
-rw-r--r--src/framework/Utilities/LinkedList.h30
-rw-r--r--src/framework/Utilities/LinkedReference/Reference.h12
-rw-r--r--src/game/AggressorAI.cpp6
-rw-r--r--src/game/ArenaTeam.cpp1578
-rw-r--r--src/game/ArenaTeam.h51
-rw-r--r--src/game/ArenaTeamHandler.cpp52
-rw-r--r--src/game/AuctionHouse.cpp4
-rw-r--r--src/game/BattleGround.cpp80
-rw-r--r--src/game/BattleGround.h5
-rw-r--r--src/game/BattleGroundAV.cpp1337
-rw-r--r--src/game/BattleGroundAV.h1526
-rw-r--r--src/game/BattleGroundEY.cpp4
-rw-r--r--src/game/BattleGroundMgr.cpp2
-rw-r--r--src/game/CharacterHandler.cpp46
-rw-r--r--src/game/Chat.cpp2
-rw-r--r--src/game/Creature.cpp143
-rw-r--r--src/game/Creature.h34
-rw-r--r--src/game/DynamicObject.cpp8
-rw-r--r--src/game/Formulas.h416
-rw-r--r--src/game/GMTicketHandler.cpp354
-rw-r--r--src/game/GMTicketMgr.h250
-rw-r--r--src/game/GameObject.cpp11
-rw-r--r--src/game/GridNotifiers.cpp2
-rw-r--r--src/game/GridNotifiers.h64
-rw-r--r--src/game/GridNotifiersImpl.h12
-rw-r--r--src/game/GridStates.cpp8
-rw-r--r--src/game/GuardAI.cpp2
-rw-r--r--src/game/Guild.cpp20
-rw-r--r--src/game/GuildHandler.cpp14
-rw-r--r--src/game/InstanceData.h4
-rw-r--r--src/game/Language.h198
-rw-r--r--src/game/Level2.cpp8484
-rw-r--r--src/game/Level3.cpp127
-rw-r--r--src/game/LootHandler.cpp10
-rw-r--r--src/game/Mail.cpp8
-rw-r--r--src/game/Map.cpp171
-rw-r--r--src/game/Map.h9
-rw-r--r--src/game/MapRefManager.h88
-rw-r--r--src/game/MapReference.h102
-rw-r--r--src/game/MiscHandler.cpp22
-rw-r--r--src/game/MovementHandler.cpp15
-rw-r--r--src/game/Object.cpp19
-rw-r--r--src/game/Object.h2
-rw-r--r--src/game/ObjectAccessor.cpp63
-rw-r--r--src/game/ObjectAccessor.h6
-rw-r--r--src/game/ObjectMgr.cpp15022
-rw-r--r--src/game/ObjectMgr.h1877
-rw-r--r--src/game/OutdoorPvPObjectiveAI.cpp1
-rw-r--r--src/game/Pet.cpp11
-rw-r--r--src/game/PetAI.cpp2
-rw-r--r--src/game/PetHandler.cpp12
-rw-r--r--src/game/Player.cpp594
-rw-r--r--src/game/Player.h15
-rw-r--r--src/game/PlayerDump.cpp1262
-rw-r--r--src/game/PossessedAI.cpp254
-rw-r--r--src/game/QuestHandler.cpp8
-rw-r--r--src/game/ReactorAI.cpp11
-rw-r--r--src/game/SharedDefines.h21
-rw-r--r--src/game/Spell.cpp462
-rw-r--r--src/game/Spell.h12
-rw-r--r--src/game/SpellAuras.cpp378
-rw-r--r--src/game/SpellAuras.h8
-rw-r--r--src/game/SpellEffects.cpp364
-rw-r--r--src/game/SpellHandler.cpp62
-rw-r--r--src/game/SpellMgr.cpp261
-rw-r--r--src/game/SpellMgr.h123
-rw-r--r--src/game/StatSystem.cpp30
-rw-r--r--src/game/Totem.cpp7
-rw-r--r--src/game/TradeHandler.cpp16
-rw-r--r--src/game/Unit.cpp2419
-rw-r--r--src/game/Unit.h98
-rw-r--r--src/game/WaypointManager.cpp652
-rw-r--r--src/game/WaypointManager.h185
-rw-r--r--src/game/WaypointMovementGenerator.cpp1305
-rw-r--r--src/game/World.cpp257
-rw-r--r--src/game/World.h38
-rw-r--r--src/game/WorldSession.cpp9
-rw-r--r--src/game/WorldSession.h4
-rw-r--r--src/shared/Database/DBCEnums.h208
-rw-r--r--src/shared/Database/DBCStores.cpp16
-rw-r--r--src/shared/Database/DBCStores.h2
-rw-r--r--src/shared/Database/DBCStructure.h20
-rw-r--r--src/shared/Database/DBCfmt.cpp5
-rw-r--r--src/shared/Database/SQLStorageImpl.h428
-rw-r--r--src/shared/Log.cpp148
-rw-r--r--src/shared/Log.h15
-rw-r--r--src/shared/Util.h12
-rw-r--r--src/trinitycore/CliRunnable.cpp4
-rw-r--r--src/trinitycore/WorldRunnable.cpp1
-rw-r--r--src/trinitycore/trinitycore.conf.dist366
-rw-r--r--win/VC80/framework.vcproj2
-rw-r--r--win/VC90/framework.vcproj2
171 files changed, 28410 insertions, 19317 deletions
diff --git a/sql/updates/262_characters.sql b/sql/updates/262_characters.sql
index 9e9fbc1caf7..fc08d8cda85 100644
--- a/sql/updates/262_characters.sql
+++ b/sql/updates/262_characters.sql
@@ -1,5 +1,5 @@
-ALTER TABLE `guild_bank_tab`
- CHANGE COLUMN `TabText` `TabText` text;
-
-ALTER TABLE `character_aura` ADD `stackcount` INT NOT NULL DEFAULT '1' AFTER `effect_index` ;
+ALTER TABLE `guild_bank_tab`
+ CHANGE COLUMN `TabText` `TabText` text;
+
+ALTER TABLE `character_aura` ADD `stackcount` INT NOT NULL DEFAULT '1' AFTER `effect_index` ;
ALTER TABLE `pet_aura` ADD `stackcount` INT NOT NULL DEFAULT '1' AFTER `effect_index` ; \ No newline at end of file
diff --git a/sql/updates/262_realmd.sql b/sql/updates/262_realmd.sql
index 62e5c050c4a..facffa9a7d1 100644
--- a/sql/updates/262_realmd.sql
+++ b/sql/updates/262_realmd.sql
@@ -1,2 +1,2 @@
-ALTER TABLE `account`
+ALTER TABLE `account`
CHANGE COLUMN `email` `email` text; \ No newline at end of file
diff --git a/sql/updates/262_world.sql b/sql/updates/262_world.sql
index 8e9d8b47687..2fe599e76e7 100644
--- a/sql/updates/262_world.sql
+++ b/sql/updates/262_world.sql
@@ -1,70 +1,70 @@
-DELETE FROM trinity_string WHERE entry IN (1119,1120,1121);
-
-INSERT INTO trinity_string VALUES
-(1119,'You must use male or female as gender.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
-(1120,'You change gender of %s to %s.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
-(1121,'Your gender changed to %s by %s.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
-
-
-DELETE FROM command WHERE name IN ('modify gender');
-
-INSERT INTO command VALUES
-('modify gender',2,'Syntax: .modify gender male/female\r\n\r\nChange gender of selected player.');
-
-
-delete from `command` where `name` IN ('senditems','sendmail');
-insert into `command` (`name`, `security`, `help`) values
-('senditems',3,'Syntax: .senditems #playername "#subject" "#text" itemid1[:count1] itemid2[:count2] ... itemidN[:countN]\r\n\r\nSend a mail to a player. Subject and mail text must be in "". If for itemid not provided related count values then expected 1, if count > max items in stack then items will be send in required amount stacks. All stacks amount in mail limited to 12.'),
-('sendmail',1,'Syntax: .sendmail #playername "#subject" "#text"\r\n\r\nSend a mail to a player. Subject and mail text must be in "".');
-
-
-delete from `command` where `name` = 'sendmoney';
-insert into `command` (`name`, `security`, `help`) values
-('sendmoney',3,'Syntax: .sendmoney #playername "#subject" "#text" #money\r\n\r\nSend mail with money to a player. Subject and mail text must be in "".');
-
-
-DELETE FROM trinity_string WHERE entry IN (453);
-
-
-DROP TABLE IF EXISTS `db_script_string`;
-CREATE TABLE `db_script_string` (
- `entry` int(11) unsigned NOT NULL default '0',
- `content_default` text NOT NULL,
- `content_loc1` text,
- `content_loc2` text,
- `content_loc3` text,
- `content_loc4` text,
- `content_loc5` text,
- `content_loc6` text,
- `content_loc7` text,
- `content_loc8` text,
- PRIMARY KEY (`entry`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-
-
-DELETE FROM `command` WHERE `name` IN (
- 'server exit',
- 'server idleshutdown',
- 'server idleshutdown cancel',
- 'server idlerestart',
- 'server idlerestart cancel',
- 'server restart',
- 'server restart cancel',
- 'server shutdown',
- 'server shutdown cancel'
-);
-
-INSERT INTO `command` (`name`, `security`, `help`) VALUES
-('server exit',4,'Syntax: .server exit\r\n\r\nTerminate mangosd NOW. Exit code 0.'),
-('server idleshutdown',3,'Syntax: .server idleshutdown #delay [#exist_code]\r\n\r\nShut the server down after #delay seconds if no active connections are present (no players). Use #exist_code or 0 as program exist code.'),
-('server idleshutdown cancel',3,'Syntax: .server idleshutdown cancel\r\n\r\nCancel the restart/shutdown timer if any.'),
-('server idlerestart',3,'Syntax: .server idlerestart #delay\r\n\r\nRestart the server after #delay seconds if no active connections are present (no players). Use #exist_code or 2 as program exist code.'),
-('server idlerestart cancel',3,'Syntax: .server idlerestart cancel\r\n\r\nCancel the restart/shutdown timer if any.'),
-('server restart',3,'Syntax: .server restart #delay\r\n\r\nRestart the server after #delay seconds. Use #exist_code or 2 as program exist code.'),
-('server restart cancel',3,'Syntax: .server restart cancel\r\n\r\nCancel the restart/shutdown timer if any.'),
-('server shutdown',3,'Syntax: .server shutdown #delay [#exist_code]\r\n\r\nShut the server down after #delay seconds. Use #exist_code or 0 as program exist code.'),
-('server shutdown cancel',3,'Syntax: .server shutdown cancel\r\n\r\nCancel the restart/shutdown timer if any.');
-
-DELETE FROM trinity_string WHERE entry IN (251);
-INSERT INTO trinity_string VALUES
+DELETE FROM trinity_string WHERE entry IN (1119,1120,1121);
+
+INSERT INTO trinity_string VALUES
+(1119,'You must use male or female as gender.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(1120,'You change gender of %s to %s.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(1121,'Your gender changed to %s by %s.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+
+
+DELETE FROM command WHERE name IN ('modify gender');
+
+INSERT INTO command VALUES
+('modify gender',2,'Syntax: .modify gender male/female\r\n\r\nChange gender of selected player.');
+
+
+delete from `command` where `name` IN ('senditems','sendmail');
+insert into `command` (`name`, `security`, `help`) values
+('senditems',3,'Syntax: .senditems #playername "#subject" "#text" itemid1[:count1] itemid2[:count2] ... itemidN[:countN]\r\n\r\nSend a mail to a player. Subject and mail text must be in "". If for itemid not provided related count values then expected 1, if count > max items in stack then items will be send in required amount stacks. All stacks amount in mail limited to 12.'),
+('sendmail',1,'Syntax: .sendmail #playername "#subject" "#text"\r\n\r\nSend a mail to a player. Subject and mail text must be in "".');
+
+
+delete from `command` where `name` = 'sendmoney';
+insert into `command` (`name`, `security`, `help`) values
+('sendmoney',3,'Syntax: .sendmoney #playername "#subject" "#text" #money\r\n\r\nSend mail with money to a player. Subject and mail text must be in "".');
+
+
+DELETE FROM trinity_string WHERE entry IN (453);
+
+
+DROP TABLE IF EXISTS `db_script_string`;
+CREATE TABLE `db_script_string` (
+ `entry` int(11) unsigned NOT NULL default '0',
+ `content_default` text NOT NULL,
+ `content_loc1` text,
+ `content_loc2` text,
+ `content_loc3` text,
+ `content_loc4` text,
+ `content_loc5` text,
+ `content_loc6` text,
+ `content_loc7` text,
+ `content_loc8` text,
+ PRIMARY KEY (`entry`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+
+DELETE FROM `command` WHERE `name` IN (
+ 'server exit',
+ 'server idleshutdown',
+ 'server idleshutdown cancel',
+ 'server idlerestart',
+ 'server idlerestart cancel',
+ 'server restart',
+ 'server restart cancel',
+ 'server shutdown',
+ 'server shutdown cancel'
+);
+
+INSERT INTO `command` (`name`, `security`, `help`) VALUES
+('server exit',4,'Syntax: .server exit\r\n\r\nTerminate mangosd NOW. Exit code 0.'),
+('server idleshutdown',3,'Syntax: .server idleshutdown #delay [#exist_code]\r\n\r\nShut the server down after #delay seconds if no active connections are present (no players). Use #exist_code or 0 as program exist code.'),
+('server idleshutdown cancel',3,'Syntax: .server idleshutdown cancel\r\n\r\nCancel the restart/shutdown timer if any.'),
+('server idlerestart',3,'Syntax: .server idlerestart #delay\r\n\r\nRestart the server after #delay seconds if no active connections are present (no players). Use #exist_code or 2 as program exist code.'),
+('server idlerestart cancel',3,'Syntax: .server idlerestart cancel\r\n\r\nCancel the restart/shutdown timer if any.'),
+('server restart',3,'Syntax: .server restart #delay\r\n\r\nRestart the server after #delay seconds. Use #exist_code or 2 as program exist code.'),
+('server restart cancel',3,'Syntax: .server restart cancel\r\n\r\nCancel the restart/shutdown timer if any.'),
+('server shutdown',3,'Syntax: .server shutdown #delay [#exist_code]\r\n\r\nShut the server down after #delay seconds. Use #exist_code or 0 as program exist code.'),
+('server shutdown cancel',3,'Syntax: .server shutdown cancel\r\n\r\nCancel the restart/shutdown timer if any.');
+
+DELETE FROM trinity_string WHERE entry IN (251);
+INSERT INTO trinity_string VALUES
(251,'Text%d (ID: %i): %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); \ No newline at end of file
diff --git a/sql/updates/262_world_runthisonlyonce.sql b/sql/updates/262_world_runthisonlyonce.sql
index 31926c3a4d1..fc5cc708063 100644
--- a/sql/updates/262_world_runthisonlyonce.sql
+++ b/sql/updates/262_world_runthisonlyonce.sql
@@ -1,31 +1,31 @@
-ALTER TABLE event_scripts
- DROP datatext,
- ADD COLUMN dataint int(11) NOT NULL default '0' AFTER datalong2;
-
-ALTER TABLE gameobject_scripts
- DROP datatext,
- ADD COLUMN dataint int(11) NOT NULL default '0' AFTER datalong2;
-
-ALTER TABLE quest_end_scripts
- DROP datatext,
- ADD COLUMN dataint int(11) NOT NULL default '0' AFTER datalong2;
-
-ALTER TABLE quest_start_scripts
- DROP datatext,
- ADD COLUMN dataint int(11) NOT NULL default '0' AFTER datalong2;
-
-ALTER TABLE spell_scripts
- DROP datatext,
- ADD COLUMN dataint int(11) NOT NULL default '0' AFTER datalong2;
-
-ALTER TABLE creature_movement
- DROP `text1`,
- DROP `text2`,
- DROP `text3`,
- DROP `text4`,
- DROP `text5`,
- ADD COLUMN textid1 int(11) NOT NULL default '0' AFTER waittime,
- ADD COLUMN textid2 int(11) NOT NULL default '0' AFTER textid1,
- ADD COLUMN textid3 int(11) NOT NULL default '0' AFTER textid2,
- ADD COLUMN textid4 int(11) NOT NULL default '0' AFTER textid3,
+ALTER TABLE event_scripts
+ DROP datatext,
+ ADD COLUMN dataint int(11) NOT NULL default '0' AFTER datalong2;
+
+ALTER TABLE gameobject_scripts
+ DROP datatext,
+ ADD COLUMN dataint int(11) NOT NULL default '0' AFTER datalong2;
+
+ALTER TABLE quest_end_scripts
+ DROP datatext,
+ ADD COLUMN dataint int(11) NOT NULL default '0' AFTER datalong2;
+
+ALTER TABLE quest_start_scripts
+ DROP datatext,
+ ADD COLUMN dataint int(11) NOT NULL default '0' AFTER datalong2;
+
+ALTER TABLE spell_scripts
+ DROP datatext,
+ ADD COLUMN dataint int(11) NOT NULL default '0' AFTER datalong2;
+
+ALTER TABLE creature_movement
+ DROP `text1`,
+ DROP `text2`,
+ DROP `text3`,
+ DROP `text4`,
+ DROP `text5`,
+ ADD COLUMN textid1 int(11) NOT NULL default '0' AFTER waittime,
+ ADD COLUMN textid2 int(11) NOT NULL default '0' AFTER textid1,
+ ADD COLUMN textid3 int(11) NOT NULL default '0' AFTER textid2,
+ ADD COLUMN textid4 int(11) NOT NULL default '0' AFTER textid3,
ADD COLUMN textid5 int(11) NOT NULL default '0' AFTER textid4; \ No newline at end of file
diff --git a/sql/updates/273_world_scripts.sql b/sql/updates/273_world_scripts.sql
new file mode 100644
index 00000000000..d3188c1306c
--- /dev/null
+++ b/sql/updates/273_world_scripts.sql
@@ -0,0 +1,2 @@
+UPDATE `creature_template` SET `ScriptName`='npc_wounded_blood_elf' WHERE `entry`='16993';
+UPDATE `creature_template` SET `ScriptName` = 'mob_phase_hunter' WHERE `entry` = '18879'; \ No newline at end of file
diff --git a/sql/updates/285_world.sql b/sql/updates/285_world.sql
new file mode 100644
index 00000000000..146947f5973
--- /dev/null
+++ b/sql/updates/285_world.sql
@@ -0,0 +1,470 @@
+-- general stuff
+
+REPLACE INTO gameobject_template VALUES (178364,1,5773,"Horde Banner","",84,0,1,0,1479,196608,180101,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"");
+REPLACE INTO gameobject_template VALUES (178365,1,5771,"Alliance Banner","",83,0,1,0,1479,196608,180100,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"");
+REPLACE INTO gameobject_template VALUES (178925,1,5651,"Alliance Banner","",83,0,1,0,1479,196608,180421,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"");
+REPLACE INTO gameobject_template VALUES (178940,1,5653,"Contested Banner","",83,0,1,0,1479,196608,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"");
+REPLACE INTO gameobject_template VALUES (178943,1,5652,"Horde Banner","",84,0,1,0,1479,196608,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"");
+REPLACE INTO gameobject_template VALUES (179286,1,5772,"Contested Banner","",83,0,1,0,1479,196608,180102,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"");
+REPLACE INTO gameobject_template VALUES (179287,1,5774,"Contested Banner","",84,0,1,0,1479,0,180102,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"");
+REPLACE INTO gameobject_template VALUES (179435,1,5654,"Contested Banner","",84,0,1,0,1479,196608,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"");
+REPLACE INTO gameobject_template VALUES (180100,6,2232,"Alliance Banner Aura","",0,0,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,"");
+REPLACE INTO gameobject_template VALUES (180101,6,1311,"Horde Banner Aura","",0,0,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,"");
+REPLACE INTO gameobject_template VALUES (180102,6,266,"Neutral Banner Aura","",0,0,2,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,"");
+REPLACE INTO gameobject_template VALUES (180418,1,6211,"Snowfall Banner","",0,0,1,0,1479,196608,180100,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"");
+REPLACE INTO gameobject_template VALUES (180421,6,2232,"Alliance Banner Aura, Large","",0,0,5,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,"");
+REPLACE INTO gameobject_template VALUES (180422,6,1311,"Horde Banner Aura, Large","",0,0,5,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,"");
+REPLACE INTO gameobject_template VALUES (180423,6,266,"Neutral Banner Aura, Large","",0,0,5,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,"");
+REPLACE INTO gameobject_template VALUES (180424,0,3751,"Alterac Valley Gate","",100,0,3.5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"");
+
+-- following is the player loot.. it takes the id 1 - be sure that i don't delete anything
+REPLACE INTO `world`.`creature_loot_template` (`entry` ,`item` ,`ChanceOrQuestChance` ,`groupid` ,`mincountOrRef` ,`maxcount` ,`lootcondition` ,`condition_value1` ,`condition_value2`)
+VALUES ('1', '17306', '33', '0', '5', '15', '6', '67', '0'),
+('1', '17422', '100', '0', '20', '40', '0', '0', '0'),
+('1', '17423', '33', '0', '5', '15', '6', '469', '0'),
+( '1', '17502', '30', '1', '5', '10', '6', '469', '0' ),
+( '1', '17503', '30', '1', '5', '10', '6', '469', '0'),
+( '1', '17504', '30', '1', '5', '10', '6', '469', '0' ),
+( '1', '17326', '30', '2', '5', '10', '6', '67', '0' ),
+( '1', '17327', '30', '2', '5', '10', '6', '67', '0' ),
+( '1', '17328', '30', '2', '5', '10', '6', '67', '0' );
+
+-- blizzlike mobs in the mines don't have any loot (not even gold, it doesn't show the looticon if i go with my mouse over them)
+-- broken after the strange new loot-table appeared (but not important) delete from creature_loot_template where entry in (13396,13080,13098,13078,13397,13099,13081,13079,11603,11604,11605,11677,10982,13317,13096,13087,13086,13316,13097,13089,13088);
+-- TODO: write own loottable
+
+
+
+-- language
+
+delete from trinity_string where entry>716 and entry<750;
+INSERT INTO trinity_string VALUES
+(717,'Alliance',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(718,'Horde',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(719,'%s was destroyed by the %s!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(720,'The %s is under attack! If left unchecked, the %s will destroy it!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(721,'The %s was taken by the %s!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(722,'The %s was taken by the %s!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(723,'The %s was taken by the %s!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(724,'The %s is under attack! If left unchecked, the %s will capture it!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(725,'The %s has taken the %s! Its supplies will now be used for reinforcements!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(726,'Irondeep Mine',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(727,'Coldtooth Mine',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(728,'Stormpike Aid Station',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(729,'Dun Baldar South Bunker',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(730,'Dun Baldar North Bunker',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(731,'Stormpike Graveyard',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(732,'Icewing Bunker',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(733,'Stonehearth Graveyard',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(734,'Stonehearth Bunker',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(735,'Snowfall Graveyard',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(736,'Iceblood Tower',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(737,'Iceblood Graveyard',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(738,'Tower Point',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(739,'Frostwolf Graveyard',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(740,'East Frostwolf Tower',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(741,'West Frostwolf Tower',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(742,'Frostwolf Relief Hut',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(743,'The Battle for Alterac Valley begins in 1 minute.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(744,'The Battle for Alterac Valley begins in 30 seconds. Prepare yourselves!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(745,'The Battle for Alterac Valley has begun!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(746,'The Alliance Team is running out of reinforcements!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(747,'The Horde Team is running out of reinforcements!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(748,'The Frostwolf General is Dead!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(749,'The Stormpike General is Dead!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL)
+;
+
+UPDATE trinity_string SET content_loc3='Allianz' WHERE entry=717;
+UPDATE trinity_string SET content_loc3='Horde' WHERE entry=718;
+
+UPDATE trinity_string SET content_loc3='%s wurde von der %s zerstört!' WHERE entry=719;
+
+UPDATE trinity_string SET content_loc3='%s wird angegriffen! Wenn er unbewacht bleibt, wird die %s ihn zerstören!' WHERE entry=720;
+-- Wenn _sie_ unbewacht bleibt wird allianz _sie_ TODO: don't store towers and gravenames, store complete strings with the names inside it, else i don't know how to implement this feature
+
+UPDATE trinity_string SET content_loc3='%s wurde von der %s erobert!' WHERE entry=721;
+UPDATE trinity_string SET content_loc3='%s wurde von der %s erobert!' WHERE entry=722;
+UPDATE trinity_string SET content_loc3='%s wurde von der %s erobert!' WHERE entry=723;
+
+UPDATE trinity_string SET content_loc3='%s wird angegriffen! Wenn er unbewacht bleibt, wird die %s ihn erobern!' WHERE entry=724;
+-- Wenn _sie_ unbewacht bleibt ... TODO...
+
+UPDATE trinity_string SET content_loc3='Die %s hat die %s eingenommen! Die dort befindlichen Vorräte werden zur Verstärkung eingesetzt!' WHERE entry=725;
+
+UPDATE trinity_string SET content_loc3='Eisenschachtmine' WHERE entry=726;
+UPDATE trinity_string SET content_loc3='Eisbeißermine' WHERE entry=727;
+UPDATE trinity_string SET content_loc3='Das Lazarett der Sturmlanzen' WHERE entry=728;
+UPDATE trinity_string SET content_loc3='Der Südbunker von Dun Baldar' WHERE entry=729;
+UPDATE trinity_string SET content_loc3='Der Nordbunker von Dun Baldar' WHERE entry=730;
+UPDATE trinity_string SET content_loc3='Der Friedhof der Sturmlanzen' WHERE entry=731;
+UPDATE trinity_string SET content_loc3='Der Eisschwingenbunker' WHERE entry=732;
+UPDATE trinity_string SET content_loc3='Der Steinbruchfriedhof' WHERE entry=733;
+UPDATE trinity_string SET content_loc3='Der Steinbruchbunker' WHERE entry=734;
+UPDATE trinity_string SET content_loc3='Der Schneewehenfriedhof' WHERE entry=735;
+UPDATE trinity_string SET content_loc3='Der Eisblutturm' WHERE entry=736;
+UPDATE trinity_string SET content_loc3='Der Eisblutfriedhof' WHERE entry=737;
+UPDATE trinity_string SET content_loc3='Die Turmstellung' WHERE entry=738;
+UPDATE trinity_string SET content_loc3='Der Friedhof der Frostwölfe' WHERE entry=739;
+UPDATE trinity_string SET content_loc3='Der östliche Frostwolfturm' WHERE entry=740;
+UPDATE trinity_string SET content_loc3='Der westliche Frostwolfturm' WHERE entry=741;
+UPDATE trinity_string SET content_loc3='Die Heilerhütte der Frostwölfe' WHERE entry=742;
+UPDATE trinity_string SET content_loc3='Der Kampf um das Alteractal beginnt in 1 Minute.' WHERE entry=743;
+UPDATE trinity_string SET content_loc3='Der Kampf um das Alteractal beginnt in 30 Sekunden.' WHERE entry=744;
+UPDATE trinity_string SET content_loc3='Der Kampf um das Alteractal hat begonnen!' WHERE entry=745;
+UPDATE trinity_string SET content_loc3='Die Allianz hat nurnoch wenige Verstärkungspunkte' WHERE entry=746; -- TODO find right msg
+UPDATE trinity_string SET content_loc3='Die Horde hat nurnoch wenige Verstärkungspunkte' WHERE entry=747; -- TODO same here
+UPDATE trinity_string SET content_loc3='Der General der Allianz ist tot!' WHERE entry=748;
+UPDATE trinity_string SET content_loc3='Der General der Horde ist tot!' WHERE entry=749;
+
+
+-- CHAT_MSG_BG_SYSTEM_ALLIANCE', 'txt': '$N hat den Schneewehenfriedhof besetzt! Wenn niemand eingreift, erlangt die Allianz die Kontrolle \xc3\xbcber ihn
+
+-- creature stats
+
+REPLACE INTO creature_template
+ (`entry`, `heroic_entry`, `modelid_A`, `modelid_A2`, `modelid_H`, `modelid_H2`, `name`, `subname`, `IconName`, `minlevel`, `maxlevel`, `minhealth`, `maxhealth`, `minmana`, `maxmana`, `armor`, `faction_A`, `faction_H`, `npcflag`, `speed`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `baseattacktime`, `rangeattacktime`, `unit_flags`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `class`, `race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `PetSpellDataId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `RacialLeader`, `RegenHealth`, `equipment_id`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`)
+VALUES
+ (11946, 0, 11894, 0, 11894, 0, 'Drek\'Thar', 'Frostwolf General', '', 72, 72, 220000, 250000, 0, 0, 0, 1214, 1214, 1, 2, 1, 3, 5000, 8000, 0, 15000, 2000, 0, 4096, 0, 0, 0, 0, 0, 0, 203.77, 289.86, 100, 7, 4, 0, 11946, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 1, 3, 0, 1, 994, 80428891, 1, 'mob_eventai');
+
+REPLACE INTO creature_template
+ (`entry`, `heroic_entry`, `modelid_A`, `modelid_A2`, `modelid_H`, `modelid_H2`, `name`, `subname`, `IconName`, `minlevel`, `maxlevel`, `minhealth`, `maxhealth`, `minmana`, `maxmana`, `armor`, `faction_A`, `faction_H`, `npcflag`, `speed`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `baseattacktime`, `rangeattacktime`, `unit_flags`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `class`, `race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `PetSpellDataId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `RacialLeader`, `RegenHealth`, `equipment_id`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`)
+VALUES
+ (11947, 0, 11895, 0, 11895, 0, 'Captain Galvangar', 'Frostwolf Captain', '', 71, 71, 180000, 200000, 0, 0, 0, 1214, 1214, 0, 2, 1, 3, 4000, 4000, 0, 8000, 2000, 0, 4160, 0, 0, 0, 0, 0, 0, 172.1, 240.07, 100, 7, 4, 11947, 11947, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24055, 31418, '', 1, 3, 0, 1, 1389, 80428891, 1, 'mob_eventai');
+
+REPLACE INTO creature_template
+ (`entry`, `heroic_entry`, `modelid_A`, `modelid_A2`, `modelid_H`, `modelid_H2`, `name`, `subname`, `IconName`, `minlevel`, `maxlevel`, `minhealth`, `maxhealth`, `minmana`, `maxmana`, `armor`, `faction_A`, `faction_H`, `npcflag`, `speed`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `baseattacktime`, `rangeattacktime`, `unit_flags`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `class`, `race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `PetSpellDataId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `RacialLeader`, `RegenHealth`, `equipment_id`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`)
+VALUES
+ (11948, 0, 11896, 0, 11896, 0, 'Vanndar Stormpike', 'Stormpike General', '', 73, 73, 220000, 250000, 0, 0, 0, 1216, 1216, 0, 2, 1, 3, 5000, 8000, 0, 15000, 1158, 1274, 0, 0, 0, 0, 0, 0, 0, 203.77, 289.86, 100, 7, 4, 11948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 1, 3, 0, 1, 0, 80428891, 1, 'mob_eventai');
+
+REPLACE INTO creature_template
+ (`entry`, `heroic_entry`, `modelid_A`, `modelid_A2`, `modelid_H`, `modelid_H2`, `name`, `subname`, `IconName`, `minlevel`, `maxlevel`, `minhealth`, `maxhealth`, `minmana`, `maxmana`, `armor`, `faction_A`, `faction_H`, `npcflag`, `speed`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `baseattacktime`, `rangeattacktime`, `unit_flags`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `class`, `race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `PetSpellDataId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `RacialLeader`, `RegenHealth`, `equipment_id`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`)
+VALUES
+ (11949, 0, 12823, 0, 12823, 0, 'Captain Balinda Stonehearth', 'Stormpike Captain', '', 71, 71, 180000, 200000, 38772, 38772, 0, 1216, 1216, 0, 2, 1, 3, 1000, 2000, 0, 2000, 2000, 0, 4096, 0, 0, 0, 0, 0, 0, 172.1, 240.07, 100, 7, 4, 11949, 11949, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19805, 25868, '', 1, 3, 0, 1, 1364, 80428891, 1, 'mob_eventai');
+
+REPLACE INTO creature_template
+ (`entry`, `heroic_entry`, `modelid_A`, `modelid_A2`, `modelid_H`, `modelid_H2`, `name`, `subname`, `IconName`, `minlevel`, `maxlevel`, `minhealth`, `maxhealth`, `minmana`, `maxmana`, `armor`, `faction_A`, `faction_H`, `npcflag`, `speed`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `baseattacktime`, `rangeattacktime`, `unit_flags`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `class`, `race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `PetSpellDataId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `RacialLeader`, `RegenHealth`, `equipment_id`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`)
+VALUES
+ (13358, 0, 13390, 0, 13393, 0, 'Stormpike Bowman', '', '', 69, 70, 4500, 10000, 0, 0, 0, 1216, 1216, 0, 1.27, 1, 0, 65, 135, 0, 696, 2000, 0, 4608, 0, 0, 0, 0, 0, 0, 200, 600, 1000, 7, 0, 13358, 13358, 0, 0, 0, 0, 0, 0, 0, 22121, 0, 0, 0, 0, 260, 344, '', 0, 3, 0, 1, 8, 0, 0, 'mob_eventai');
+
+REPLACE INTO creature_template
+ (`entry`, `heroic_entry`, `modelid_A`, `modelid_A2`, `modelid_H`, `modelid_H2`, `name`, `subname`, `IconName`, `minlevel`, `maxlevel`, `minhealth`, `maxhealth`, `minmana`, `maxmana`, `armor`, `faction_A`, `faction_H`, `npcflag`, `speed`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `baseattacktime`, `rangeattacktime`, `unit_flags`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `class`, `race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `PetSpellDataId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `RacialLeader`, `RegenHealth`, `equipment_id`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`)
+VALUES
+ (13359, 0, 13398, 0, 13401, 0, 'Frostwolf Bowman', '', '', 69, 70, 4500, 10000, 0, 0, 0, 1214, 1214, 0, 1.27, 1, 0, 66, 137, 0, 712, 2000, 0, 4608, 0, 0, 0, 0, 0, 0, 200, 600, 1000, 7, 0, 13359, 13359, 0, 0, 0, 0, 0, 0, 0, 22121, 0, 0, 0, 0, 262, 347, '', 0, 3, 0, 1, 6, 0, 0, 'mob_eventai');
+
+REPLACE INTO creature_template
+ (`entry`, `heroic_entry`, `modelid_A`, `modelid_A2`, `modelid_H`, `modelid_H2`, `name`, `subname`, `IconName`, `minlevel`, `maxlevel`, `minhealth`, `maxhealth`, `minmana`, `maxmana`, `armor`, `faction_A`, `faction_H`, `npcflag`, `speed`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `baseattacktime`, `rangeattacktime`, `unit_flags`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `class`, `race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `PetSpellDataId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `RacialLeader`, `RegenHealth`, `equipment_id`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`)
+VALUES
+ (14770, 0, 14797, 0, 14798, 0, 'Dun Baldar North Warmaster', '', '', 70, 70, 139780, 139780, 0, 0, 0, 1214, 1214, 0, 2, 1, 3, 3000, 5000, 0, 2175, 2000, 0, 4096, 0, 0, 0, 0, 0, 0, 62.016, 85.272, 100, 7, 0, 14770, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 3, 0, 1, 1416, 0, 0, 'mob_eventai');
+
+REPLACE INTO creature_template
+ (`entry`, `heroic_entry`, `modelid_A`, `modelid_A2`, `modelid_H`, `modelid_H2`, `name`, `subname`, `IconName`, `minlevel`, `maxlevel`, `minhealth`, `maxhealth`, `minmana`, `maxmana`, `armor`, `faction_A`, `faction_H`, `npcflag`, `speed`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `baseattacktime`, `rangeattacktime`, `unit_flags`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `class`, `race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `PetSpellDataId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `RacialLeader`, `RegenHealth`, `equipment_id`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`)
+VALUES
+ (14771, 0, 14798, 0, 14799, 0, 'Dun Baldar South Warmaster', '', '', 70, 70, 36600, 36600, 0, 0, 0, 1214, 1214, 0, 2, 1, 3, 3000, 6000, 0, 10000, 2000, 0, 4096, 0, 0, 0, 0, 0, 0, 62.016, 85.272, 100, 7, 0, 14771, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 3, 0, 1, 1416, 0, 0, 'mob_eventai');
+
+REPLACE INTO creature_template
+ (`entry`, `heroic_entry`, `modelid_A`, `modelid_A2`, `modelid_H`, `modelid_H2`, `name`, `subname`, `IconName`, `minlevel`, `maxlevel`, `minhealth`, `maxhealth`, `minmana`, `maxmana`, `armor`, `faction_A`, `faction_H`, `npcflag`, `speed`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `baseattacktime`, `rangeattacktime`, `unit_flags`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `class`, `race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `PetSpellDataId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `RacialLeader`, `RegenHealth`, `equipment_id`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`)
+VALUES
+ (14772, 0, 14798, 0, 14800, 0, 'East Frostwolf Warmaster', '', '', 70, 70, 139362, 139362, 0, 0, 0, 1214, 1214, 0, 2, 1, 3, 3000, 6000, 0, 10000, 2000, 0, 4096, 0, 0, 0, 0, 0, 0, 59.9488, 82.4296, 100, 7, 0, 14772, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6049, 7904, '', 1, 3, 0, 1, 1416, 0, 0, 'mob_eventai');
+
+REPLACE INTO creature_template
+ (`entry`, `heroic_entry`, `modelid_A`, `modelid_A2`, `modelid_H`, `modelid_H2`, `name`, `subname`, `IconName`, `minlevel`, `maxlevel`, `minhealth`, `maxhealth`, `minmana`, `maxmana`, `armor`, `faction_A`, `faction_H`, `npcflag`, `speed`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `baseattacktime`, `rangeattacktime`, `unit_flags`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `class`, `race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `PetSpellDataId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `RacialLeader`, `RegenHealth`, `equipment_id`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`)
+VALUES
+ (14773, 0, 14797, 0, 14797, 0, 'Iceblood Warmaster', '', '', 70, 70, 141144, 141144, 0, 0, 0, 1214, 1214, 0, 2, 1, 3, 3000, 6000, 0, 10000, 2000, 0, 4096, 0, 0, 0, 0, 0, 0, 62.016, 85.272, 100, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 1, 3, 0, 1, 1416, 0, 0, 'mob_eventai');
+
+REPLACE INTO creature_template
+ (`entry`, `heroic_entry`, `modelid_A`, `modelid_A2`, `modelid_H`, `modelid_H2`, `name`, `subname`, `IconName`, `minlevel`, `maxlevel`, `minhealth`, `maxhealth`, `minmana`, `maxmana`, `armor`, `faction_A`, `faction_H`, `npcflag`, `speed`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `baseattacktime`, `rangeattacktime`, `unit_flags`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `class`, `race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `PetSpellDataId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `RacialLeader`, `RegenHealth`, `equipment_id`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`)
+VALUES
+ (14774, 0, 14800, 0, 14800, 0, 'Icewing Warmaster', '', '', 70, 70, 122300, 122300, 0, 0, 0, 1214, 1214, 0, 2, 1, 3, 3000, 6000, 0, 10000, 2000, 0, 4096, 0, 0, 0, 0, 0, 0, 62.016, 85.272, 100, 7, 0, 14774, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6049, 7904, '', 1, 3, 0, 1, 1416, 0, 0, 'mob_eventai');
+
+REPLACE INTO creature_template
+ (`entry`, `heroic_entry`, `modelid_A`, `modelid_A2`, `modelid_H`, `modelid_H2`, `name`, `subname`, `IconName`, `minlevel`, `maxlevel`, `minhealth`, `maxhealth`, `minmana`, `maxmana`, `armor`, `faction_A`, `faction_H`, `npcflag`, `speed`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `baseattacktime`, `rangeattacktime`, `unit_flags`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `class`, `race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `PetSpellDataId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `RacialLeader`, `RegenHealth`, `equipment_id`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`)
+VALUES
+ (14775, 0, 14798, 0, 14800, 0, 'Stonehearth Warmaster', '', '', 70, 70, 140204, 140204, 0, 0, 0, 1214, 1214, 0, 2, 1, 3, 3000, 6000, 0, 10000, 2000, 0, 4096, 0, 0, 0, 0, 0, 0, 62.016, 85.272, 100, 7, 0, 14775, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6049, 7904, '', 1, 3, 0, 1, 1416, 0, 0, 'mob_eventai');
+
+REPLACE INTO creature_template
+ (`entry`, `heroic_entry`, `modelid_A`, `modelid_A2`, `modelid_H`, `modelid_H2`, `name`, `subname`, `IconName`, `minlevel`, `maxlevel`, `minhealth`, `maxhealth`, `minmana`, `maxmana`, `armor`, `faction_A`, `faction_H`, `npcflag`, `speed`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `baseattacktime`, `rangeattacktime`, `unit_flags`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `class`, `race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `PetSpellDataId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `RacialLeader`, `RegenHealth`, `equipment_id`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`)
+VALUES
+ (14776, 0, 14798, 0, 14800, 0, 'Tower Point Warmaster', '', '', 70, 70, 131536, 131536, 0, 0, 0, 1214, 1214, 0, 2, 1, 3, 3000, 6000, 0, 10000, 2000, 0, 4096, 0, 0, 0, 0, 0, 0, 62.016, 85.272, 100, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 1, 3, 0, 1, 1416, 0, 0, 'mob_eventai');
+
+REPLACE INTO creature_template
+ (`entry`, `heroic_entry`, `modelid_A`, `modelid_A2`, `modelid_H`, `modelid_H2`, `name`, `subname`, `IconName`, `minlevel`, `maxlevel`, `minhealth`, `maxhealth`, `minmana`, `maxmana`, `armor`, `faction_A`, `faction_H`, `npcflag`, `speed`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `baseattacktime`, `rangeattacktime`, `unit_flags`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `class`, `race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `PetSpellDataId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `RacialLeader`, `RegenHealth`, `equipment_id`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`)
+VALUES
+ (14777, 0, 14797, 0, 14798, 0, 'West Frostwolf Warmaster', '', '', 70, 70, 138920, 138920, 0, 0, 0, 1214, 1214, 0, 2, 1, 3, 3000, 6000, 0, 10000, 2000, 0, 4096, 0, 0, 0, 0, 0, 0, 59.9488, 82.4296, 100, 7, 0, 14777, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 1, 3, 0, 1, 1416, 0, 0, 'mob_eventai');
+
+REPLACE INTO creature_template
+ (`entry`, `heroic_entry`, `modelid_A`, `modelid_A2`, `modelid_H`, `modelid_H2`, `name`, `subname`, `IconName`, `minlevel`, `maxlevel`, `minhealth`, `maxhealth`, `minmana`, `maxmana`, `armor`, `faction_A`, `faction_H`, `npcflag`, `speed`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `baseattacktime`, `rangeattacktime`, `unit_flags`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `class`, `race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `PetSpellDataId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `RacialLeader`, `RegenHealth`, `equipment_id`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`)
+VALUES
+ (25040, 0, 4606, 0, 4606, 0, 'Greater Water Elemental', '', '', 1, 1, 1, 1, 0, 0, 0, 35, 35, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 3, 0, 1, 0, 0, 0, 'mob_eventai');
+
+
+-- eventai
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1335801, 13358, 0, 0, 100, 1, 1000, 1000, 3000, 3000, 11, 22121, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Bowman AV shoot');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1335901, 13359, 0, 0, 100, 1, 1000, 1000, 3000, 3000, 11, 22121, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Bowman AV shoot');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1194901, 11949, 0, 0, 100, 1, 10000, 15000, 10000, 15000, 11, 46608, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Balinda AV AoE');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1194902, 11949, 0, 0, 100, 1, 6000, 8000, 10000, 20000, 11, 38384, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Balinda AV CoC');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1194903, 11949, 0, 0, 50, 1, 1000, 1000, 4000, 6000, 11, 46988, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Balinda AV fireball');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1194904, 11949, 0, 0, 50, 1, 1000, 2000, 5000, 7000, 11, 46987, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Balinda AV frostbolt');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1194905, 11949, 0, 0, 100, 1, 3000, 4000, 20000, 20000, 11, 45067, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Balinda AV Summon');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1194801, 11948, 0, 0, 100, 1, 2000, 3000, 15000, 18000, 11, 19135, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Vanndar AV avatar');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1194802, 11948, 0, 0, 100, 1, 4000, 4000, 6000, 15000, 11, 15588, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Vanndar AV thunderclap');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1194803, 11948, 0, 0, 100, 1, 6000, 8000, 5000, 25000, 11, 15589, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Vanndar AV cleave');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (2504001, 25040, 0, 0, 100, 1, 1000, 1000, 2000, 2000, 11, 46983, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'water element AV waterbolt');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1194701, 11947, 0, 0, 100, 1, 1000, 11000, 10000, 16000, 11, 15284, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'Galvanar');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1194702, 11947, 0, 0, 100, 1, 2000, 20000, 10000, 15000, 11, 19134, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'galvanar');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1194703, 11947, 0, 0, 100, 1, 1000, 12000, 6000, 20000, 11, 16856, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'galvanar');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1194704, 11947, 0, 0, 100, 1, 5000, 20000, 10000, 25000, 11, 15589, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'galvangar');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1194705, 11947, 0, 0, 100, 1, 5000, 20000, 10000, 25000, 11, 13736, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'galvangar');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1194601, 11946, 0, 0, 100, 1, 5000, 6000, 20000, 21000, 11, 8269, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'drekthar');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1194602, 11946, 0, 0, 100, 1, 10000, 12000, 10000, 15000, 11, 19128, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'drekthar');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1194603, 11946, 0, 0, 100, 1, 1000, 20000, 8000, 20000, 11, 15589, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'drekthar');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1194604, 11946, 0, 0, 100, 1, 1000, 25000, 7000, 25000, 11, 13736, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 'drejthar');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477001, 14770, 0, 0, 100, 1, 10, 10, 10000, 15000, 11, 22911, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477002, 14770, 0, 0, 100, 1, 3000, 5000, 10000, 15000, 11, 40504, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477003, 14770, 0, 0, 100, 1, 5000, 15000, 10000, 20000, 11, 15589, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477101, 14771, 0, 0, 100, 1, 10, 10, 10000, 15000, 11, 22911, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477102, 14771, 0, 0, 100, 1, 3000, 5000, 10000, 15000, 11, 40504, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477103, 14771, 0, 0, 100, 1, 5000, 15000, 10000, 20000, 11, 15589, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477201, 14772, 0, 0, 100, 1, 10, 10, 10000, 15000, 11, 22911, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477202, 14772, 0, 0, 100, 1, 3000, 5000, 10000, 15000, 11, 40504, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477203, 14772, 0, 0, 100, 1, 5000, 15000, 10000, 20000, 11, 15589, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477301, 14773, 0, 0, 100, 1, 10, 10, 10000, 15000, 11, 22911, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477302, 14773, 0, 0, 100, 1, 3000, 5000, 10000, 15000, 11, 40504, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477303, 14773, 0, 0, 100, 1, 5000, 15000, 10000, 20000, 11, 15589, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477401, 14774, 0, 0, 100, 1, 10, 10, 10000, 15000, 11, 22911, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477402, 14774, 0, 0, 100, 1, 3000, 5000, 10000, 15000, 11, 40504, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477403, 14774, 0, 0, 100, 1, 5000, 15000, 10000, 20000, 11, 15589, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477501, 14775, 0, 0, 100, 1, 10, 10, 10000, 15000, 11, 22911, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477502, 14775, 0, 0, 100, 1, 3000, 5000, 10000, 15000, 11, 40504, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477503, 14775, 0, 0, 100, 1, 5000, 15000, 10000, 20000, 11, 15589, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477601, 14776, 0, 0, 100, 1, 10, 10, 10000, 15000, 11, 22911, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477602, 14776, 0, 0, 100, 1, 3000, 5000, 10000, 15000, 11, 40504, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477603, 14776, 0, 0, 100, 1, 5000, 15000, 10000, 20000, 11, 15589, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477701, 14777, 0, 0, 100, 1, 10, 10, 10000, 15000, 11, 22911, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477702, 14777, 0, 0, 100, 1, 3000, 5000, 10000, 15000, 11, 40504, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477703, 14777, 0, 0, 100, 1, 5000, 15000, 10000, 20000, 11, 15589, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1194906, 11949, 7, 0, 100, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1194804, 11948, 7, 0, 100, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477004, 14770, 7, 0, 100, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477104, 14771, 7, 0, 100, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477204, 14772, 7, 0, 100, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477304, 14773, 7, 0, 100, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477404, 14774, 7, 0, 100, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477504, 14775, 7, 0, 100, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477604, 14776, 7, 0, 100, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '');
+
+REPLACE INTO eventai_scripts
+ (`id`, `creature_id`, `event_type`, `event_inverse_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `action1_type`, `action1_param1`, `action1_param2`, `action1_param3`, `action2_type`, `action2_param1`, `action2_param2`, `action2_param3`, `action3_type`, `action3_param1`, `action3_param2`, `action3_param3`, `comment`)
+VALUES
+ (1477704, 14777, 7, 0, 100, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ''); \ No newline at end of file
diff --git a/sql/updates/285_world.sql.disabled b/sql/updates/285_world.sql.disabled
new file mode 100644
index 00000000000..e2aac8a99e0
--- /dev/null
+++ b/sql/updates/285_world.sql.disabled
@@ -0,0 +1,110 @@
+Warning: these sql may have conflict with official DB.
+Use them at your own risk!
+
+/*
+-- people with custom content now have a problem
+-- all creatures and gameobjects where removed from alterac, cause udb have wrong spawns..
+delete from creature where map=30;
+delete from gameobject where map=30;
+
+-- gameobject-spawns
+
+-- following gameobjects are static
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (2061,30,-1423.16,-318.436,89.1136,2.35619,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (2061,30,-1290.27,-172.471,72.1853,3.06305,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (2061,30,-1286.25,-184.48,71.8334,-2.05076,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (2061,30,-1282.21,-284.083,87.256,-0.0610855,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (2061,30,-1280.17,-220.537,72.2686,1.62316,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (2061,30,-1256.55,-280.278,73.9473,-0.0610855,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (2061,30,-1241.25,-345.115,59.6867,0.357794,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (2061,30,-1215.59,-371.946,56.5293,0.357794,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (2061,30,-1202.8,-271.599,72.5805,0.357794,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (2061,30,-1140.82,-343.392,50.9077,-2.7838,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (2061,30,-1139.68,-356.288,51.264,-0.706858,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (2061,30,-1099.21,-266.231,57.8849,-2.28638,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (2061,30,-1082.6,-266.681,57.8575,2.40855,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (2061,30,30.4168,-428.853,41.528,-2.59181,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (2061,30,31.2216,-428.08,41.528,0.549779,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (2061,30,50.6401,-421.166,44.7325,-0.00875192,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (2066,30,-743.427,-398.242,76.4266,0.872664,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (3832,30,-1235.57,-241.478,73.4377,1.48353,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (3833,30,-1248.85,-254.06,73.4377,1.48353,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (3834,30,-1248.15,-245.599,73.4377,-0.0523605,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (3835,30,-1237.21,-260.168,73.4377,1.48353,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (3836,30,-1260.37,-248.767,77.9454,1.48353,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (3837,30,-1249.32,-244.907,92.3372,0.401426,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (3838,30,-1250.09,-254.604,92.3015,0.148352,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (22205,30,50.6401,-421.166,44.7325,-0.00875192,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (22207,30,30.4168,-428.853,41.528,-2.59181,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (22208,30,31.2216,-428.08,41.528,0.549779,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (28048,30,41.1672,-426.866,44.6828,2.7838,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (28049,30,39.0988,-425.746,44.688,-0.619592,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (28605,30,25.2482,-433.104,47.6369,2.38237,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (28606,30,25.758,-425.837,47.6369,-1.98095,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (28607,30,27.6786,-427.69,47.6369,-2.67908,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (29784,30,-1338.28,-297.628,91.4867,0.248971,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (31442,30,-1338.28,-297.628,91.4867,0.248971,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (50984,30,-1250.39,-310.191,61.185,-1.10828,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (51704,30,-1245.2,-307.059,63.3199,3.07959,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (51705,30,-1258.23,-310.977,63.2015,0.862906,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (177261,30,-1290.27,-172.471,72.1853,3.06305,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (177262,30,-1286.25,-184.48,71.8334,-2.05076,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (177263,30,-1280.17,-220.537,72.2686,1.62316,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (177292,30,-1099.21,-266.231,57.8849,-2.28638,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (177293,30,-1082.6,-266.681,57.8575,2.40855,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (177405,30,-1140.82,-343.392,50.9077,-2.7838,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (177406,30,-1139.68,-356.288,51.264,-0.706858,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (177408,30,-743.427,-398.242,76.4266,0.872664,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (177409,30,-1215.59,-371.946,56.5293,0.357794,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (177410,30,-1241.25,-345.115,59.6867,0.357794,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (177411,30,-1202.8,-271.599,72.5805,0.357794,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (177412,30,-1282.21,-284.083,87.256,-0.0610855,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (177413,30,-1256.55,-280.278,73.9473,-0.0610855,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (178684,30,649.265,-59.1102,41.5476,-2.68781,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (178685,30,646.207,-57.2428,41.6587,-0.157079,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179384,30,-145.341,-444.846,26.4163,-0.0523596,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179384,30,560.834,-75.4266,37.9558,0.785398,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179385,30,-155.405,-440.24,33.2862,2.34747,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179385,30,550.678,-79.8234,44.8257,-3.09796,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179386,30,-150.787,-459.829,26.4163,0.558507,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179386,30,568.326,-89.4992,37.9558,1.39626,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179387,30,-153.748,-438.639,33.2862,-2.88852,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179387,30,550.597,-77.5213,44.8257,-2.05076,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179388,30,-149.057,-461.089,26.4163,1.38754,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179388,30,570.419,-89.0567,37.9558,2.2253,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179389,30,-168.342,-458.4,33.2862,-0.445059,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179389,30,555.517,-101.589,44.8257,0.392699,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179390,30,-142.968,-444.076,26.4163,-2.23402,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179390,30,561.851,-73.1481,37.9558,-1.39626,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179391,30,-172.363,-452.824,33.2796,0.62832,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179391,30,548.682,-100.846,44.8191,1.46608,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179392,30,-171.282,-456.892,33.2796,1.63188,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179392,30,552.429,-102.764,44.8191,2.46964,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179393,30,-172.356,-453.88,33.2796,0.322886,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179393,30,549.472,-101.547,44.8191,1.16064,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179394,30,-171.882,-454.632,33.2796,0.759218,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179394,30,550.347,-101.698,44.8191,1.59698,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179395,30,-171.656,-455.671,33.2796,0.0610861,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179395,30,551.271,-102.226,44.8191,0.898843,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179396,30,-170.699,-458.41,33.2796,-1.02974,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179396,30,553.947,-103.347,44.8191,-0.191986,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179397,30,-170.14,-457.609,33.2796,-0.680678,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179397,30,553.725,-102.396,44.8191,0.15708,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179419,30,-1423.16,-318.436,89.1136,2.35619,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179437,30,618.748,-52.1126,42.1122,-0.0698131,60);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179438,30,-1181.1,-370.747,53.6246,2.68781,60);
+
+-- nest 2 gos were inserted by hand..
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179024,30,40.0913,0.0153897,-4.0962,0.96131,120);
+INSERT INTO `mangos`.`gameobject` (`id` ,`map`,position_x,position_y,position_z,orientation,spawntimesecs) VALUES (179025,30,-1552.55, -359.738, 66.948,2.8875,120);
+
+
+-- hack
+-- removes the damage from the fire-gos (used for destroyed towers) - but this is not blizzlike TODO remove this hack
+ UPDATE `mangos`.`gameobject_template` SET `type` = '5',`data0` = '0',`data1` = '0',`data2` = '0',`data3` = '1',`data5` = '0',`data10` = '0' WHERE `gameobject_template`.`entry` =179065 LIMIT 1 ;
+
+-- bowman apply aura entangling root (so they can't move)
+DELETE FROM `creature_template_addon` WHERE `entry` IN(13358,13359);
+INSERT INTO `creature_template_addon` (`entry`, `auras`) VALUES ('13358', '42716 0 42716 1');
+INSERT INTO `creature_template_addon` (`entry`, `auras`) VALUES ('13359', '42716 0 42716 1');
+*/ \ No newline at end of file
diff --git a/sql/updates/287_world_scripts.sql b/sql/updates/287_world_scripts.sql
new file mode 100644
index 00000000000..8021ee2b01e
--- /dev/null
+++ b/sql/updates/287_world_scripts.sql
@@ -0,0 +1,2 @@
+UPDATE `creature_template` SET `ScriptName` = 'npc_steam_tonk' WHERE `entry` = '19405';
+UPDATE `creature_template` SET `ScriptName` = 'npc_tonk_mine' WHERE `entry` = '15368'; \ No newline at end of file
diff --git a/sql/updates/329_world_spell_proc_event.sql b/sql/updates/329_world_spell_proc_event.sql
new file mode 100644
index 00000000000..a43aa8baa45
--- /dev/null
+++ b/sql/updates/329_world_spell_proc_event.sql
@@ -0,0 +1,605 @@
+/*
+These are Trinity sql. Need to check if they should be added again.
+[\sql\updates\230_world.sql]
+Line 1 : UPDATE `spell_proc_event` SET `procFlags` = '8396800' WHERE `entry` =14774;
+Line 2 : UPDATE `spell_proc_event` SET `procFlags` = '8396800' WHERE `entry` =14531;
+[\sql\updates\233_world.sql]
+Line 1 : UPDATE `spell_proc_event` SET `SchoolMask` = '1' WHERE `entry` = '41434';
+[\sql\updates\57_world_scripts.sql]
+Line 34 : DELETE FROM `spell_proc_event` WHERE `entry` = 43983;
+Line 35 : INSERT INTO `spell_proc_event` VALUES ('43983', '0', '0', '0', '0', '0', '16384', '0', '0');
+[\updates\78_world.sql]
+Line 12 : DELETE FROM spell_proc_event WHERE entry IN (34139,42368,43726,46092);
+Line 13 : INSERT INTO spell_proc_event (entry, SchoolMask, Category, SkillID, SpellFamilyName, SpellFamilyMask, procFlags, ppmRate, cooldown) VALUES
+Line 19 : DELETE FROM spell_proc_event where entry IN (34598, 34584, 36488);
+Line 20 : INSERT INTO spell_proc_event (entry, SchoolMask, Category, SkillID, SpellFamilyName, SpellFamilyMask, procFlags, ppmRate, cooldown) VALUES
+[\updates\79_world.sql]
+Line 1 : DELETE FROM spell_proc_event where entry = 42083;
+Line 2 : INSERT INTO spell_proc_event (entry, SchoolMask, Category, SkillID, SpellFamilyName, SpellFamilyMask, procFlags, ppmRate, cooldown) VALUES
+*/
+
+DROP TABLE IF EXISTS `spell_proc_event`;
+
+SET FOREIGN_KEY_CHECKS=0;
+-- ----------------------------
+-- Table structure for spell_proc_event
+-- ----------------------------
+CREATE TABLE `spell_proc_event` (
+ `entry` smallint(6) unsigned NOT NULL default '0',
+ `SchoolMask` tinyint(4) NOT NULL default '0',
+ `SpellFamilyName` smallint(6) unsigned NOT NULL default '0',
+ `SpellFamilyMask` bigint(40) unsigned NOT NULL default '0',
+ `procFlags` int(10) unsigned NOT NULL default '0',
+ `procEx` int(10) unsigned NOT NULL default '0',
+ `ppmRate` float NOT NULL default '0',
+ `CustomChance` float NOT NULL default '0',
+ `Cooldown` int(10) unsigned NOT NULL default '0',
+ PRIMARY KEY (`entry`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Records
+-- ----------------------------
+INSERT INTO `spell_proc_event` VALUES ('9452', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34917', '32', '6', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34916', '32', '6', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34914', '32', '6', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29076', '20', '3', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29075', '20', '3', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29074', '20', '3', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12704', '0', '0', '0', '0', '0', '1.6626', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12289', '0', '4', '2', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12311', '0', '4', '2048', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28849', '0', '11', '128', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28847', '0', '7', '32', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28823', '0', '11', '192', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28809', '0', '6', '4096', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28719', '0', '7', '32', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12668', '0', '4', '2', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12703', '0', '0', '0', '0', '0', '1.33008', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12702', '0', '0', '0', '0', '0', '0.99756', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12701', '0', '0', '0', '0', '0', '0.66504', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12284', '0', '0', '0', '0', '0', '0.33252', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12797', '0', '4', '1024', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12799', '0', '4', '1024', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12800', '0', '4', '1024', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28595', '16', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28594', '16', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28593', '16', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12958', '0', '4', '2048', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13754', '0', '8', '16', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13867', '0', '8', '16', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14186', '0', '8', '1082131720', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14190', '0', '8', '9672066312', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14193', '0', '8', '9672066312', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14194', '0', '8', '9672066312', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14195', '0', '8', '9672066312', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28592', '16', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23721', '0', '9', '2048', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15277', '0', '0', '0', '0', '0', '6', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23572', '0', '11', '192', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23551', '0', '11', '192', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20235', '0', '10', '32768', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20234', '0', '10', '32768', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19415', '0', '9', '512', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15346', '0', '0', '0', '0', '0', '6', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19414', '0', '9', '512', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19413', '0', '9', '512', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15600', '0', '0', '0', '0', '0', '1', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19412', '0', '9', '512', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16850', '0', '7', '4', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16864', '0', '0', '0', '0', '0', '2', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16923', '0', '7', '4', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16924', '0', '7', '4', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16952', '0', '7', '4398046744576', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16954', '0', '7', '4398046744576', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19407', '0', '9', '512', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18096', '0', '5', '549755813984', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18073', '0', '5', '549755813984', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17793', '0', '5', '1', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17796', '0', '5', '1', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17801', '0', '5', '1', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18095', '0', '5', '10', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18094', '0', '5', '10', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17802', '0', '5', '1', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18119', '0', '5', '18416819766245', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18120', '0', '5', '18416819766245', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18121', '0', '5', '18416819766245', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18122', '0', '5', '18416819766245', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18123', '0', '5', '18416819766245', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19228', '0', '0', '64', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19232', '0', '9', '64', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19233', '0', '9', '64', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17803', '0', '5', '1', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16164', '0', '11', '2416967683', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15363', '0', '6', '17448312320', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15362', '0', '6', '17448312320', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15326', '0', '6', '8691163136', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20164', '0', '0', '0', '0', '0', '5', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20165', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20166', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20215', '0', '10', '3223322624', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20214', '0', '10', '3223322624', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20213', '0', '10', '3223322624', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20212', '0', '10', '3223322624', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20210', '0', '10', '3223322624', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15325', '0', '6', '8691163136', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15324', '0', '6', '8691163136', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20347', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20348', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20349', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20356', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20357', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20375', '0', '0', '0', '0', '0', '7', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20500', '0', '4', '268435456', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20501', '0', '4', '268435456', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20915', '0', '0', '0', '0', '0', '7', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20918', '0', '0', '0', '0', '0', '7', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20919', '0', '0', '0', '0', '0', '7', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20920', '0', '0', '0', '0', '0', '7', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('21890', '0', '4', '3763103747823', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15323', '0', '6', '8691163136', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15286', '32', '6', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23578', '0', '0', '0', '0', '0', '2', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23581', '0', '0', '0', '0', '0', '2', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23686', '0', '0', '0', '0', '0', '2', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23689', '0', '0', '0', '0', '0', '4', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23695', '0', '4', '2', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15268', '0', '6', '8691163136', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('25669', '0', '0', '0', '0', '0', '1', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('26016', '0', '0', '0', '0', '0', '2', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('26021', '0', '0', '0', '0', '0', '2', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('26119', '0', '10', '2416967683', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('26480', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27160', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27166', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27170', '0', '0', '0', '0', '0', '7', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27419', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27498', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27656', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27787', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14892', '0', '6', '17448312320', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12848', '4', '3', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12847', '4', '3', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12846', '4', '3', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('11255', '0', '3', '16384', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28789', '0', '10', '3221225472', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12360', '4', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28816', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12359', '4', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12358', '4', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12357', '4', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12598', '0', '3', '16384', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('11180', '16', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('11129', '0', '3', '274890489879', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29150', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29501', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29624', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29625', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29626', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29632', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29633', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29634', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29635', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29636', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29637', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30299', '36', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30675', '0', '11', '3', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30678', '0', '11', '3', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30679', '0', '11', '3', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30680', '0', '11', '3', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30681', '0', '11', '3', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31801', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31833', '0', '10', '2147483648', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31835', '0', '10', '2147483648', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31836', '0', '10', '2147483648', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30302', '36', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30301', '36', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32385', '0', '5', '73014445058', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32387', '0', '5', '73014445058', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32392', '0', '5', '73014445058', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32393', '0', '5', '73014445058', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32394', '0', '5', '73014445058', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('11120', '4', '3', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('11119', '4', '3', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('11103', '4', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37195', '0', '10', '8388608', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37377', '32', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('39437', '4', '5', '824633725796', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33191', '0', '6', '4398054932480', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33192', '0', '6', '4398054932480', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33193', '0', '6', '4398054932480', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33194', '0', '6', '4398054932480', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33195', '0', '6', '4398054932480', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40475', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('41434', '0', '0', '0', '0', '0', '2', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('37523', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30293', '0', '5', '824633721729', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30295', '0', '5', '824633721729', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30296', '0', '5', '824633721729', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40407', '0', '0', '0', '0', '0', '6', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31895', '0', '0', '0', '0', '0', '5', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37247', '8', '0', '0', '0', '65536', '0', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('33510', '0', '0', '0', '0', '0', '5', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16624', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28752', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16176', '0', '11', '448', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16235', '0', '11', '448', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16240', '0', '11', '448', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23920', '0', '0', '0', '0', '2048', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27811', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27815', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27816', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33142', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33145', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33146', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16487', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16489', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16492', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('26605', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16550', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('22648', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34320', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29977', '0', '3', '274890489879', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37443', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('38350', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('38347', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12834', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12849', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12867', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30160', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29179', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29180', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12317', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13045', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13046', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13047', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13048', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34500', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34502', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34503', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('9799', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('25988', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29062', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29064', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29065', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15088', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12319', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16256', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12971', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16281', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12972', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16282', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12973', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16283', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12974', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16284', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('42083', '0', '0', '0', '0', '2', '0', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('34950', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34954', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28812', '0', '8', '33554438', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37227', '0', '11', '448', '0', '2', '0', '0', '60');
+INSERT INTO `spell_proc_event` VALUES ('32885', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('21882', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34258', '0', '10', '34359739392', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37237', '0', '11', '1', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37657', '0', '0', '0', '0', '2', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('40482', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37213', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14531', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14774', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16880', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('35121', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20705', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16958', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16961', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33648', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37189', '0', '10', '3221225472', '0', '2', '0', '0', '60');
+INSERT INTO `spell_proc_event` VALUES ('43338', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33150', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33154', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34497', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34498', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34499', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30802', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30808', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30809', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30810', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30811', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20049', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20056', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20057', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20058', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20059', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37519', '0', '0', '0', '0', '48', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('26107', '0', '7', '549764202496', '0', '116', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23548', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37514', '0', '0', '0', '0', '32', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40444', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20911', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20912', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20913', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20914', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27168', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17495', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('22618', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('25899', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27169', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31904', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32777', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20925', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20927', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20928', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27179', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12298', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12724', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12725', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12726', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12727', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32642', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33089', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('26128', '0', '0', '0', '0', '8', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29441', '0', '0', '0', '0', '8', '0', '0', '1');
+INSERT INTO `spell_proc_event` VALUES ('29444', '0', '0', '0', '0', '8', '0', '0', '1');
+INSERT INTO `spell_proc_event` VALUES ('29445', '0', '0', '0', '0', '8', '0', '0', '1');
+INSERT INTO `spell_proc_event` VALUES ('29446', '0', '0', '0', '0', '8', '0', '0', '1');
+INSERT INTO `spell_proc_event` VALUES ('29447', '0', '0', '0', '0', '8', '0', '0', '1');
+INSERT INTO `spell_proc_event` VALUES ('34749', '0', '0', '0', '0', '8', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13983', '0', '0', '0', '0', '24', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14070', '0', '0', '0', '0', '24', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14071', '0', '0', '0', '0', '24', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('41034', '0', '0', '0', '0', '1024', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32734', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('974', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('32593', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('32594', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('40899', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('324', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('325', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('905', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('945', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('8134', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('10431', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('10432', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('25469', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('25472', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('34355', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('39027', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('34827', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('24398', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('33736', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('41260', '0', '0', '0', '0', '0', '0', '0', '10');
+INSERT INTO `spell_proc_event` VALUES ('41262', '0', '0', '0', '0', '0', '0', '0', '10');
+INSERT INTO `spell_proc_event` VALUES ('34935', '0', '0', '0', '0', '0', '0', '0', '8');
+INSERT INTO `spell_proc_event` VALUES ('34938', '0', '0', '0', '0', '0', '0', '0', '8');
+INSERT INTO `spell_proc_event` VALUES ('34939', '0', '0', '0', '0', '0', '0', '0', '8');
+INSERT INTO `spell_proc_event` VALUES ('33746', '0', '0', '0', '0', '0', '0', '0', '10');
+INSERT INTO `spell_proc_event` VALUES ('33759', '0', '0', '0', '0', '0', '0', '0', '10');
+INSERT INTO `spell_proc_event` VALUES ('16620', '0', '0', '0', '0', '0', '0', '0', '30');
+INSERT INTO `spell_proc_event` VALUES ('21185', '0', '0', '0', '0', '0', '0', '0', '10');
+INSERT INTO `spell_proc_event` VALUES ('29801', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30030', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30033', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30701', '28', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30705', '28', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43748', '0', '11', '2416967680', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43750', '0', '11', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('42370', '0', '11', '64', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30881', '0', '0', '0', '0', '0', '0', '0', '5');
+INSERT INTO `spell_proc_event` VALUES ('30883', '0', '0', '0', '0', '0', '0', '0', '5');
+INSERT INTO `spell_proc_event` VALUES ('30884', '0', '0', '0', '0', '0', '0', '0', '5');
+INSERT INTO `spell_proc_event` VALUES ('30885', '0', '0', '0', '0', '0', '0', '0', '5');
+INSERT INTO `spell_proc_event` VALUES ('30886', '0', '0', '0', '0', '0', '0', '0', '5');
+INSERT INTO `spell_proc_event` VALUES ('34138', '0', '11', '128', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43728', '0', '11', '128', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('26135', '0', '10', '8388608', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43745', '0', '10', '2199023255552', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34139', '0', '10', '1073741824', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43741', '0', '10', '2147483648', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('42368', '0', '10', '1073741824', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34262', '0', '10', '8388608', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('41469', '0', '0', '0', '0', '0', '7', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33127', '0', '0', '0', '0', '0', '7', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29385', '0', '0', '0', '0', '0', '7', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43726', '0', '10', '1073741824', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('35100', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('35102', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('35103', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40485', '0', '9', '4294967296', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31124', '0', '8', '536870926', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31126', '0', '8', '536870926', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31233', '0', '8', '38658768896', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31239', '0', '8', '38658768896', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31240', '0', '8', '38658768896', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31241', '0', '8', '38658768896', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31242', '0', '8', '38658768896', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37168', '0', '8', '38658768896', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37170', '0', '0', '0', '0', '0', '1', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37165', '0', '8', '2098176', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31244', '0', '8', '38658768896', '0', '4', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31245', '0', '8', '38658768896', '0', '4', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('41393', '0', '0', '0', '0', '32', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14156', '0', '8', '4063232', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14160', '0', '8', '4063232', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14161', '0', '8', '4063232', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('38326', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17106', '0', '7', '524288', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17107', '0', '7', '524288', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17108', '0', '7', '524288', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43739', '0', '7', '2', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43737', '0', '7', '4672924418048', '0', '0', '0', '0', '10');
+INSERT INTO `spell_proc_event` VALUES ('39372', '48', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37568', '0', '6', '2048', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37594', '0', '6', '4096', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34753', '0', '6', '17179875328', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34859', '0', '6', '17179875328', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34860', '0', '6', '17179875328', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37603', '0', '6', '32768', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('38394', '0', '5', '6', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37384', '0', '5', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40478', '0', '5', '2', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37528', '0', '4', '4', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37516', '0', '4', '1024', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40458', '0', '4', '6601398288384', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('22007', '0', '3', '2097185', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('3232', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17364', '8', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30937', '32', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15128', '4', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37193', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32776', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20132', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20131', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20128', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17794', '32', '0', '0', '0', '1', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31394', '32', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('25050', '4', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('24353', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20134', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17797', '32', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17798', '32', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('24389', '0', '3', '274890489879', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20133', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('36111', '0', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29455', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34774', '0', '0', '0', '0', '0', '1.5', '0', '20');
+INSERT INTO `spell_proc_event` VALUES ('9784', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31785', '0', '0', '0', '34816', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('9782', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('24932', '0', '0', '0', '0', '2', '0', '0', '6');
+INSERT INTO `spell_proc_event` VALUES ('33776', '0', '0', '0', '34816', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34586', '0', '0', '0', '0', '0', '1.5', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('2565', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12169', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32587', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('38031', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34080', '0', '0', '0', '0', '8', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('42136', '0', '0', '0', '0', '0', '0', '0', '90');
+INSERT INTO `spell_proc_event` VALUES ('42135', '0', '0', '0', '0', '0', '0', '0', '90');
+INSERT INTO `spell_proc_event` VALUES ('23547', '0', '0', '0', '0', '32', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32837', '0', '0', '0', '0', '65536', '0', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('17799', '32', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17800', '32', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37197', '0', '0', '0', '0', '65536', '0', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('23688', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34783', '0', '0', '0', '0', '2048', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27521', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27774', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28802', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37600', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19184', '0', '9', '35184372088852', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19387', '0', '9', '35184372088852', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19388', '0', '9', '35184372088852', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37655', '0', '0', '0', '0', '0', '0', '0', '60');
+INSERT INTO `spell_proc_event` VALUES ('38334', '0', '0', '0', '0', '0', '0', '0', '60');
+INSERT INTO `spell_proc_event` VALUES ('12966', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12967', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12968', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12969', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12970', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16257', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16277', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16278', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16279', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16280', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('36096', '0', '0', '0', '0', '2048', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43443', '0', '0', '0', '0', '2048', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30003', '0', '0', '0', '0', '2048', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27181', '1', '0', '0', '0', '256', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('41381', '0', '0', '0', '0', '256', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('38026', '1', '0', '0', '0', '256', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31569', '0', '3', '65536', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31570', '0', '3', '65536', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('7383', '1', '0', '0', '0', '256', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('39530', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33299', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37214', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31794', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18820', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37601', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43819', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('6346', '0', '0', '0', '0', '256', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23552', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('46025', '0', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40442', '0', '7', '4672924418068', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40470', '0', '10', '3229614080', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40438', '0', '6', '32832', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40463', '0', '11', '68719476865', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12322', '0', '0', '0', '0', '0', '2', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12999', '0', '0', '0', '0', '0', '4', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13000', '0', '0', '0', '0', '0', '6', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13001', '0', '0', '0', '0', '0', '8', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13002', '0', '0', '0', '0', '0', '10', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14318', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13165', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14319', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14320', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14321', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14322', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('25296', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27044', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('39443', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('39442', '0', '0', '0', '0', '1', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('35080', '0', '0', '0', '0', '0', '1', '0', '60');
+INSERT INTO `spell_proc_event` VALUES ('35077', '0', '0', '0', '0', '0', '0', '0', '60');
+INSERT INTO `spell_proc_event` VALUES ('35086', '0', '0', '0', '0', '0', '0', '0', '60');
+INSERT INTO `spell_proc_event` VALUES ('35083', '0', '0', '0', '0', '0', '0', '0', '60');
+INSERT INTO `spell_proc_event` VALUES ('18137', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('19308', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('19309', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('19310', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('19311', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('19312', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('25477', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('38327', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33881', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33882', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33883', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33719', '0', '0', '0', '0', '2048', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29834', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29838', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('39958', '0', '0', '0', '0', '0', '0.7', '0', '40');
+INSERT INTO `spell_proc_event` VALUES ('1463', '0', '0', '0', '0', '1024', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('8494', '0', '0', '0', '0', '1024', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('8495', '0', '0', '0', '0', '1024', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('10191', '0', '0', '0', '0', '1024', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('10192', '0', '0', '0', '0', '1024', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('10193', '0', '0', '0', '0', '1024', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27131', '0', '0', '0', '0', '1024', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32844', '0', '0', '0', '0', '0', '2', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33076', '0', '0', '0', '656040', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('46662', '0', '0', '0', '0', '0', '0', '0', '20');
+INSERT INTO `spell_proc_event` VALUES ('38857', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('8178', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('41635', '0', '0', '0', '656040', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30823', '0', '0', '0', '0', '0', '10.5', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('24905', '0', '0', '0', '0', '0', '15', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('46098', '0', '11', '128', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('46092', '0', '10', '1073741824', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('38290', '0', '0', '0', '0', '0', '1.6', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('45234', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('45243', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('45244', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23602', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('45483', '0', '0', '0', '0', '0', '0', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('45482', '0', '0', '0', '0', '0', '0', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('45484', '0', '0', '0', '16384', '0', '0', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('46569', '0', '0', '0', '0', '0', '0', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('45481', '0', '0', '0', '0', '0', '0', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('32748', '0', '8', '4294967296', '320', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('24658', '0', '0', '0', '82192', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('44835', '0', '7', '549755813888', '16', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('46832', '0', '7', '1', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('45057', '0', '0', '0', '0', '0', '0', '0', '30');
+INSERT INTO `spell_proc_event` VALUES ('37173', '0', '8', '1126031951256', '0', '0', '0', '0', '30');
+INSERT INTO `spell_proc_event` VALUES ('45054', '0', '0', '0', '0', '0', '0', '0', '15');
+INSERT INTO `spell_proc_event` VALUES ('45354', '0', '0', '0', '0', '0', '0', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('41989', '0', '0', '0', '0', '0', '0.5', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('11185', '0', '3', '128', '327680', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12487', '0', '3', '128', '327680', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19572', '0', '9', '8388608', '16384', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28716', '0', '7', '16', '294912', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28744', '0', '7', '64', '278528', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12488', '0', '3', '128', '327680', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19573', '0', '9', '8388608', '16384', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33757', '0', '0', '0', '0', '0', '0', '0', '3'); \ No newline at end of file
diff --git a/sql/updates/332_world_spell_script_target.sql b/sql/updates/332_world_spell_script_target.sql
new file mode 100644
index 00000000000..bb102d9a134
--- /dev/null
+++ b/sql/updates/332_world_spell_script_target.sql
@@ -0,0 +1,2 @@
+DELETE FROM `spell_script_target` WHERE `entry` in (30659);
+INSERT INTO `spell_script_target` VALUES (30659, 1, 17281); \ No newline at end of file
diff --git a/sql/updates/333_world_spell_proc_event.sql b/sql/updates/333_world_spell_proc_event.sql
new file mode 100644
index 00000000000..de0b3089259
--- /dev/null
+++ b/sql/updates/333_world_spell_proc_event.sql
@@ -0,0 +1,618 @@
+/*
+These are Trinity sql. Need to check if they should be added again.
+[\sql\updates\230_world.sql]
+Line 1 : UPDATE `spell_proc_event` SET `procFlags` = '8396800' WHERE `entry` =14774;
+Line 2 : UPDATE `spell_proc_event` SET `procFlags` = '8396800' WHERE `entry` =14531;
+[\sql\updates\233_world.sql]
+Line 1 : UPDATE `spell_proc_event` SET `SchoolMask` = '1' WHERE `entry` = '41434';
+[\sql\updates\57_world_scripts.sql]
+Line 34 : DELETE FROM `spell_proc_event` WHERE `entry` = 43983;
+Line 35 : INSERT INTO `spell_proc_event` VALUES ('43983', '0', '0', '0', '0', '0', '16384', '0', '0');
+[\updates\78_world.sql]
+Line 12 : DELETE FROM spell_proc_event WHERE entry IN (34139,42368,43726,46092);
+Line 13 : INSERT INTO spell_proc_event (entry, SchoolMask, Category, SkillID, SpellFamilyName, SpellFamilyMask, procFlags, ppmRate, cooldown) VALUES
+Line 19 : DELETE FROM spell_proc_event where entry IN (34598, 34584, 36488);
+Line 20 : INSERT INTO spell_proc_event (entry, SchoolMask, Category, SkillID, SpellFamilyName, SpellFamilyMask, procFlags, ppmRate, cooldown) VALUES
+[\updates\79_world.sql]
+Line 1 : DELETE FROM spell_proc_event where entry = 42083;
+Line 2 : INSERT INTO spell_proc_event (entry, SchoolMask, Category, SkillID, SpellFamilyName, SpellFamilyMask, procFlags, ppmRate, cooldown) VALUES
+
+DELETE FROM spell_proc_event where entry = 35080;
+INSERT INTO spell_proc_event (entry, SchoolMask, Category, SkillID, SpellFamilyName, SpellFamilyMask, procFlags, ppmRate, cooldown) VALUES
+(35080,0,0,0,0,0x0000000000000000,0x00080001,0,60);
+*/
+
+DROP TABLE IF EXISTS `spell_proc_event`;
+
+SET FOREIGN_KEY_CHECKS=0;
+-- ----------------------------
+-- Table structure for spell_proc_event
+-- ----------------------------
+CREATE TABLE `spell_proc_event` (
+ `entry` smallint(6) unsigned NOT NULL default '0',
+ `SchoolMask` tinyint(4) NOT NULL default '0',
+ `SpellFamilyName` smallint(6) unsigned NOT NULL default '0',
+ `SpellFamilyMask` bigint(40) unsigned NOT NULL default '0',
+ `procFlags` int(10) unsigned NOT NULL default '0',
+ `procEx` int(10) unsigned NOT NULL default '0',
+ `ppmRate` float NOT NULL default '0',
+ `CustomChance` float NOT NULL default '0',
+ `Cooldown` int(10) unsigned NOT NULL default '0',
+ PRIMARY KEY (`entry`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+-- ----------------------------
+-- Records
+-- ----------------------------
+INSERT INTO `spell_proc_event` VALUES ('9452', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34917', '32', '6', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34916', '32', '6', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34914', '32', '6', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29076', '20', '3', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29075', '20', '3', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29074', '20', '3', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12704', '0', '0', '0', '0', '0', '1.6626', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12289', '0', '4', '2', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12311', '0', '4', '2048', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28849', '0', '11', '128', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28847', '0', '7', '32', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28823', '0', '11', '192', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28809', '0', '6', '4096', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28719', '0', '7', '32', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12668', '0', '4', '2', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12703', '0', '0', '0', '0', '0', '1.33008', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12702', '0', '0', '0', '0', '0', '0.99756', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12701', '0', '0', '0', '0', '0', '0.66504', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12284', '0', '0', '0', '0', '0', '0.33252', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12797', '0', '4', '1024', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12799', '0', '4', '1024', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12800', '0', '4', '1024', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28595', '16', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28594', '16', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28593', '16', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12958', '0', '4', '2048', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13754', '0', '8', '16', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13867', '0', '8', '16', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14186', '0', '8', '1082131720', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14190', '0', '8', '9672066312', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14193', '0', '8', '9672066312', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14194', '0', '8', '9672066312', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14195', '0', '8', '9672066312', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28592', '16', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23721', '0', '9', '2048', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15277', '0', '0', '0', '0', '0', '6', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23572', '0', '11', '192', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23551', '0', '11', '192', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20235', '0', '10', '32768', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20234', '0', '10', '32768', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19415', '0', '9', '512', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15346', '0', '0', '0', '0', '0', '6', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19414', '0', '9', '512', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19413', '0', '9', '512', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15600', '0', '0', '0', '0', '0', '1', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19412', '0', '9', '512', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16850', '0', '7', '4', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16864', '0', '0', '0', '0', '0', '2', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16923', '0', '7', '4', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16924', '0', '7', '4', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16952', '0', '7', '4398046744576', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16954', '0', '7', '4398046744576', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19407', '0', '9', '512', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18096', '0', '5', '549755813984', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18073', '0', '5', '549755813984', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17793', '0', '5', '1', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17796', '0', '5', '1', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17801', '0', '5', '1', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18095', '0', '5', '10', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18094', '0', '5', '10', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17802', '0', '5', '1', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18119', '0', '5', '18416819766245', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18120', '0', '5', '18416819766245', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18121', '0', '5', '18416819766245', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18122', '0', '5', '18416819766245', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18123', '0', '5', '18416819766245', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19228', '0', '0', '64', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19232', '0', '9', '64', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19233', '0', '9', '64', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17803', '0', '5', '1', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16164', '0', '11', '2416967683', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15363', '0', '6', '17448312320', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15362', '0', '6', '17448312320', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15326', '0', '6', '8691163136', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20164', '0', '0', '0', '0', '0', '5', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20165', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20166', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20215', '0', '10', '3223322624', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20214', '0', '10', '3223322624', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20213', '0', '10', '3223322624', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20212', '0', '10', '3223322624', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20210', '0', '10', '3223322624', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15325', '0', '6', '8691163136', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15324', '0', '6', '8691163136', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20347', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20348', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20349', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20356', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20357', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20375', '0', '0', '0', '0', '0', '7', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20500', '0', '4', '268435456', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20501', '0', '4', '268435456', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20915', '0', '0', '0', '0', '0', '7', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20918', '0', '0', '0', '0', '0', '7', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20919', '0', '0', '0', '0', '0', '7', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20920', '0', '0', '0', '0', '0', '7', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('21890', '0', '4', '3763103747823', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15323', '0', '6', '8691163136', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15286', '32', '6', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23578', '0', '0', '0', '0', '0', '2', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23581', '0', '0', '0', '0', '0', '2', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23686', '0', '0', '0', '0', '0', '2', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23689', '0', '0', '0', '0', '0', '4', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23695', '0', '4', '2', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15268', '0', '6', '8691163136', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('25669', '0', '0', '0', '0', '0', '1', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('26016', '0', '0', '0', '0', '0', '2', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('26021', '0', '0', '0', '0', '0', '2', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('26119', '0', '10', '2416967683', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('26480', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27160', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27166', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27170', '0', '0', '0', '0', '0', '7', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27419', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27498', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27656', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27787', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14892', '0', '6', '17448312320', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12848', '4', '3', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12847', '4', '3', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12846', '4', '3', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('11255', '0', '3', '16384', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28789', '0', '10', '3221225472', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12360', '4', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28816', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12359', '4', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12358', '4', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12357', '4', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12598', '0', '3', '16384', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('11180', '16', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('11129', '0', '3', '274890489879', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29150', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29501', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29624', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29625', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29626', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29632', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29633', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29634', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29635', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29636', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29637', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30299', '36', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30675', '0', '11', '3', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30678', '0', '11', '3', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30679', '0', '11', '3', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30680', '0', '11', '3', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30681', '0', '11', '3', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31801', '0', '0', '0', '0', '0', '20', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31833', '0', '10', '2147483648', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31835', '0', '10', '2147483648', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31836', '0', '10', '2147483648', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30302', '36', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30301', '36', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32385', '0', '5', '73014445058', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32387', '0', '5', '73014445058', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32392', '0', '5', '73014445058', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32393', '0', '5', '73014445058', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32394', '0', '5', '73014445058', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('11120', '4', '3', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('11119', '4', '3', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('11103', '4', '3', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37195', '0', '10', '8388608', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37377', '32', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('39437', '4', '5', '824633725796', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33191', '0', '6', '4398054932480', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33192', '0', '6', '4398054932480', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33193', '0', '6', '4398054932480', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33194', '0', '6', '4398054932480', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33195', '0', '6', '4398054932480', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40475', '0', '0', '0', '0', '0', '3', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('41434', '0', '0', '0', '0', '0', '2', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('37523', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30293', '0', '5', '824633721729', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30295', '0', '5', '824633721729', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30296', '0', '5', '824633721729', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40407', '0', '0', '0', '0', '0', '6', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31895', '0', '0', '0', '0', '0', '5', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37247', '8', '0', '0', '0', '65536', '0', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('33510', '0', '0', '0', '0', '0', '5', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16624', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28752', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16176', '0', '11', '448', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16235', '0', '11', '448', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16240', '0', '11', '448', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23920', '0', '0', '0', '0', '2048', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27811', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27815', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27816', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33142', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33145', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33146', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16487', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16489', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16492', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('26605', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16550', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('22648', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34320', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29977', '0', '3', '274890489879', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37443', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('38350', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('38347', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12834', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12849', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12867', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30160', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29179', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29180', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12317', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13045', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13046', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13047', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13048', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34500', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34502', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34503', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('9799', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('25988', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29062', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29064', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29065', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15088', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12319', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16256', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12971', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16281', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12972', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16282', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12973', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16283', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12974', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16284', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('42083', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34950', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34954', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28812', '0', '8', '33554438', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37227', '0', '11', '448', '0', '2', '0', '0', '60');
+INSERT INTO `spell_proc_event` VALUES ('32885', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('21882', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34258', '0', '10', '34359739392', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37237', '0', '11', '1', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37657', '0', '0', '0', '0', '2', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('40482', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37213', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14531', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14774', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16880', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('35121', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20705', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16958', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16961', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33648', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37189', '0', '10', '3221225472', '0', '2', '0', '0', '60');
+INSERT INTO `spell_proc_event` VALUES ('43338', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33150', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33154', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34497', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34498', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34499', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30802', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30808', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30809', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30810', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30811', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20049', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20056', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20057', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20058', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20059', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37519', '0', '0', '0', '0', '48', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('26107', '0', '7', '549764202496', '0', '116', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23548', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37514', '0', '0', '0', '0', '32', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40444', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20911', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20912', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20913', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20914', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27168', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17495', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('22618', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('25899', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27169', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31904', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32777', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20925', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20927', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20928', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27179', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12298', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12724', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12725', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12726', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12727', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32642', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33089', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('26128', '0', '0', '0', '0', '8', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29441', '0', '0', '0', '0', '8', '0', '0', '1');
+INSERT INTO `spell_proc_event` VALUES ('29444', '0', '0', '0', '0', '8', '0', '0', '1');
+INSERT INTO `spell_proc_event` VALUES ('29445', '0', '0', '0', '0', '8', '0', '0', '1');
+INSERT INTO `spell_proc_event` VALUES ('29446', '0', '0', '0', '0', '8', '0', '0', '1');
+INSERT INTO `spell_proc_event` VALUES ('29447', '0', '0', '0', '0', '8', '0', '0', '1');
+INSERT INTO `spell_proc_event` VALUES ('34749', '0', '0', '0', '0', '8', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13983', '0', '0', '0', '0', '24', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14070', '0', '0', '0', '0', '24', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14071', '0', '0', '0', '0', '24', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('41034', '0', '0', '0', '0', '1024', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32734', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('974', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('32593', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('32594', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('40899', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('324', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('325', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('905', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('945', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('8134', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('10431', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('10432', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('25469', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('25472', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('34355', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('39027', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('34827', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('24398', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('33736', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('41260', '0', '0', '0', '0', '0', '0', '0', '10');
+INSERT INTO `spell_proc_event` VALUES ('41262', '0', '0', '0', '0', '0', '0', '0', '10');
+INSERT INTO `spell_proc_event` VALUES ('34935', '0', '0', '0', '0', '0', '0', '0', '8');
+INSERT INTO `spell_proc_event` VALUES ('34938', '0', '0', '0', '0', '0', '0', '0', '8');
+INSERT INTO `spell_proc_event` VALUES ('34939', '0', '0', '0', '0', '0', '0', '0', '8');
+INSERT INTO `spell_proc_event` VALUES ('33746', '0', '0', '0', '0', '0', '0', '0', '10');
+INSERT INTO `spell_proc_event` VALUES ('33759', '0', '0', '0', '0', '0', '0', '0', '10');
+INSERT INTO `spell_proc_event` VALUES ('16620', '0', '0', '0', '0', '0', '0', '0', '30');
+INSERT INTO `spell_proc_event` VALUES ('21185', '0', '0', '0', '0', '0', '0', '0', '10');
+INSERT INTO `spell_proc_event` VALUES ('29801', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30030', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30033', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30701', '28', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30705', '28', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43748', '0', '11', '2416967680', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43750', '0', '11', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('42370', '0', '11', '64', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30881', '0', '0', '0', '0', '0', '0', '0', '5');
+INSERT INTO `spell_proc_event` VALUES ('30883', '0', '0', '0', '0', '0', '0', '0', '5');
+INSERT INTO `spell_proc_event` VALUES ('30884', '0', '0', '0', '0', '0', '0', '0', '5');
+INSERT INTO `spell_proc_event` VALUES ('30885', '0', '0', '0', '0', '0', '0', '0', '5');
+INSERT INTO `spell_proc_event` VALUES ('30886', '0', '0', '0', '0', '0', '0', '0', '5');
+INSERT INTO `spell_proc_event` VALUES ('34138', '0', '11', '128', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43728', '0', '11', '128', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('26135', '0', '10', '8388608', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43745', '0', '10', '2199023255552', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34139', '0', '10', '1073741824', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43741', '0', '10', '2147483648', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('42368', '0', '10', '1073741824', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34262', '0', '10', '8388608', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('41469', '0', '0', '0', '0', '0', '7', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33127', '0', '0', '0', '0', '0', '7', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29385', '0', '0', '0', '0', '0', '7', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43726', '0', '10', '1073741824', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('35100', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('35102', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('35103', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40485', '0', '9', '4294967296', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31124', '0', '8', '536870926', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31126', '0', '8', '536870926', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31233', '0', '8', '38658768896', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31239', '0', '8', '38658768896', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31240', '0', '8', '38658768896', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31241', '0', '8', '38658768896', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31242', '0', '8', '38658768896', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37168', '0', '8', '38658768896', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37170', '0', '0', '0', '0', '0', '1', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37165', '0', '8', '2098176', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31244', '0', '8', '38658768896', '0', '4', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31245', '0', '8', '38658768896', '0', '4', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('41393', '0', '0', '0', '0', '32', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14156', '0', '8', '4063232', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14160', '0', '8', '4063232', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14161', '0', '8', '4063232', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('38326', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17106', '0', '7', '524288', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17107', '0', '7', '524288', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17108', '0', '7', '524288', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43739', '0', '7', '2', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43737', '0', '7', '4672924418048', '0', '0', '0', '0', '10');
+INSERT INTO `spell_proc_event` VALUES ('39372', '48', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37568', '0', '6', '2048', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37594', '0', '6', '4096', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34753', '0', '6', '17179875328', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34859', '0', '6', '17179875328', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34860', '0', '6', '17179875328', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37603', '0', '6', '32768', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('38394', '0', '5', '6', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37384', '0', '5', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40478', '0', '5', '2', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37528', '0', '4', '4', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37516', '0', '4', '1024', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40458', '0', '4', '6601398288384', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('22007', '0', '3', '2097185', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('3232', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17364', '8', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30937', '32', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('15128', '4', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37193', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32776', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20132', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20131', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20128', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17794', '32', '0', '0', '0', '1', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31394', '32', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('25050', '4', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('24353', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20134', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17797', '32', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17798', '32', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('24389', '0', '3', '274890489879', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('20133', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('36111', '0', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29455', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34774', '0', '0', '0', '0', '0', '1.5', '0', '20');
+INSERT INTO `spell_proc_event` VALUES ('9784', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31785', '0', '0', '0', '34816', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('9782', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('24932', '0', '0', '0', '0', '2', '0', '0', '6');
+INSERT INTO `spell_proc_event` VALUES ('33776', '0', '0', '0', '34816', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34586', '0', '0', '0', '0', '0', '1.5', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('2565', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12169', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32587', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('38031', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34080', '0', '0', '0', '0', '8', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('42136', '0', '0', '0', '0', '0', '0', '0', '90');
+INSERT INTO `spell_proc_event` VALUES ('42135', '0', '0', '0', '0', '0', '0', '0', '90');
+INSERT INTO `spell_proc_event` VALUES ('23547', '0', '0', '0', '0', '32', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32837', '0', '0', '0', '0', '65536', '0', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('17799', '32', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('17800', '32', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37197', '0', '0', '0', '0', '65536', '0', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('23688', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('34783', '0', '0', '0', '0', '2048', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27521', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27774', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28802', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37600', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19184', '0', '9', '35184372088852', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19387', '0', '9', '35184372088852', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19388', '0', '9', '35184372088852', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37655', '0', '0', '0', '0', '0', '0', '0', '60');
+INSERT INTO `spell_proc_event` VALUES ('38334', '0', '0', '0', '0', '0', '0', '0', '60');
+INSERT INTO `spell_proc_event` VALUES ('12966', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12967', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12968', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12969', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12970', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16257', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16277', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16278', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16279', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('16280', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('36096', '0', '0', '0', '0', '2048', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43443', '0', '0', '0', '0', '2048', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30003', '0', '0', '0', '0', '2048', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27181', '1', '0', '0', '0', '256', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('41381', '0', '0', '0', '0', '256', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('38026', '1', '0', '0', '0', '256', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31569', '0', '3', '65536', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31570', '0', '3', '65536', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('7383', '1', '0', '0', '0', '256', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('39530', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33299', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37214', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('31794', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('18820', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('37601', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('43819', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('6346', '0', '0', '0', '0', '256', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23552', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('46025', '0', '0', '0', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40442', '0', '7', '4672924418068', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40470', '0', '10', '3229614080', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40438', '0', '6', '32832', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('40463', '0', '11', '68719476865', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12322', '0', '0', '0', '0', '0', '2', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12999', '0', '0', '0', '0', '0', '4', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13000', '0', '0', '0', '0', '0', '6', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13001', '0', '0', '0', '0', '0', '8', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13002', '0', '0', '0', '0', '0', '10', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14318', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('13165', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14319', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14320', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14321', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('14322', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('25296', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27044', '0', '9', '1', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('39443', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('39442', '0', '0', '0', '0', '1', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('35080', '0', '0', '0', '0', '0', '1', '0', '60');
+INSERT INTO `spell_proc_event` VALUES ('35077', '0', '0', '0', '0', '0', '0', '0', '60');
+INSERT INTO `spell_proc_event` VALUES ('35086', '0', '0', '0', '0', '0', '0', '0', '60');
+INSERT INTO `spell_proc_event` VALUES ('35083', '0', '0', '0', '0', '0', '0', '0', '60');
+INSERT INTO `spell_proc_event` VALUES ('18137', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('19308', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('19309', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('19310', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('19311', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('19312', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('25477', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('38327', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33881', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33882', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33883', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33719', '0', '0', '0', '0', '2048', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29834', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('29838', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('39958', '0', '0', '0', '0', '0', '0.7', '0', '40');
+INSERT INTO `spell_proc_event` VALUES ('1463', '0', '0', '0', '0', '1024', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('8494', '0', '0', '0', '0', '1024', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('8495', '0', '0', '0', '0', '1024', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('10191', '0', '0', '0', '0', '1024', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('10192', '0', '0', '0', '0', '1024', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('10193', '0', '0', '0', '0', '1024', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('27131', '0', '0', '0', '0', '1024', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('32844', '0', '0', '0', '0', '0', '2', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33076', '0', '0', '0', '656040', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('46662', '0', '0', '0', '0', '0', '0', '0', '20');
+INSERT INTO `spell_proc_event` VALUES ('38857', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('8178', '0', '0', '0', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('41635', '0', '0', '0', '656040', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('30823', '0', '0', '0', '0', '0', '10.5', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('24905', '0', '0', '0', '0', '0', '15', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('46098', '0', '11', '128', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('46092', '0', '10', '1073741824', '0', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('38290', '0', '0', '0', '0', '0', '1.6', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('45234', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('45243', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('45244', '0', '0', '0', '0', '2', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('23602', '0', '0', '0', '0', '64', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('45483', '0', '0', '0', '0', '0', '0', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('45482', '0', '0', '0', '0', '0', '0', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('45484', '0', '0', '0', '16384', '0', '0', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('46569', '0', '0', '0', '0', '0', '0', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('45481', '0', '0', '0', '0', '0', '0', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('32748', '0', '8', '4294967296', '320', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('24658', '0', '0', '0', '82192', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('44835', '0', '7', '549755813888', '16', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('46832', '0', '7', '1', '0', '65536', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('45057', '0', '0', '0', '0', '0', '0', '0', '30');
+INSERT INTO `spell_proc_event` VALUES ('37173', '0', '8', '1126031951256', '0', '0', '0', '0', '30');
+INSERT INTO `spell_proc_event` VALUES ('45054', '0', '0', '0', '0', '0', '0', '0', '15');
+INSERT INTO `spell_proc_event` VALUES ('45354', '0', '0', '0', '0', '0', '0', '0', '45');
+INSERT INTO `spell_proc_event` VALUES ('41989', '0', '0', '0', '0', '0', '0.5', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('11185', '0', '3', '128', '327680', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12487', '0', '3', '128', '327680', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19572', '0', '9', '8388608', '16384', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28716', '0', '7', '16', '294912', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('28744', '0', '7', '64', '278528', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('12488', '0', '3', '128', '327680', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('19573', '0', '9', '8388608', '16384', '0', '0', '0', '0');
+INSERT INTO `spell_proc_event` VALUES ('33727', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('33754', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('33755', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('33756', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('33757', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('8516', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('10608', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('10610', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('25583', '0', '0', '0', '0', '0', '0', '0', '3');
+INSERT INTO `spell_proc_event` VALUES ('25584', '0', '0', '0', '0', '0', '0', '0', '3'); \ No newline at end of file
diff --git a/sql/updates/334_world_trinity_string.sql b/sql/updates/334_world_trinity_string.sql
new file mode 100644
index 00000000000..6cd6cb7714a
--- /dev/null
+++ b/sql/updates/334_world_trinity_string.sql
@@ -0,0 +1,20 @@
+DELETE FROM `trinity_string` WHERE `entry` BETWEEN 770 AND 787;
+INSERT INTO `trinity_string` (`entry`,`content_default`,`content_loc1`,`content_loc2`,`content_loc3`,`content_loc4`,`content_loc5`,`content_loc6`,`content_loc7`,`content_loc8`) VALUES
+(770,'Your group has members not in your arena team. Please regroup to join.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(771,'Your group does not have enough players to join this match.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(772,'The Gold Team wins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(773,'The Green Team wins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(774,'There aren\'t enough players in this battleground. It will end soon unless some more players join to balance the fight.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(775,'Your group has an offline member. Please remove him before joining.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(776,'Your group has players from the opposing faction. You can\'t join the battleground as a group.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(777,'Your group has players from different battleground brakets. You can\'t join as group.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(778,'Someone in your party is already in this battleground queue. (S)he must leave it before joining as group.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(779,'Someone in your party is Deserter. You can\'t join as group.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(780,'Someone in your party is already in three battleground queues. You cannot join as group.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(781,'You cannot teleport to a battleground or arena map.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(782,'You cannot summon players to a battleground or arena map.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(783,'You must be in GM mode to teleport to a player in a battleground.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(784,'You cannot teleport to a battleground from another battleground. Please leave the current battleground first.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(785,'Arena testing turned %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(786,'|cffff0000[Automatic]:|r',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(787,'|cffffff00[|c1f40af20Announce by|r |cffff0000%s|cffffff00]:|r %s|r',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); \ No newline at end of file
diff --git a/sql/updates/341_world.sql b/sql/updates/341_world.sql
new file mode 100644
index 00000000000..7d1eb4a0c8d
--- /dev/null
+++ b/sql/updates/341_world.sql
@@ -0,0 +1 @@
+TRUNCATE TABLE playercreateinfo_item; \ No newline at end of file
diff --git a/sql/updates/356_world.sql b/sql/updates/356_world.sql
new file mode 100644
index 00000000000..9fbc2379976
--- /dev/null
+++ b/sql/updates/356_world.sql
@@ -0,0 +1,2 @@
+DELETE FROM `spell_elixir` WHERE `entry` = 45373;
+INSERT INTO `spell_elixir` VALUES (45373,0x1); \ No newline at end of file
diff --git a/sql/updates/360_characters.sql b/sql/updates/360_characters.sql
new file mode 100644
index 00000000000..40662c380ce
--- /dev/null
+++ b/sql/updates/360_characters.sql
@@ -0,0 +1,4 @@
+ALTER TABLE arena_team_member CHANGE played_week games_week int(10) unsigned NOT NULL default '0';
+ALTER TABLE arena_team_member CHANGE wons_week wins_week int(10) unsigned NOT NULL default '0';
+ALTER TABLE arena_team_member CHANGE played_season games_season int(10) unsigned NOT NULL default '0';
+ALTER TABLE arena_team_member CHANGE wons_season wins_season int(10) unsigned NOT NULL default '0'; \ No newline at end of file
diff --git a/sql/updates/373_world_scripts.sql b/sql/updates/373_world_scripts.sql
new file mode 100644
index 00000000000..537f5ac6e2a
--- /dev/null
+++ b/sql/updates/373_world_scripts.sql
@@ -0,0 +1,3 @@
+update creature_template set scriptname = 'boss_warchief_kargath_bladefist' where entry = 16808;
+UPDATE `instance_template` SET `script`='instance_deadmines' WHERE map = 36;
+UPDATE `item_template` SET `ScriptName`='item_defias_gunpowder' WHERE entry = 5397; \ No newline at end of file
diff --git a/sql/updates/377_world_scripts.sql b/sql/updates/377_world_scripts.sql
new file mode 100644
index 00000000000..3fb8ef12fe8
--- /dev/null
+++ b/sql/updates/377_world_scripts.sql
@@ -0,0 +1,10 @@
+update creature_template set scriptname = 'npc_second_trial_paladin' where entry in (17809,17810,17811,17812);
+update creature_template set scriptname = 'npc_second_trial_controller' where entry in (17807);
+update gameobject_template set scriptname = 'go_second_trial' where entry in (182052);
+
+delete from `script_texts` where entry between -1645009 and -1645006;
+INSERT INTO `script_texts` (`entry`, `content_default`, `content_loc1`, `content_loc2`, `content_loc3`, `content_loc4`, `content_loc5`, `content_loc6`, `content_loc7`, `content_loc8`, `sound`, `type`, `language`, `comment`) VALUES
+(-1645006,'Let the trial begin, Bloodwrath, attack!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,1,0,'master_kelerun_bloodmourn YELL_PHASE'),
+(-1645007,'Champion Lightrend, make me proud!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,1,0,'master_kelerun_bloodmourn YELL_PHASE'),
+(-1645008,'Show this upstart how a real Blood Knight fights, Swiftblade!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,1,0,'master_kelerun_bloodmourn YELL_PHASE'),
+(-1645009,'Show $N the meaning of pain, Sunstriker!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,1,0,'master_kelerun_bloodmourn YELL_PHASE'); \ No newline at end of file
diff --git a/sql/updates/381_world.sql b/sql/updates/381_world.sql
new file mode 100644
index 00000000000..742c8b7612b
--- /dev/null
+++ b/sql/updates/381_world.sql
@@ -0,0 +1,82 @@
+-- SELECT `gameobject_template` WHERE `entry` IN (186648, 187021, 186672, 186667);
+DELETE FROM `gameobject_loot_template` WHERE `entry` IN (22699, 22790, 22797, 22968);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33480, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33481, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33483, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33489, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33590, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33591, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33805, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33971, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33490, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33491, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33492, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33493, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33494, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33495, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33496, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33497, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33498, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33499, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33500, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22699, 33809, 100, 0, 13, 7, 4);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33480, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33481, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33483, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33489, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33590, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33591, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33805, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33971, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33490, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33491, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33492, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33493, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33494, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33495, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33496, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33497, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33498, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33499, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33500, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22790, 33809, 100, 0, 13, 7, 4);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33480, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33481, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33483, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33489, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33590, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33591, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33805, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33971, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33490, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33491, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33492, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33493, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33494, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33495, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33496, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33497, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33498, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33499, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33500, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22797, 33809, 100, 0, 13, 7, 4);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33480, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33481, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33483, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33489, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33590, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33591, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33805, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33971, 0, 1, 13, 7, 1);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33490, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33491, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33492, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33493, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33494, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33495, 0, 1, 13, 7, 2);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33496, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33497, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33498, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33499, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33500, 0, 1, 13, 7, 3);
+INSERT INTO `gameobject_loot_template` (`entry`, `item`, `chanceorquestchance`, `groupid`, `lootcondition`, `condition_value1`, `condition_value2`) VALUES (22968, 33809, 100, 0, 13, 7, 4); \ No newline at end of file
diff --git a/src/bindings/interface/ScriptMgr.cpp b/src/bindings/interface/ScriptMgr.cpp
index 2db437526d1..027b5b1fe57 100644
--- a/src/bindings/interface/ScriptMgr.cpp
+++ b/src/bindings/interface/ScriptMgr.cpp
@@ -78,23 +78,31 @@ Script* GetScriptByName(std::string Name)
return NULL;
}
+//********************************
+//*** Functions to be Exported ***
+
+TRINITY_DLL_EXPORT
+char const* ScriptsVersion()
+{
+ return "Default Trinity scripting library";
+}
TRINITY_DLL_EXPORT
bool GossipHello ( Player * player, Creature *_Creature )
{
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
- if(!tmpscript || !tmpscript->pGossipHello) return false;
+ Script *tmpscript = m_scripts[_Creature->GetScriptId()];
+ if (!tmpscript || !tmpscript->pGossipHello) return false;
player->PlayerTalkClass->ClearMenus();
return tmpscript->pGossipHello(player,_Creature);
}
TRINITY_DLL_EXPORT
-bool GossipSelect( Player *player, Creature *_Creature,uint32 sender, uint32 action )
+bool GossipSelect( Player *player, Creature *_Creature, uint32 sender, uint32 action )
{
- debug_log("DEBUG: Gossip selection, sender: %d, action: %d",sender, action);
+ debug_log("TSCR: Gossip selection, sender: %d, action: %d",sender, action);
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
- if(!tmpscript || !tmpscript->pGossipSelect) return false;
+ Script *tmpscript = m_scripts[_Creature->GetScriptId()];
+ if (!tmpscript || !tmpscript->pGossipSelect) return false;
player->PlayerTalkClass->ClearMenus();
return tmpscript->pGossipSelect(player,_Creature,sender,action);
@@ -103,50 +111,50 @@ bool GossipSelect( Player *player, Creature *_Creature,uint32 sender, uint32 act
TRINITY_DLL_EXPORT
bool GossipSelectWithCode( Player *player, Creature *_Creature, uint32 sender, uint32 action, const char* sCode )
{
- debug_log("DEBUG: Gossip selection, sender: %d, action: %d",sender, action);
+ debug_log("TSCR: Gossip selection with code, sender: %d, action: %d",sender, action);
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
- if(!tmpscript || !tmpscript->pGossipSelectWithCode) return false;
+ Script *tmpscript = m_scripts[_Creature->GetScriptId()];
+ if (!tmpscript || !tmpscript->pGossipSelectWithCode) return false;
player->PlayerTalkClass->ClearMenus();
return tmpscript->pGossipSelectWithCode(player,_Creature,sender,action,sCode);
}
TRINITY_DLL_EXPORT
-bool QuestAccept( Player *player, Creature *_Creature, Quest *_Quest )
+bool QuestAccept( Player *player, Creature *_Creature, Quest const *_Quest )
{
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
- if(!tmpscript || !tmpscript->pQuestAccept) return false;
+ Script *tmpscript = m_scripts[_Creature->GetScriptId()];
+ if (!tmpscript || !tmpscript->pQuestAccept) return false;
player->PlayerTalkClass->ClearMenus();
return tmpscript->pQuestAccept(player,_Creature,_Quest);
}
TRINITY_DLL_EXPORT
-bool QuestSelect( Player *player, Creature *_Creature, Quest *_Quest )
+bool QuestSelect( Player *player, Creature *_Creature, Quest const *_Quest )
{
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
- if(!tmpscript || !tmpscript->pQuestSelect) return false;
+ Script *tmpscript = m_scripts[_Creature->GetScriptId()];
+ if (!tmpscript || !tmpscript->pQuestSelect) return false;
player->PlayerTalkClass->ClearMenus();
return tmpscript->pQuestSelect(player,_Creature,_Quest);
}
TRINITY_DLL_EXPORT
-bool QuestComplete( Player *player, Creature *_Creature, Quest *_Quest )
+bool QuestComplete( Player *player, Creature *_Creature, Quest const *_Quest )
{
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
- if(!tmpscript || !tmpscript->pQuestComplete) return false;
+ Script *tmpscript = m_scripts[_Creature->GetScriptId()];
+ if (!tmpscript || !tmpscript->pQuestComplete) return false;
player->PlayerTalkClass->ClearMenus();
return tmpscript->pQuestComplete(player,_Creature,_Quest);
}
TRINITY_DLL_EXPORT
-bool ChooseReward( Player *player, Creature *_Creature, Quest *_Quest, uint32 opt )
+bool ChooseReward( Player *player, Creature *_Creature, Quest const *_Quest, uint32 opt )
{
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
- if(!tmpscript || !tmpscript->pChooseReward) return false;
+ Script *tmpscript = m_scripts[_Creature->GetScriptId()];
+ if (!tmpscript || !tmpscript->pChooseReward) return false;
player->PlayerTalkClass->ClearMenus();
return tmpscript->pChooseReward(player,_Creature,_Quest,opt);
@@ -155,8 +163,8 @@ bool ChooseReward( Player *player, Creature *_Creature, Quest *_Quest, uint32 op
TRINITY_DLL_EXPORT
uint32 NPCDialogStatus( Player *player, Creature *_Creature )
{
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
- if(!tmpscript || !tmpscript->pNPCDialogStatus) return 100;
+ Script *tmpscript = m_scripts[_Creature->GetScriptId()];
+ if (!tmpscript || !tmpscript->pNPCDialogStatus) return 100;
player->PlayerTalkClass->ClearMenus();
return tmpscript->pNPCDialogStatus(player,_Creature);
@@ -165,34 +173,28 @@ uint32 NPCDialogStatus( Player *player, Creature *_Creature )
TRINITY_DLL_EXPORT
uint32 GODialogStatus( Player *player, GameObject *_GO )
{
- Script *tmpscript = NULL;
-
- tmpscript = GetScriptByName(_GO->GetGOInfo()->ScriptName);
- if(!tmpscript || !tmpscript->pGODialogStatus) return 100;
+ Script *tmpscript = m_scripts[_GO->GetGOInfo()->ScriptId];
+ if (!tmpscript || !tmpscript->pGODialogStatus) return 100;
player->PlayerTalkClass->ClearMenus();
return tmpscript->pGODialogStatus(player,_GO);
}
TRINITY_DLL_EXPORT
-bool ItemHello( Player *player, Item *_Item, Quest *_Quest )
+bool ItemHello( Player *player, Item *_Item, Quest const *_Quest )
{
- Script *tmpscript = NULL;
-
- tmpscript = GetScriptByName(_Item->GetProto()->ScriptName);
- if(!tmpscript || !tmpscript->pItemHello) return false;
+ Script *tmpscript = m_scripts[_Item->GetProto()->ScriptId];
+ if (!tmpscript || !tmpscript->pItemHello) return false;
player->PlayerTalkClass->ClearMenus();
return tmpscript->pItemHello(player,_Item,_Quest);
}
TRINITY_DLL_EXPORT
-bool ItemQuestAccept( Player *player, Item *_Item, Quest *_Quest )
+bool ItemQuestAccept( Player *player, Item *_Item, Quest const *_Quest )
{
- Script *tmpscript = NULL;
-
- tmpscript = GetScriptByName(_Item->GetProto()->ScriptName);
- if(!tmpscript || !tmpscript->pItemQuestAccept) return false;
+ Script *tmpscript = m_scripts[_Item->GetProto()->ScriptId];
+ if (!tmpscript || !tmpscript->pItemQuestAccept) return false;
player->PlayerTalkClass->ClearMenus();
return tmpscript->pItemQuestAccept(player,_Item,_Quest);
@@ -201,91 +203,80 @@ bool ItemQuestAccept( Player *player, Item *_Item, Quest *_Quest )
TRINITY_DLL_EXPORT
bool GOHello( Player *player, GameObject *_GO )
{
- Script *tmpscript = NULL;
-
- tmpscript = GetScriptByName(_GO->GetGOInfo()->ScriptName);
- if(!tmpscript || !tmpscript->pGOHello) return false;
+ Script *tmpscript = m_scripts[_GO->GetGOInfo()->ScriptId];
+ if (!tmpscript || !tmpscript->pGOHello) return false;
player->PlayerTalkClass->ClearMenus();
return tmpscript->pGOHello(player,_GO);
}
TRINITY_DLL_EXPORT
-bool GOQuestAccept( Player *player, GameObject *_GO, Quest *_Quest )
+bool GOQuestAccept( Player *player, GameObject *_GO, Quest const *_Quest )
{
- Script *tmpscript = NULL;
-
- tmpscript = GetScriptByName(_GO->GetGOInfo()->ScriptName);
- if(!tmpscript || !tmpscript->pGOQuestAccept) return false;
+ Script *tmpscript = m_scripts[_GO->GetGOInfo()->ScriptId];
+ if (!tmpscript || !tmpscript->pGOQuestAccept) return false;
player->PlayerTalkClass->ClearMenus();
return tmpscript->pGOQuestAccept(player,_GO,_Quest);
}
TRINITY_DLL_EXPORT
-bool GOChooseReward( Player *player, GameObject *_GO, Quest *_Quest, uint32 opt )
+bool GOChooseReward( Player *player, GameObject *_GO, Quest const *_Quest, uint32 opt )
{
- Script *tmpscript = NULL;
-
- tmpscript = GetScriptByName(_GO->GetGOInfo()->ScriptName);
- if(!tmpscript || !tmpscript->pGOChooseReward) return false;
+ Script *tmpscript = m_scripts[_GO->GetGOInfo()->ScriptId];
+ if (!tmpscript || !tmpscript->pGOChooseReward) return false;
player->PlayerTalkClass->ClearMenus();
return tmpscript->pGOChooseReward(player,_GO,_Quest,opt);
}
TRINITY_DLL_EXPORT
-bool AreaTrigger ( Player *player, AreaTriggerEntry* atEntry )
+bool AreaTrigger( Player *player, AreaTriggerEntry * atEntry)
{
- Script *tmpscript = NULL;
-
- tmpscript = GetScriptByName(GetAreaTriggerScriptNameById(atEntry->id));
- if(!tmpscript || !tmpscript->pAreaTrigger) return false;
+ Script *tmpscript = m_scripts[GetAreaTriggerScriptId(atEntry->id)];
+ if (!tmpscript || !tmpscript->pAreaTrigger) return false;
return tmpscript->pAreaTrigger(player, atEntry);
}
TRINITY_DLL_EXPORT
-bool ReceiveEmote ( Player *player, Creature *_Creature, uint32 emote )
+CreatureAI* GetAI(Creature *_Creature)
{
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
- if(!tmpscript || !tmpscript->pReceiveEmote) return false;
+ Script *tmpscript = m_scripts[_Creature->GetScriptId()];
+ if (!tmpscript || !tmpscript->GetAI) return NULL;
- return tmpscript->pReceiveEmote(player,_Creature, emote);
+ return tmpscript->GetAI(_Creature);
}
TRINITY_DLL_EXPORT
bool ItemUse( Player *player, Item* _Item, SpellCastTargets const& targets)
{
- Script *tmpscript = NULL;
-
- tmpscript = GetScriptByName(_Item->GetProto()->ScriptName);
- if(!tmpscript || !tmpscript->pItemUse) return false;
+ Script *tmpscript = m_scripts[_Item->GetProto()->ScriptId];
+ if (!tmpscript || !tmpscript->pItemUse) return false;
return tmpscript->pItemUse(player,_Item,targets);
}
TRINITY_DLL_EXPORT
-CreatureAI* GetAI(Creature *_Creature )
+bool ReceiveEmote( Player *player, Creature *_Creature, uint32 emote )
{
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
- if(!tmpscript || !tmpscript->GetAI) return NULL;
+ Script *tmpscript = m_scripts[_Creature->GetScriptId()];
+ if (!tmpscript || !tmpscript->pReceiveEmote) return false;
- return tmpscript->GetAI(_Creature);
+ return tmpscript->pReceiveEmote(player, _Creature, emote);
}
-TRINITY_DLL_EXPORT
+/*TRINITY_DLL_EXPORT
InstanceData* CreateInstanceData(Map *map)
{
- if(!map->IsDungeon()) return NULL;
- std::string name = ((InstanceMap*)map)->GetScript();
- if(!name.empty())
- for(int i=0;i<num_inst_scripts;i++)
- if(m_instance_scripts[i] && m_instance_scripts[i]->name == name)
- return m_instance_scripts[i]->GetInstanceData(map);
- return NULL;
-}
+ if (!map->IsDungeon()) return NULL;
+ Script *tmpscript = m_scripts[((InstanceMap*)map)->GetScriptId()];
+ if (!tmpscript || !tmpscript->GetInstanceData) return NULL;
+
+ return tmpscript->GetInstanceData(map);
+}
+*/
void ScriptedAI::UpdateAI(const uint32)
{
//Check if we have a current target
diff --git a/src/bindings/scripts/Makefile.am b/src/bindings/scripts/Makefile.am
index 19b28005497..b691b0cbdc2 100644
--- a/src/bindings/scripts/Makefile.am
+++ b/src/bindings/scripts/Makefile.am
@@ -173,6 +173,7 @@ scripts/zone/coilfang_resevoir/steam_vault/instance_steam_vault.cpp \
scripts/zone/coilfang_resevoir/underbog/boss_hungarfen.cpp \
scripts/zone/darkshore/darkshore.cpp \
scripts/zone/deadmines/deadmines.cpp \
+scripts/zone/deadmines/def_deadmines.h \
scripts/zone/dun_morogh/dun_morogh.cpp \
scripts/zone/dustwallow_marsh/dustwallow_marsh.cpp \
scripts/zone/eastern_plaguelands/eastern_plaguelands.cpp \
@@ -195,6 +196,7 @@ scripts/zone/hellfire_citadel/magtheridons_lair/def_magtheridons_lair.h \
scripts/zone/hellfire_citadel/magtheridons_lair/instance_magtheridons_lair.cpp \
scripts/zone/hellfire_citadel/shattered_halls/boss_nethekurse.cpp \
scripts/zone/hellfire_citadel/shattered_halls/boss_warbringer_omrogg.cpp \
+scripts/zone/hellfire_citadel/shattered_halls/boss_warchief_kargath_bladefist.cpp \
scripts/zone/hellfire_citadel/shattered_halls/def_shattered_halls.h \
scripts/zone/hellfire_citadel/shattered_halls/instance_shattered_halls.cpp \
scripts/zone/hellfire_peninsula/boss_doomlord_kazzak.cpp \
diff --git a/src/bindings/scripts/ScriptMgr.cpp b/src/bindings/scripts/ScriptMgr.cpp
index ad6bcf76c08..344a865b7dd 100644
--- a/src/bindings/scripts/ScriptMgr.cpp
+++ b/src/bindings/scripts/ScriptMgr.cpp
@@ -253,6 +253,8 @@ extern void AddSC_boss_hungarfen();
//Darkshore
//Darnassus
//Deadmines
+extern void AddSC_instance_deadmines();
+
//Deadwind pass
//Desolace
//Dire Maul
@@ -302,6 +304,7 @@ extern void AddSC_instance_magtheridons_lair();
//--Shattered Halls
extern void AddSC_boss_grand_warlock_nethekurse();
extern void AddSC_boss_warbringer_omrogg();
+extern void AddSC_boss_warchief_kargath_bladefist();
extern void AddSC_instance_shattered_halls();
//--Ramparts
@@ -1440,6 +1443,8 @@ void ScriptsInit()
//Darkshore
//Darnassus
//Deadmines
+ AddSC_instance_deadmines();
+
//Deadwind pass
//Desolace
//Dire Maul
@@ -1489,6 +1494,7 @@ void ScriptsInit()
//--Shattered Halls
AddSC_boss_grand_warlock_nethekurse();
AddSC_boss_warbringer_omrogg();
+ AddSC_boss_warchief_kargath_bladefist();
AddSC_instance_shattered_halls();
//--Ramparts
diff --git a/src/bindings/scripts/VC71/71ScriptDev2.vcproj b/src/bindings/scripts/VC71/71ScriptDev2.vcproj
index f0f7131b1f6..8cb81e141a3 100644
--- a/src/bindings/scripts/VC71/71ScriptDev2.vcproj
+++ b/src/bindings/scripts/VC71/71ScriptDev2.vcproj
@@ -309,6 +309,10 @@
RelativePath="..\scripts\zone\deadmines\deadmines.cpp"
>
</File>
+ <File
+ RelativePath="..\scripts\zone\deadmines\def_deadmines.h"
+ >
+ </File>
</Filter>
<Filter
Name="Deadwind Pass"
@@ -1377,6 +1381,10 @@
>
</File>
<File
+ RelativePath="..\scripts\zone\hellfire_citadel\shattered_halls\boss_warchief_kargath_bladefist.cpp"
+ >
+ </File>
+ <File
RelativePath="..\scripts\zone\hellfire_citadel\shattered_halls\def_shattered_halls.h"
>
</File>
diff --git a/src/bindings/scripts/VC80/80ScriptDev2.vcproj b/src/bindings/scripts/VC80/80ScriptDev2.vcproj
index fdb376e833f..e41472e7a91 100644
--- a/src/bindings/scripts/VC80/80ScriptDev2.vcproj
+++ b/src/bindings/scripts/VC80/80ScriptDev2.vcproj
@@ -554,6 +554,10 @@
RelativePath="..\scripts\zone\deadmines\deadmines.cpp"
>
</File>
+ <File
+ RelativePath="..\scripts\zone\deadmines\def_deadmines.h"
+ >
+ </File>
</Filter>
<Filter
Name="Deadwind Pass"
@@ -1622,6 +1626,10 @@
>
</File>
<File
+ RelativePath="..\scripts\zone\hellfire_citadel\shattered_halls\boss_warchief_kargath_bladefist.cpp"
+ >
+ </File>
+ <File
RelativePath="..\scripts\zone\hellfire_citadel\shattered_halls\def_shattered_halls.h"
>
</File>
diff --git a/src/bindings/scripts/VC90/90ScriptDev2.vcproj b/src/bindings/scripts/VC90/90ScriptDev2.vcproj
index b4f467d0470..530e99ea70c 100644
--- a/src/bindings/scripts/VC90/90ScriptDev2.vcproj
+++ b/src/bindings/scripts/VC90/90ScriptDev2.vcproj
@@ -540,6 +540,10 @@
RelativePath="..\scripts\zone\deadmines\deadmines.cpp"
>
</File>
+ <File
+ RelativePath="..\scripts\zone\deadmines\def_deadmines.h"
+ >
+ </File>
</Filter>
<Filter
Name="Deadwind Pass"
@@ -1608,6 +1612,10 @@
>
</File>
<File
+ RelativePath="..\scripts\zone\hellfire_citadel\shattered_halls\boss_warchief_kargath_bladefist.cpp"
+ >
+ </File>
+ <File
RelativePath="..\scripts\zone\hellfire_citadel\shattered_halls\def_shattered_halls.h"
>
</File>
diff --git a/src/bindings/scripts/include/sc_creature.cpp b/src/bindings/scripts/include/sc_creature.cpp
index 0c946b8f26d..6061c15ec1b 100644
--- a/src/bindings/scripts/include/sc_creature.cpp
+++ b/src/bindings/scripts/include/sc_creature.cpp
@@ -73,17 +73,7 @@ bool ScriptedAI::IsVisible(Unit* who) const
void ScriptedAI::MoveInLineOfSight(Unit *who)
{
- if(m_creature->getVictim() || !m_creature->IsHostileTo(who) || !who->isInAccessiblePlaceFor(m_creature))
- return;
-
- if(!m_creature->canFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
- return;
-
- if(!m_creature->IsWithinDistInMap(who, m_creature->GetAttackDistance(who)) || !m_creature->IsWithinLOSInMap(who))
- return;
-
- if(m_creature->canAttack(who))
- //who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ if(!m_creature->getVictim() && m_creature->canStartAttack(who))
AttackStart(who);
}
@@ -151,17 +141,24 @@ void ScriptedAI::UpdateAI(const uint32 diff)
void ScriptedAI::EnterEvadeMode()
{
- m_creature->InterruptNonMeleeSpells(true);
+ //m_creature->InterruptNonMeleeSpells(true);
m_creature->RemoveAllAuras();
m_creature->DeleteThreatList();
m_creature->CombatStop();
m_creature->LoadCreaturesAddon();
-
- if (m_creature->isAlive())
- m_creature->GetMotionMaster()->MoveTargetedHome();
-
m_creature->SetLootRecipient(NULL);
+ if(m_creature->isAlive())
+ {
+ if(Unit* owner = m_creature->GetOwner())
+ {
+ if(owner->isAlive())
+ m_creature->GetMotionMaster()->MoveFollow(owner,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE);
+ }
+ else
+ m_creature->GetMotionMaster()->MoveTargetedHome();
+ }
+
InCombat = false;
Reset();
}
@@ -193,7 +190,7 @@ void ScriptedAI::DoStartNoMovement(Unit* victim)
void ScriptedAI::DoMeleeAttackIfReady()
{
//Make sure our attack is ready and we aren't currently casting before checking distance
- if (m_creature->isAttackReady() && !m_creature->IsNonMeleeSpellCasted(false))
+ if (m_creature->isAttackReady() && !m_creature->hasUnitState(UNIT_STAT_CASTING))
{
//If we are within range melee the target
if (m_creature->IsWithinCombatDist(m_creature->getVictim(), ATTACK_DISTANCE))
@@ -202,7 +199,7 @@ void ScriptedAI::DoMeleeAttackIfReady()
m_creature->resetAttackTimer();
}
}
- if (m_creature->haveOffhandWeapon() && m_creature->isAttackReady(OFF_ATTACK) && !m_creature->IsNonMeleeSpellCasted(false))
+ if (m_creature->haveOffhandWeapon() && m_creature->isAttackReady(OFF_ATTACK) && !m_creature->hasUnitState(UNIT_STAT_CASTING))
{
//If we are within range melee the target
if (m_creature->IsWithinCombatDist(m_creature->getVictim(), ATTACK_DISTANCE))
@@ -679,11 +676,17 @@ void ScriptedAI::DoZoneInCombat(Unit* pUnit)
return;
}
- Map::PlayerList const &PlayerList = map->GetPlayers();
- for(Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
- if (Player* i_pl = i->getSource())
- if (!i_pl->isAlive())
+ Map::PlayerList const &PlayerList = map->GetPlayers();
+ for(Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
+ {
+ if (Player* i_pl = i->getSource())
+ if (!i_pl->isAlive())
+ {
+ pUnit->SetInCombatWith(i_pl);
+ i_pl->SetInCombatWith(pUnit);
pUnit->AddThreat(i_pl, 0.0f);
+ }
+ }
}
void ScriptedAI::DoResetThreat()
@@ -725,10 +728,10 @@ void ScriptedAI::DoTeleportAll(float x, float y, float z, float o)
if (!map->IsDungeon())
return;
- Map::PlayerList const &PlayerList = map->GetPlayers();
- for(Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
- if (Player* i_pl = i->getSource())
- if (!i_pl->isAlive())
+ Map::PlayerList const &PlayerList = map->GetPlayers();
+ for(Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
+ if (Player* i_pl = i->getSource())
+ if (!i_pl->isAlive())
i_pl->TeleportTo(m_creature->GetMapId(), x, y, z, o, TELE_TO_NOT_LEAVE_COMBAT);
}
@@ -796,7 +799,7 @@ std::list<Creature*> ScriptedAI::DoFindFriendlyMissingBuff(float range, uint32 s
return pList;
}
-void Scripted_NoMovementAI::MoveInLineOfSight(Unit *who)
+/*void Scripted_NoMovementAI::MoveInLineOfSight(Unit *who)
{
if( !m_creature->getVictim() && m_creature->canAttack(who) && ( m_creature->IsHostileTo( who )) && who->isInAccessiblePlaceFor(m_creature) )
{
@@ -810,7 +813,7 @@ void Scripted_NoMovementAI::MoveInLineOfSight(Unit *who)
AttackStart(who);
}
}
-}
+}*/
void Scripted_NoMovementAI::AttackStart(Unit* who)
{
diff --git a/src/bindings/scripts/include/sc_creature.h b/src/bindings/scripts/include/sc_creature.h
index c1d7f06f029..01f5df473c1 100644
--- a/src/bindings/scripts/include/sc_creature.h
+++ b/src/bindings/scripts/include/sc_creature.h
@@ -177,7 +177,7 @@ struct TRINITY_DLL_DECL Scripted_NoMovementAI : public ScriptedAI
Scripted_NoMovementAI(Creature* creature) : ScriptedAI(creature) {}
//Called if IsVisible(Unit *who) is true at each *who move
- void MoveInLineOfSight(Unit *);
+ //void MoveInLineOfSight(Unit *);
//Called at each attack of m_creature by any victim
void AttackStart(Unit *);
diff --git a/src/bindings/scripts/include/sc_instance.h b/src/bindings/scripts/include/sc_instance.h
index 8de13c10f72..cb6374b0415 100644
--- a/src/bindings/scripts/include/sc_instance.h
+++ b/src/bindings/scripts/include/sc_instance.h
@@ -33,10 +33,6 @@ class TRINITY_DLL_DECL ScriptedInstance : public InstanceData
virtual uint64 GetData64(uint32) {return 0; }
virtual void SetData64(uint32, uint64) { }
- //All-purpose data storage 32 bit
- virtual uint32 GetData(uint32) { return 0; }
- virtual void SetData(uint32, uint32 data) {}
-
// Called every instance update
virtual void Update(uint32) {}
diff --git a/src/bindings/scripts/scripts/creature/mob_event_ai.cpp b/src/bindings/scripts/scripts/creature/mob_event_ai.cpp
index af945282935..c5ec311d310 100644
--- a/src/bindings/scripts/scripts/creature/mob_event_ai.cpp
+++ b/src/bindings/scripts/scripts/creature/mob_event_ai.cpp
@@ -6,12 +6,12 @@
*
* 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
+ * 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
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* ScriptData
@@ -965,6 +965,17 @@ struct TRINITY_DLL_DECL Mob_EventAI : public ScriptedAI
DoZoneInCombat();
}
break;
+
+ // TRINITY ONLY
+ case ACTION_T_SET_ACTIVE:
+ m_creature->setActive(param1 ? true : false);
+ break;
+ case ACTION_T_SET_AGGRESSIVE:
+ m_creature->SetAggressive(param1 ? true : false);
+ break;
+ case ACTION_T_ATTACK_START_PULSE:
+ AttackStart(m_creature->SelectNearestTarget((float)param1));
+ break;
}
}
@@ -1022,18 +1033,9 @@ struct TRINITY_DLL_DECL Mob_EventAI : public ScriptedAI
void EnterEvadeMode()
{
- m_creature->RemoveAllAuras();
- m_creature->DeleteThreatList();
- m_creature->CombatStop();
- m_creature->LoadCreaturesAddon();
- if( m_creature->isAlive() )
- m_creature->GetMotionMaster()->MoveTargetedHome();
+ ScriptedAI::EnterEvadeMode();
- m_creature->SetLootRecipient(NULL);
-
- InCombat = false;
IsFleeing = false;
- Reset();
//Handle Evade events
for (std::list<EventHolder>::iterator i = EventList.begin(); i != EventList.end(); ++i)
@@ -1192,24 +1194,12 @@ struct TRINITY_DLL_DECL Mob_EventAI : public ScriptedAI
}
}
- if (m_creature->isCivilian() && m_creature->IsNeutralToAll())
- return;
-
- if (m_creature->canAttack(who) && who->isInAccessiblePlaceFor(m_creature) && m_creature->IsHostileTo(who))
- {
- if (!m_creature->canFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
- return;
-
- float attackRadius = m_creature->GetAttackDistance(who);
- if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who))
- {
- //if(who->HasStealthAura())
- // who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ // do we need this?
+ //if (m_creature->isCivilian() && m_creature->IsNeutralToAll())
+ // return;
- //Begin melee attack if we are within range
- AttackStart(who);
- }
- }
+ if(m_creature->canStartAttack(who))
+ AttackStart(who);
}
void SpellHit(Unit* pUnit, const SpellEntry* pSpell)
@@ -1247,8 +1237,8 @@ struct TRINITY_DLL_DECL Mob_EventAI : public ScriptedAI
&& m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() != FLEEING_MOTION_TYPE)
{
m_creature->GetMotionMaster()->Clear(false);
- m_creature->SetNoCallAssistence(false);
- m_creature->CallAssistence();
+ m_creature->SetNoCallAssistance(false);
+ m_creature->CallAssistance();
if(m_creature->getVictim())
m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim());
IsFleeing = false;
@@ -1292,6 +1282,7 @@ struct TRINITY_DLL_DECL Mob_EventAI : public ScriptedAI
//Do not decrement timers if event cannot trigger in this phase
if (!((*i).Event.event_inverse_phase_mask & (1 << Phase)))
(*i).Time -= EventDiff;
+
//Skip processing of events that have time remaining
continue;
}
@@ -1328,6 +1319,7 @@ struct TRINITY_DLL_DECL Mob_EventAI : public ScriptedAI
//Melee Auto-Attack
if (Combat && MeleeEnabled)
DoMeleeAttackIfReady();
+
}
};
diff --git a/src/bindings/scripts/scripts/creature/mob_event_ai.h b/src/bindings/scripts/scripts/creature/mob_event_ai.h
index 1183fdd3c73..d08a6b33a2b 100644
--- a/src/bindings/scripts/scripts/creature/mob_event_ai.h
+++ b/src/bindings/scripts/scripts/creature/mob_event_ai.h
@@ -1,6 +1,6 @@
/* Copyright (C) 2006 - 2008 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
-* This program is free software licensed under GPL version 2
-* Please see the included DOCS/LICENSE.TXT for more information */
+ * This program is free software licensed under GPL version 2
+ * Please see the included DOCS/LICENSE.TXT for more information */
#ifndef SC_EVENTAI_H
#define SC_EVENTAI_H
@@ -76,6 +76,10 @@ enum Action_Types
ACTION_T_DIE = 37, //No Params
ACTION_T_ZONE_COMBAT_PULSE = 38, //No Params
+ ACTION_T_SET_ACTIVE = 101, //Apply
+ ACTION_T_SET_AGGRESSIVE = 102, //Apply
+ ACTION_T_ATTACK_START_PULSE = 103, //Distance
+
ACTION_T_END,
};
diff --git a/src/bindings/scripts/scripts/npc/npc_escortAI.cpp b/src/bindings/scripts/scripts/npc/npc_escortAI.cpp
index 0197fe24b29..a616fa809c7 100644
--- a/src/bindings/scripts/scripts/npc/npc_escortAI.cpp
+++ b/src/bindings/scripts/scripts/npc/npc_escortAI.cpp
@@ -60,35 +60,26 @@ void npc_escortAI::MoveInLineOfSight(Unit *who)
if (IsBeingEscorted && !Attack)
return;
- if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessiblePlaceFor(m_creature) )
- {
- if (!m_creature->canFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
- return;
-
- float attackRadius = m_creature->GetAttackDistance(who);
- if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) )
- {
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ if(m_creature->getVictim() || !m_creature->canStartAttack(who))
+ return;
- //Begin attack
- if ( m_creature->Attack(who, true) )
- {
- m_creature->GetMotionMaster()->MovementExpired();
- m_creature->GetMotionMaster()->MoveChase(who);
- m_creature->AddThreat(who, 0.0f);
- }
+ //Begin attack
+ if ( m_creature->Attack(who, true) )
+ {
+ m_creature->GetMotionMaster()->MovementExpired();
+ m_creature->GetMotionMaster()->MoveChase(who);
+ m_creature->AddThreat(who, 0.0f);
+ }
- if (!InCombat)
- {
- InCombat = true;
+ if (!InCombat)
+ {
+ InCombat = true;
- //Store last position
- m_creature->GetPosition(LastPos.x, LastPos.y, LastPos.z);
- debug_log("SD2: EscortAI has entered combat via LOS and stored last location");
+ //Store last position
+ m_creature->GetPosition(LastPos.x, LastPos.y, LastPos.z);
+ debug_log("SD2: EscortAI has entered combat via LOS and stored last location");
- Aggro(who);
- }
- }
+ Aggro(who);
}
}
diff --git a/src/bindings/scripts/scripts/npc/npcs_special.cpp b/src/bindings/scripts/scripts/npc/npcs_special.cpp
index 00116746a68..d762c8803e6 100644
--- a/src/bindings/scripts/scripts/npc/npcs_special.cpp
+++ b/src/bindings/scripts/scripts/npc/npcs_special.cpp
@@ -825,6 +825,71 @@ bool GossipSelect_npc_sayge(Player *player, Creature *_Creature, uint32 sender,
return true;
}
+struct TRINITY_DLL_DECL npc_steam_tonkAI : public ScriptedAI
+{
+ npc_steam_tonkAI(Creature *c) : ScriptedAI(c) {Reset();}
+
+ void Reset() {}
+ void Aggro(Unit *who) {}
+
+ void OnPossess(bool apply)
+ {
+ if (apply)
+ {
+ // Initialize the action bar without the melee attack command
+ m_creature->InitCharmInfo(m_creature);
+ m_creature->GetCharmInfo()->InitEmptyActionBar(false);
+
+ m_creature->SetAggressive(false);
+ }
+ else
+ m_creature->SetAggressive(true);
+ }
+
+};
+
+CreatureAI* GetAI_npc_steam_tonk(Creature *_Creature)
+{
+ return new npc_steam_tonkAI(_Creature);
+}
+
+#define SPELL_TONK_MINE_DETONATE 25099
+
+struct TRINITY_DLL_DECL npc_tonk_mineAI : public ScriptedAI
+{
+ npc_tonk_mineAI(Creature *c) : ScriptedAI(c)
+ {
+ m_creature->SetAggressive(false);
+ Reset();
+ }
+
+ uint32 ExplosionTimer;
+
+ void Reset()
+ {
+ ExplosionTimer = 3000;
+ }
+
+ void Aggro(Unit *who) {}
+ void AttackStart(Unit *who) {}
+ void MoveInLineOfSight(Unit *who) {}
+
+ void UpdateAI(const uint32 diff)
+ {
+ if (ExplosionTimer < diff)
+ {
+ m_creature->CastSpell(m_creature, SPELL_TONK_MINE_DETONATE, true);
+ m_creature->setDeathState(DEAD); // unsummon it
+ } else
+ ExplosionTimer -= diff;
+ }
+};
+
+CreatureAI* GetAI_npc_tonk_mine(Creature *_Creature)
+{
+ return new npc_tonk_mineAI(_Creature);
+}
+
void AddSC_npcs_special()
{
Script *newscript;
@@ -875,4 +940,14 @@ void AddSC_npcs_special()
newscript->pGossipHello = &GossipHello_npc_sayge;
newscript->pGossipSelect = &GossipSelect_npc_sayge;
newscript->RegisterSelf();
+
+ newscript = new Script;
+ newscript->Name="npc_steam_tonk";
+ newscript->GetAI = &GetAI_npc_steam_tonk;
+ newscript->RegisterSelf();
+
+ newscript = new Script;
+ newscript->Name="npc_tonk_mine";
+ newscript->GetAI = &GetAI_npc_tonk_mine;
+ newscript->RegisterSelf();
}
diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/auchenai_crypts/boss_exarch_maladaar.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/auchenai_crypts/boss_exarch_maladaar.cpp
index 810486aede7..7f0cc22121c 100644
--- a/src/bindings/scripts/scripts/zone/aunchindoun/auchenai_crypts/boss_exarch_maladaar.cpp
+++ b/src/bindings/scripts/scripts/zone/aunchindoun/auchenai_crypts/boss_exarch_maladaar.cpp
@@ -186,7 +186,7 @@ struct TRINITY_DLL_DECL boss_exarch_maladaarAI : public ScriptedAI
float attackRadius = m_creature->GetAttackDistance(who);
if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who))
{
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ //who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
AttackStart(who);
}
}
diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/mana_tombs/boss_nexusprince_shaffar.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/mana_tombs/boss_nexusprince_shaffar.cpp
index a9589736784..5f3ce4d0358 100644
--- a/src/bindings/scripts/scripts/zone/aunchindoun/mana_tombs/boss_nexusprince_shaffar.cpp
+++ b/src/bindings/scripts/scripts/zone/aunchindoun/mana_tombs/boss_nexusprince_shaffar.cpp
@@ -92,7 +92,7 @@ struct TRINITY_DLL_DECL boss_nexusprince_shaffarAI : public ScriptedAI
float attackRadius = m_creature->GetAttackDistance(who);
if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) )
{
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ //who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
AttackStart(who);
}
}
diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/boss_tailonking_ikiss.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/boss_tailonking_ikiss.cpp
index be69ee79844..26b05e04def 100644
--- a/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/boss_tailonking_ikiss.cpp
+++ b/src/bindings/scripts/scripts/zone/aunchindoun/sethekk_halls/boss_tailonking_ikiss.cpp
@@ -102,7 +102,7 @@ struct TRINITY_DLL_DECL boss_talon_king_ikissAI : public ScriptedAI
float attackRadius = m_creature->GetAttackDistance(who);
if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) )
{
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ //who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
AttackStart(who);
}
}
diff --git a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp
index ed7108ad3e7..12dbc0104f7 100644
--- a/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp
+++ b/src/bindings/scripts/scripts/zone/aunchindoun/shadow_labyrinth/boss_grandmaster_vorpil.cpp
@@ -183,8 +183,8 @@ struct TRINITY_DLL_DECL boss_grandmaster_vorpilAI : public ScriptedAI
float attackRadius = m_creature->GetAttackDistance(who);
if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who))
{
- if(who->HasStealthAura())
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ //if(who->HasStealthAura())
+ // who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
AttackStart(who);
}
diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp
index c7f2ec460d9..dbce8089dd7 100644
--- a/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp
+++ b/src/bindings/scripts/scripts/zone/black_temple/boss_illidan.cpp
@@ -1914,7 +1914,7 @@ void boss_illidan_stormrageAI::Reset()
TransformCount = 0;
m_creature->SetUInt32Value(UNIT_FIELD_DISPLAYID, 21135);
- m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN2);
+ m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2);
m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
m_creature->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_DISPLAY, 0);
diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_reliquary_of_souls.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_reliquary_of_souls.cpp
index 8c5bdbc4a4a..da71688674b 100644
--- a/src/bindings/scripts/scripts/zone/black_temple/boss_reliquary_of_souls.cpp
+++ b/src/bindings/scripts/scripts/zone/black_temple/boss_reliquary_of_souls.cpp
@@ -187,29 +187,15 @@ struct TRINITY_DLL_DECL boss_reliquary_of_soulsAI : public ScriptedAI
Timer = 0;
}
- void MoveInLineOfSight(Unit *who)
+ void AttackStart(Unit* who)
{
- if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessiblePlaceFor(m_creature) )
+ if (!InCombat)
{
- if (m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
- return;
-
- float attackRadius = m_creature->GetAttackDistance(who);
- if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) )
- {
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
-
- if (!InCombat)
- {
- Aggro(who);
- InCombat = true;
- }
- }
+ Aggro(who);
+ InCombat = true;
}
}
- void AttackStart(Unit*) {}
-
bool SummonSoul()
{
uint32 random = rand()%6;
diff --git a/src/bindings/scripts/scripts/zone/black_temple/boss_teron_gorefiend.cpp b/src/bindings/scripts/scripts/zone/black_temple/boss_teron_gorefiend.cpp
index 97fcde9265f..d212ec10f44 100644
--- a/src/bindings/scripts/scripts/zone/black_temple/boss_teron_gorefiend.cpp
+++ b/src/bindings/scripts/scripts/zone/black_temple/boss_teron_gorefiend.cpp
@@ -168,8 +168,8 @@ struct TRINITY_DLL_DECL mob_shadowy_constructAI : public ScriptedAI
if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who))
{
- if(who->HasStealthAura())
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ //if(who->HasStealthAura())
+ // who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
m_creature->AddThreat(who, 1.0f);
}
@@ -282,8 +282,8 @@ struct TRINITY_DLL_DECL boss_teron_gorefiendAI : public ScriptedAI
if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who))
{
- if(who->HasStealthAura())
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ //if(who->HasStealthAura())
+ // who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
m_creature->AddThreat(who, 1.0f);
}
diff --git a/src/bindings/scripts/scripts/zone/blades_edge_mountains/blades_edge_mountains.cpp b/src/bindings/scripts/scripts/zone/blades_edge_mountains/blades_edge_mountains.cpp
index c47153aed7a..c8acd8b65d0 100644
--- a/src/bindings/scripts/scripts/zone/blades_edge_mountains/blades_edge_mountains.cpp
+++ b/src/bindings/scripts/scripts/zone/blades_edge_mountains/blades_edge_mountains.cpp
@@ -286,18 +286,7 @@ struct TRINITY_DLL_DECL npc_daranelleAI : public ScriptedAI
}
}
- if (!m_creature->getVictim() && who->isTargetableForAttack() && who->isInAccessiblePlaceFor(m_creature) && m_creature->IsHostileTo(who))
- {
- if (!m_creature->canFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
- return;
-
- float attackRadius = m_creature->GetAttackDistance(who);
- if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who))
- {
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
- AttackStart(who);
- }
- }
+ ScriptedAI::MoveInLineOfSight(who);
}
};
diff --git a/src/bindings/scripts/scripts/zone/burning_steppes/burning_steppes.cpp b/src/bindings/scripts/scripts/zone/burning_steppes/burning_steppes.cpp
index 7f0c2f45118..f845624c5d6 100644
--- a/src/bindings/scripts/scripts/zone/burning_steppes/burning_steppes.cpp
+++ b/src/bindings/scripts/scripts/zone/burning_steppes/burning_steppes.cpp
@@ -48,18 +48,7 @@ struct TRINITY_DLL_DECL npc_ragged_johnAI : public ScriptedAI
}
}
- if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessiblePlaceFor(m_creature) )
- {
- if (!m_creature->canFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
- return;
-
- float attackRadius = m_creature->GetAttackDistance(who);
- if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) )
- {
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
- AttackStart(who);
- }
- }
+ ScriptedAI::MoveInLineOfSight(who);
}
void Aggro(Unit *who) {}
diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_temporus.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_temporus.cpp
index 2dad8913576..b6f77f31c88 100644
--- a/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_temporus.cpp
+++ b/src/bindings/scripts/scripts/zone/caverns_of_time/dark_portal/boss_temporus.cpp
@@ -88,18 +88,7 @@ struct TRINITY_DLL_DECL boss_temporusAI : public ScriptedAI
}
}
- if (!m_creature->getVictim() && who->isTargetableForAttack() && who->isInAccessiblePlaceFor(m_creature) && m_creature->IsHostileTo(who))
- {
- if (!m_creature->canFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
- return;
-
- float attackRadius = m_creature->GetAttackDistance(who);
- if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who))
- {
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
- AttackStart(who);
- }
- }
+ ScriptedAI::MoveInLineOfSight(who);
}
void UpdateAI(const uint32 diff)
diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjalAI.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjalAI.cpp
index 3ccd790a648..2f92a1e6cd4 100644
--- a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjalAI.cpp
+++ b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/hyjalAI.cpp
@@ -301,7 +301,7 @@ void hyjalAI::UpdateWorldState(uint32 field, uint32 value)
data << field;
data << value;
- ((InstanceMap*)map)->SendToPlayers(&data);
+ map->SendToPlayers(&data);
// TODO: Uncomment and remove everything above this line only when the core patch for this is accepted
//m_creature->GetMap()->UpdateWorldState(field, value);
diff --git a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/instance_hyjal.cpp b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/instance_hyjal.cpp
index 3c3971d6036..66b9a7bfcc3 100644
--- a/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/instance_hyjal.cpp
+++ b/src/bindings/scripts/scripts/zone/caverns_of_time/hyjal/instance_hyjal.cpp
@@ -149,7 +149,7 @@ struct TRINITY_DLL_DECL instance_mount_hyjal : public ScriptedInstance
data << field;
data << value;
- ((InstanceMap*)instance)->SendToPlayers(&data);
+ instance->SendToPlayers(&data);
}
const char* Save()
diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lady_vashj.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lady_vashj.cpp
index 232a828150c..ff6669b35a4 100644
--- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lady_vashj.cpp
+++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_lady_vashj.cpp
@@ -283,8 +283,8 @@ struct TRINITY_DLL_DECL boss_lady_vashjAI : public ScriptedAI
float attackRadius = m_creature->GetAttackDistance(who);
if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who))
{
- if(who->HasStealthAura())
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ //if(who->HasStealthAura())
+ // who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
if(Phase != 2)
AttackStart(who);
diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_leotheras_the_blind.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_leotheras_the_blind.cpp
index 70d4d6d2c56..571376bca4b 100644
--- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_leotheras_the_blind.cpp
+++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_leotheras_the_blind.cpp
@@ -248,12 +248,6 @@ struct TRINITY_DLL_DECL boss_leotheras_the_blindAI : public ScriptedAI
if( m_creature->HasInArc(M_PI/2.0f, who) && m_creature->IsWithinLOSInMap(who) )
{
AttackStart(who);
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
- if (!InCombat)
- {
- Aggro(who);
- InCombat = true;
- }
}
}
}
diff --git a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_morogrim_tidewalker.cpp b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_morogrim_tidewalker.cpp
index 900c3aad6d9..c5828c3977d 100644
--- a/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_morogrim_tidewalker.cpp
+++ b/src/bindings/scripts/scripts/zone/coilfang_resevoir/serpent_shrine/boss_morogrim_tidewalker.cpp
@@ -306,7 +306,7 @@ struct TRINITY_DLL_DECL mob_water_globuleAI : public ScriptedAI
if (who->isTargetableForAttack() && who->isInAccessiblePlaceFor(m_creature) && m_creature->IsHostileTo(who))
{
//no attack radius check - it attacks the first target that moves in his los
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ //who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
AttackStart(who);
}
}
diff --git a/src/bindings/scripts/scripts/zone/deadmines/deadmines.cpp b/src/bindings/scripts/scripts/zone/deadmines/deadmines.cpp
index 08bba7d4bc6..23d65ce42f7 100644
--- a/src/bindings/scripts/scripts/zone/deadmines/deadmines.cpp
+++ b/src/bindings/scripts/scripts/zone/deadmines/deadmines.cpp
@@ -22,3 +22,209 @@ SDCategory: Deadmines
EndScriptData */
#include "precompiled.h"
+#include "def_deadmines.h"
+#include "Spell.h"
+
+#define SOUND_CANNONFIRE 1400
+#define SOUND_DESTROYDOOR 3079
+#define SAY_MR_SMITE_ALARM1 "You there, check out that noise!"
+#define SOUND_MR_SMITE_ALARM1 5775
+#define SAY_MR_SMITE_ALARM2 "We're under attack! A vast, ye swabs! Repel the invaders!"
+#define SOUND_MR_SMITE_ALARM2 5777
+
+#define GO_IRONCLAD_DOOR 16397
+#define GO_DEFIAS_CANNON 16398
+#define GO_DOOR_LEVER 101833
+
+#define CANNON_BLAST_TIMER 3000
+#define PIRATES_DELAY_TIMER 1000
+
+struct TRINITY_DLL_DECL instance_deadmines : public ScriptedInstance
+{
+ instance_deadmines(Map *Map) : ScriptedInstance(Map) {Initialize();};
+
+ GameObject* IronCladDoor;
+ GameObject* DefiasCannon;
+ GameObject* DoorLever;
+ Creature* DefiasPirate1;
+ Creature* DefiasPirate2;
+ Creature* DefiasCompanion;
+ uint32 State;
+ uint32 CannonBlast_Timer;
+ uint32 PiratesDelay_Timer;
+
+ void Initialize()
+ {
+ IronCladDoor = NULL;
+ DefiasCannon = NULL;
+ DoorLever = NULL;
+ State = CANNON_NOT_USED;
+ }
+
+ virtual void Update(uint32 diff)
+ {
+ switch(State)
+ {
+ case CANNON_GUNPOWDER_USED:
+ CannonBlast_Timer = CANNON_BLAST_TIMER;
+ // it's a hack - Mr. Smite should do that but his too far away
+ IronCladDoor->SetName("Mr. Smite");
+ IronCladDoor->Yell(SAY_MR_SMITE_ALARM1, LANG_UNIVERSAL, 0);
+ DoPlaySound(IronCladDoor, SOUND_MR_SMITE_ALARM1);
+ State=CANNON_BLAST_INITIATED;
+ break;
+ case CANNON_BLAST_INITIATED:
+ PiratesDelay_Timer = PIRATES_DELAY_TIMER;
+ if(CannonBlast_Timer<diff)
+ {
+ SummonCreatures();
+ ShootCannon();
+ BlastOutDoor();
+ LeverStucked();
+ IronCladDoor->Yell(SAY_MR_SMITE_ALARM2, LANG_UNIVERSAL, 0);
+ DoPlaySound(IronCladDoor, SOUND_MR_SMITE_ALARM2);
+ State = PIRATES_ATTACK;
+ }else
+ CannonBlast_Timer-=diff;
+ break;
+ case PIRATES_ATTACK:
+ if(PiratesDelay_Timer<diff)
+ {
+ MoveCreaturesInside();
+ State = EVENT_DONE;
+ }else
+ PiratesDelay_Timer-=diff;
+ break;
+ }
+ }
+
+ void SummonCreatures()
+ {
+ DefiasPirate1 = IronCladDoor->SummonCreature(657,IronCladDoor->GetPositionX() - 2,IronCladDoor->GetPositionY()-7,IronCladDoor->GetPositionZ(), 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000);
+ DefiasPirate2 = IronCladDoor->SummonCreature(657,IronCladDoor->GetPositionX() + 3,IronCladDoor->GetPositionY()-6,IronCladDoor->GetPositionZ(), 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000);
+ DefiasCompanion = IronCladDoor->SummonCreature(3450,IronCladDoor->GetPositionX() + 2,IronCladDoor->GetPositionY()-6,IronCladDoor->GetPositionZ(), 0, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000);
+ }
+
+ void MoveCreaturesInside()
+ {
+ MoveCreatureInside(DefiasPirate1);
+ MoveCreatureInside(DefiasPirate2);
+ MoveCreatureInside(DefiasCompanion);
+ }
+
+ void MoveCreatureInside(Creature *creature)
+ {
+ creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
+ creature->GetMotionMaster()->MovePoint(0, -102.7,-655.9, creature->GetPositionZ());
+ }
+
+ void ShootCannon()
+ {
+ DefiasCannon->SetUInt32Value(GAMEOBJECT_STATE, 0);
+ DoPlaySound(DefiasCannon, SOUND_CANNONFIRE);
+ }
+
+ void BlastOutDoor()
+ {
+ IronCladDoor->SetUInt32Value(GAMEOBJECT_STATE, 2);
+ DoPlaySound(IronCladDoor, SOUND_DESTROYDOOR);
+ }
+
+ void LeverStucked()
+ {
+ DoorLever->SetUInt32Value(GAMEOBJECT_FLAGS, 4);
+ }
+
+ void OnObjectCreate(GameObject *go)
+ {
+ switch(go->GetEntry())
+ {
+ case GO_IRONCLAD_DOOR:
+ IronCladDoor = go;
+ break;
+ case GO_DEFIAS_CANNON:
+ DefiasCannon = go;
+ break;
+ case GO_DOOR_LEVER:
+ DoorLever = go;
+ break;
+ }
+ }
+
+ void SetData(uint32 type, uint32 data)
+ {
+ if (type == EVENT_STATE)
+ {
+ if (DefiasCannon && IronCladDoor)
+ State=data;
+ }
+ }
+
+ uint32 GetData(uint32 type)
+ {
+ if (type == EVENT_STATE)
+ return State;
+ return 0;
+ }
+
+ void DoPlaySound(GameObject* unit, uint32 sound)
+ {
+ WorldPacket data(4);
+ data.SetOpcode(SMSG_PLAY_SOUND);
+ data << uint32(sound);
+ unit->SendMessageToSet(&data,false);
+ }
+
+ void DoPlaySoundCreature(Unit* unit, uint32 sound)
+ {
+ WorldPacket data(4);
+ data.SetOpcode(SMSG_PLAY_SOUND);
+ data << uint32(sound);
+ unit->SendMessageToSet(&data,false);
+ }
+};
+
+/*#####
+# item_Defias_Gunpowder
+#####*/
+
+bool ItemUse_item_defias_gunpowder(Player *player, Item* _Item, SpellCastTargets const& targets)
+{
+ ScriptedInstance *pInstance = (player->GetInstanceData()) ? ((ScriptedInstance*)player->GetInstanceData()) : NULL;
+
+ if(!pInstance)
+ {
+ player->GetSession()->SendNotification("Instance script not initialized");
+ return true;
+ }
+ if (pInstance->GetData(EVENT_STATE)!=CANNON_NOT_USED)
+ return false;
+ if(targets.getGOTarget() && targets.getGOTarget()->GetTypeId()==TYPEID_GAMEOBJECT &&
+ targets.getGOTarget()->GetEntry() == GO_DEFIAS_CANNON)
+ {
+ pInstance->SetData(EVENT_STATE, CANNON_GUNPOWDER_USED);
+ }
+
+ player->DestroyItemCount(_Item->GetEntry(), 1, true);
+ return true;
+}
+
+InstanceData* GetInstanceData_instance_deadmines(Map* map)
+{
+ return new instance_deadmines(map);
+}
+
+void AddSC_instance_deadmines()
+{
+ Script *newscript;
+ newscript = new Script;
+ newscript->Name = "instance_deadmines";
+ newscript->GetInstanceData = &GetInstanceData_instance_deadmines;
+ newscript->RegisterSelf();
+
+ newscript = new Script;
+ newscript->Name = "item_defias_gunpowder";
+ newscript->pItemUse = &ItemUse_item_defias_gunpowder;
+ newscript->RegisterSelf();
+}
+
diff --git a/src/bindings/scripts/scripts/zone/deadmines/def_deadmines.h b/src/bindings/scripts/scripts/zone/deadmines/def_deadmines.h
new file mode 100644
index 00000000000..73b95a30bd3
--- /dev/null
+++ b/src/bindings/scripts/scripts/zone/deadmines/def_deadmines.h
@@ -0,0 +1,13 @@
+#ifndef DEF_DEADMINES_H
+#define DEF_DEADMINES_H
+
+#include "precompiled.h"
+
+#define CANNON_NOT_USED 1
+#define CANNON_GUNPOWDER_USED 2
+#define CANNON_BLAST_INITIATED 3
+#define PIRATES_ATTACK 4
+#define EVENT_DONE 5
+
+#define EVENT_STATE 1
+#endif
diff --git a/src/bindings/scripts/scripts/zone/eversong_woods/eversong_woods.cpp b/src/bindings/scripts/scripts/zone/eversong_woods/eversong_woods.cpp
index 4f9c2a775af..b2a09b547e4 100644
--- a/src/bindings/scripts/scripts/zone/eversong_woods/eversong_woods.cpp
+++ b/src/bindings/scripts/scripts/zone/eversong_woods/eversong_woods.cpp
@@ -145,6 +145,408 @@ bool GossipSelect_npc_prospector_anvilward(Player *player, Creature *_Creature,
return true;
}
+/*######
+## Quest 9686 Second Trial
+######*/
+
+#define QUEST_SECOND_TRIAL 9686
+
+#define MASTER_KELERUN_BLOODMOURN 17807
+
+#define CHAMPION_BLOODWRATH 17809
+#define CHAMPION_LIGHTREND 17810
+#define CHAMPION_SWIFTBLADE 17811
+#define CHAMPION_SUNSTRIKER 17812
+
+#define HARBINGER_OF_THE_SECOND_TRIAL 182052
+
+#define SPELL_FLASH_OF_LIGHT 19939
+#define TIMER_FLASH_OF_LIGHT 3225
+
+#define SPELL_SEAL_OF_JUSTICE 20164
+#define TIMER_SEAL_OF_JUSTICE 10000
+
+#define SPELL_JUDGEMENT_OF_LIGHT 20271
+#define TIMER_JUDGEMENT_OF_LIGHT 10000
+
+#define SPELL_SEAL_OF_COMMAND 20375
+#define TIMER_SEAL_OF_COMMAND 20000
+
+#define OFFSET_NEXT_ATTACK 750
+
+#define FACTION_HOSTILE 45
+#define FACTION_FRIENDLY 7
+
+#define TEXT_SECOND_TRIAL_1 -1645006
+#define TEXT_SECOND_TRIAL_2 -1645007
+#define TEXT_SECOND_TRIAL_3 -1645008
+#define TEXT_SECOND_TRIAL_4 -1645009
+
+struct Locations
+{
+ float x, y, z, o;
+};
+
+static Locations SpawnPosition[]=
+{
+ {5.3, -11.8, 0.361, 4.2},
+ {11.2, -29.17, 0.361, 2.7},
+ {-5.7, -34.85, 0.361, 1.09},
+ {-11.9, -18, 0.361, 5.87}
+};
+
+static uint32 PaladinEntry[]= {CHAMPION_BLOODWRATH, CHAMPION_LIGHTREND, CHAMPION_SWIFTBLADE, CHAMPION_SUNSTRIKER};
+
+/*######
+## npc_second_trial_paladin
+######*/
+
+struct TRINITY_DLL_DECL npc_secondTrialAI : public ScriptedAI
+{
+ npc_secondTrialAI(Creature *c) : ScriptedAI(c) {Reset();}
+
+ uint32 timer;
+ uint8 questPhase;
+ uint64 summonerGuid;
+
+ bool spellFlashLight;
+ bool spellJustice;
+ bool spellJudLight;
+ bool spellCommand;
+
+ uint32 timerFlashLight;
+ uint32 timerJustice;
+ uint32 timerJudLight;
+ uint32 timerCommand;
+
+
+ void Reset() {
+
+ timer = 2000;
+ questPhase = 0;
+ summonerGuid = 0;
+
+ m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, PLAYER_STATE_KNEEL);
+ m_creature->setFaction(FACTION_FRIENDLY);
+
+ spellFlashLight = false;
+ spellJustice = false;
+ spellJudLight = false;
+ spellCommand = false;
+
+ switch(m_creature->GetEntry() ) {
+ case CHAMPION_BLOODWRATH :
+ spellFlashLight = true;
+ timerFlashLight = TIMER_FLASH_OF_LIGHT;
+ break;
+ case CHAMPION_LIGHTREND :
+ spellJustice = true;
+ timerJustice = 500;
+ break;
+ case CHAMPION_SWIFTBLADE :
+ spellJudLight = false; // Misses Script Effect // http://www.wowhead.com/?spell=20271
+ timerJudLight = 500;
+ break;
+ case CHAMPION_SUNSTRIKER :
+ spellFlashLight = true;
+ spellJudLight = false; // Misses Script Effect // http://www.wowhead.com/?spell=20271
+ spellCommand = false; // Misses Dummy // http://www.wowhead.com/?spell=20375
+ timerFlashLight = TIMER_FLASH_OF_LIGHT;
+ timerJudLight = 500;
+ timerCommand = 1500;
+ break;
+ }
+ }
+
+ void Aggro(Unit *who) { }
+
+ void UpdateAI(const uint32 diff)
+ {
+ if ( questPhase == 1 ) {
+
+ if ( timer < diff ) {
+ m_creature->SetUInt32Value(UNIT_FIELD_BYTES_1, PLAYER_STATE_NONE);
+ m_creature->setFaction(FACTION_HOSTILE);
+ questPhase = 0;
+
+ Unit *target = SelectUnit(SELECT_TARGET_RANDOM, 0);
+ if(target && target->GetTypeId() == TYPEID_PLAYER) // only on players.
+ {
+ m_creature->AddThreat(target, 5000000.0f);
+ AttackStart(target);
+ }
+ }
+ else timer -= diff;
+ }
+
+ if (!m_creature->SelectHostilTarget() || !m_creature->getVictim())
+ return;
+
+ // healer
+ if ( spellFlashLight ) {
+ if ( m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 70 ){
+ if ( timerFlashLight < diff ) {
+ DoCast(m_creature, SPELL_FLASH_OF_LIGHT);
+ timerFlashLight = TIMER_FLASH_OF_LIGHT + rand()%( TIMER_FLASH_OF_LIGHT );
+ }
+ else
+ timerFlashLight -= diff;
+ }
+ }
+
+ if ( spellJustice ) {
+ if ( timerJustice < diff )
+ {
+ DoCast(m_creature, SPELL_SEAL_OF_JUSTICE);
+ timerJustice = TIMER_SEAL_OF_JUSTICE + rand()%( TIMER_SEAL_OF_JUSTICE );
+ }
+ else
+ timerJustice -= diff;
+ }
+
+ if ( spellJudLight ) {
+ if ( timerJudLight < diff ) {
+ DoCast(m_creature, SPELL_JUDGEMENT_OF_LIGHT);
+ timerJudLight = TIMER_JUDGEMENT_OF_LIGHT + rand()%( TIMER_JUDGEMENT_OF_LIGHT );
+ }
+ else
+ timerJudLight -= diff;
+ }
+
+ if ( spellCommand ) {
+ if ( timerCommand < diff ) {
+ DoCast(m_creature, TIMER_SEAL_OF_COMMAND);
+ timerCommand = TIMER_SEAL_OF_COMMAND + rand()%( TIMER_SEAL_OF_COMMAND );
+ }
+ else
+ timerCommand -= diff;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ void Activate(uint64 summonerguid);
+ void KilledUnit(Unit* Killed);
+ void JustDied(Unit* Killer);
+
+};
+
+/*######
+## npc_second_trial_controller
+######*/
+
+struct TRINITY_DLL_DECL master_kelerun_bloodmournAI : public ScriptedAI
+{
+ master_kelerun_bloodmournAI(Creature *c) : ScriptedAI(c) {Reset();}
+
+ uint8 questPhase;
+ uint8 paladinPhase;
+ uint32 timer;
+
+ uint64 paladinGuid[4];
+
+ void Reset() {
+
+ questPhase = 0;
+ timer = 60000;
+ paladinPhase = 0;
+ uint64 paladinGuid[] = {0,0,0,0};
+
+ }
+
+ void Aggro(Unit *who) {}
+
+ void UpdateAI(const uint32 diff)
+ {
+ // Quest accepted but object not activated, object despawned (if in sync 1 minute! )
+ if ( questPhase == 1 ) {
+ if ( timer < diff ) Reset();
+ else timer -= diff;
+ }
+ // fight the 4 paladin mobs phase
+ else if ( questPhase == 2 ) {
+
+ if ( timer < diff ) {
+
+ Creature* paladinSpawn;
+ paladinSpawn = ((Creature*)Unit::GetUnit((*m_creature), paladinGuid[paladinPhase]));
+ if ( paladinSpawn ) {
+ ((npc_secondTrialAI*)paladinSpawn->AI())->Activate(m_creature->GetGUID());
+
+ switch(paladinPhase) {
+ case 0:
+ DoScriptText(TEXT_SECOND_TRIAL_1,m_creature);
+ break;
+ case 1:
+ DoScriptText(TEXT_SECOND_TRIAL_2,m_creature);
+ break;
+ case 2:
+ DoScriptText(TEXT_SECOND_TRIAL_3,m_creature);
+ break;
+ case 3:
+ DoScriptText(TEXT_SECOND_TRIAL_4,m_creature);
+ break;
+ }
+ }
+ else
+ Reset();
+
+ questPhase=4;
+ timer = OFFSET_NEXT_ATTACK;
+ }
+ else timer -= diff;
+ }
+
+ if (!m_creature->SelectHostilTarget() || !m_creature->getVictim())
+ return;
+
+ DoMeleeAttackIfReady();
+ }
+
+ void StartEvent()
+ {
+
+ if ( questPhase == 1 ) { // no player check, quest can be finished as group, so no complex playerguid/group search code
+
+ for (int i = 0; i<4; i++) {
+ Creature* Summoned;
+ Summoned = DoSpawnCreature(PaladinEntry[i], SpawnPosition[i].x, SpawnPosition[i].y, SpawnPosition[i].z, SpawnPosition[i].o, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 180000);
+
+ if(Summoned)
+ paladinGuid[i] = Summoned->GetGUID();
+ }
+
+ timer = OFFSET_NEXT_ATTACK;
+ questPhase = 2;
+ }
+ }
+
+ void SecondTrialKill();
+ void SummonedCreatureDespawn(Creature* c) {Reset();}
+};
+
+
+bool GossipHello_master_kelerun_bloodmourn(Player *player, Creature *_Creature)
+{
+ // quest only available if not already started
+ // Quest_template flag is set to : QUEST_FLAGS_EVENT
+ // Escort quests or any other event-driven quests. If player in party, all players that can accept this quest will receive confirmation box to accept quest.
+ // !not sure if this really works!
+
+ if ( ((master_kelerun_bloodmournAI*)_Creature->AI())->questPhase == 0 ) {
+ player->PrepareQuestMenu(_Creature->GetGUID());
+ player->SendPreparedQuest(_Creature->GetGUID());
+ }
+
+ player->SEND_GOSSIP_MENU(_Creature->GetEntry(), _Creature->GetGUID());
+ return true;
+}
+
+bool QuestAccept_master_kelerun_bloodmourn(Player *player, Creature *creature, Quest const *quest )
+{
+ // One Player exclusive quest, wait for user go activation
+ if(quest->GetQuestId() == QUEST_SECOND_TRIAL )
+ ((master_kelerun_bloodmournAI*)creature->AI())->questPhase = 1;
+
+ return true;
+}
+
+void master_kelerun_bloodmournAI::SecondTrialKill() {
+
+ if ( questPhase > 0 ) {
+
+ ++paladinPhase;
+
+ if ( paladinPhase < 4 )
+ questPhase=2;
+ else
+ Reset(); // Quest Complete, QuestComplete handler is in npc_secondTrialAI::JustDied
+ }
+ }
+
+void npc_secondTrialAI::JustDied(Unit* Killer) {
+
+ if (Killer->GetTypeId() == TYPEID_PLAYER)
+ {
+ Creature* Summoner;
+ Summoner = ((Creature*)Unit::GetUnit((*m_creature), summonerGuid));
+
+ if ( Summoner )
+ ((master_kelerun_bloodmournAI*)Summoner->AI())->SecondTrialKill();
+
+ // last kill quest complete for group
+ if ( m_creature->GetEntry() == CHAMPION_SUNSTRIKER ) {
+
+ if( Group *pGroup = ((Player*)Killer)->GetGroup() )
+ {
+ for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player *pGroupGuy = itr->getSource();
+
+ // for any leave or dead (with not released body) group member at appropriate distance
+ if( pGroupGuy && pGroupGuy->IsAtGroupRewardDistance(m_creature) && !pGroupGuy->GetCorpse() && pGroupGuy->GetQuestStatus( QUEST_SECOND_TRIAL ) == QUEST_STATUS_INCOMPLETE )
+ pGroupGuy->CompleteQuest( QUEST_SECOND_TRIAL );
+ }
+ }
+ else {
+ if ( ((Player*)Killer)->GetQuestStatus( QUEST_SECOND_TRIAL ) == QUEST_STATUS_INCOMPLETE )
+ ((Player*)Killer)->CompleteQuest( QUEST_SECOND_TRIAL );
+ }
+ }
+ }
+ }
+
+void npc_secondTrialAI::KilledUnit(Unit* Killed) {
+
+ if ( Killed->GetTypeId() == TYPEID_PLAYER ) {
+
+ if ( ((Player*)Killed)->GetQuestStatus(QUEST_SECOND_TRIAL) == QUEST_STATUS_INCOMPLETE )
+ ((Player*)Killed)->FailQuest(QUEST_SECOND_TRIAL);
+ }
+}
+
+void npc_secondTrialAI::Activate(uint64 summonerguid) {
+
+ questPhase=1;
+ summonerGuid = summonerguid;
+ }
+
+CreatureAI* GetAI_master_kelerun_bloodmourn(Creature *_Creature)
+{
+ return new master_kelerun_bloodmournAI (_Creature);
+}
+
+CreatureAI* GetAI_npc_secondTrial(Creature *_Creature)
+{
+ return new npc_secondTrialAI (_Creature);
+}
+
+/*######
+## go_second_trial
+######*/
+
+bool GOHello_go_second_trial(Player *player, GameObject* _GO)
+{
+ // find spawn :: master_kelerun_bloodmourn
+ CellPair p(Trinity::ComputeCellPair(_GO->GetPositionX(), _GO->GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+ cell.SetNoCreate();
+ CellLock<GridReadGuard> cell_lock(cell, p);
+
+ Creature* event_controller = NULL;
+ Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*_GO, MASTER_KELERUN_BLOODMOURN, true, 30);
+ Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(event_controller, u_check);
+ TypeContainerVisitor<Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher);
+ //cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(_GO->GetMap(), _GO));
+ cell_lock->Visit(cell_lock, grid_unit_searcher, *(_GO->GetMap()));
+
+ if ( event_controller )
+ ((master_kelerun_bloodmournAI*)event_controller->AI())->StartEvent();
+
+ return true;
+}
+
void AddSC_eversong_woods()
{
Script *newscript;
@@ -160,4 +562,21 @@ void AddSC_eversong_woods()
newscript->pGossipHello = &GossipHello_npc_prospector_anvilward;
newscript->pGossipSelect = &GossipSelect_npc_prospector_anvilward;
newscript->RegisterSelf();
+
+ newscript = new Script;
+ newscript->Name="npc_second_trial_controller";
+ newscript->GetAI = GetAI_master_kelerun_bloodmourn;
+ newscript->pGossipHello = &GossipHello_master_kelerun_bloodmourn;
+ newscript->pQuestAccept = &QuestAccept_master_kelerun_bloodmourn;
+ newscript->RegisterSelf();
+
+ newscript = new Script;
+ newscript->Name="npc_second_trial_paladin";
+ newscript->GetAI = GetAI_npc_secondTrial;
+ newscript->RegisterSelf();
+
+ newscript = new Script;
+ newscript->Name="go_second_trial";
+ newscript->pGOHello = &GOHello_go_second_trial;
+ newscript->RegisterSelf();
}
diff --git a/src/bindings/scripts/scripts/zone/gruuls_lair/boss_high_king_maulgar.cpp b/src/bindings/scripts/scripts/zone/gruuls_lair/boss_high_king_maulgar.cpp
index b0e53373a2f..20fb7a00532 100644
--- a/src/bindings/scripts/scripts/zone/gruuls_lair/boss_high_king_maulgar.cpp
+++ b/src/bindings/scripts/scripts/zone/gruuls_lair/boss_high_king_maulgar.cpp
@@ -450,32 +450,7 @@ struct TRINITY_DLL_DECL boss_kiggler_the_crazedAI : public ScriptedAI
((boss_high_king_maulgarAI*)Maulgar->AI())->AddDeath();
}
}
- void MoveInLineOfSight(Unit *who)
- {
- if (!m_creature->getVictim() && who->isTargetableForAttack() && who->isInAccessiblePlaceFor(m_creature) && m_creature->IsHostileTo(who))
- {
- if (!m_creature->canFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
- return;
-
- float attackRadius = m_creature->GetAttackDistance(who);
- if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who))
- {
- if(who->HasStealthAura())
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
-
- if(!InCombat)
- {
- AttackStart(who);
- if(pInstance)
- {
- pInstance->SetData64(DATA_MAULGAREVENT_TANK, who->GetGUID());
- pInstance->SetData(DATA_MAULGAREVENT, IN_PROGRESS);
- }
- }
- }
- }
- }
-
+
void UpdateAI(const uint32 diff)
{
//Only if not incombat check if the event is started
@@ -580,33 +555,7 @@ struct TRINITY_DLL_DECL boss_blindeye_the_seerAI : public ScriptedAI
}
}
- void MoveInLineOfSight(Unit *who)
- {
- if (!m_creature->getVictim() && who->isTargetableForAttack() && who->isInAccessiblePlaceFor(m_creature) && m_creature->IsHostileTo(who))
- {
- if (!m_creature->canFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
- return;
-
- float attackRadius = m_creature->GetAttackDistance(who);
- if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who))
- {
- if(who->HasStealthAura())
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
-
- if(!InCombat)
- {
- AttackStart(who);
- if(pInstance)
- {
- pInstance->SetData64(DATA_MAULGAREVENT_TANK, who->GetGUID());
- pInstance->SetData(DATA_MAULGAREVENT, IN_PROGRESS);
- }
- }
- }
- }
- }
-
- void UpdateAI(const uint32 diff)
+ void UpdateAI(const uint32 diff)
{
//Only if not incombat check if the event is started
if(!InCombat && pInstance && pInstance->GetData(DATA_MAULGAREVENT))
@@ -694,31 +643,6 @@ struct TRINITY_DLL_DECL boss_krosh_firehandAI : public ScriptedAI
((boss_high_king_maulgarAI*)Maulgar->AI())->AddDeath();
}
}
- void MoveInLineOfSight(Unit *who)
- {
- if (!m_creature->getVictim() && who->isTargetableForAttack() && who->isInAccessiblePlaceFor(m_creature) && m_creature->IsHostileTo(who))
- {
- if (!m_creature->canFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
- return;
-
- float attackRadius = m_creature->GetAttackDistance(who);
- if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who))
- {
- if(who->HasStealthAura())
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
-
- if(!InCombat)
- {
- AttackStart(who);
- if(pInstance)
- {
- pInstance->SetData64(DATA_MAULGAREVENT_TANK, who->GetGUID());
- pInstance->SetData(DATA_MAULGAREVENT, IN_PROGRESS);
- }
- }
- }
- }
- }
void UpdateAI(const uint32 diff)
{
diff --git a/src/bindings/scripts/scripts/zone/hellfire_citadel/hellfire_ramparts/boss_watchkeeper_gargolmar.cpp b/src/bindings/scripts/scripts/zone/hellfire_citadel/hellfire_ramparts/boss_watchkeeper_gargolmar.cpp
index 0d9e200c6e7..ab90c52ae4a 100644
--- a/src/bindings/scripts/scripts/zone/hellfire_citadel/hellfire_ramparts/boss_watchkeeper_gargolmar.cpp
+++ b/src/bindings/scripts/scripts/zone/hellfire_citadel/hellfire_ramparts/boss_watchkeeper_gargolmar.cpp
@@ -85,7 +85,7 @@ struct TRINITY_DLL_DECL boss_watchkeeper_gargolmarAI : public ScriptedAI
float attackRadius = m_creature->GetAttackDistance(who);
if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who))
{
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ //who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
AttackStart(who);
}
else if (!HasTaunted && m_creature->IsWithinDistInMap(who, 60.0f))
diff --git a/src/bindings/scripts/scripts/zone/hellfire_citadel/magtheridons_lair/boss_magtheridon.cpp b/src/bindings/scripts/scripts/zone/hellfire_citadel/magtheridons_lair/boss_magtheridon.cpp
index 4d819b3537b..9c5b3b4e6e7 100644
--- a/src/bindings/scripts/scripts/zone/hellfire_citadel/magtheridons_lair/boss_magtheridon.cpp
+++ b/src/bindings/scripts/scripts/zone/hellfire_citadel/magtheridons_lair/boss_magtheridon.cpp
@@ -227,7 +227,7 @@ struct TRINITY_DLL_DECL boss_magtheridonAI : public ScriptedAI
m_creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN2);
+ m_creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_2);
m_creature->addUnitState(UNIT_STAT_STUNNED);
m_creature->CastSpell(m_creature, SPELL_SHADOW_CAGE_C, true);
}
diff --git a/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_nethekurse.cpp b/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_nethekurse.cpp
index 299f72a041b..d57e65280ab 100644
--- a/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_nethekurse.cpp
+++ b/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_nethekurse.cpp
@@ -207,7 +207,7 @@ struct TRINITY_DLL_DECL boss_grand_warlock_nethekurseAI : public ScriptedAI
float attackRadius = m_creature->GetAttackDistance(who);
if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) )
{
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ //who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
AttackStart(who);
}
}
@@ -328,7 +328,7 @@ struct TRINITY_DLL_DECL mob_fel_orc_convertAI : public ScriptedAI
void Reset()
{
- m_creature->SetNoCallAssistence(true); //we don't want any assistance (WE R HEROZ!)
+ m_creature->SetNoCallAssistance(true); //we don't want any assistance (WE R HEROZ!)
Hemorrhage_Timer = 3000;
}
diff --git a/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_warchief_kargath_bladefist.cpp b/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_warchief_kargath_bladefist.cpp
new file mode 100644
index 00000000000..88ddf64b162
--- /dev/null
+++ b/src/bindings/scripts/scripts/zone/hellfire_citadel/shattered_halls/boss_warchief_kargath_bladefist.cpp
@@ -0,0 +1,298 @@
+/* Copyright (C) 2008 - 2009 BroodWyrm */
+#include "precompiled.h"
+
+#define SPELL_BLADE_DANCE 30739
+#define H_SPELL_CHARGE 25821
+
+#define TARGET_NUM 5
+
+#define MOB_SHATTERED_ASSASSIN 17695
+#define MOB_HEARTHEN_GUARD 17621
+#define MOB_SHARPSHOOTER_GUARD 17622
+#define MOB_REAVER_GUARD 17623
+
+float AssassEntrance[3] = {275.136,-84.29,2.3}; // y +-8
+float AssassExit[3] = {184.233,-84.29,2.3}; // y +-8
+float AddsEntrance[3] = {306.036,-84.29,1.93};
+
+#define SOUND_AGGRO1 10323
+#define SAY_AGGRO1 "Ours is the true Horde! The only Horde!"
+#define SOUND_AGGRO2 10324
+#define SAY_AGGRO2 "I'll carve the meat from your bones!"
+#define SOUND_AGGRO3 10325
+#define SAY_AGGRO3 "I am called Bladefist for a reason, as you will see!"
+#define SOUND_SLAY1 10326
+#define SAY_SLAY1 "For the real Horde!"
+#define SOUND_SLAY2 10327
+#define SAY_SLAY2 "I am the only Warchief!"
+#define SOUND_DEATH 10328
+#define SAY_DEATH "The true Horde... will.. prevail.."
+
+struct TRINITY_DLL_DECL boss_warchief_kargath_bladefistAI : public ScriptedAI
+{
+ boss_warchief_kargath_bladefistAI(Creature *c) : ScriptedAI(c)
+ {
+ pInstance = ((ScriptedInstance*)c->GetInstanceData());
+ HeroicMode = m_creature->GetMap()->IsHeroic();
+ Reset();
+ }
+
+ ScriptedInstance* pInstance;
+ bool HeroicMode;
+
+ std::vector<uint64> adds;
+ std::vector<uint64> assassins;
+
+ uint32 Charge_timer;
+ uint32 Blade_Dance_Timer;
+ uint32 Summon_Assistant_Timer;
+ uint32 resetcheck_timer;
+ uint32 Wait_Timer;
+
+ uint32 Assassins_Timer;
+
+ uint32 summoned;
+ bool InBlade;
+
+ uint32 target_num;
+
+ void Reset()
+ {
+ removeAdds();
+
+ m_creature->SetSpeed(MOVE_RUN,2);
+ m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
+
+ summoned = 2;
+ InBlade = false;
+ Wait_Timer = 0;
+
+ Charge_timer = 0;
+ Blade_Dance_Timer = 30000;
+ Summon_Assistant_Timer = 15000;
+ Assassins_Timer = 5000;
+ resetcheck_timer = 5000;
+ }
+
+ void Aggro(Unit *who)
+ {
+ switch (rand()%3)
+ {
+ case 0:
+ DoPlaySoundToSet(m_creature,SOUND_AGGRO1);
+ DoYell(SAY_AGGRO1,LANG_UNIVERSAL,NULL);
+ break;
+ case 1:
+ DoPlaySoundToSet(m_creature,SOUND_AGGRO2);
+ DoYell(SAY_AGGRO2,LANG_UNIVERSAL,NULL);
+ break;
+ case 2:
+ DoPlaySoundToSet(m_creature,SOUND_AGGRO3);
+ DoYell(SAY_AGGRO3,LANG_UNIVERSAL,NULL);
+ break;
+ }
+ }
+
+ void JustSummoned(Creature *summoned)
+ {
+ switch(summoned->GetEntry())
+ {
+ case MOB_HEARTHEN_GUARD:
+ case MOB_SHARPSHOOTER_GUARD:
+ case MOB_REAVER_GUARD:
+ summoned->AI()->AttackStart(SelectUnit(SELECT_TARGET_RANDOM,0));
+ adds.push_back(summoned->GetGUID());
+ break;
+ case MOB_SHATTERED_ASSASSIN:
+ assassins.push_back(summoned->GetGUID());
+ break;
+ }
+ }
+
+ void KilledUnit(Unit *victim)
+ {
+ if(victim->GetTypeId() == TYPEID_PLAYER)
+ {
+ switch(rand()%2)
+ {
+ case 0:
+ DoPlaySoundToSet(m_creature, SOUND_SLAY1);
+ DoYell(SAY_SLAY1,LANG_UNIVERSAL,NULL);
+ break;
+ case 1:
+ DoPlaySoundToSet(m_creature, SOUND_SLAY2);
+ DoYell(SAY_SLAY2,LANG_UNIVERSAL,NULL);
+ break;
+ }
+ }
+ }
+
+ void JustDied(Unit* Killer)
+ {
+ DoPlaySoundToSet(m_creature, SOUND_DEATH);
+ DoYell(SAY_DEATH,LANG_UNIVERSAL,NULL);
+ removeAdds();
+ }
+
+ void MovementInform(uint32 type, uint32 id)
+ {
+ if(InBlade)
+ {
+ if(type != POINT_MOTION_TYPE)
+ return;
+
+ if(id != 1)
+ return;
+
+ if(target_num > 0) // to prevent loops
+ {
+ Wait_Timer = 1;
+ DoCast(m_creature,SPELL_BLADE_DANCE,true);
+ target_num--;
+ }
+ }
+ }
+
+ void removeAdds()
+ {
+ for(std::vector<uint64>::iterator itr = adds.begin(); itr!= adds.end(); ++itr)
+ {
+ Unit* temp = Unit::GetUnit((*m_creature),*itr);
+ if(temp && temp->isAlive())
+ {
+ (*temp).GetMotionMaster()->Clear(true);
+ m_creature->DealDamage(temp,temp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
+ ((Creature*)temp)->RemoveCorpse();
+ }
+ }
+ adds.clear();
+
+ for(std::vector<uint64>::iterator itr = assassins.begin(); itr!= assassins.end(); ++itr)
+ {
+ Unit* temp = Unit::GetUnit((*m_creature),*itr);
+ if(temp && temp->isAlive())
+ {
+ (*temp).GetMotionMaster()->Clear(true);
+ m_creature->DealDamage(temp,temp->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
+ ((Creature*)temp)->RemoveCorpse();
+ }
+ }
+ assassins.clear();
+ }
+ void SpawnAssassin()
+ {
+ m_creature->SummonCreature(MOB_SHATTERED_ASSASSIN,AssassEntrance[0],AssassEntrance[1]+8, AssassEntrance[2], 0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,10000);
+ m_creature->SummonCreature(MOB_SHATTERED_ASSASSIN,AssassEntrance[0],AssassEntrance[1]-8, AssassEntrance[2], 0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,10000);
+ m_creature->SummonCreature(MOB_SHATTERED_ASSASSIN,AssassExit[0],AssassExit[1]+8, AssassExit[2], 0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,10000);
+ m_creature->SummonCreature(MOB_SHATTERED_ASSASSIN,AssassExit[0],AssassExit[1]-8, AssassExit[2], 0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,10000);
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() )
+ return;
+
+ if(Assassins_Timer)
+ if(Assassins_Timer < diff)
+ {
+ SpawnAssassin();
+ Assassins_Timer = 0;
+ }else Assassins_Timer -= diff;
+
+ if(InBlade)
+ {
+ if(Wait_Timer)
+ if(Wait_Timer < diff)
+ {
+ if(target_num <= 0)
+ {
+ // stop bladedance
+ InBlade = false;
+ m_creature->SetSpeed(MOVE_RUN,2);
+ (*m_creature).GetMotionMaster()->MoveChase(m_creature->getVictim());
+ Blade_Dance_Timer = 30000;
+ Wait_Timer = 0;
+ if(HeroicMode)
+ Charge_timer = 5000;
+ }
+ else
+ {
+ //move in bladedance
+ float x,y,randx,randy;
+ randx = (rand()%40);
+ randy = (rand()%40);
+ x = 210+ randx ;
+ y = -60- randy ;
+ (*m_creature).GetMotionMaster()->MovePoint(1,x,y,m_creature->GetPositionZ());
+ Wait_Timer = 0;
+ }
+ }else Wait_Timer -= diff;
+ }
+ else
+ {
+ if(Blade_Dance_Timer)
+ if(Blade_Dance_Timer < diff)
+ {
+ target_num = TARGET_NUM;
+ Wait_Timer = 1;
+ InBlade = true;
+ Blade_Dance_Timer = 0;
+ m_creature->SetSpeed(MOVE_RUN,4);
+ return;
+ }else Blade_Dance_Timer -= diff;
+
+ if(Charge_timer)
+ if(Charge_timer < diff)
+ {
+ DoCast(SelectUnit(SELECT_TARGET_RANDOM,0),H_SPELL_CHARGE);
+ Charge_timer = 0;
+ }else Charge_timer -= diff;
+
+ if (Summon_Assistant_Timer < diff)
+ {
+ Unit* target = NULL;
+ Creature* Summoned;
+
+ for(int i = 0; i < summoned; i++)
+ {
+ switch(rand()%3)
+ {
+ case 0: Summoned = m_creature->SummonCreature(MOB_HEARTHEN_GUARD,AddsEntrance[0],AddsEntrance[1], AddsEntrance[2], 0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,10000); break;
+ case 1: Summoned = m_creature->SummonCreature(MOB_SHARPSHOOTER_GUARD,AddsEntrance[0],AddsEntrance[1], AddsEntrance[2], 0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,10000); break;
+ case 2: Summoned = m_creature->SummonCreature(MOB_REAVER_GUARD,AddsEntrance[0],AddsEntrance[1], AddsEntrance[2], 0,TEMPSUMMON_CORPSE_TIMED_DESPAWN,10000); break;
+ }
+ }
+ if(rand()%100 < 20) summoned++;
+ Summon_Assistant_Timer = 15000 + (rand()%5000) ;
+ }else Summon_Assistant_Timer -= diff;
+
+ DoMeleeAttackIfReady();
+ }
+
+ if(resetcheck_timer < diff)
+ {
+ uint32 tempx,tempy;
+ tempx = m_creature->GetPositionX();
+ tempy = m_creature->GetPositionY();
+ if ( tempx > 255 || tempx < 205)
+ {
+ EnterEvadeMode();
+ }
+ resetcheck_timer = 5000;
+ }else resetcheck_timer -= diff;
+ }
+};
+
+CreatureAI* GetAI_boss_warchief_kargath_bladefist(Creature *_Creature)
+{
+ return new boss_warchief_kargath_bladefistAI (_Creature);
+}
+
+void AddSC_boss_warchief_kargath_bladefist()
+{
+ Script *newscript;
+ newscript = new Script;
+ newscript->Name="boss_warchief_kargath_bladefist";
+ newscript->GetAI = GetAI_boss_warchief_kargath_bladefist;
+ newscript->RegisterSelf();
+}
diff --git a/src/bindings/scripts/scripts/zone/hellfire_peninsula/hellfire_peninsula.cpp b/src/bindings/scripts/scripts/zone/hellfire_peninsula/hellfire_peninsula.cpp
index 81d23457aab..d272ac81cb1 100644
--- a/src/bindings/scripts/scripts/zone/hellfire_peninsula/hellfire_peninsula.cpp
+++ b/src/bindings/scripts/scripts/zone/hellfire_peninsula/hellfire_peninsula.cpp
@@ -17,7 +17,7 @@
/* ScriptData
SDName: Hellfire_Peninsula
SD%Complete: 100
-SDComment: Quest support: 10129, 10146, 10162, 10163, 10340, 10346, 10347, 10382 (Special flight paths)
+SDComment: Quest support: 9375, 10129, 10146, 10162, 10163, 10340, 10346, 10347, 10382 (Special flight paths)
SDCategory: Hellfire Peninsula
EndScriptData */
@@ -25,9 +25,11 @@ EndScriptData */
npc_wing_commander_dabiree
npc_gryphoneer_windbellow
npc_wing_commander_brack
+npc_wounded_blood_elf
EndContentData */
#include "precompiled.h"
+#include "../../npc/npc_escortAI.h"
/*######
## npc_wing_commander_dabiree
@@ -160,6 +162,151 @@ bool GossipSelect_npc_wing_commander_brack(Player *player, Creature *_Creature,
}
/*######
+## npc_wounded_blood_elf
+######*/
+
+#define QUEST_THE_ROAD_TO_FALCON_WATCH 9375
+#define SAY1 "Thank you for agreeing to help. Now, let's get out of here $N."
+#define SAY2 "Over there! They're following us!"
+#define SAY3 "Allow me a moment to rest. The journey taxes what little strength I have."
+#define SAY4 "Did you hear something?"
+#define SAY5 "Falcon Watch, at last! Now, where's my... Oh no! My pack, it's missing! Where has -"
+#define SAYAGGRO "You won't keep me from getting to Falcon Watch!"
+
+struct TRINITY_DLL_DECL npc_wounded_blood_elfAI : public npc_escortAI
+{
+ npc_wounded_blood_elfAI(Creature *c) : npc_escortAI(c) {Reset();}
+
+ void WaypointReached(uint32 i)
+ {
+ Unit* player = Unit::GetUnit((*m_creature), PlayerGUID);
+
+ if (!player)
+ return;
+
+ switch (i)
+ {
+
+ case 0:
+ DoSay(SAY1, LANG_UNIVERSAL, player);
+ // Change faction, so mobs can attack
+ m_creature->setFaction(1610);
+ break;
+
+ case 9:
+ DoSay(SAY2, LANG_UNIVERSAL, player);
+ // Spawn two Haal'eshi Talonguard
+ {
+ Creature* temp1 = m_creature->SummonCreature(16967, m_creature->GetPositionX()-15, m_creature->GetPositionY()-15, m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 3000);
+ if (temp1) temp1->AI()->AttackStart(m_creature);
+ Creature* temp2 = m_creature->SummonCreature(16967, m_creature->GetPositionX()-17, m_creature->GetPositionY()-17, m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 3000);
+ if (temp2) temp2->AI()->AttackStart(m_creature);
+ }
+ break;
+
+ case 13:
+ DoSay(SAY3, LANG_UNIVERSAL, player);
+ // NPC "should" kneel
+ m_creature->HandleEmoteCommand(EMOTE_STATE_KNEEL);
+ break;
+
+ case 14:
+ DoSay(SAY4, LANG_UNIVERSAL, player);
+ // Spawn two Haal'eshi Windwalker
+ {
+ Creature* temp3 = m_creature->SummonCreature(16966, m_creature->GetPositionX()-15, m_creature->GetPositionY()-15, m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 3000);
+ if (temp3) temp3->AI()->AttackStart(m_creature);
+ Creature* temp4 = m_creature->SummonCreature(16966, m_creature->GetPositionX()-17, m_creature->GetPositionY()-17, m_creature->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 3000);
+ if (temp4) temp4->AI()->AttackStart(m_creature);
+ }
+ break;
+
+ case 27:
+ DoSay(SAY5, LANG_UNIVERSAL, player);
+ // Set faction back to normal
+ m_creature->setFaction(1604);
+ // Award quest credit
+ if( PlayerGUID )
+ {
+ Unit* player = Unit::GetUnit((*m_creature), PlayerGUID);
+ if( player && player->GetTypeId() == TYPEID_PLAYER )
+ ((Player*)player)->GroupEventHappens(9375,m_creature);
+ }
+ break;
+ }
+ }
+
+ void Aggro(Unit* who)
+ {
+ DoSay(SAYAGGRO, LANG_UNIVERSAL, who);
+ }
+
+ void Reset() { }
+
+ void JustDied(Unit* killer)
+ // If NPC dies, Quest fail
+ {
+ if (PlayerGUID)
+ {
+ Unit* player = Unit::GetUnit((*m_creature), PlayerGUID);
+ if (player)
+ ((Player*)player)->FailQuest(QUEST_THE_ROAD_TO_FALCON_WATCH);
+ }
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ npc_escortAI::UpdateAI(diff);
+ }
+};
+
+bool QuestAccept_wounded_blood_elf(Player* player, Creature* creature, Quest const* quest)
+// Begin the escort quest
+{
+ if (quest->GetQuestId() == QUEST_THE_ROAD_TO_FALCON_WATCH)
+ {
+ ((npc_escortAI*)(creature->AI()))->Start(true, true, false, player->GetGUID());
+ }
+ return true;
+}
+
+CreatureAI* GetAI_npc_wounded_blood_elf(Creature *_Creature)
+{
+ npc_wounded_blood_elfAI* thisAI = new npc_wounded_blood_elfAI(_Creature);
+
+ thisAI->AddWaypoint(0, -1137.72, 4272.10, 14.04, 3000);
+ thisAI->AddWaypoint(1, -1141.34, 4232.42, 14.63);
+ thisAI->AddWaypoint(2, -1133.47, 4220.88, 11.78);
+ thisAI->AddWaypoint(3, -1126.18, 4213.26, 13.51);
+ thisAI->AddWaypoint(4, -1100.12, 4204.32, 16.41);
+ thisAI->AddWaypoint(5, -1063.68, 4197.92, 15.51);
+ thisAI->AddWaypoint(6, -1027.28, 4194.36, 15.52);
+ thisAI->AddWaypoint(7, -995.68, 4189.59, 19.84);
+ thisAI->AddWaypoint(8, -970.90, 4188.60, 24.61);
+ thisAI->AddWaypoint(9, -961.93, 4193.34, 26.11, 80000); // Summon 1
+ thisAI->AddWaypoint(10, -935.52, 4210.99, 31.98);
+ thisAI->AddWaypoint(11, -913.42, 4218.27, 37.29);
+ thisAI->AddWaypoint(12, -896.53, 4207.73, 43.23);
+ thisAI->AddWaypoint(13, -868.49, 4194.77, 46.75, 17000); // Kneel and Rest Here
+ thisAI->AddWaypoint(14, -852.83, 4198.29, 47.28, 80000); // Summon 2
+ thisAI->AddWaypoint(15, -819.85, 4200.50, 46.37);
+ thisAI->AddWaypoint(16, -791.92, 4201.96, 44.19);
+ thisAI->AddWaypoint(17, -774.42, 4202.46, 47.41);
+ thisAI->AddWaypoint(18, -762.90, 4202.17, 48.81);
+ thisAI->AddWaypoint(19, -728.25, 4195.35, 50.68);
+ thisAI->AddWaypoint(20, -713.58, 4192.07, 53.98);
+ thisAI->AddWaypoint(21, -703.09, 4189.74, 56.96);
+ thisAI->AddWaypoint(22, -693.70, 4185.43, 57.06);
+ thisAI->AddWaypoint(23, -686.38, 4159.81, 60.26);
+ thisAI->AddWaypoint(24, -679.88, 4147.04, 64.20);
+ thisAI->AddWaypoint(25, -656.74, 4147.72, 64.11);
+ thisAI->AddWaypoint(26, -652.22, 4137.50, 64.58);
+ thisAI->AddWaypoint(27, -649.99, 4136.38, 64.63, 20000); // Award Quest Credit
+
+ return (CreatureAI*)thisAI;
+}
+
+/*######
##
######*/
@@ -184,4 +331,10 @@ void AddSC_hellfire_peninsula()
newscript->pGossipHello = &GossipHello_npc_wing_commander_brack;
newscript->pGossipSelect = &GossipSelect_npc_wing_commander_brack;
newscript->RegisterSelf();
-}
+
+ newscript = new Script;
+ newscript->Name="npc_wounded_blood_elf";
+ newscript->GetAI = &GetAI_npc_wounded_blood_elf;
+ newscript->pQuestAccept = &QuestAccept_wounded_blood_elf;
+ newscript->RegisterSelf();
+} \ No newline at end of file
diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_anubrekhan.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_anubrekhan.cpp
index 2b93e7828f9..63b05e77f70 100644
--- a/src/bindings/scripts/scripts/zone/naxxramas/boss_anubrekhan.cpp
+++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_anubrekhan.cpp
@@ -126,7 +126,7 @@ struct TRINITY_DLL_DECL boss_anubrekhanAI : public ScriptedAI
}
}
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ //who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
AttackStart(who);
}
else if (!HasTaunted && m_creature->IsWithinDistInMap(who, 60.0f))
diff --git a/src/bindings/scripts/scripts/zone/naxxramas/boss_faerlina.cpp b/src/bindings/scripts/scripts/zone/naxxramas/boss_faerlina.cpp
index dbcf72510aa..3766d725a9b 100644
--- a/src/bindings/scripts/scripts/zone/naxxramas/boss_faerlina.cpp
+++ b/src/bindings/scripts/scripts/zone/naxxramas/boss_faerlina.cpp
@@ -121,7 +121,7 @@ struct TRINITY_DLL_DECL boss_faerlinaAI : public ScriptedAI
}
}
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ //who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
AttackStart(who);
}
else if (!HasTaunted && m_creature->IsWithinDistInMap(who, 60.0f))
diff --git a/src/bindings/scripts/scripts/zone/netherstorm/netherstorm.cpp b/src/bindings/scripts/scripts/zone/netherstorm/netherstorm.cpp
index 4125c4e888e..fbb4c20379b 100644
--- a/src/bindings/scripts/scripts/zone/netherstorm/netherstorm.cpp
+++ b/src/bindings/scripts/scripts/zone/netherstorm/netherstorm.cpp
@@ -390,6 +390,99 @@ bool GossipSelect_npc_veronia(Player *player, Creature *_Creature, uint32 sender
}
/*######
+## mob_phase_hunter
+######*/
+
+#define SUMMONED_MOB 19595
+#define EMOTE_WEAK "is very weak"
+
+// Spells
+#define SPELL_PHASE_SLIP 36574
+#define SPELL_MANA_BURN 13321
+
+struct TRINITY_DLL_DECL mob_phase_hunterAI : public ScriptedAI
+{
+
+ mob_phase_hunterAI(Creature *c) : ScriptedAI(c) {Reset();}
+
+ bool Weak;
+ int WeakPercent;
+ uint32 PlayerGUID;
+ uint32 Health;
+ uint32 Level;
+ uint32 PhaseSlipVulnerabilityTimer;
+ uint32 ManaBurnTimer;
+
+ void Reset()
+ {
+ Weak = false;
+ WeakPercent = 25 + (rand()%16); // 25-40
+ PlayerGUID = 0;
+ ManaBurnTimer = 5000 + (rand()%3 * 1000); // 5-8 sec cd
+ }
+
+ void Aggro(Unit *who)
+ {
+ PlayerGUID = who->GetGUID();
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+
+ Player* target = NULL;
+ target = ((Player*)Unit::GetUnit((*m_creature), PlayerGUID));
+
+ if(!target)
+ return;
+
+ if(m_creature->HasAuraType(SPELL_AURA_MOD_DECREASE_SPEED) || m_creature->hasUnitState(UNIT_STAT_ROOT)) // if the mob is rooted/slowed by spells eg.: Entangling Roots, Frost Nova, Hamstring, Crippling Poison, etc. => remove it
+ DoCast(m_creature, SPELL_PHASE_SLIP);
+ if(ManaBurnTimer < diff) // cast Mana Burn
+ {
+ if(target->GetCreateMana() > 0)
+ {
+ DoCast(target, SPELL_MANA_BURN);
+ ManaBurnTimer = 8000 + (rand()%10 * 1000); // 8-18 sec cd
+ }
+ }
+ else ManaBurnTimer -= diff;
+
+ if(!Weak && m_creature->GetHealth() < (m_creature->GetMaxHealth() / 100 * WeakPercent) && target->GetQuestStatus(10190) == QUEST_STATUS_INCOMPLETE) // start: support for quest 10190
+ {
+ DoTextEmote(EMOTE_WEAK, 0);
+ Weak = true;
+ }
+ if(Weak && m_creature->HasAura(34219, 0))
+ {
+ Health = m_creature->GetHealth(); // get the normal mob's data
+ Level = m_creature->getLevel();
+
+ m_creature->AttackStop(); // delete the normal mob
+ m_creature->DealDamage(m_creature, m_creature->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
+ m_creature->RemoveCorpse();
+
+ Creature* DrainedPhaseHunter = NULL;
+
+ if(!DrainedPhaseHunter)
+ DrainedPhaseHunter = m_creature->SummonCreature(SUMMONED_MOB, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(), m_creature->GetOrientation(), TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 60000); // summon the mob
+
+ if(DrainedPhaseHunter)
+ {
+ DrainedPhaseHunter->SetLevel(Level); // set the summoned mob's data
+ DrainedPhaseHunter->SetHealth(Health);
+ DrainedPhaseHunter->AI()->AttackStart(target);
+ }
+ } // end: support for quest 10190
+ }
+
+};
+
+CreatureAI* GetAI_mob_phase_hunter(Creature *_Creature)
+{
+ return new mob_phase_hunterAI (_Creature);
+}
+
+/*######
##
######*/
@@ -418,4 +511,9 @@ void AddSC_netherstorm()
newscript->pGossipHello = &GossipHello_npc_veronia;
newscript->pGossipSelect = &GossipSelect_npc_veronia;
newscript->RegisterSelf();
+
+ newscript = new Script;
+ newscript->Name = "mob_phase_hunter";
+ newscript->GetAI = GetAI_mob_phase_hunter;
+ newscript->RegisterSelf();
}
diff --git a/src/bindings/scripts/scripts/zone/shadowfang_keep/instance_shadowfang_keep.cpp b/src/bindings/scripts/scripts/zone/shadowfang_keep/instance_shadowfang_keep.cpp
index a854cc96989..fb1bfe380c8 100644
--- a/src/bindings/scripts/scripts/zone/shadowfang_keep/instance_shadowfang_keep.cpp
+++ b/src/bindings/scripts/scripts/zone/shadowfang_keep/instance_shadowfang_keep.cpp
@@ -26,75 +26,49 @@ EndScriptData */
#define ENCOUNTERS 4
-//#define ENTRY_BOSS_RETHILGORE 3914
-//#define ENTRY_BOSS_FENRUS 4274
-//#define ENTRY_BOSS_NANDOS 3927
-
-#define ENTRY_COURTYARD_DOOR 18895 //door to open when talking to NPC's
-#define ENTRY_SORCERER_DOOR 18972 //door to open when Fenrus the Devourer
-#define ENTRY_ARUGAL_DOOR 18971 //door to open when Wolf Master Nandos
-
struct TRINITY_DLL_DECL instance_shadowfang_keep : public ScriptedInstance
{
instance_shadowfang_keep(Map *Map) : ScriptedInstance(Map) {Initialize();};
uint32 Encounter[ENCOUNTERS];
- /*uint64 RethilgoreGUID;
- uint64 FenrusGUID;
- uint64 NandosGUID;*/
-
- GameObject *DoorCourtyard;
- GameObject *DoorSorcerer;
- GameObject *DoorArugal;
+ uint64 DoorCourtyard;
+ uint64 DoorSorcerer;
+ uint64 DoorArugal;
void Initialize()
{
- /*RethilgoreGUID = 0;
- FenrusGUID = 0;
- NandosGUID = 0;*/
+ DoorCourtyard = 0;
+ DoorSorcerer = 0;
+ DoorArugal = 0;
- DoorCourtyard = NULL;
- DoorSorcerer = NULL;
- DoorArugal = NULL;
+ for(uint8 i=0; i < ENCOUNTERS; ++i)
+ Encounter[i] = NOT_STARTED;
}
void OnObjectCreate(GameObject *go)
{
switch(go->GetEntry())
{
- case ENTRY_COURTYARD_DOOR: DoorCourtyard = go; break;
- case ENTRY_SORCERER_DOOR: DoorSorcerer = go; break;
- case ENTRY_ARUGAL_DOOR: DoorArugal = go; break;
+ case 18895: DoorCourtyard = go->GetGUID(); break;
+ case 18972: DoorSorcerer = go->GetGUID(); break;
+ case 18971: DoorArugal = go->GetGUID(); break;
}
}
- /*void OnCreatureCreate(Creature *creature, uint32 creature_entry)
+ void OpenDoor(uint64 DoorGUID, bool open)
{
- switch(creature_entry)
- {
- case ENTRY_BOSS_RETHILGORE:
- RethilgoreGUID = creature->GetGUID();
- break;
- case ENTRY_BOSS_FENRUS:
- FenrusGUID = creature->GetGUID();
- break;
- case ENTRY_BOSS_NANDOS:
- NandosGUID = creature->GetGUID();
- break;
- }
- }*/
+ if(GameObject *Door = instance->GetGameObjectInMap(DoorGUID))
+ Door->SetUInt32Value(GAMEOBJECT_STATE, open ? 0 : 1);
+ }
void SetData(uint32 type, uint32 data)
{
switch(type)
{
case TYPE_FREE_NPC:
- if(data == DONE)
- {
- if(DoorCourtyard)
- DoorCourtyard->UseDoorOrButton();
- }
+ if(data == DONE)
+ OpenDoor(DoorCourtyard, true);
Encounter[0] = data;
break;
case TYPE_RETHILGORE:
@@ -102,18 +76,12 @@ struct TRINITY_DLL_DECL instance_shadowfang_keep : public ScriptedInstance
break;
case TYPE_FENRUS:
if(data == DONE)
- {
- if(DoorSorcerer)
- DoorSorcerer->UseDoorOrButton();
- }
+ OpenDoor(DoorSorcerer, true);
Encounter[2] = data;
break;
case TYPE_NANDOS:
- if(data == DONE)
- {
- if(DoorArugal)
- DoorArugal->UseDoorOrButton();
- }
+ if(data == DONE)
+ OpenDoor(DoorArugal, true);
Encounter[3] = data;
break;
}
diff --git a/src/bindings/scripts/scripts/zone/shadowmoon_valley/boss_doomwalker.cpp b/src/bindings/scripts/scripts/zone/shadowmoon_valley/boss_doomwalker.cpp
index a67318bc41c..89d5c056c9e 100644
--- a/src/bindings/scripts/scripts/zone/shadowmoon_valley/boss_doomwalker.cpp
+++ b/src/bindings/scripts/scripts/zone/shadowmoon_valley/boss_doomwalker.cpp
@@ -125,7 +125,7 @@ struct TRINITY_DLL_DECL boss_doomwalkerAI : public ScriptedAI
if (!m_creature->SelectHostilTarget() || !m_creature->getVictim())
return;
- if (m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE))
+ //if (m_creature->IsWithinDistInMap(m_creature->getVictim(), ATTACK_DISTANCE))
{
//Spell Enrage
if (((m_creature->GetHealth()*100)/ m_creature->GetMaxHealth()) <= 20)//when hp <= 20% gain enrage
diff --git a/src/bindings/scripts/scripts/zone/stratholme/boss_timmy_the_cruel.cpp b/src/bindings/scripts/scripts/zone/stratholme/boss_timmy_the_cruel.cpp
index 4f526041e35..10633d91529 100644
--- a/src/bindings/scripts/scripts/zone/stratholme/boss_timmy_the_cruel.cpp
+++ b/src/bindings/scripts/scripts/zone/stratholme/boss_timmy_the_cruel.cpp
@@ -42,28 +42,11 @@ struct TRINITY_DLL_DECL boss_timmy_the_cruelAI : public ScriptedAI
void Aggro(Unit *who)
{
- }
-
- void MoveInLineOfSight(Unit *who)
- {
- if (!who || m_creature->getVictim())
- return;
-
- if (who->isTargetableForAttack() && who->isInAccessiblePlaceFor(m_creature) && m_creature->IsHostileTo(who))
- {
- float attackRadius = m_creature->GetAttackDistance(who);
- if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who))
- {
if (!HasYelled)
{
DoYell(SAY_SPAWN,LANG_UNIVERSAL,NULL);
HasYelled = true;
}
-
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
- AttackStart(who);
- }
- }
}
void UpdateAI(const uint32 diff)
diff --git a/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_eredar_twins.cpp b/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_eredar_twins.cpp
index b7e076b85d3..0bcd6a0eacf 100644
--- a/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_eredar_twins.cpp
+++ b/src/bindings/scripts/scripts/zone/sunwell_plateau/boss_eredar_twins.cpp
@@ -427,9 +427,6 @@ struct TRINITY_DLL_DECL boss_alythessAI : public ScriptedAI
float attackRadius = m_creature->GetAttackDistance(who);
if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && m_creature->IsWithinLOSInMap(who))
{
- if(who->HasStealthAura())
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
-
if (!InCombat)
{
DoStartNoMovement(who);
diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/arcatraz.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/arcatraz.cpp
index 624ad419243..8afd498f699 100644
--- a/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/arcatraz.cpp
+++ b/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/arcatraz.cpp
@@ -311,6 +311,8 @@ CreatureAI* GetAI_npc_millhouse_manastorm(Creature *_Creature)
#define SPELL_TARGET_OMEGA 36852
#define SPELL_BUBBLE_VISUAL 36849
+#define GOBJECT_SHIELD 184802
+
struct TRINITY_DLL_DECL npc_warden_mellicharAI : public ScriptedAI
{
npc_warden_mellicharAI(Creature *c) : ScriptedAI(c)
@@ -368,7 +370,7 @@ struct TRINITY_DLL_DECL npc_warden_mellicharAI : public ScriptedAI
DoPlaySoundToSet(m_creature,SOUND_INTRO1);
//possibly wrong spell OR should also cast second spell to make bubble appear (visual for this spell appear to be the correct)
DoCast(m_creature,SPELL_BUBBLE_VISUAL);
-
+
if( pInstance )
{
pInstance->SetData(TYPE_HARBINGERSKYRISS,IN_PROGRESS);
@@ -411,6 +413,7 @@ struct TRINITY_DLL_DECL npc_warden_mellicharAI : public ScriptedAI
case 2:
DoCast(m_creature,SPELL_TARGET_ALPHA);
pInstance->SetData(TYPE_WARDEN_1,IN_PROGRESS);
+ m_creature->SummonGameObject(GOBJECT_SHIELD, m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()-0.5, m_creature->GetOrientation(), 0, 0, 0, 0, 0);
break;
case 3:
DoCast(m_creature,SPELL_TARGET_BETA);
diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/boss_harbinger_skyriss.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/boss_harbinger_skyriss.cpp
index 808604d2375..754c316313f 100644
--- a/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/boss_harbinger_skyriss.cpp
+++ b/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/boss_harbinger_skyriss.cpp
@@ -94,7 +94,7 @@ struct TRINITY_DLL_DECL boss_harbinger_skyrissAI : public ScriptedAI
void Reset()
{
- m_creature->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_UNKNOWN2);
+ m_creature->SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_NOT_ATTACKABLE_2);
if( Intro )
Intro = true;
@@ -114,47 +114,19 @@ struct TRINITY_DLL_DECL boss_harbinger_skyrissAI : public ScriptedAI
void MoveInLineOfSight(Unit *who)
{
- if( !Intro )
- return;
-
- if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessiblePlaceFor(m_creature) )
- {
- if (!m_creature->canFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
- return;
-
- float attackRadius = m_creature->GetAttackDistance(who);
- if( m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) )
- {
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
- AttackStart(who);
- }
- }
+ if(Intro)
+ ScriptedAI::MoveInLineOfSight(who);
}
void AttackStart(Unit* who)
{
- if( !Intro )
- return;
-
- if (m_creature->Attack(who, true))
- {
- m_creature->AddThreat(who, 0.0f);
- m_creature->SetInCombatWith(who);
- who->SetInCombatWith(m_creature);
-
- if (!InCombat)
- {
- InCombat = true;
- Aggro(who);
- }
-
- DoStartMovement(who);
- }
+ if(!Intro)
+ ScriptedAI::AttackStart(who);
}
void Aggro(Unit *who)
{
- m_creature->RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_UNKNOWN2);
+ m_creature->RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_NOT_ATTACKABLE_2);
}
void JustDied(Unit* Killer)
@@ -227,6 +199,7 @@ struct TRINITY_DLL_DECL boss_harbinger_skyrissAI : public ScriptedAI
//should have a better way to do this. possibly spell exist.
mellic->setDeathState(JUST_DIED);
mellic->SetHealth(0);
+ pInstance->SetData(TYPE_SHIELD_OPEN,IN_PROGRESS);
}
++Intro_Phase;
Intro_Timer = 3000;
diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/def_arcatraz.h b/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/def_arcatraz.h
index 8868a36d70c..e175194e936 100644
--- a/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/def_arcatraz.h
+++ b/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/def_arcatraz.h
@@ -14,6 +14,6 @@
#define TYPE_WARDEN_3 7
#define TYPE_WARDEN_4 8
#define TYPE_WARDEN_5 9
-
#define DATA_MELLICHAR 10
+#define TYPE_SHIELD_OPEN 11
#endif
diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/instance_arcatraz.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/instance_arcatraz.cpp
index 2325680d53b..857928936e8 100644
--- a/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/instance_arcatraz.cpp
+++ b/src/bindings/scripts/scripts/zone/tempest_keep/arcatraz/instance_arcatraz.cpp
@@ -33,8 +33,9 @@ EndScriptData */
#define POD_DELTA 183964 //pod third boss wave
#define POD_GAMMA 183962 //pod fourth boss wave
#define POD_OMEGA 183965 //pod fifth boss wave
+#define WARDENS_SHIELD 184802 // warden shield
-#define MELLICHAR 21436 //skyriss will kill this unit
+#define MELLICHAR 20904 //skyriss will kill this unit
/* Arcatraz encounters:
1 - Zereketh the Unbound event
@@ -56,6 +57,7 @@ struct TRINITY_DLL_DECL instance_arcatraz : public ScriptedInstance
GameObject *Pod_Beta;
GameObject *Pod_Delta;
GameObject *Pod_Omega;
+ GameObject *Wardens_Shield;
uint64 Mellichar;
@@ -68,6 +70,7 @@ struct TRINITY_DLL_DECL instance_arcatraz : public ScriptedInstance
Pod_Delta = NULL;
Pod_Gamma = NULL;
Pod_Omega = NULL;
+ Wardens_Shield = NULL;
Mellichar = 0;
@@ -94,6 +97,7 @@ struct TRINITY_DLL_DECL instance_arcatraz : public ScriptedInstance
case POD_DELTA: Pod_Delta = go; break;
case POD_GAMMA: Pod_Gamma = go; break;
case POD_OMEGA: Pod_Omega = go; break;
+ case WARDENS_SHIELD: Wardens_Shield = go; break;
}
}
@@ -175,6 +179,12 @@ struct TRINITY_DLL_DECL instance_arcatraz : public ScriptedInstance
Pod_Omega->UseDoorOrButton();
Encounter[8] = data;
break;
+
+ case TYPE_SHIELD_OPEN:
+ if( data == IN_PROGRESS )
+ if( Wardens_Shield )
+ Wardens_Shield->UseDoorOrButton();
+ break;
}
}
diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_kaelthas.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_kaelthas.cpp
index ca5d8dcf7dd..bf1ed32c937 100644
--- a/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_kaelthas.cpp
+++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_eye/boss_kaelthas.cpp
@@ -202,39 +202,15 @@ struct TRINITY_DLL_DECL advisorbase_ai : public ScriptedAI
if (!who || FakeDeath || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE))
return;
- if( !m_creature->getVictim() && who->isTargetableForAttack() && ( m_creature->IsHostileTo( who )) && who->isInAccessiblePlaceFor(m_creature) )
- {
- if (!m_creature->canFly() && m_creature->GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE)
- return;
-
- float attackRadius = m_creature->GetAttackDistance(who);
- if(m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who) )
- {
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
- AttackStart(who);
- }
- }
+ ScriptedAI::MoveInLineOfSight(who);
}
void AttackStart(Unit* who)
{
if (!who || FakeDeath || m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE))
return;
-
- if (m_creature->Attack(who, true))
- {
- m_creature->AddThreat(who, 0.0f);
- m_creature->SetInCombatWith(who);
- who->SetInCombatWith(m_creature);
-
- if (!InCombat)
- {
- InCombat = true;
- Aggro(who);
- }
-
- DoStartMovement(who);
- }
+
+ ScriptedAI::AttackStart(who);
}
void Reset()
@@ -503,7 +479,7 @@ struct TRINITY_DLL_DECL boss_kaelthasAI : public ScriptedAI
float attackRadius = m_creature->GetAttackDistance(who);
if (Phase >= 4 && m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->IsWithinLOSInMap(who))
{
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ //who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
AttackStart(who);
}
else if(who->isAlive())
diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_pathaleon_the_calculator.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_pathaleon_the_calculator.cpp
index 91ceea65cdd..842da61d9bf 100644
--- a/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_pathaleon_the_calculator.cpp
+++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/boss_pathaleon_the_calculator.cpp
@@ -1,306 +1,306 @@
-/* Copyright (C) 2006 - 2008 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
-* 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
-*/
-
-/* ScriptData
-SDName: Boss Pathaleon the Calculator
-SD%Complete: 50
-SDComment: Event missing. Script for himself 99% blizzlike.
-SDCategory: Tempest Keep, The Mechanar
-EndScriptData */
-
-#include "precompiled.h"
-
-// Spells to be casted
-#define SPELL_SUMMON_NETHER_WRAITH 35287 //Spell not working. Summon is working but Pets dont attack and wrong HP.
-#define SPELL_MANA_TAP 36021
-#define SPELL_ARCANE_TORRENT 36022
-#define SPELL_DOMINATION 35280
-#define H_SPELL_ARCANE_EXPLOSION 34791 //Spell not right.
-#define SPELL_ENRAGE 36992
-
-// Add Spells
-#define SPELL_DETONATION 35058
-#define SPELL_ARCANE_MISSILES 35034
-
-// On Domination
-#define SAY_SPELL_DOMINATION_1 "I'm looking for a team player... "
-#define SOUND_SPELL_DOMINATION_1 11197
-#define SAY_SPELL_DOMINATION_2 "You work for me now!"
-#define SOUND_SPELL_DOMINATION_2 11198
-
-// On Summon
-#define SAY_SUMMON_1 "Time to supplement my work force."
-#define SOUND_SAY_SUMMON_1 11196
-
-// On Enrage
-#define SAY_ENRAGE_1 "A minor inconvenience."
-#define SOUND_SAY_ENRAGE_1 11199
-
-// On Aggro
-#define SAY_AGGRO_1 "We are on a strict timetable. You will not interfere!"
-#define SOUND_SAY_AGGRO_1 11193
-
-//On Kill Unit
-#define SAY_SLAY_1 "Looks like you lose"
-#define SOUND_SLAY_1 11195
-
-// On Death
-#define SAY_DEATH_1 "The project will... continue."
-#define SOUND_DEATH_1 11200
-
-
-struct TRINITY_DLL_DECL boss_pathaleon_the_calculatorAI : public ScriptedAI
-{
- boss_pathaleon_the_calculatorAI(Creature *c) : ScriptedAI(c)
- {
- HeroicMode = m_creature->GetMap()->IsHeroic();
- Reset();
- }
-
- uint32 Summon_Timer;
- uint32 ManaTap_Timer;
- uint32 ArcaneTorrent_Timer;
- uint32 Domination_Timer;
- uint32 ArcaneExplosion_Timer;
- bool HeroicMode;
- bool Enraged;
-
- uint32 Counter;
- Creature* Wraith;
-
- void Reset()
- {
- Summon_Timer = 30000;
- ManaTap_Timer = 12000 + rand()%8000;
- ArcaneTorrent_Timer = 16000 + rand()%9000;
- Domination_Timer = 25000 + rand()%15000;
- ArcaneExplosion_Timer = 8000 + rand()%5000;
-
- Enraged = false;
-
- Counter = 0;
-
- }
- void Aggro(Unit *who)
- {
- DoYell(SAY_AGGRO_1,LANG_UNIVERSAL,NULL);
- DoPlaySoundToSet(m_creature, SOUND_SAY_AGGRO_1);
- }
-
- // On Killed Unit
- void KilledUnit(Unit* victim)
- {
-
- DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL);
- DoPlaySoundToSet(m_creature,SOUND_SLAY_1);
-
- }
-
- // On Death
- void JustDied(Unit* Killer)
- {
- DoYell(SAY_DEATH_1,LANG_UNIVERSAL,NULL);
- DoPlaySoundToSet(m_creature, SOUND_DEATH_1);
- }
-
- void UpdateAI(const uint32 diff)
- {
- //Return since we have no target
- if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() )
- return;
-
- if(Summon_Timer < diff)
- {
-
- Unit* target = NULL;
-
- for(int i = 0; i < 3;i++)
- {
- target = SelectUnit(SELECT_TARGET_RANDOM,0);
- Wraith = m_creature->SummonCreature(21062,m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(),0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
- if (target)
- Wraith->AI()->AttackStart(target);
- }
-
- DoYell(SAY_SUMMON_1,LANG_UNIVERSAL,NULL);
- DoPlaySoundToSet(m_creature, SOUND_SAY_SUMMON_1);
-
- Summon_Timer = 30000 + rand()%15000;
- }else Summon_Timer -= diff;
-
- if(ManaTap_Timer < diff)
- {
- //time to cast
- DoCast(m_creature->getVictim(),SPELL_MANA_TAP);
-
- //Cast again on time
- ManaTap_Timer = 14000 + rand()%8000;
- }else ManaTap_Timer -= diff;
-
- if(ArcaneTorrent_Timer < diff)
- {
- //time to cast
- DoCast(m_creature->getVictim(),SPELL_ARCANE_TORRENT);
-
- //Cast again on time
- ArcaneTorrent_Timer = 12000 + rand()%6000;
- }else ArcaneTorrent_Timer -= diff;
-
- if(Domination_Timer < diff)
- {
- //time to cast
- switch(rand()%2)
- {
- case 0:
- DoYell(SAY_SPELL_DOMINATION_1, LANG_UNIVERSAL, NULL);
- DoPlaySoundToSet(m_creature, SOUND_SPELL_DOMINATION_1);
- break;
-
- case 1:
- DoYell(SAY_SPELL_DOMINATION_2, LANG_UNIVERSAL, NULL);
- DoPlaySoundToSet(m_creature, SOUND_SPELL_DOMINATION_2);
- break;
- }
-
- Unit* target = NULL;
- target = SelectUnit(SELECT_TARGET_RANDOM,1);
- if (target) DoCast(target,SPELL_DOMINATION);
-
- //Cast again on time
- Domination_Timer = 25000 + rand()%5000;
- }else Domination_Timer -= diff;
-
- //Only casting if Heroic Mode is used
- if (HeroicMode)
- {
- if(ArcaneExplosion_Timer < diff)
- {
- //time to cast
- DoCast(m_creature->getVictim(),H_SPELL_ARCANE_EXPLOSION);
-
- //Cast again on time
- ArcaneExplosion_Timer = 10000 + rand()%4000;
- }else ArcaneExplosion_Timer -= diff;
- }
-
- if (!Enraged && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 21)
- {
-
- DoCast(m_creature, SPELL_ENRAGE);
- DoYell(SAY_ENRAGE_1, LANG_UNIVERSAL, NULL);
- DoPlaySoundToSet(m_creature,SOUND_SAY_ENRAGE_1);
- Enraged = true;
-
- }
-
- DoMeleeAttackIfReady();
- }
-};
-CreatureAI* GetAI_boss_pathaleon_the_calculator(Creature *_Creature)
-{
- return new boss_pathaleon_the_calculatorAI (_Creature);
-}
-
-struct TRINITY_DLL_DECL mob_nether_wraithAI : public ScriptedAI
-{
- mob_nether_wraithAI(Creature *c) : ScriptedAI(c) {Reset();}
-
- ScriptedInstance *pInstance;
-
- uint32 ArcaneMissiles_Timer;
- uint32 Detonation_Timer;
- uint32 Die_Timer;
- bool Detonation;
-
- void Reset()
- {
- ArcaneMissiles_Timer = 1000 + rand()%3000;
- Detonation_Timer = 20000;
- Die_Timer = 2200;
- Detonation = false;
-
- }
-
- void Aggro(Unit* who)
- {
- }
-
- void UpdateAI(const uint32 diff)
- {
- Unit* target = NULL;
-
- if (!m_creature->SelectHostilTarget() || !m_creature->getVictim())
- return;
-
- if(ArcaneMissiles_Timer < diff)
- {
-
- Unit* target = NULL;
- target = SelectUnit(SELECT_TARGET_RANDOM,1);
- if (!target)
- target = m_creature->getVictim();
- if (target)
- {
- DoCast(target,SPELL_ARCANE_MISSILES);
- }
-
- ArcaneMissiles_Timer = 5000 + rand()%5000;
- }else ArcaneMissiles_Timer -=diff;
-
- if (!Detonation)
- {
- if(Detonation_Timer < diff)
- {
- //time to cast
- DoCast(m_creature,SPELL_DETONATION);
- Detonation = true;
-
- }else Detonation_Timer -= diff;
-
- }
-
- if (Detonation)
- {
- if (Die_Timer < diff)
- {
- m_creature->setDeathState(JUST_DIED);
- m_creature->RemoveCorpse();
- }else Die_Timer -= diff;
- }
-
-
- DoMeleeAttackIfReady();
- }
-
-};
-CreatureAI* GetAI_mob_nether_wraith(Creature *_Creature)
-{
- return new mob_nether_wraithAI (_Creature);
-}
-
-void AddSC_boss_pathaleon_the_calculator()
-{
- Script *newscript;
- newscript = new Script;
- newscript->Name="boss_pathaleon_the_calculator";
- newscript->GetAI = GetAI_boss_pathaleon_the_calculator;
- newscript->RegisterSelf();
-
- newscript = new Script;
- newscript->Name="mob_nether_wraith";
- newscript->GetAI = GetAI_mob_nether_wraith;
- newscript->RegisterSelf();
-}
+/* Copyright (C) 2006 - 2008 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
+* 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
+*/
+
+/* ScriptData
+SDName: Boss Pathaleon the Calculator
+SD%Complete: 50
+SDComment: Event missing. Script for himself 99% blizzlike.
+SDCategory: Tempest Keep, The Mechanar
+EndScriptData */
+
+#include "precompiled.h"
+
+// Spells to be casted
+#define SPELL_SUMMON_NETHER_WRAITH 35287 //Spell not working. Summon is working but Pets dont attack and wrong HP.
+#define SPELL_MANA_TAP 36021
+#define SPELL_ARCANE_TORRENT 36022
+#define SPELL_DOMINATION 35280
+#define H_SPELL_ARCANE_EXPLOSION 34791 //Spell not right.
+#define SPELL_ENRAGE 36992
+
+// Add Spells
+#define SPELL_DETONATION 35058
+#define SPELL_ARCANE_MISSILES 35034
+
+// On Domination
+#define SAY_SPELL_DOMINATION_1 "I'm looking for a team player... "
+#define SOUND_SPELL_DOMINATION_1 11197
+#define SAY_SPELL_DOMINATION_2 "You work for me now!"
+#define SOUND_SPELL_DOMINATION_2 11198
+
+// On Summon
+#define SAY_SUMMON_1 "Time to supplement my work force."
+#define SOUND_SAY_SUMMON_1 11196
+
+// On Enrage
+#define SAY_ENRAGE_1 "A minor inconvenience."
+#define SOUND_SAY_ENRAGE_1 11199
+
+// On Aggro
+#define SAY_AGGRO_1 "We are on a strict timetable. You will not interfere!"
+#define SOUND_SAY_AGGRO_1 11193
+
+//On Kill Unit
+#define SAY_SLAY_1 "Looks like you lose"
+#define SOUND_SLAY_1 11195
+
+// On Death
+#define SAY_DEATH_1 "The project will... continue."
+#define SOUND_DEATH_1 11200
+
+
+struct TRINITY_DLL_DECL boss_pathaleon_the_calculatorAI : public ScriptedAI
+{
+ boss_pathaleon_the_calculatorAI(Creature *c) : ScriptedAI(c)
+ {
+ HeroicMode = m_creature->GetMap()->IsHeroic();
+ Reset();
+ }
+
+ uint32 Summon_Timer;
+ uint32 ManaTap_Timer;
+ uint32 ArcaneTorrent_Timer;
+ uint32 Domination_Timer;
+ uint32 ArcaneExplosion_Timer;
+ bool HeroicMode;
+ bool Enraged;
+
+ uint32 Counter;
+ Creature* Wraith;
+
+ void Reset()
+ {
+ Summon_Timer = 30000;
+ ManaTap_Timer = 12000 + rand()%8000;
+ ArcaneTorrent_Timer = 16000 + rand()%9000;
+ Domination_Timer = 25000 + rand()%15000;
+ ArcaneExplosion_Timer = 8000 + rand()%5000;
+
+ Enraged = false;
+
+ Counter = 0;
+
+ }
+ void Aggro(Unit *who)
+ {
+ DoYell(SAY_AGGRO_1,LANG_UNIVERSAL,NULL);
+ DoPlaySoundToSet(m_creature, SOUND_SAY_AGGRO_1);
+ }
+
+ // On Killed Unit
+ void KilledUnit(Unit* victim)
+ {
+
+ DoYell(SAY_SLAY_1, LANG_UNIVERSAL, NULL);
+ DoPlaySoundToSet(m_creature,SOUND_SLAY_1);
+
+ }
+
+ // On Death
+ void JustDied(Unit* Killer)
+ {
+ DoYell(SAY_DEATH_1,LANG_UNIVERSAL,NULL);
+ DoPlaySoundToSet(m_creature, SOUND_DEATH_1);
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ //Return since we have no target
+ if (!m_creature->SelectHostilTarget() || !m_creature->getVictim() )
+ return;
+
+ if(Summon_Timer < diff)
+ {
+
+ Unit* target = NULL;
+
+ for(int i = 0; i < 3;i++)
+ {
+ target = SelectUnit(SELECT_TARGET_RANDOM,0);
+ Wraith = m_creature->SummonCreature(21062,m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ(),0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000);
+ if (target)
+ Wraith->AI()->AttackStart(target);
+ }
+
+ DoYell(SAY_SUMMON_1,LANG_UNIVERSAL,NULL);
+ DoPlaySoundToSet(m_creature, SOUND_SAY_SUMMON_1);
+
+ Summon_Timer = 30000 + rand()%15000;
+ }else Summon_Timer -= diff;
+
+ if(ManaTap_Timer < diff)
+ {
+ //time to cast
+ DoCast(m_creature->getVictim(),SPELL_MANA_TAP);
+
+ //Cast again on time
+ ManaTap_Timer = 14000 + rand()%8000;
+ }else ManaTap_Timer -= diff;
+
+ if(ArcaneTorrent_Timer < diff)
+ {
+ //time to cast
+ DoCast(m_creature->getVictim(),SPELL_ARCANE_TORRENT);
+
+ //Cast again on time
+ ArcaneTorrent_Timer = 12000 + rand()%6000;
+ }else ArcaneTorrent_Timer -= diff;
+
+ if(Domination_Timer < diff)
+ {
+ //time to cast
+ switch(rand()%2)
+ {
+ case 0:
+ DoYell(SAY_SPELL_DOMINATION_1, LANG_UNIVERSAL, NULL);
+ DoPlaySoundToSet(m_creature, SOUND_SPELL_DOMINATION_1);
+ break;
+
+ case 1:
+ DoYell(SAY_SPELL_DOMINATION_2, LANG_UNIVERSAL, NULL);
+ DoPlaySoundToSet(m_creature, SOUND_SPELL_DOMINATION_2);
+ break;
+ }
+
+ Unit* target = NULL;
+ target = SelectUnit(SELECT_TARGET_RANDOM,1);
+ if (target) DoCast(target,SPELL_DOMINATION);
+
+ //Cast again on time
+ Domination_Timer = 25000 + rand()%5000;
+ }else Domination_Timer -= diff;
+
+ //Only casting if Heroic Mode is used
+ if (HeroicMode)
+ {
+ if(ArcaneExplosion_Timer < diff)
+ {
+ //time to cast
+ DoCast(m_creature->getVictim(),H_SPELL_ARCANE_EXPLOSION);
+
+ //Cast again on time
+ ArcaneExplosion_Timer = 10000 + rand()%4000;
+ }else ArcaneExplosion_Timer -= diff;
+ }
+
+ if (!Enraged && m_creature->GetHealth()*100 / m_creature->GetMaxHealth() < 21)
+ {
+
+ DoCast(m_creature, SPELL_ENRAGE);
+ DoYell(SAY_ENRAGE_1, LANG_UNIVERSAL, NULL);
+ DoPlaySoundToSet(m_creature,SOUND_SAY_ENRAGE_1);
+ Enraged = true;
+
+ }
+
+ DoMeleeAttackIfReady();
+ }
+};
+CreatureAI* GetAI_boss_pathaleon_the_calculator(Creature *_Creature)
+{
+ return new boss_pathaleon_the_calculatorAI (_Creature);
+}
+
+struct TRINITY_DLL_DECL mob_nether_wraithAI : public ScriptedAI
+{
+ mob_nether_wraithAI(Creature *c) : ScriptedAI(c) {Reset();}
+
+ ScriptedInstance *pInstance;
+
+ uint32 ArcaneMissiles_Timer;
+ uint32 Detonation_Timer;
+ uint32 Die_Timer;
+ bool Detonation;
+
+ void Reset()
+ {
+ ArcaneMissiles_Timer = 1000 + rand()%3000;
+ Detonation_Timer = 20000;
+ Die_Timer = 2200;
+ Detonation = false;
+
+ }
+
+ void Aggro(Unit* who)
+ {
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ Unit* target = NULL;
+
+ if (!m_creature->SelectHostilTarget() || !m_creature->getVictim())
+ return;
+
+ if(ArcaneMissiles_Timer < diff)
+ {
+
+ Unit* target = NULL;
+ target = SelectUnit(SELECT_TARGET_RANDOM,1);
+ if (!target)
+ target = m_creature->getVictim();
+ if (target)
+ {
+ DoCast(target,SPELL_ARCANE_MISSILES);
+ }
+
+ ArcaneMissiles_Timer = 5000 + rand()%5000;
+ }else ArcaneMissiles_Timer -=diff;
+
+ if (!Detonation)
+ {
+ if(Detonation_Timer < diff)
+ {
+ //time to cast
+ DoCast(m_creature,SPELL_DETONATION);
+ Detonation = true;
+
+ }else Detonation_Timer -= diff;
+
+ }
+
+ if (Detonation)
+ {
+ if (Die_Timer < diff)
+ {
+ m_creature->setDeathState(JUST_DIED);
+ m_creature->RemoveCorpse();
+ }else Die_Timer -= diff;
+ }
+
+
+ DoMeleeAttackIfReady();
+ }
+
+};
+CreatureAI* GetAI_mob_nether_wraith(Creature *_Creature)
+{
+ return new mob_nether_wraithAI (_Creature);
+}
+
+void AddSC_boss_pathaleon_the_calculator()
+{
+ Script *newscript;
+ newscript = new Script;
+ newscript->Name="boss_pathaleon_the_calculator";
+ newscript->GetAI = GetAI_boss_pathaleon_the_calculator;
+ newscript->RegisterSelf();
+
+ newscript = new Script;
+ newscript->Name="mob_nether_wraith";
+ newscript->GetAI = GetAI_mob_nether_wraith;
+ newscript->RegisterSelf();
+}
diff --git a/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/instance_mechanar.cpp b/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/instance_mechanar.cpp
index 4ea1fcfad5b..d25b9d05470 100644
--- a/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/instance_mechanar.cpp
+++ b/src/bindings/scripts/scripts/zone/tempest_keep/the_mechanar/instance_mechanar.cpp
@@ -1,90 +1,90 @@
-/* Copyright (C) 2006 - 2008 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
- * 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
- */
-
-/* ScriptData
-SDName: Instance_Mechanar
-SD%Complete: 100
-SDComment:
-SDCategory: Mechanar
-EndScriptData */
-
-#include "precompiled.h"
-#include "def_mechanar.h"
-
-struct TRINITY_DLL_DECL instance_mechanar : public ScriptedInstance
-{
- instance_mechanar(Map *Map) : ScriptedInstance(Map) {Initialize();};
-
-
- bool IsBossDied[1];
-
- void OnCreatureCreate (Creature *creature, uint32 creature_entry)
- {
- }
-
- void Initialize()
- {
- IsBossDied[0] = false;
- }
-
- bool IsEncounterInProgress() const
- {
- //not active
- return false;
- }
-
- uint32 GetData(uint32 type)
- {
- switch(type)
- {
- case DATA_SEPETHREAISDEAD:
- if(IsBossDied[0])
- return 1;
- break;
- }
-
- return 0;
- }
-
- uint64 GetData64 (uint32 identifier)
- {
- return 0;
- }
-
- void SetData(uint32 type, uint32 data)
- {
- switch(type)
- {
- case DATA_SEPETHREA_DEATH:
- IsBossDied[0] = true;
- break;
- }
- }
-};
-
-InstanceData* GetInstanceData_instance_mechanar(Map* map)
-{
- return new instance_mechanar(map);
-}
-
-void AddSC_instance_mechanar()
-{
- Script *newscript;
- newscript = new Script;
- newscript->Name = "instance_mechanar";
- newscript->GetInstanceData = GetInstanceData_instance_mechanar;
- newscript->RegisterSelf();
-}
+/* Copyright (C) 2006 - 2008 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
+ * 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
+ */
+
+/* ScriptData
+SDName: Instance_Mechanar
+SD%Complete: 100
+SDComment:
+SDCategory: Mechanar
+EndScriptData */
+
+#include "precompiled.h"
+#include "def_mechanar.h"
+
+struct TRINITY_DLL_DECL instance_mechanar : public ScriptedInstance
+{
+ instance_mechanar(Map *Map) : ScriptedInstance(Map) {Initialize();};
+
+
+ bool IsBossDied[1];
+
+ void OnCreatureCreate (Creature *creature, uint32 creature_entry)
+ {
+ }
+
+ void Initialize()
+ {
+ IsBossDied[0] = false;
+ }
+
+ bool IsEncounterInProgress() const
+ {
+ //not active
+ return false;
+ }
+
+ uint32 GetData(uint32 type)
+ {
+ switch(type)
+ {
+ case DATA_SEPETHREAISDEAD:
+ if(IsBossDied[0])
+ return 1;
+ break;
+ }
+
+ return 0;
+ }
+
+ uint64 GetData64 (uint32 identifier)
+ {
+ return 0;
+ }
+
+ void SetData(uint32 type, uint32 data)
+ {
+ switch(type)
+ {
+ case DATA_SEPETHREA_DEATH:
+ IsBossDied[0] = true;
+ break;
+ }
+ }
+};
+
+InstanceData* GetInstanceData_instance_mechanar(Map* map)
+{
+ return new instance_mechanar(map);
+}
+
+void AddSC_instance_mechanar()
+{
+ Script *newscript;
+ newscript = new Script;
+ newscript->Name = "instance_mechanar";
+ newscript->GetInstanceData = GetInstanceData_instance_mechanar;
+ newscript->RegisterSelf();
+}
diff --git a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_cthun.cpp b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_cthun.cpp
index b789f68e9aa..d1dfbf8d79e 100644
--- a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_cthun.cpp
+++ b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_cthun.cpp
@@ -335,7 +335,7 @@ struct TRINITY_DLL_DECL eye_of_cthunAI : public Scripted_NoMovementAI
m_creature->StopMoving();
//Actual dark glare cast, maybe something missing here?
- m_creature->CastSpell(NULL, SPELL_DARK_GLARE, false);
+ m_creature->CastSpell(m_creature, SPELL_DARK_GLARE, false);
//Increase tick
DarkGlareTick++;
diff --git a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_twinemperors.cpp b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_twinemperors.cpp
index 93525ad7246..b9b37991629 100644
--- a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_twinemperors.cpp
+++ b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/boss_twinemperors.cpp
@@ -352,8 +352,8 @@ struct TRINITY_DLL_DECL boss_twinemperorsAI : public ScriptedAI
attackRadius = PULL_RANGE;
if (m_creature->IsWithinDistInMap(who, attackRadius) && m_creature->GetDistanceZ(who) <= /*CREATURE_Z_ATTACK_RANGE*/7 /*there are stairs*/)
{
- if(who->HasStealthAura())
- who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ //if(who->HasStealthAura())
+ // who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
AttackStart(who);
}
}
diff --git a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp
index f5a55d711b7..a8cbf0310d9 100644
--- a/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp
+++ b/src/bindings/scripts/scripts/zone/temple_of_ahnqiraj/mob_anubisath_sentinel.cpp
@@ -157,7 +157,7 @@ struct TRINITY_DLL_DECL aqsentinelAI : public ScriptedAI
{
if (!c->isInCombat())
{
- c->SetNoCallAssistence(true);
+ c->SetNoCallAssistance(true);
if(c->AI())
c->AI()->AttackStart(who);
}
diff --git a/src/bindings/scripts/scripts/zone/westfall/westfall.cpp b/src/bindings/scripts/scripts/zone/westfall/westfall.cpp
index b311bf674eb..40faa01a9f0 100644
--- a/src/bindings/scripts/scripts/zone/westfall/westfall.cpp
+++ b/src/bindings/scripts/scripts/zone/westfall/westfall.cpp
@@ -1,179 +1,179 @@
-/* Copyright (C) 2006 - 2008 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
- * 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
- */
-
-/* ScriptData
-SDName: Westfall
-SD%Complete: 90
-SDComment: Quest support: 155
-SDCategory: Westfall
-EndScriptData */
-
-/* ContentData
-npc_defias_traitor
-EndContentData */
-
-#include "precompiled.h"
-#include "../../npc/npc_escortAI.h"
-
-#define SAY_START -1000101
-#define SAY_PROGRESS -1000102
-#define SAY_END -1000103
-#define SAY_AGGRO_1 -1000104
-#define SAY_AGGRO_2 -1000105
-
-#define QUEST_DEFIAS_BROTHERHOOD 155
-
-struct TRINITY_DLL_DECL npc_defias_traitorAI : public npc_escortAI
-{
- npc_defias_traitorAI(Creature *c) : npc_escortAI(c) {Reset();}
-
- bool IsWalking;
-
- void WaypointReached(uint32 i)
- {
- Unit* player = Unit::GetUnit((*m_creature), PlayerGUID);
-
- if (!player)
- return;
-
- if (IsWalking && !m_creature->HasUnitMovementFlag(MOVEMENTFLAG_WALK_MODE))
- m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
-
- switch (i)
- {
- case 35:
- IsWalking = true;
- break;
- case 36:
- DoScriptText(SAY_PROGRESS, m_creature, player);
- break;
- case 44:
- DoScriptText(SAY_END, m_creature, player);
- {
- if (player && player->GetTypeId() == TYPEID_PLAYER)
- ((Player*)player)->GroupEventHappens(QUEST_DEFIAS_BROTHERHOOD,m_creature);
- }
- break;
- }
- }
- void Aggro(Unit* who)
- {
- switch(rand()%2)
- {
- case 0: DoScriptText(SAY_AGGRO_1, m_creature, who); break;
- case 1: DoScriptText(SAY_AGGRO_2, m_creature, who); break;
- }
- }
-
- void Reset()
- {
- if (IsWalking && !m_creature->HasUnitMovementFlag(MOVEMENTFLAG_WALK_MODE))
- {
- m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
- return;
- }
- IsWalking = false;
- }
-
- void JustDied(Unit* killer)
- {
- if (PlayerGUID)
- {
- if (Unit* player = Unit::GetUnit((*m_creature), PlayerGUID))
- ((Player*)player)->FailQuest(QUEST_DEFIAS_BROTHERHOOD);
- }
- }
-
- void UpdateAI(const uint32 diff)
- {
- npc_escortAI::UpdateAI(diff);
- }
-};
-
-bool QuestAccept_npc_defias_traitor(Player* player, Creature* creature, Quest const* quest)
-{
- if (quest->GetQuestId() == QUEST_DEFIAS_BROTHERHOOD)
- {
- ((npc_escortAI*)(creature->AI()))->Start(true, true, true, player->GetGUID());
- DoScriptText(SAY_START, creature, player);
- }
-
- return true;
-}
-
-CreatureAI* GetAI_npc_defias_traitor(Creature *_Creature)
-{
- npc_defias_traitorAI* thisAI = new npc_defias_traitorAI(_Creature);
-
- thisAI->AddWaypoint(0, -10508.40, 1068.00, 55.21);
- thisAI->AddWaypoint(1, -10518.30, 1074.84, 53.96);
- thisAI->AddWaypoint(2, -10534.82, 1081.92, 49.88);
- thisAI->AddWaypoint(3, -10546.51, 1084.88, 50.13);
- thisAI->AddWaypoint(4, -10555.29, 1084.45, 45.75);
- thisAI->AddWaypoint(5, -10566.57, 1083.53, 42.10);
- thisAI->AddWaypoint(6, -10575.83, 1082.34, 39.46);
- thisAI->AddWaypoint(7, -10585.67, 1081.08, 37.77);
- thisAI->AddWaypoint(8, -10600.08, 1078.19, 36.23);
- thisAI->AddWaypoint(9, -10608.69, 1076.08, 35.88);
- thisAI->AddWaypoint(10, -10621.26, 1073.00, 35.40);
- thisAI->AddWaypoint(11, -10638.12, 1060.18, 33.61);
- thisAI->AddWaypoint(12, -10655.87, 1038.99, 33.48);
- thisAI->AddWaypoint(13, -10664.68, 1030.54, 32.70);
- thisAI->AddWaypoint(14, -10708.68, 1033.86, 33.32);
- thisAI->AddWaypoint(15, -10754.43, 1017.93, 32.79);
- thisAI->AddWaypoint(16, -10802.26, 1018.01, 32.16);
- thisAI->AddWaypoint(17, -10832.60, 1009.04, 32.71);
- thisAI->AddWaypoint(18, -10866.56, 1006.51, 31.71); // Fix waypoints from roughly this point, test first to get proper one
- thisAI->AddWaypoint(19, -10879.98, 1005.10, 32.84);
- thisAI->AddWaypoint(20, -10892.45, 1001.32, 34.46);
- thisAI->AddWaypoint(21, -10906.14, 997.11, 36.15);
- thisAI->AddWaypoint(22, -10922.26, 1002.23, 35.74);
- thisAI->AddWaypoint(23, -10936.32, 1023.38, 36.52);
- thisAI->AddWaypoint(24, -10933.35, 1052.61, 35.85);
- thisAI->AddWaypoint(25, -10940.25, 1077.66, 36.49);
- thisAI->AddWaypoint(26, -10957.09, 1099.33, 36.83);
- thisAI->AddWaypoint(27, -10956.53, 1119.90, 36.73);
- thisAI->AddWaypoint(28, -10939.30, 1150.75, 37.42);
- thisAI->AddWaypoint(29, -10915.14, 1202.09, 36.55);
- thisAI->AddWaypoint(30, -10892.59, 1257.03, 33.37);
- thisAI->AddWaypoint(31, -10891.93, 1306.66, 35.45);
- thisAI->AddWaypoint(32, -10896.17, 1327.86, 37.77);
- thisAI->AddWaypoint(33, -10906.03, 1368.05, 40.91);
- thisAI->AddWaypoint(34, -10910.18, 1389.33, 42.62);
- thisAI->AddWaypoint(35, -10915.42, 1417.72, 42.93);
- thisAI->AddWaypoint(36, -10926.37, 1421.18, 43.04); // walk here and say
- thisAI->AddWaypoint(37, -10952.31, 1421.74, 43.40);
- thisAI->AddWaypoint(38, -10980.04, 1411.38, 42.79);
- thisAI->AddWaypoint(39, -11006.06, 1420.47, 43.26);
- thisAI->AddWaypoint(40, -11021.98, 1450.59, 43.09);
- thisAI->AddWaypoint(41, -11025.36, 1491.59, 43.15);
- thisAI->AddWaypoint(42, -11036.09, 1508.32, 43.28);
- thisAI->AddWaypoint(43, -11060.68, 1526.72, 43.19);
- thisAI->AddWaypoint(44, -11072.75, 1527.77, 43.20, 5000);// say and quest credit
-
- return (CreatureAI*)thisAI;
-}
-
-void AddSC_westfall()
-{
- Script *newscript;
-
- newscript = new Script;
- newscript->Name="npc_defias_traitor";
- newscript->GetAI = &GetAI_npc_defias_traitor;
- newscript->pQuestAccept = &QuestAccept_npc_defias_traitor;
- newscript->RegisterSelf();
-}
+/* Copyright (C) 2006 - 2008 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
+ * 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
+ */
+
+/* ScriptData
+SDName: Westfall
+SD%Complete: 90
+SDComment: Quest support: 155
+SDCategory: Westfall
+EndScriptData */
+
+/* ContentData
+npc_defias_traitor
+EndContentData */
+
+#include "precompiled.h"
+#include "../../npc/npc_escortAI.h"
+
+#define SAY_START -1000101
+#define SAY_PROGRESS -1000102
+#define SAY_END -1000103
+#define SAY_AGGRO_1 -1000104
+#define SAY_AGGRO_2 -1000105
+
+#define QUEST_DEFIAS_BROTHERHOOD 155
+
+struct TRINITY_DLL_DECL npc_defias_traitorAI : public npc_escortAI
+{
+ npc_defias_traitorAI(Creature *c) : npc_escortAI(c) {Reset();}
+
+ bool IsWalking;
+
+ void WaypointReached(uint32 i)
+ {
+ Unit* player = Unit::GetUnit((*m_creature), PlayerGUID);
+
+ if (!player)
+ return;
+
+ if (IsWalking && !m_creature->HasUnitMovementFlag(MOVEMENTFLAG_WALK_MODE))
+ m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
+
+ switch (i)
+ {
+ case 35:
+ IsWalking = true;
+ break;
+ case 36:
+ DoScriptText(SAY_PROGRESS, m_creature, player);
+ break;
+ case 44:
+ DoScriptText(SAY_END, m_creature, player);
+ {
+ if (player && player->GetTypeId() == TYPEID_PLAYER)
+ ((Player*)player)->GroupEventHappens(QUEST_DEFIAS_BROTHERHOOD,m_creature);
+ }
+ break;
+ }
+ }
+ void Aggro(Unit* who)
+ {
+ switch(rand()%2)
+ {
+ case 0: DoScriptText(SAY_AGGRO_1, m_creature, who); break;
+ case 1: DoScriptText(SAY_AGGRO_2, m_creature, who); break;
+ }
+ }
+
+ void Reset()
+ {
+ if (IsWalking && !m_creature->HasUnitMovementFlag(MOVEMENTFLAG_WALK_MODE))
+ {
+ m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
+ return;
+ }
+ IsWalking = false;
+ }
+
+ void JustDied(Unit* killer)
+ {
+ if (PlayerGUID)
+ {
+ if (Unit* player = Unit::GetUnit((*m_creature), PlayerGUID))
+ ((Player*)player)->FailQuest(QUEST_DEFIAS_BROTHERHOOD);
+ }
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ npc_escortAI::UpdateAI(diff);
+ }
+};
+
+bool QuestAccept_npc_defias_traitor(Player* player, Creature* creature, Quest const* quest)
+{
+ if (quest->GetQuestId() == QUEST_DEFIAS_BROTHERHOOD)
+ {
+ ((npc_escortAI*)(creature->AI()))->Start(true, true, true, player->GetGUID());
+ DoScriptText(SAY_START, creature, player);
+ }
+
+ return true;
+}
+
+CreatureAI* GetAI_npc_defias_traitor(Creature *_Creature)
+{
+ npc_defias_traitorAI* thisAI = new npc_defias_traitorAI(_Creature);
+
+ thisAI->AddWaypoint(0, -10508.40, 1068.00, 55.21);
+ thisAI->AddWaypoint(1, -10518.30, 1074.84, 53.96);
+ thisAI->AddWaypoint(2, -10534.82, 1081.92, 49.88);
+ thisAI->AddWaypoint(3, -10546.51, 1084.88, 50.13);
+ thisAI->AddWaypoint(4, -10555.29, 1084.45, 45.75);
+ thisAI->AddWaypoint(5, -10566.57, 1083.53, 42.10);
+ thisAI->AddWaypoint(6, -10575.83, 1082.34, 39.46);
+ thisAI->AddWaypoint(7, -10585.67, 1081.08, 37.77);
+ thisAI->AddWaypoint(8, -10600.08, 1078.19, 36.23);
+ thisAI->AddWaypoint(9, -10608.69, 1076.08, 35.88);
+ thisAI->AddWaypoint(10, -10621.26, 1073.00, 35.40);
+ thisAI->AddWaypoint(11, -10638.12, 1060.18, 33.61);
+ thisAI->AddWaypoint(12, -10655.87, 1038.99, 33.48);
+ thisAI->AddWaypoint(13, -10664.68, 1030.54, 32.70);
+ thisAI->AddWaypoint(14, -10708.68, 1033.86, 33.32);
+ thisAI->AddWaypoint(15, -10754.43, 1017.93, 32.79);
+ thisAI->AddWaypoint(16, -10802.26, 1018.01, 32.16);
+ thisAI->AddWaypoint(17, -10832.60, 1009.04, 32.71);
+ thisAI->AddWaypoint(18, -10866.56, 1006.51, 31.71); // Fix waypoints from roughly this point, test first to get proper one
+ thisAI->AddWaypoint(19, -10879.98, 1005.10, 32.84);
+ thisAI->AddWaypoint(20, -10892.45, 1001.32, 34.46);
+ thisAI->AddWaypoint(21, -10906.14, 997.11, 36.15);
+ thisAI->AddWaypoint(22, -10922.26, 1002.23, 35.74);
+ thisAI->AddWaypoint(23, -10936.32, 1023.38, 36.52);
+ thisAI->AddWaypoint(24, -10933.35, 1052.61, 35.85);
+ thisAI->AddWaypoint(25, -10940.25, 1077.66, 36.49);
+ thisAI->AddWaypoint(26, -10957.09, 1099.33, 36.83);
+ thisAI->AddWaypoint(27, -10956.53, 1119.90, 36.73);
+ thisAI->AddWaypoint(28, -10939.30, 1150.75, 37.42);
+ thisAI->AddWaypoint(29, -10915.14, 1202.09, 36.55);
+ thisAI->AddWaypoint(30, -10892.59, 1257.03, 33.37);
+ thisAI->AddWaypoint(31, -10891.93, 1306.66, 35.45);
+ thisAI->AddWaypoint(32, -10896.17, 1327.86, 37.77);
+ thisAI->AddWaypoint(33, -10906.03, 1368.05, 40.91);
+ thisAI->AddWaypoint(34, -10910.18, 1389.33, 42.62);
+ thisAI->AddWaypoint(35, -10915.42, 1417.72, 42.93);
+ thisAI->AddWaypoint(36, -10926.37, 1421.18, 43.04); // walk here and say
+ thisAI->AddWaypoint(37, -10952.31, 1421.74, 43.40);
+ thisAI->AddWaypoint(38, -10980.04, 1411.38, 42.79);
+ thisAI->AddWaypoint(39, -11006.06, 1420.47, 43.26);
+ thisAI->AddWaypoint(40, -11021.98, 1450.59, 43.09);
+ thisAI->AddWaypoint(41, -11025.36, 1491.59, 43.15);
+ thisAI->AddWaypoint(42, -11036.09, 1508.32, 43.28);
+ thisAI->AddWaypoint(43, -11060.68, 1526.72, 43.19);
+ thisAI->AddWaypoint(44, -11072.75, 1527.77, 43.20, 5000);// say and quest credit
+
+ return (CreatureAI*)thisAI;
+}
+
+void AddSC_westfall()
+{
+ Script *newscript;
+
+ newscript = new Script;
+ newscript->Name="npc_defias_traitor";
+ newscript->GetAI = &GetAI_npc_defias_traitor;
+ newscript->pQuestAccept = &QuestAccept_npc_defias_traitor;
+ newscript->RegisterSelf();
+}
diff --git a/src/bindings/scripts/scripts/zone/zulaman/boss_akilzon.cpp b/src/bindings/scripts/scripts/zone/zulaman/boss_akilzon.cpp
index 4b9eb2afa88..8f4b4b8d942 100644
--- a/src/bindings/scripts/scripts/zone/zulaman/boss_akilzon.cpp
+++ b/src/bindings/scripts/scripts/zone/zulaman/boss_akilzon.cpp
@@ -169,7 +169,7 @@ struct TRINITY_DLL_DECL boss_akilzonAI : public ScriptedAI
WorldPacket data(SMSG_WEATHER, (4+4+4));
data << uint32(weather) << (float)grade << uint8(0);
- ((InstanceMap*)map)->SendToPlayers(&data);
+ map->SendToPlayers(&data);
}
void HandleStormSequence(Unit *Cloud) // 1: begin, 2-9: tick, 10: end
diff --git a/src/bindings/scripts/scripts/zone/zulaman/boss_hexlord.cpp b/src/bindings/scripts/scripts/zone/zulaman/boss_hexlord.cpp
index 4d36a138765..09d24f4d42f 100644
--- a/src/bindings/scripts/scripts/zone/zulaman/boss_hexlord.cpp
+++ b/src/bindings/scripts/scripts/zone/zulaman/boss_hexlord.cpp
@@ -433,7 +433,8 @@ struct TRINITY_DLL_DECL boss_hex_lord_malacrassAI : public ScriptedAI
}
break;
}
- m_creature->CastSpell(target, PlayerAbility[PlayerClass][random].spell, false);
+ if(target)
+ m_creature->CastSpell(target, PlayerAbility[PlayerClass][random].spell, false);
}
};
diff --git a/src/bindings/scripts/scripts/zone/zulaman/boss_janalai.cpp b/src/bindings/scripts/scripts/zone/zulaman/boss_janalai.cpp
index 463425a5ef3..cc176127282 100644
--- a/src/bindings/scripts/scripts/zone/zulaman/boss_janalai.cpp
+++ b/src/bindings/scripts/scripts/zone/zulaman/boss_janalai.cpp
@@ -117,6 +117,13 @@ struct TRINITY_DLL_DECL boss_janalaiAI : public ScriptedAI
{
pInstance =((ScriptedInstance*)c->GetInstanceData());
Reset();
+
+ SpellEntry *TempSpell = (SpellEntry*)GetSpellStore()->LookupEntry(SPELL_HATCH_EGG);
+ if(TempSpell && TempSpell->EffectImplicitTargetA[0] != 1)
+ {
+ TempSpell->EffectImplicitTargetA[0] = 1;
+ TempSpell->EffectImplicitTargetB[0] = 0;
+ }
}
ScriptedInstance *pInstance;
diff --git a/src/bindings/scripts/scripts/zone/zulaman/instance_zulaman.cpp b/src/bindings/scripts/scripts/zone/zulaman/instance_zulaman.cpp
index c0c68c1a2e4..bb847169e78 100644
--- a/src/bindings/scripts/scripts/zone/zulaman/instance_zulaman.cpp
+++ b/src/bindings/scripts/scripts/zone/zulaman/instance_zulaman.cpp
@@ -176,7 +176,7 @@ struct TRINITY_DLL_DECL instance_zulaman : public ScriptedInstance
{
WorldPacket data(SMSG_UPDATE_WORLD_STATE, 8);
data << field << value;
- ((InstanceMap*)instance)->SendToPlayers(&data);
+ instance->SendToPlayers(&data);
}
const char* Save()
diff --git a/src/bindings/scripts/scripts/zone/zulaman/zulaman.cpp b/src/bindings/scripts/scripts/zone/zulaman/zulaman.cpp
index b28b8a9bd06..a5706027f55 100644
--- a/src/bindings/scripts/scripts/zone/zulaman/zulaman.cpp
+++ b/src/bindings/scripts/scripts/zone/zulaman/zulaman.cpp
@@ -103,7 +103,8 @@ CreatureAI* GetAI_npc_forest_frog(Creature *_Creature)
#define GOSSIP_HOSTAGE1 "I am glad to help you."
-static uint32 HostageInfo[] = {23790, 23999, 24024, 24001};
+static uint32 HostageEntry[] = {23790, 23999, 24024, 24001};
+static uint32 ChestEntry[] = {186648, 187021, 186672, 186667};
struct TRINITY_DLL_DECL npc_zulaman_hostageAI : public ScriptedAI
{
@@ -142,11 +143,20 @@ bool GossipSelect_npc_zulaman_hostage(Player* player, Creature* _Creature, uint3
ScriptedInstance* pInstance = ((ScriptedInstance*)_Creature->GetInstanceData());
if(pInstance)
{
- uint8 progress = pInstance->GetData(DATA_CHESTLOOTED);
+ //uint8 progress = pInstance->GetData(DATA_CHESTLOOTED);
pInstance->SetData(DATA_CHESTLOOTED, 0);
float x, y, z;
_Creature->GetPosition(x, y, z);
- Creature* summon = _Creature->SummonCreature(HostageInfo[progress], x-2, y, z, 0, TEMPSUMMON_DEAD_DESPAWN, 0);
+ uint32 entry = _Creature->GetEntry();
+ for(uint8 i = 0; i < 4; ++i)
+ {
+ if(HostageEntry[i] == entry)
+ {
+ _Creature->SummonGameObject(ChestEntry[i], x-2, y, z, 0, 0, 0, 0, 0, 0);
+ break;
+ }
+ }
+ /*Creature* summon = _Creature->SummonCreature(HostageInfo[progress], x-2, y, z, 0, TEMPSUMMON_DEAD_DESPAWN, 0);
if(summon)
{
((npc_zulaman_hostageAI*)summon->AI())->PlayerGUID = player->GetGUID();
@@ -154,7 +164,7 @@ bool GossipSelect_npc_zulaman_hostage(Player* player, Creature* _Creature, uint3
summon->SetDisplayId(10056);
summon->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
summon->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
- }
+ }*/
}
return true;
}
diff --git a/src/framework/Platform/Define.h b/src/framework/Platform/Define.h
index 3c1b50ce21f..395245d3955 100644
--- a/src/framework/Platform/Define.h
+++ b/src/framework/Platform/Define.h
@@ -48,6 +48,7 @@
# define TRINITY_IMPORT __cdecl
# define TRINITY_SCRIPT_EXT ".dll"
# define TRINITY_SCRIPT_NAME "TrinityScript"
+# define TRINITY_PATH_MAX MAX_PATH
#else //PLATFORM != PLATFORM_WINDOWS
# define TRINITY_LIBRARY_HANDLE void*
# define TRINITY_EXPORT export
@@ -61,6 +62,7 @@
# endif //__APPLE_CC__ && BIG_ENDIAN
# define TRINITY_SCRIPT_EXT ".so"
# define TRINITY_SCRIPT_NAME "libtrinityscript"
+# define TRINITY_PATH_MAX PATH_MAX
#endif //PLATFORM
#if PLATFORM == PLATFORM_WINDOWS
diff --git a/src/framework/Utilities/LinkedList.h b/src/framework/Utilities/LinkedList.h
index fe4d1b7dd8d..3f9c99b31ff 100644
--- a/src/framework/Utilities/LinkedList.h
+++ b/src/framework/Utilities/LinkedList.h
@@ -46,6 +46,11 @@ class LinkedListElement
LinkedListElement * prev() { return hasPrev() ? iPrev : NULL; }
LinkedListElement const* prev() const { return hasPrev() ? iPrev : NULL; }
+ LinkedListElement * nocheck_next() { return iNext; }
+ LinkedListElement const* nocheck_next() const { return iNext; }
+ LinkedListElement * nocheck_prev() { return iPrev; }
+ LinkedListElement const* nocheck_prev() const { return iPrev; }
+
void delink()
{
if(isInList())
@@ -136,7 +141,10 @@ class LinkedListHead
typedef ptrdiff_t difference_type;
typedef ptrdiff_t distance_type;
typedef _Ty* pointer;
+ typedef _Ty const* const_pointer;
typedef _Ty& reference;
+ typedef _Ty const & const_reference;
+
Iterator() : _Ptr(0)
{ // construct with null node pointer
@@ -146,6 +154,17 @@ class LinkedListHead
{ // construct with node pointer _Pnode
}
+ Iterator& operator=(Iterator const &_Right)
+ {
+ return (*this) = _Right._Ptr;
+ }
+
+ Iterator& operator=(const_pointer const &_Right)
+ {
+ _Ptr = (pointer)_Right;
+ return (*this);
+ }
+
reference operator*()
{ // return designated value
return *_Ptr;
@@ -202,6 +221,17 @@ class LinkedListHead
return (!(*this == _Right));
}
+ bool operator==(const_reference _Right) const
+ { // test for reference equality
+ return (_Ptr == &_Right);
+ }
+
+ bool operator!=(const_reference _Right) const
+ { // test for reference equality
+ return (_Ptr != &_Right);
+ }
+
+
pointer _Mynode()
{ // return node pointer
return (_Ptr);
diff --git a/src/framework/Utilities/LinkedReference/Reference.h b/src/framework/Utilities/LinkedReference/Reference.h
index ca837c81f91..bce0e0f387c 100644
--- a/src/framework/Utilities/LinkedReference/Reference.h
+++ b/src/framework/Utilities/LinkedReference/Reference.h
@@ -73,9 +73,15 @@ template <class TO, class FROM> class Reference : public LinkedListElement
return iRefTo != NULL;
}
- Reference<TO,FROM>* next() { return((Reference<TO,FROM>*)LinkedListElement::next()); }
- Reference<TO,FROM>const* next() const { return((Reference<TO,FROM> const*)LinkedListElement::next()); }
- Reference<TO,FROM>* prev() { return((Reference<TO,FROM>*)LinkedListElement::prev()); }
+ Reference<TO,FROM> * next() { return((Reference<TO,FROM> *) LinkedListElement::next()); }
+ Reference<TO,FROM> const * next() const { return((Reference<TO,FROM> const *) LinkedListElement::next()); }
+ Reference<TO,FROM> * prev() { return((Reference<TO,FROM> *) LinkedListElement::prev()); }
+ Reference<TO,FROM> const * prev() const { return((Reference<TO,FROM> const *) LinkedListElement::prev()); }
+
+ Reference<TO,FROM> * nocheck_next() { return((Reference<TO,FROM> *) LinkedListElement::nocheck_next()); }
+ Reference<TO,FROM> const * nocheck_next() const { return((Reference<TO,FROM> const *) LinkedListElement::nocheck_next()); }
+ Reference<TO,FROM> * nocheck_prev() { return((Reference<TO,FROM> *) LinkedListElement::nocheck_prev()); }
+ Reference<TO,FROM> const * nocheck_prev() const { return((Reference<TO,FROM> const *) LinkedListElement::nocheck_prev()); }
inline TO* operator ->() const { return iRefTo; }
inline TO* getTarget() const { return iRefTo; }
diff --git a/src/game/AggressorAI.cpp b/src/game/AggressorAI.cpp
index 0c45fff79f4..27c1ad6ee6c 100644
--- a/src/game/AggressorAI.cpp
+++ b/src/game/AggressorAI.cpp
@@ -57,7 +57,7 @@ AggressorAI::MoveInLineOfSight(Unit *u)
if(i_creature.IsWithinDistInMap(u, attackRadius) && i_creature.IsWithinLOSInMap(u) )
{
AttackStart(u);
- u->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ //u->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
}
}
}
@@ -98,7 +98,7 @@ void AggressorAI::EnterEvadeMode()
//i_tracker.Reset(TIME_INTERVAL_LOOK);
}
- if(!i_creature.isCharmed())
+ if(!i_creature.GetCharmerOrOwner())
{
i_creature.RemoveAllAuras();
@@ -106,6 +106,8 @@ void AggressorAI::EnterEvadeMode()
if( i_creature.GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE )
i_creature.GetMotionMaster()->MoveTargetedHome();
}
+ else if (i_creature.GetOwner() && i_creature.GetOwner()->isAlive())
+ i_creature.GetMotionMaster()->MoveFollow(i_creature.GetOwner(),PET_FOLLOW_DIST,PET_FOLLOW_ANGLE);
i_creature.DeleteThreatList();
i_victimGuid = 0;
diff --git a/src/game/ArenaTeam.cpp b/src/game/ArenaTeam.cpp
index b8f38f88f52..56c1c0e1746 100644
--- a/src/game/ArenaTeam.cpp
+++ b/src/game/ArenaTeam.cpp
@@ -1,796 +1,782 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
- *
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
- *
- * 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
- */
-
-#include "WorldPacket.h"
-#include "ObjectMgr.h"
-#include "ArenaTeam.h"
-
-ArenaTeam::ArenaTeam()
-{
- Id = 0;
- Type = 0;
- Name = "";
- CaptainGuid = 0;
- BackgroundColor = 0; // background
- EmblemStyle = 0; // icon
- EmblemColor = 0; // icon color
- BorderStyle = 0; // border
- BorderColor = 0; // border color
- stats.games = 0;
- stats.played = 0;
- stats.rank = 0;
- stats.rating = 1500;
- stats.wins = 0;
- stats.wins2 = 0;
-}
-
-ArenaTeam::~ArenaTeam()
-{
-
-}
-
-bool ArenaTeam::create(uint64 captainGuid, uint32 type, std::string ArenaTeamName)
-{
- if(!objmgr.GetPlayer(captainGuid)) // player not exist
- return false;
- if(objmgr.GetArenaTeamByName(ArenaTeamName)) // arena team with this name already exist
- return false;
-
- sLog.outDebug("GUILD: creating arena team %s to leader: %u", ArenaTeamName.c_str(), GUID_LOPART(captainGuid));
-
- CaptainGuid = captainGuid;
- Name = ArenaTeamName;
- Type = type;
-
- QueryResult *result = CharacterDatabase.Query("SELECT MAX(arenateamid) FROM arena_team");
- if( result )
- {
- Id = (*result)[0].GetUInt32()+1;
- delete result;
- }
- else Id = 1;
-
- // ArenaTeamName already assigned to ArenaTeam::name, use it to encode string for DB
- CharacterDatabase.escape_string(ArenaTeamName);
-
- CharacterDatabase.BeginTransaction();
- // CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid='%u'", Id); - MAX(arenateam)+1 not exist
- CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid='%u'", Id);
- CharacterDatabase.PExecute("INSERT INTO arena_team (arenateamid,name,captainguid,type,BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor) "
- "VALUES('%u','%s','%u','%u','%u','%u','%u','%u','%u')",
- Id, ArenaTeamName.c_str(), GUID_LOPART(CaptainGuid), Type, BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor);
- CharacterDatabase.PExecute("INSERT INTO arena_team_stats (arenateamid, rating, games, wins, played, wins2, rank) VALUES "
- "('%u', '%u', '%u', '%u', '%u', '%u', '%u')", Id,stats.rating,stats.games,stats.wins,stats.played,stats.wins2,stats.rank);
-
- CharacterDatabase.CommitTransaction();
-
- AddMember(CaptainGuid);
- return true;
-}
-
-bool ArenaTeam::AddMember(uint64 PlayerGuid)
-{
- std::string plName;
- uint8 plClass;
-
- // arena team is full (can't have more than type * 2 players!)
- if(GetMembersSize() >= GetType() * 2)
- return false;
-
- Player *pl = objmgr.GetPlayer(PlayerGuid);
- if(pl)
- {
- if(pl->GetArenaTeamId(GetSlot()))
- {
- sLog.outError("Arena::AddMember() : player already in this sized team");
- return false;
- }
-
- plClass = (uint8)pl->getClass();
- plName = pl->GetName();
- }
- else
- {
- // 0 1
- QueryResult *result = CharacterDatabase.PQuery("SELECT name, class FROM characters WHERE guid='%u'", GUID_LOPART(PlayerGuid));
- if(!result)
- return false;
-
- plName = (*result)[0].GetCppString();
- plClass = (*result)[1].GetUInt8();
- delete result;
-
- // check if player already in arenateam of that size
- if(Player::GetArenaTeamIdFromDB(PlayerGuid, GetType()) != 0)
- {
- sLog.outError("Arena::AddMember() : player already in this sized team");
- return false;
- }
- }
-
- // remove all player signs from another petitions
- // this will be prevent attempt joining player to many arenateams and corrupt arena team data integrity
- Player::RemovePetitionsAndSigns(PlayerGuid, GetType());
-
- ArenaTeamMember newmember;
- newmember.name = plName;
- newmember.guid = PlayerGuid;
- newmember.Class = plClass;
- newmember.played_season = 0;
- newmember.played_week = 0;
- newmember.wons_season = 0;
- newmember.wons_week = 0;
- members.push_back(newmember);
-
- CharacterDatabase.PExecute("INSERT INTO arena_team_member (arenateamid,guid) VALUES ('%u', '%u')", Id, GUID_LOPART(newmember.guid));
-
- if(pl)
- {
- pl->SetInArenaTeam(Id, GetSlot());
- pl->SetArenaTeamIdInvited(0);
- // personal rating
- pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 5, 1500);
- }
-
- // hide promote/remove buttons
- if(CaptainGuid != PlayerGuid)
- {
- if(pl)
- pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1);
- }
-
- // setuint32valueindb is asynch, can't be used here
- Tokens tokens;
- if(!Player::LoadValuesArrayFromDB(tokens,PlayerGuid))
- return false;
-
- // arena team id
- uint16 index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6);
- char buf[11];
- snprintf(buf,11,"%u",Id);
- tokens[index] = buf;
- // pers rating
- index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 5;
- buf[11];
- snprintf(buf,11,"%u",1500);
- tokens[index] = buf;
- // hide promote/remove buttons
- if(CaptainGuid != PlayerGuid)
- {
- index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6);
- buf[11];
- snprintf(buf,11,"%u",1);
- tokens[index] = buf;
- }
-
- Player::SaveValuesArrayInDB(tokens,PlayerGuid);
-
- return true;
-}
-
-bool ArenaTeam::LoadArenaTeamFromDB(uint32 ArenaTeamId)
-{
- QueryResult *result = CharacterDatabase.PQuery("SELECT arenateamid,name,captainguid,type,BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor FROM arena_team WHERE arenateamid = '%u'", ArenaTeamId);
-
- if(!result)
- return false;
-
- Field *fields = result->Fetch();
-
- Id = fields[0].GetUInt32();
- Name = fields[1].GetCppString();
- CaptainGuid = MAKE_NEW_GUID(fields[2].GetUInt32(), 0, HIGHGUID_PLAYER);
- Type = fields[3].GetUInt32();
- BackgroundColor = fields[4].GetUInt32();
- EmblemStyle = fields[5].GetUInt32();
- EmblemColor = fields[6].GetUInt32();
- BorderStyle = fields[7].GetUInt32();
- BorderColor = fields[8].GetUInt32();
-
- delete result;
-
- // only load here, so additional checks can be made
- LoadStatsFromDB(ArenaTeamId);
- LoadMembersFromDB(ArenaTeamId);
-
- if(!GetMembersSize())
- {
- // arena team is empty, delete from db
- CharacterDatabase.BeginTransaction();
- CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", ArenaTeamId);
- CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId);
- CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", ArenaTeamId);
- CharacterDatabase.CommitTransaction();
- // return false
- return false;
- }
-
- return true;
-}
-
-void ArenaTeam::LoadStatsFromDB(uint32 ArenaTeamId)
-{
- // 0 1 2 3 4 5
- QueryResult *result = CharacterDatabase.PQuery("SELECT rating,games,wins,played,wins2,rank FROM arena_team_stats WHERE arenateamid = '%u'", ArenaTeamId);
-
- if(!result)
- return;
-
- Field *fields = result->Fetch();
-
- stats.rating = fields[0].GetUInt32();
- stats.games = fields[1].GetUInt32();
- stats.wins = fields[2].GetUInt32();
- stats.played = fields[3].GetUInt32();
- stats.wins2 = fields[4].GetUInt32();
- stats.rank = fields[5].GetUInt32();
-
- delete result;
-}
-
-void ArenaTeam::LoadMembersFromDB(uint32 ArenaTeamId)
-{
- Field *fields;
-
- QueryResult *result = CharacterDatabase.PQuery("SELECT guid,played_week,wons_week,played_season,wons_season,points_to_add FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId);
- if(!result)
- return;
-
- do
- {
- fields = result->Fetch();
- ArenaTeamMember newmember;
- newmember.guid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
- // check if this member is in this arenateam
- // based on character data field
- if(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6),newmember.guid) != ArenaTeamId)
- {
- // the player's registered arena team for this slot isn't this team, so delete member info from here
- CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE guid = '%u' AND arenateamid = '%u'",fields[0].GetUInt32(), ArenaTeamId);
- continue;
- }
- LoadPlayerStats(&newmember);
- newmember.played_week = fields[1].GetUInt32();
- newmember.wons_week = fields[2].GetUInt32();
- newmember.played_season = fields[3].GetUInt32();
- newmember.wons_season = fields[4].GetUInt32();
- members.push_back(newmember);
- }while( result->NextRow() );
- delete result;
-}
-
-void ArenaTeam::LoadPlayerStats(ArenaTeamMember *member)
-{
- Field *fields;
-
- QueryResult *result = CharacterDatabase.PQuery("SELECT name,class FROM characters WHERE guid = '%u'", GUID_LOPART(member->guid));
- if(!result)
- return;
- fields = result->Fetch();
- member->name = fields[0].GetCppString();
- member->Class = fields[1].GetUInt8();
-
- delete result;
-}
-
-void ArenaTeam::SetCaptain(uint64 guid)
-{
- // disable remove/promote buttons
- Player *oldcaptain = objmgr.GetPlayer(GetCaptain());
- if(oldcaptain)
- oldcaptain->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1);
- else
- Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1, GetCaptain());
-
- // set new captain
- CaptainGuid = guid;
-
- // update database
- CharacterDatabase.PExecute("UPDATE arena_team SET captainguid = '%u' WHERE arenateamid = '%u'", GUID_LOPART(guid), Id);
-
- // enable remove/promote buttons
- Player *newcaptain = objmgr.GetPlayer(guid);
- if(newcaptain)
- newcaptain->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 0);
- else
- Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 0, guid);
-}
-
-void ArenaTeam::DelMember(uint64 guid)
-{
- MemberList::iterator itr;
- for (itr = members.begin(); itr != members.end(); itr++)
- {
- if (itr->guid == guid)
- {
- members.erase(itr);
- break;
- }
- }
-
- Player *player = objmgr.GetPlayer(guid);
- // this will be ugly. because of the asynchronous sql handling, we have to set all the fields of the player at once, and save them at once, or else the save will only modify the last field.
- // rip off of setuint32valueindb
- if(player)
- {
- player->SetInArenaTeam(0, GetSlot());
- player->GetSession()->SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, GetName(), "", 0);
- // delete all info regarding this team
- for(int i = 0; i < 6; ++i)
- {
- player->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i, 0);
- }
- }
-
- // we have to do it this way, setuint32valueindb is asynch, unsafe to use multiple times in a row on the same player
- Tokens tokens;
- if(!Player::LoadValuesArrayFromDB(tokens,guid))
- return;
-
- for(int i = 0; i < 6; ++i)
- {
- uint16 index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i;
- char buf[11];
- snprintf(buf,11,"%u",0);
- tokens[index] = buf;
- }
-
- Player::SaveValuesArrayInDB(tokens,guid);
-
- // only delete from this arena team!
- CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u' AND guid = '%u'", GetId(), GUID_LOPART(guid));
-}
-
-void ArenaTeam::Disband(WorldSession *session)
-{
- // event
- WorldPacket data;
- session->BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_DISBANDED_S, 2, session->GetPlayerName(), GetName(), "");
- BroadcastPacket(&data);
-
- uint32 count = members.size();
- uint64 *memberGuids = new uint64[count];
-
- MemberList::iterator itr;
- uint32 i=0;
- for(itr = members.begin(); itr != members.end(); itr++)
- {
- memberGuids[i] = itr->guid;
- ++i;
- }
-
- for(uint32 j = 0; j < count; j++)
- DelMember(memberGuids[j]);
- delete[] memberGuids;
-
- CharacterDatabase.BeginTransaction();
- CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", Id);
- CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", Id);
- CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", Id);
- CharacterDatabase.CommitTransaction();
- objmgr.RemoveArenaTeam(this);
-}
-
-void ArenaTeam::Roster(WorldSession *session)
-{
- Player *pl = NULL;
-
- WorldPacket data(SMSG_ARENA_TEAM_ROSTER, 100);
- data << uint32(GetId()); // arena team id
- data << uint32(GetMembersSize()); // members count
- data << uint32(GetType()); // arena team type?
-
- for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
- {
- pl = objmgr.GetPlayer(itr->guid);
- if(pl)
- {
- data << uint64(pl->GetGUID()); // guid
- data << uint8(1); // online flag
- data << pl->GetName(); // member name
- data << uint32(itr->guid == GetCaptain() ? 0 : 1);// unknown
- data << uint8(pl->getLevel()); // unknown, probably level
- data << uint8(pl->getClass()); // class
- data << uint32(itr->played_week); // played this week
- data << uint32(itr->wons_week); // wins this week
- data << uint32(itr->played_season); // played this season
- data << uint32(itr->wons_season); // wins this season
- data << uint32(pl->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + GetSlot() * 6 + 5)); // personal rating?
- }
- else
- {
- data << uint64(itr->guid); // guid
- data << uint8(0); // online flag
- data << itr->name; // member name
- data << uint32(itr->guid == GetCaptain() ? 0 : 1);// unknown
- data << uint8(0); // unknown, level?
- data << uint8(itr->Class); // class
- data << uint32(itr->played_week); // played this week
- data << uint32(itr->wons_week); // wins this week
- data << uint32(itr->played_season); // played this season
- data << uint32(itr->wons_season); // wins this season
- data << uint32(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + GetSlot() * 6 + 5, itr->guid)); // personal rating?
- }
- }
- session->SendPacket(&data);
- sLog.outDebug("WORLD: Sent SMSG_ARENA_TEAM_ROSTER");
-}
-
-void ArenaTeam::Query(WorldSession *session)
-{
- WorldPacket data(SMSG_ARENA_TEAM_QUERY_RESPONSE, 4*7+GetName().size()+1);
- data << uint32(GetId()); // team id
- data << GetName(); // team name
- data << uint32(GetType()); // arena team type (2=2x2, 3=3x3 or 5=5x5)
- data << uint32(BackgroundColor); // background color
- data << uint32(EmblemStyle); // emblem style
- data << uint32(EmblemColor); // emblem color
- data << uint32(BorderStyle); // border style
- data << uint32(BorderColor); // border color
- session->SendPacket(&data);
- sLog.outDebug("WORLD: Sent SMSG_ARENA_TEAM_QUERY_RESPONSE");
-}
-
-void ArenaTeam::Stats(WorldSession *session)
-{
- WorldPacket data(SMSG_ARENA_TEAM_STATS, 4*7);
- data << uint32(GetId()); // arena team id
- data << uint32(stats.rating); // rating
- data << uint32(stats.games); // games
- data << uint32(stats.wins); // wins
- data << uint32(stats.played); // played
- data << uint32(stats.wins2); // wins(again o_O)
- data << uint32(stats.rank); // rank
- session->SendPacket(&data);
-}
-
-void ArenaTeam::NotifyStatsChanged()
-{
- // this is called after a rated match ended
- // updates arena team stats for every member of the team (not only the ones who participated!)
- for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
- {
- Player * plr=objmgr.GetPlayer(itr->guid);
- if(plr)
- Stats(plr->GetSession());
- }
-}
-
-void ArenaTeam::InspectStats(WorldSession *session, uint64 guid)
-{
- WorldPacket data(MSG_INSPECT_ARENA_TEAMS, 8+1+4*6);
- data << uint64(guid); // player guid
- data << uint8(GetSlot()); // slot (0...2)
- data << uint32(GetId()); // arena team id
- data << uint32(stats.rating); // rating
- data << uint32(stats.played); // season played
- data << uint32(stats.wins2); // season wins
- uint32 participated = 0;
- for(MemberList::iterator itr = members.begin(); itr!= members.end(); ++itr)
- {
- if(itr->guid == guid)
- {
- participated = itr->played_season;
- break;
- }
- }
- data << uint32(participated); // played (count of all games, that the inspected member participated...)
- data << uint32(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + GetSlot() * 6 + 5, guid)); // unk, 2.3.3 (personal rating?)
-
- session->SendPacket(&data);
-}
-
-void ArenaTeam::SetEmblem(uint32 backgroundColor, uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor)
-{
- BackgroundColor = backgroundColor;
- EmblemStyle = emblemStyle;
- EmblemColor = emblemColor;
- BorderStyle = borderStyle;
- BorderColor = borderColor;
-
- CharacterDatabase.PExecute("UPDATE arena_team SET BackgroundColor='%u', EmblemStyle='%u', EmblemColor='%u', BorderStyle='%u', BorderColor='%u' WHERE arenateamid='%u'", BackgroundColor, EmblemStyle, EmblemColor, BorderStyle, BorderColor, Id);
-}
-
-void ArenaTeam::SetStats(uint32 stat_type, uint32 value)
-{
- switch(stat_type)
- {
- case STAT_TYPE_RATING:
- stats.rating = value;
- CharacterDatabase.PExecute("UPDATE arena_team_stats SET rating = '%u' WHERE arenateamid = '%u'", value, GetId());
- break;
- case STAT_TYPE_GAMES:
- stats.games = value;
- CharacterDatabase.PExecute("UPDATE arena_team_stats SET games = '%u' WHERE arenateamid = '%u'", value, GetId());
- break;
- case STAT_TYPE_WINS:
- stats.wins = value;
- CharacterDatabase.PExecute("UPDATE arena_team_stats SET wins = '%u' WHERE arenateamid = '%u'", value, GetId());
- break;
- case STAT_TYPE_PLAYED:
- stats.played = value;
- CharacterDatabase.PExecute("UPDATE arena_team_stats SET played = '%u' WHERE arenateamid = '%u'", value, GetId());
- break;
- case STAT_TYPE_WINS2:
- stats.wins2 = value;
- CharacterDatabase.PExecute("UPDATE arena_team_stats SET wins2 = '%u' WHERE arenateamid = '%u'", value, GetId());
- break;
- case STAT_TYPE_RANK:
- stats.rank = value;
- CharacterDatabase.PExecute("UPDATE arena_team_stats SET rank = '%u' WHERE arenateamid = '%u'", value, GetId());
- break;
- default:
- sLog.outDebug("unknown stat type in ArenaTeam::SetStats() %u", stat_type);
- break;
- }
-}
-
-uint8 ArenaTeam::GetSlot() const
-{
- uint8 slot = GetSlotByType(GetType());
- if(slot >= MAX_ARENA_SLOT)
- {
- sLog.outError("Unknown arena team type %u for arena team %u", uint32(GetType()), GetId());
- return 0; // better return existed slot to prevent untelated data curruption
- }
-
- return slot;
-}
-
-void ArenaTeam::BroadcastPacket(WorldPacket *packet)
-{
- for (MemberList::iterator itr = members.begin(); itr != members.end(); itr++)
- {
- Player *player = objmgr.GetPlayer(itr->guid);
- if(player)
- player->GetSession()->SendPacket(packet);
- }
-}
-
-uint8 ArenaTeam::GetSlotByType( uint32 type )
-{
- switch(type)
- {
- case ARENA_TEAM_2v2: return 0;
- case ARENA_TEAM_3v3: return 1;
- case ARENA_TEAM_5v5: return 2;
- default:
- break;
- }
- return 0xFF;
-}
-
-bool ArenaTeam::HaveMember( uint64 guid ) const
-{
- for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
- if(itr->guid==guid)
- return true;
-
- return false;
-}
-
-uint32 ArenaTeam::GetPoints(uint32 MemberRating)
-{
- // returns how many points would be awarded with this team type with this rating
- float points;
-
- uint32 rating = MemberRating + 150 < stats.rating ? MemberRating : stats.rating;
-
- if(rating<=1500)
- {
- points = (float)rating * 0.22f + 14.0f;
- }
- else
- {
- points = 1511.26f / (1.0f + 1639.28f * exp(-0.00412f * (float)rating));
- }
-
- // type penalties for <5v5 teams
- if(Type == ARENA_TEAM_2v2)
- points *= 0.76f;
- else if(Type == ARENA_TEAM_3v3)
- points *= 0.88f;
-
- return (uint32) points;
-}
-
-float ArenaTeam::GetChanceAgainst(uint32 rating)
-{
- // returns the chance to win against a team with the given rating, used in the rating adjustment calculation
- // ELO system
- return 1.0f/(1.0f+exp(log(10.0f)*(float)((float)rating - (float)stats.rating)/400.0f));
-}
-
-int32 ArenaTeam::WonAgainstChance(float chance)
-{
- // called when the team has won, and had 'chance' calculated chance to beat the opponent
- // calculate the rating modification (ELO system with k=32)
- int32 mod = (int32)floor(32.0f * (1.0f - chance));
- // modify the team stats accordingly
- stats.rating += mod;
- stats.games += 1;
- stats.wins += 1;
- stats.played += 1;
- stats.wins2 += 1;
-/* this should be done in .flusharenapoints; not a breaker though.
- uint32 higher_rank = 0;
- QueryResult *result = CharacterDatabase.PQuery("SELECT DISTINCT COUNT(arenateamid) FROM arena_team_stats WHERE rating > '%u' AND arenateamid <> '%u'",stats.rating, Id);
- if(result)
- {
- higher_rank = result->Fetch()->GetUInt32();
- delete result;
- }
- stats.rank = higher_rank + 1;*/
- // return the rating change, used to display it on the results screen
- return mod;
-}
-
-int32 ArenaTeam::LostAgainstChance(float chance)
-{
- // called when the team has lost, and had 'chance' calculated chance to beat the opponent
- // calculate the rating modification (ELO system with k=32)
- int32 mod = (int32)ceil(32.0f * (0.0f - chance));
- // modify the team stats accordingly
- stats.rating += mod;
- stats.games += 1;
- stats.played += 1;
-/* uint32 higher_rank = 0;
- QueryResult *result = CharacterDatabase.PQuery("SELECT DISTINCT COUNT (arenateamid) FROM arena_team_stats WHERE rating > '%u' AND arenateamid <> '%u'",stats.rating, Id);
- if(result)
- {
- higher_rank = result->Fetch()->GetUInt32();
- delete result;
- }
- stats.rank = higher_rank + 1;*/
- // return the rating adjustment for display
- return mod;
-}
-
-void ArenaTeam::MemberLost(Player * plr, uint32 againstrating)
-{
- // called for each participant of a match after losing
- for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
- {
- if(itr->guid == plr->GetGUID())
- {
- // update personal rating
- int32 personalrating = plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5);
- float chance = 1.0f/(1.0f+exp(log(10.0f)*(float)((float)againstrating - (float)personalrating)/400.0f));
- int32 mod = (int32)ceil(32.0f * (0.0f - chance));
- personalrating += mod;
- if(personalrating < 0)
- personalrating = 0;
- plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, personalrating);
- // update personal played stats
- itr->played_week +=1;
- itr->played_season +=1;
- // update the unit fields
- plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->played_week);
- plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->played_season);
- return;
- }
- }
-}
-
-void ArenaTeam::MemberWon(Player * plr, uint32 againstrating)
-{
- // called for each participant after winning a match
- for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
- {
- if(itr->guid == plr->GetGUID())
- {
- // update personal rating
- int32 personalrating = plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5);
- float chance = 1.0f/(1.0f+exp(log(10.0f)*(float)((float)againstrating - (float)personalrating)/400.0f));
- int32 mod = (int32)floor(32.0f * (1.0f - chance));
- personalrating += mod;
- if(personalrating < 0)
- personalrating = 0;
- plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, personalrating);
- // update personal stats
- itr->played_week +=1;
- itr->played_season +=1;
- itr->wons_season += 1;
- itr->wons_week += 1;
- // update unit fields
- plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->played_week);
- plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->played_season);
- return;
- }
- }
-}
-
-void ArenaTeam::UpdateArenaPointsHelper()
-{
- // called after a match has ended and the stats are already modified
- // helper function for arena point distribution (this way, when distributing, no actual calculation is required, just a few comparisons)
- // 10 played games per week is a minimum
- if(stats.games < 10)
- return;
- // to get points, a player has to participate in at least 30% of the matches
- uint32 min_plays = (uint32)ceil(stats.games * 0.3);
- for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
- {
- // the player participated in enough games, update his points
- if(itr->played_week >= min_plays)
- {
- // do it separately for online and offline players
- // online players might have modified personal rating in MemberLost/MemberWon, that's not already saved to DB because of asynch queries
- // offline player cant have a personal rating not matching the db
- Player * plr = objmgr.GetPlayer(itr->guid);
- uint32 points_to_add = 0;
- if(plr)
- points_to_add = GetPoints(plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5));
- else
- points_to_add = GetPoints(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5,itr->guid));
- // it's enough to set the points in memory, the saving is done in separate function
- CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", points_to_add, Id, itr->guid);
- }
- // the player failed to participate in enough games, so no points for him
- else
- {
- CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", 0, Id, itr->guid);
- }
- }
-}
-
-void ArenaTeam::SaveToDB()
-{
- // save team and member stats to db
- // called after a match has ended
- CharacterDatabase.PExecute("UPDATE arena_team_stats SET rating = '%u',games = '%u',played = '%u',rank = '%u',wins = '%u',wins2 = '%u' WHERE arenateamid = '%u'", stats.rating, stats.games, stats.played, stats.rank, stats.wins, stats.wins2, GetId());
- for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
- {
- CharacterDatabase.PExecute("UPDATE arena_team_member SET played_week = '%u', wons_week = '%u', played_season = '%u', wons_season = '%u' WHERE arenateamid = '%u' AND guid = '%u'", itr->played_week, itr->wons_week, itr->played_season, itr->wons_season, Id, itr->guid);
- }
-}
-
-void ArenaTeam::FinishWeek()
-{
- stats.games = 0; // played this week
- stats.wins = 0; // wins this week
- for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
- {
- itr->played_week = 0;
- itr->wons_week = 0;
- }
-}
-
-/*
-arenateam fields (id from 2.3.3 client):
-1414 - arena team id 2v2
-1415 - 0=captain, 1=member
-1416 - played this week
-1417 - played this season
-1418 - unk
-1419 - personal arena rating
-1420 - arena team id 3v3
-1421 - 0=captain, 1=member
-1422 - played this week
-1423 - played this season
-1424 - unk
-1425 - personal arena rating
-1426 - arena team id 5v5
-1427 - 0=captain, 1=member
-1428 - played this week
-1429 - played this season
-1430 - unk
-1431 - personal arena rating
-*/
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ *
+ * 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
+ */
+
+#include "WorldPacket.h"
+#include "ObjectMgr.h"
+#include "ArenaTeam.h"
+
+ArenaTeam::ArenaTeam()
+{
+ Id = 0;
+ Type = 0;
+ Name = "";
+ CaptainGuid = 0;
+ BackgroundColor = 0; // background
+ EmblemStyle = 0; // icon
+ EmblemColor = 0; // icon color
+ BorderStyle = 0; // border
+ BorderColor = 0; // border color
+ stats.games_week = 0;
+ stats.games_season = 0;
+ stats.rank = 0;
+ stats.rating = 1500;
+ stats.wins_week = 0;
+ stats.wins_season = 0;
+}
+
+ArenaTeam::~ArenaTeam()
+{
+
+}
+
+bool ArenaTeam::create(uint64 captainGuid, uint32 type, std::string ArenaTeamName)
+{
+ if(!objmgr.GetPlayer(captainGuid)) // player not exist
+ return false;
+ if(objmgr.GetArenaTeamByName(ArenaTeamName)) // arena team with this name already exist
+ return false;
+
+ sLog.outDebug("GUILD: creating arena team %s to leader: %u", ArenaTeamName.c_str(), GUID_LOPART(captainGuid));
+
+ CaptainGuid = captainGuid;
+ Name = ArenaTeamName;
+ Type = type;
+
+ QueryResult *result = CharacterDatabase.Query("SELECT MAX(arenateamid) FROM arena_team");
+ if( result )
+ {
+ Id = (*result)[0].GetUInt32()+1;
+ delete result;
+ }
+ else Id = 1;
+
+ // ArenaTeamName already assigned to ArenaTeam::name, use it to encode string for DB
+ CharacterDatabase.escape_string(ArenaTeamName);
+
+ CharacterDatabase.BeginTransaction();
+ // CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid='%u'", Id); - MAX(arenateam)+1 not exist
+ CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid='%u'", Id);
+ CharacterDatabase.PExecute("INSERT INTO arena_team (arenateamid,name,captainguid,type,BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor) "
+ "VALUES('%u','%s','%u','%u','%u','%u','%u','%u','%u')",
+ Id, ArenaTeamName.c_str(), GUID_LOPART(CaptainGuid), Type, BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor);
+ CharacterDatabase.PExecute("INSERT INTO arena_team_stats (arenateamid, rating, games, wins, played, wins2, rank) VALUES "
+ "('%u', '%u', '%u', '%u', '%u', '%u', '%u')", Id,stats.rating,stats.games_week,stats.wins_week,stats.games_season,stats.wins_season,stats.rank);
+
+ CharacterDatabase.CommitTransaction();
+
+ AddMember(CaptainGuid);
+ return true;
+}
+
+bool ArenaTeam::AddMember(uint64 PlayerGuid)
+{
+ std::string plName;
+ uint8 plClass;
+
+ // arena team is full (can't have more than type * 2 players!)
+ if(GetMembersSize() >= GetType() * 2)
+ return false;
+
+ Player *pl = objmgr.GetPlayer(PlayerGuid);
+ if(pl)
+ {
+ if(pl->GetArenaTeamId(GetSlot()))
+ {
+ sLog.outError("Arena::AddMember() : player already in this sized team");
+ return false;
+ }
+
+ plClass = (uint8)pl->getClass();
+ plName = pl->GetName();
+ }
+ else
+ {
+ // 0 1
+ QueryResult *result = CharacterDatabase.PQuery("SELECT name, class FROM characters WHERE guid='%u'", GUID_LOPART(PlayerGuid));
+ if(!result)
+ return false;
+
+ plName = (*result)[0].GetCppString();
+ plClass = (*result)[1].GetUInt8();
+ delete result;
+
+ // check if player already in arenateam of that size
+ if(Player::GetArenaTeamIdFromDB(PlayerGuid, GetType()) != 0)
+ {
+ sLog.outError("Arena::AddMember() : player already in this sized team");
+ return false;
+ }
+ }
+
+ // remove all player signs from another petitions
+ // this will be prevent attempt joining player to many arenateams and corrupt arena team data integrity
+ Player::RemovePetitionsAndSigns(PlayerGuid, GetType());
+
+ ArenaTeamMember newmember;
+ newmember.name = plName;
+ newmember.guid = PlayerGuid;
+ newmember.Class = plClass;
+ newmember.games_season = 0;
+ newmember.games_week = 0;
+ newmember.wins_season = 0;
+ newmember.wins_week = 0;
+ //newmember.personal_rating = 1500;
+ members.push_back(newmember);
+
+ CharacterDatabase.PExecute("INSERT INTO arena_team_member (arenateamid,guid) VALUES ('%u', '%u')", Id, GUID_LOPART(newmember.guid));
+
+ if(pl)
+ {
+ pl->SetInArenaTeam(Id, GetSlot());
+ pl->SetArenaTeamIdInvited(0);
+
+ // hide promote/remove buttons
+ if(CaptainGuid != PlayerGuid)
+ pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1);
+ // TODO: personal_rating
+ pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 5, 1500);
+ }
+ else
+ {
+ Tokens tokens;
+ if(Player::LoadValuesArrayFromDB(tokens,PlayerGuid))
+ {
+ Player::SetUInt32ValueInArray(tokens,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6), Id);
+ // hide promote/remove buttons
+ if(CaptainGuid != PlayerGuid)
+ Player::SetUInt32ValueInArray(tokens,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1);
+ // TODO: personal_rating
+ Player::SetUInt32ValueInArray(tokens,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 5, 1500);
+
+ Player::SaveValuesArrayInDB(tokens,PlayerGuid);
+ }
+ }
+ return true;
+}
+
+bool ArenaTeam::LoadArenaTeamFromDB(uint32 ArenaTeamId)
+{
+ QueryResult *result = CharacterDatabase.PQuery("SELECT arenateamid,name,captainguid,type,BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor FROM arena_team WHERE arenateamid = '%u'", ArenaTeamId);
+
+ if(!result)
+ return false;
+
+ Field *fields = result->Fetch();
+
+ Id = fields[0].GetUInt32();
+ Name = fields[1].GetCppString();
+ CaptainGuid = MAKE_NEW_GUID(fields[2].GetUInt32(), 0, HIGHGUID_PLAYER);
+ Type = fields[3].GetUInt32();
+ BackgroundColor = fields[4].GetUInt32();
+ EmblemStyle = fields[5].GetUInt32();
+ EmblemColor = fields[6].GetUInt32();
+ BorderStyle = fields[7].GetUInt32();
+ BorderColor = fields[8].GetUInt32();
+
+ delete result;
+
+ // only load here, so additional checks can be made
+ LoadStatsFromDB(ArenaTeamId);
+ LoadMembersFromDB(ArenaTeamId);
+
+ if(!GetMembersSize())
+ {
+ // arena team is empty, delete from db
+ CharacterDatabase.BeginTransaction();
+ CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", ArenaTeamId);
+ CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId);
+ CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", ArenaTeamId);
+ CharacterDatabase.CommitTransaction();
+ // return false
+ return false;
+ }
+
+ return true;
+}
+
+void ArenaTeam::LoadStatsFromDB(uint32 ArenaTeamId)
+{
+ // 0 1 2 3 4 5
+ QueryResult *result = CharacterDatabase.PQuery("SELECT rating,games,wins,played,wins2,rank FROM arena_team_stats WHERE arenateamid = '%u'", ArenaTeamId);
+
+ if(!result)
+ return;
+
+ Field *fields = result->Fetch();
+
+ stats.rating = fields[0].GetUInt32();
+ stats.games_week = fields[1].GetUInt32();
+ stats.wins_week = fields[2].GetUInt32();
+ stats.games_season = fields[3].GetUInt32();
+ stats.wins_season = fields[4].GetUInt32();
+ stats.rank = fields[5].GetUInt32();
+
+ delete result;
+}
+
+void ArenaTeam::LoadMembersFromDB(uint32 ArenaTeamId)
+{
+ Field *fields;
+
+ QueryResult *result = CharacterDatabase.PQuery("SELECT guid,games_week,wins_week,games_season,wins_season,points_to_add FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId);
+ if(!result)
+ return;
+
+ do
+ {
+ fields = result->Fetch();
+ ArenaTeamMember newmember;
+ newmember.guid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
+ // check if this member is in this arenateam
+ // based on character data field
+ if(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6),newmember.guid) != ArenaTeamId)
+ {
+ // the player's registered arena team for this slot isn't this team, so delete member info from here
+ CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE guid = '%u' AND arenateamid = '%u'",fields[0].GetUInt32(), ArenaTeamId);
+ continue;
+ }
+ LoadPlayerStats(&newmember);
+ newmember.games_week = fields[1].GetUInt32();
+ newmember.wins_week = fields[2].GetUInt32();
+ newmember.games_season = fields[3].GetUInt32();
+ newmember.wins_season = fields[4].GetUInt32();
+ members.push_back(newmember);
+ }while( result->NextRow() );
+ delete result;
+}
+
+void ArenaTeam::LoadPlayerStats(ArenaTeamMember *member)
+{
+ Field *fields;
+
+ QueryResult *result = CharacterDatabase.PQuery("SELECT name,class FROM characters WHERE guid = '%u'", GUID_LOPART(member->guid));
+ if(!result)
+ return;
+ fields = result->Fetch();
+ member->name = fields[0].GetCppString();
+ member->Class = fields[1].GetUInt8();
+
+ delete result;
+}
+
+void ArenaTeam::SetCaptain(uint64 guid)
+{
+ // disable remove/promote buttons
+ Player *oldcaptain = objmgr.GetPlayer(GetCaptain());
+ if(oldcaptain)
+ oldcaptain->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1);
+ else
+ Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1, GetCaptain());
+
+ // set new captain
+ CaptainGuid = guid;
+
+ // update database
+ CharacterDatabase.PExecute("UPDATE arena_team SET captainguid = '%u' WHERE arenateamid = '%u'", GUID_LOPART(guid), Id);
+
+ // enable remove/promote buttons
+ Player *newcaptain = objmgr.GetPlayer(guid);
+ if(newcaptain)
+ newcaptain->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 0);
+ else
+ Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 0, guid);
+}
+
+void ArenaTeam::DelMember(uint64 guid)
+{
+ MemberList::iterator itr;
+ for (itr = members.begin(); itr != members.end(); itr++)
+ {
+ if (itr->guid == guid)
+ {
+ members.erase(itr);
+ break;
+ }
+ }
+
+ Player *player = objmgr.GetPlayer(guid);
+ // this will be ugly. because of the asynchronous sql handling, we have to set all the fields of the player at once, and save them at once, or else the save will only modify the last field.
+ // rip off of setuint32valueindb
+ if(player)
+ {
+ player->SetInArenaTeam(0, GetSlot());
+ player->GetSession()->SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, GetName(), "", 0);
+ // delete all info regarding this team
+ for(int i = 0; i < 6; ++i)
+ {
+ player->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i, 0);
+ }
+ }
+
+ // we have to do it this way, setuint32valueindb is asynch, unsafe to use multiple times in a row on the same player
+ Tokens tokens;
+ if(!Player::LoadValuesArrayFromDB(tokens,guid))
+ return;
+
+ for(int i = 0; i < 6; ++i)
+ {
+ uint16 index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i;
+ char buf[11];
+ snprintf(buf,11,"%u",0);
+ tokens[index] = buf;
+ }
+
+ Player::SaveValuesArrayInDB(tokens,guid);
+
+ // only delete from this arena team!
+ CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u' AND guid = '%u'", GetId(), GUID_LOPART(guid));
+}
+
+void ArenaTeam::Disband(WorldSession *session)
+{
+ // event
+ WorldPacket data;
+ session->BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_DISBANDED_S, 2, session->GetPlayerName(), GetName(), "");
+ BroadcastPacket(&data);
+
+ uint32 count = members.size();
+ uint64 *memberGuids = new uint64[count];
+
+ MemberList::iterator itr;
+ uint32 i=0;
+ for(itr = members.begin(); itr != members.end(); itr++)
+ {
+ memberGuids[i] = itr->guid;
+ ++i;
+ }
+
+ for(uint32 j = 0; j < count; j++)
+ DelMember(memberGuids[j]);
+ delete[] memberGuids;
+
+ CharacterDatabase.BeginTransaction();
+ CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", Id);
+ CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", Id);
+ CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", Id);
+ CharacterDatabase.CommitTransaction();
+ objmgr.RemoveArenaTeam(this);
+}
+
+void ArenaTeam::Roster(WorldSession *session)
+{
+ Player *pl = NULL;
+
+ WorldPacket data(SMSG_ARENA_TEAM_ROSTER, 100);
+ data << uint32(GetId()); // arena team id
+ data << uint32(GetMembersSize()); // members count
+ data << uint32(GetType()); // arena team type?
+
+ for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ pl = objmgr.GetPlayer(itr->guid);
+ if(pl)
+ {
+ data << uint64(pl->GetGUID()); // guid
+ data << uint8(1); // online flag
+ data << pl->GetName(); // member name
+ data << uint32(itr->guid == GetCaptain() ? 0 : 1);// unknown
+ data << uint8(pl->getLevel()); // unknown, probably level
+ data << uint8(pl->getClass()); // class
+ data << uint32(itr->games_week); // played this week
+ data << uint32(itr->wins_week); // wins this week
+ data << uint32(itr->games_season); // played this season
+ data << uint32(itr->wins_season); // wins this season
+ //data << uint32(itr->personal_rating); // personal rating
+ //TODO
+ data << uint32(pl->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + GetSlot() * 6 + 5));
+ }
+ else
+ {
+ data << uint64(itr->guid); // guid
+ data << uint8(0); // online flag
+ data << itr->name; // member name
+ data << uint32(itr->guid == GetCaptain() ? 0 : 1);// unknown
+ data << uint8(0); // unknown, level?
+ data << uint8(itr->Class); // class
+ data << uint32(itr->games_week); // played this week
+ data << uint32(itr->wins_week); // wins this week
+ data << uint32(itr->games_season); // played this season
+ data << uint32(itr->wins_season); // wins this season
+ //data << uint32(itr->personal_rating); // personal rating
+ //TODO
+ data << uint32(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + GetSlot() * 6 + 5, itr->guid));
+ }
+ }
+ session->SendPacket(&data);
+ sLog.outDebug("WORLD: Sent SMSG_ARENA_TEAM_ROSTER");
+}
+
+void ArenaTeam::Query(WorldSession *session)
+{
+ WorldPacket data(SMSG_ARENA_TEAM_QUERY_RESPONSE, 4*7+GetName().size()+1);
+ data << uint32(GetId()); // team id
+ data << GetName(); // team name
+ data << uint32(GetType()); // arena team type (2=2x2, 3=3x3 or 5=5x5)
+ data << uint32(BackgroundColor); // background color
+ data << uint32(EmblemStyle); // emblem style
+ data << uint32(EmblemColor); // emblem color
+ data << uint32(BorderStyle); // border style
+ data << uint32(BorderColor); // border color
+ session->SendPacket(&data);
+ sLog.outDebug("WORLD: Sent SMSG_ARENA_TEAM_QUERY_RESPONSE");
+}
+
+void ArenaTeam::Stats(WorldSession *session)
+{
+ WorldPacket data(SMSG_ARENA_TEAM_STATS, 4*7);
+ data << uint32(GetId()); // arena team id
+ data << uint32(stats.rating); // rating
+ data << uint32(stats.games_week); // games this week
+ data << uint32(stats.wins_week); // wins this week
+ data << uint32(stats.games_season); // played this season
+ data << uint32(stats.wins_season); // wins this season
+ data << uint32(stats.rank); // rank
+ session->SendPacket(&data);
+}
+
+void ArenaTeam::NotifyStatsChanged()
+{
+ // this is called after a rated match ended
+ // updates arena team stats for every member of the team (not only the ones who participated!)
+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ Player * plr=objmgr.GetPlayer(itr->guid);
+ if(plr)
+ Stats(plr->GetSession());
+ }
+}
+
+void ArenaTeam::InspectStats(WorldSession *session, uint64 guid)
+{
+ ArenaTeamMember* member = GetMember(guid);
+ if(!member)
+ return;
+
+ WorldPacket data(MSG_INSPECT_ARENA_TEAMS, 8+1+4*6);
+ data << uint64(guid); // player guid
+ data << uint8(GetSlot()); // slot (0...2)
+ data << uint32(GetId()); // arena team id
+ data << uint32(stats.rating); // rating
+ data << uint32(stats.games_season); // season played
+ data << uint32(stats.wins_season); // season wins
+ data << member->games_season; // played (count of all games, that the inspected member participated...)
+ //data << member->personal_rating; // personal rating
+ //TODO
+ data << uint32(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + GetSlot() * 6 + 5, guid));
+ session->SendPacket(&data);
+}
+
+void ArenaTeam::SetEmblem(uint32 backgroundColor, uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor)
+{
+ BackgroundColor = backgroundColor;
+ EmblemStyle = emblemStyle;
+ EmblemColor = emblemColor;
+ BorderStyle = borderStyle;
+ BorderColor = borderColor;
+
+ CharacterDatabase.PExecute("UPDATE arena_team SET BackgroundColor='%u', EmblemStyle='%u', EmblemColor='%u', BorderStyle='%u', BorderColor='%u' WHERE arenateamid='%u'", BackgroundColor, EmblemStyle, EmblemColor, BorderStyle, BorderColor, Id);
+}
+
+void ArenaTeam::SetStats(uint32 stat_type, uint32 value)
+{
+ switch(stat_type)
+ {
+ case STAT_TYPE_RATING:
+ stats.rating = value;
+ CharacterDatabase.PExecute("UPDATE arena_team_stats SET rating = '%u' WHERE arenateamid = '%u'", value, GetId());
+ break;
+ case STAT_TYPE_GAMES_WEEK:
+ stats.games_week = value;
+ CharacterDatabase.PExecute("UPDATE arena_team_stats SET games = '%u' WHERE arenateamid = '%u'", value, GetId());
+ break;
+ case STAT_TYPE_WINS_WEEK:
+ stats.wins_week = value;
+ CharacterDatabase.PExecute("UPDATE arena_team_stats SET wins = '%u' WHERE arenateamid = '%u'", value, GetId());
+ break;
+ case STAT_TYPE_GAMES_SEASON:
+ stats.games_season = value;
+ CharacterDatabase.PExecute("UPDATE arena_team_stats SET played = '%u' WHERE arenateamid = '%u'", value, GetId());
+ break;
+ case STAT_TYPE_WINS_SEASON:
+ stats.wins_season = value;
+ CharacterDatabase.PExecute("UPDATE arena_team_stats SET wins2 = '%u' WHERE arenateamid = '%u'", value, GetId());
+ break;
+ case STAT_TYPE_RANK:
+ stats.rank = value;
+ CharacterDatabase.PExecute("UPDATE arena_team_stats SET rank = '%u' WHERE arenateamid = '%u'", value, GetId());
+ break;
+ default:
+ sLog.outDebug("unknown stat type in ArenaTeam::SetStats() %u", stat_type);
+ break;
+ }
+}
+
+uint8 ArenaTeam::GetSlot() const
+{
+ uint8 slot = GetSlotByType(GetType());
+ if(slot >= MAX_ARENA_SLOT)
+ {
+ sLog.outError("Unknown arena team type %u for arena team %u", uint32(GetType()), GetId());
+ return 0; // better return existed slot to prevent untelated data curruption
+ }
+
+ return slot;
+}
+
+void ArenaTeam::BroadcastPacket(WorldPacket *packet)
+{
+ for (MemberList::iterator itr = members.begin(); itr != members.end(); itr++)
+ {
+ Player *player = objmgr.GetPlayer(itr->guid);
+ if(player)
+ player->GetSession()->SendPacket(packet);
+ }
+}
+
+uint8 ArenaTeam::GetSlotByType( uint32 type )
+{
+ switch(type)
+ {
+ case ARENA_TEAM_2v2: return 0;
+ case ARENA_TEAM_3v3: return 1;
+ case ARENA_TEAM_5v5: return 2;
+ default:
+ break;
+ }
+ return 0xFF;
+}
+
+bool ArenaTeam::HaveMember( uint64 guid ) const
+{
+ for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
+ if(itr->guid==guid)
+ return true;
+
+ return false;
+}
+
+uint32 ArenaTeam::GetPoints(uint32 MemberRating)
+{
+ // returns how many points would be awarded with this team type with this rating
+ float points;
+
+ uint32 rating = MemberRating + 150 < stats.rating ? MemberRating : stats.rating;
+
+ if(rating<=1500)
+ {
+ points = (float)rating * 0.22f + 14.0f;
+ }
+ else
+ {
+ points = 1511.26f / (1.0f + 1639.28f * exp(-0.00412f * (float)rating));
+ }
+
+ // type penalties for <5v5 teams
+ if(Type == ARENA_TEAM_2v2)
+ points *= 0.76f;
+ else if(Type == ARENA_TEAM_3v3)
+ points *= 0.88f;
+
+ return (uint32) points;
+}
+
+float ArenaTeam::GetChanceAgainst(uint32 rating)
+{
+ // returns the chance to win against a team with the given rating, used in the rating adjustment calculation
+ // ELO system
+ return 1.0f/(1.0f+exp(log(10.0f)*(float)((float)rating - (float)stats.rating)/400.0f));
+}
+
+int32 ArenaTeam::WonAgainstChance(float chance)
+{
+ // called when the team has won, and had 'chance' calculated chance to beat the opponent
+ // calculate the rating modification (ELO system with k=32)
+ int32 mod = (int32)floor(32.0f * (1.0f - chance));
+ // modify the team stats accordingly
+ stats.rating += mod;
+ stats.games_week += 1;
+ stats.wins_week += 1;
+ stats.games_season += 1;
+ stats.wins_season += 1;
+/* this should be done in .flusharenapoints; not a breaker though.
+ uint32 higher_rank = 0;
+ QueryResult *result = CharacterDatabase.PQuery("SELECT DISTINCT COUNT(arenateamid) FROM arena_team_stats WHERE rating > '%u' AND arenateamid <> '%u'",stats.rating, Id);
+ if(result)
+ {
+ higher_rank = result->Fetch()->GetUInt32();
+ delete result;
+ }
+ stats.rank = higher_rank + 1;*/
+ // return the rating change, used to display it on the results screen
+ return mod;
+}
+
+int32 ArenaTeam::LostAgainstChance(float chance)
+{
+ // called when the team has lost, and had 'chance' calculated chance to beat the opponent
+ // calculate the rating modification (ELO system with k=32)
+ int32 mod = (int32)ceil(32.0f * (0.0f - chance));
+ // modify the team stats accordingly
+ stats.rating += mod;
+ stats.games_week += 1;
+ stats.games_season += 1;
+/* uint32 higher_rank = 0;
+ QueryResult *result = CharacterDatabase.PQuery("SELECT DISTINCT COUNT (arenateamid) FROM arena_team_stats WHERE rating > '%u' AND arenateamid <> '%u'",stats.rating, Id);
+ if(result)
+ {
+ higher_rank = result->Fetch()->GetUInt32();
+ delete result;
+ }
+ stats.rank = higher_rank + 1;*/
+ // return the rating adjustment for display
+ return mod;
+}
+
+void ArenaTeam::MemberLost(Player * plr, uint32 againstrating)
+{
+ // called for each participant of a match after losing
+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ if(itr->guid == plr->GetGUID())
+ {
+ // update personal rating
+ int32 personalrating = plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5);
+ float chance = 1.0f/(1.0f+exp(log(10.0f)*(float)((float)againstrating - (float)personalrating)/400.0f));
+ int32 mod = (int32)ceil(32.0f * (0.0f - chance));
+ personalrating += mod;
+ if(personalrating < 0)
+ personalrating = 0;
+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, personalrating);
+ // update personal played stats
+ itr->games_week +=1;
+ itr->games_season +=1;
+ // update the unit fields
+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->games_week);
+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->games_season);
+ return;
+ }
+ }
+}
+
+void ArenaTeam::MemberWon(Player * plr, uint32 againstrating)
+{
+ // called for each participant after winning a match
+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ if(itr->guid == plr->GetGUID())
+ {
+ // update personal rating
+ int32 personalrating = plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5);
+ float chance = 1.0f/(1.0f+exp(log(10.0f)*(float)((float)againstrating - (float)personalrating)/400.0f));
+ int32 mod = (int32)floor(32.0f * (1.0f - chance));
+ personalrating += mod;
+ if(personalrating < 0)
+ personalrating = 0;
+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, personalrating);
+ // update personal stats
+ itr->games_week +=1;
+ itr->games_season +=1;
+ itr->wins_season += 1;
+ itr->wins_week += 1;
+ // update unit fields
+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->games_week);
+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->games_season);
+ return;
+ }
+ }
+}
+
+void ArenaTeam::UpdateArenaPointsHelper()
+{
+ // called after a match has ended and the stats are already modified
+ // helper function for arena point distribution (this way, when distributing, no actual calculation is required, just a few comparisons)
+ // 10 played games per week is a minimum
+ if(stats.games_week < 10)
+ return;
+ // to get points, a player has to participate in at least 30% of the matches
+ uint32 min_plays = (uint32)ceil(stats.games_week * 0.3);
+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ // the player participated in enough games, update his points
+ if(itr->games_week >= min_plays)
+ {
+ // do it separately for online and offline players
+ // online players might have modified personal rating in MemberLost/MemberWon, that's not already saved to DB because of asynch queries
+ // offline player cant have a personal rating not matching the db
+ Player * plr = objmgr.GetPlayer(itr->guid);
+ uint32 points_to_add = 0;
+ if(plr)
+ points_to_add = GetPoints(plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5));
+ else
+ points_to_add = GetPoints(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5,itr->guid));
+ // it's enough to set the points in memory, the saving is done in separate function
+ CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", points_to_add, Id, itr->guid);
+ }
+ // the player failed to participate in enough games, so no points for him
+ else
+ {
+ CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", 0, Id, itr->guid);
+ }
+ }
+}
+
+void ArenaTeam::SaveToDB()
+{
+ // save team and member stats to db
+ // called after a match has ended
+ CharacterDatabase.PExecute("UPDATE arena_team_stats SET rating = '%u',games = '%u',played = '%u',rank = '%u',wins = '%u',wins2 = '%u' WHERE arenateamid = '%u'", stats.rating, stats.games_week, stats.games_season, stats.rank, stats.wins_week, stats.wins_season, GetId());
+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ CharacterDatabase.PExecute("UPDATE arena_team_member SET games_week = '%u', wins_week = '%u', games_season = '%u', wins_season = '%u' WHERE arenateamid = '%u' AND guid = '%u'", itr->games_week, itr->wins_week, itr->games_season, itr->wins_season, Id, itr->guid);
+ }
+}
+
+void ArenaTeam::FinishWeek()
+{
+ stats.games_week = 0; // played this week
+ stats.wins_week = 0; // wins this week
+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ itr->games_week = 0;
+ itr->wins_week = 0;
+ }
+}
+
+/*
+arenateam fields (id from 2.3.3 client):
+1414 - arena team id 2v2
+1415 - 0=captain, 1=member
+1416 - played this week
+1417 - played this season
+1418 - unk
+1419 - personal arena rating
+1420 - arena team id 3v3
+1421 - 0=captain, 1=member
+1422 - played this week
+1423 - played this season
+1424 - unk
+1425 - personal arena rating
+1426 - arena team id 5v5
+1427 - 0=captain, 1=member
+1428 - played this week
+1429 - played this season
+1430 - unk
+1431 - personal arena rating
+*/
diff --git a/src/game/ArenaTeam.h b/src/game/ArenaTeam.h
index 03cf5ccc7d4..2e9f32a97f7 100644
--- a/src/game/ArenaTeam.h
+++ b/src/game/ArenaTeam.h
@@ -10,12 +10,12 @@
*
* 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
+ * 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
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef TRINITYCORE_ARENATEAM_H
@@ -68,12 +68,12 @@ ERR_ARENA_TEAM_LEVEL_TOO_LOW_I
enum ArenaTeamStatTypes
{
- STAT_TYPE_RATING = 0,
- STAT_TYPE_GAMES = 1,
- STAT_TYPE_WINS = 2,
- STAT_TYPE_PLAYED = 3,
- STAT_TYPE_WINS2 = 4,
- STAT_TYPE_RANK = 5
+ STAT_TYPE_RATING = 0,
+ STAT_TYPE_GAMES_WEEK = 1,
+ STAT_TYPE_WINS_WEEK = 2,
+ STAT_TYPE_GAMES_SEASON = 3,
+ STAT_TYPE_WINS_SEASON = 4,
+ STAT_TYPE_RANK = 5
};
enum ArenaTeamTypes
@@ -90,19 +90,20 @@ struct ArenaTeamMember
//uint32 unk2;
//uint8 unk1;
uint8 Class;
- uint32 played_week;
- uint32 wons_week;
- uint32 played_season;
- uint32 wons_season;
+ uint32 games_week;
+ uint32 wins_week;
+ uint32 games_season;
+ uint32 wins_season;
+ //uint32 personal_rating;
};
struct ArenaTeamStats
{
uint32 rating;
- uint32 games;
- uint32 wins;
- uint32 played;
- uint32 wins2;
+ uint32 games_week;
+ uint32 wins_week;
+ uint32 games_season;
+ uint32 wins_season;
uint32 rank;
};
@@ -125,7 +126,7 @@ class ArenaTeam
static uint8 GetSlotByType(uint32 type);
const uint64& GetCaptain() const { return CaptainGuid; }
std::string GetName() const { return Name; }
- ArenaTeamStats GetStats() const { return stats; }
+ const ArenaTeamStats& GetStats() const { return stats; }
void SetStats(uint32 stat_type, uint32 value);
uint32 GetRating() const { return stats.rating; }
@@ -145,6 +146,22 @@ class ArenaTeam
MemberList::iterator membersbegin(){ return members.begin(); }
MemberList::iterator membersEnd(){ return members.end(); }
bool HaveMember(uint64 guid) const;
+ ArenaTeamMember* GetMember(uint64 guid)
+ {
+ for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ if(itr->guid==guid)
+ return &(*itr);
+
+ return NULL;
+ }
+ ArenaTeamMember* GetMember(std::string& name)
+ {
+ for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ if(itr->name==name)
+ return &(*itr);
+
+ return NULL;
+ }
bool LoadArenaTeamFromDB(uint32 ArenaTeamId);
void LoadMembersFromDB(uint32 ArenaTeamId);
diff --git a/src/game/ArenaTeamHandler.cpp b/src/game/ArenaTeamHandler.cpp
index b5f8e69c918..1ce844c4a26 100644
--- a/src/game/ArenaTeamHandler.cpp
+++ b/src/game/ArenaTeamHandler.cpp
@@ -291,39 +291,29 @@ void WorldSession::HandleArenaTeamRemoveFromTeamOpcode(WorldPacket & recv_data)
recv_data >> name;
ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId);
- if(!at)
- {
- // arena team not found
+ if(!at) // arena team not found
return;
- }
- uint64 guid = objmgr.GetPlayerGUIDByName(name);
- if(!guid)
+ if(at->GetCaptain() != _player->GetGUID())
{
- // player guid not found
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS);
return;
}
- if(at->GetCaptain() == guid)
- {
- // unsure
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS);
+ if(!normalizePlayerName(name))
return;
- }
- if(at->GetCaptain() != _player->GetGUID())
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS);
+ ArenaTeamMember* member = at->GetMember(name);
+ if(!member) // member not found
return;
- }
- if(at->GetCaptain() == guid)
+ if(at->GetCaptain() == member->guid)
{
SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S);
return;
}
- at->DelMember(guid);
+ at->DelMember(member->guid);
// event
WorldPacket data;
@@ -345,32 +335,26 @@ void WorldSession::HandleArenaTeamPromoteToCaptainOpcode(WorldPacket & recv_data
recv_data >> name;
ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId);
- if(!at)
- {
- // arena team not found
+ if(!at) // arena team not found
return;
- }
- uint64 guid = objmgr.GetPlayerGUIDByName(name);
- if(!guid)
+ if(at->GetCaptain() != _player->GetGUID())
{
- // player guid not found
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS);
return;
}
- if(at->GetCaptain() == guid)
- {
- // target player already captain
+ if(!normalizePlayerName(name))
return;
- }
- if(at->GetCaptain() != _player->GetGUID())
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS);
+ ArenaTeamMember* member = at->GetMember(name);
+ if(!member) // member not found
+ return;
+
+ if(at->GetCaptain() == member->guid) // target player already captain
return;
- }
- at->SetCaptain(guid);
+ at->SetCaptain(member->guid);
// event
WorldPacket data;
diff --git a/src/game/AuctionHouse.cpp b/src/game/AuctionHouse.cpp
index 5526240528b..8a2ce27d24d 100644
--- a/src/game/AuctionHouse.cpp
+++ b/src/game/AuctionHouse.cpp
@@ -278,7 +278,7 @@ void WorldSession::HandleAuctionSellItem( WorldPacket & recv_data )
if( GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
{
- sLog.outCommand("GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)",
+ sLog.outCommand(GetAccountId(),"GM %s (Account: %u) create auction: %s (Entry: %u Count: %u)",
GetPlayerName(),GetAccountId(),it->GetProto()->Name1,it->GetEntry(),it->GetCount());
}
@@ -367,7 +367,7 @@ void WorldSession::HandleAuctionPlaceBid( WorldPacket & recv_data )
return;
}
- if (price < (auction->bid + objmgr.GetAuctionOutBid(auction->bid)))
+ if ((price < (auction->bid + objmgr.GetAuctionOutBid(auction->bid))) && ((price < auction->buyout) || (auction->buyout == 0)))
{
//auction has already higher bid, client tests it!
//SendAuctionCommandResult(auction->auctionId, AUCTION_PLACE_BID, ???);
diff --git a/src/game/BattleGround.cpp b/src/game/BattleGround.cpp
index 67261b6ff20..098b5a0d28e 100644
--- a/src/game/BattleGround.cpp
+++ b/src/game/BattleGround.cpp
@@ -362,6 +362,23 @@ void BattleGround::CastSpellOnTeam(uint32 SpellID, uint32 TeamID)
}
}
+void BattleGround::YellToAll(Creature* creature, const char* text, uint32 language)
+{
+ for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
+ {
+ WorldPacket data(SMSG_MESSAGECHAT, 200);
+ Player *plr = objmgr.GetPlayer(itr->first);
+ if(!plr)
+ {
+ sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
+ continue;
+ }
+ creature->BuildMonsterChat(&data,CHAT_MSG_MONSTER_YELL,text,language,creature->GetName(),itr->first);
+ plr->GetSession()->SendPacket(&data);
+ }
+}
+
+
void BattleGround::RewardHonorToTeam(uint32 Honor, uint32 TeamID)
{
for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
@@ -929,14 +946,21 @@ void BattleGround::AddPlayer(Player *plr)
plr->RemoveArenaAuras();
plr->RemoveArenaSpellCooldowns();
plr->RemoveAllEnchantments(TEMP_ENCHANTMENT_SLOT);
- if(team == ALLIANCE && plr->GetTeam() == ALLIANCE)
- plr->CastSpell(plr,SPELL_ALLIANCE_GOLD_FLAG,true);
- else if(team == HORDE && plr->GetTeam() == ALLIANCE)
- plr->CastSpell(plr,SPELL_ALLIANCE_GREEN_FLAG,true);
- else if(team == ALLIANCE && plr->GetTeam() == HORDE)
- plr->CastSpell(plr,SPELL_HORDE_GOLD_FLAG,true);
- else
- plr->CastSpell(plr,SPELL_HORDE_GREEN_FLAG,true);
+ if(team == ALLIANCE) // gold
+ {
+ if(plr->GetTeam() == HORDE)
+ plr->CastSpell(plr, SPELL_HORDE_GOLD_FLAG,true);
+ else
+ plr->CastSpell(plr, SPELL_ALLIANCE_GOLD_FLAG,true);
+ }
+ else // green
+ {
+ if(plr->GetTeam() == HORDE)
+ plr->CastSpell(plr, SPELL_HORDE_GREEN_FLAG,true);
+ else
+ plr->CastSpell(plr, SPELL_ALLIANCE_GREEN_FLAG,true);
+ }
+
plr->DestroyConjuredItems(true);
Pet* pet = plr->GetPet();
@@ -1218,6 +1242,22 @@ void BattleGround::DoorOpen(uint32 type)
}
}
+GameObject* BattleGround::GetBGObject(uint32 type)
+{
+ GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
+ if(!obj)
+ sLog.outError("couldn't get gameobject %i",type);
+ return obj;
+}
+
+Creature* BattleGround::GetBGCreature(uint32 type)
+{
+ Creature *creature = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
+ if(!creature)
+ sLog.outError("couldn't get creature %i",type);
+ return creature;
+}
+
void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime)
{
Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
@@ -1269,6 +1309,16 @@ Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, f
return NULL;
}
+ CreatureData &data = objmgr.NewOrExistCreatureData(pCreature->GetDBTableGUIDLow());
+
+ data.id = entry;
+// data.mapid = GetMapId();
+ data.posX = x;
+ data.posY = y;
+ data.posZ = z;
+ data.orientation = o;
+ data.spawndist = 15;
+
pCreature->AIM_Initialize();
//pCreature->SetDungeonDifficulty(0);
@@ -1287,6 +1337,7 @@ bool BattleGround::DelCreature(uint32 type)
sLog.outError("Can't find creature guid: %u",GUID_LOPART(m_BgCreatures[type]));
return false;
}
+ //TODO: only delete creature after not in combat
cr->CleanupsBeforeDelete();
cr->AddObjectToRemoveList();
m_BgCreatures[type] = 0;
@@ -1474,3 +1525,16 @@ void BattleGround::SetHoliday(bool is_holiday)
else
m_HonorMode = BG_NORMAL;
}
+
+int32 BattleGround::GetObjectType(uint64 guid)
+{
+ for(uint32 i = 0;i <= m_BgObjects.size(); i++)
+ if(m_BgObjects[i] == guid)
+ return i;
+ sLog.outError("BattleGround: cheating? a player used a gameobject which isnt supposed to be a usable object!");
+ return -1;
+}
+
+void BattleGround::HandleKillUnit(Creature *creature, Player *killer)
+{
+}
diff --git a/src/game/BattleGround.h b/src/game/BattleGround.h
index e53ed1d21e6..c151a207124 100644
--- a/src/game/BattleGround.h
+++ b/src/game/BattleGround.h
@@ -354,6 +354,8 @@ class BattleGround
void StartBattleGround();
+ GameObject* GetBGObject(uint32 type);
+ Creature* GetBGCreature(uint32 type);
/* Location */
void SetMapId(uint32 MapID) { m_MapId = MapID; }
uint32 GetMapId() const { return m_MapId; }
@@ -373,6 +375,7 @@ class BattleGround
virtual void FillInitialWorldStates(WorldPacket& /*data*/) {}
void SendPacketToTeam(uint32 TeamID, WorldPacket *packet, Player *sender = NULL, bool self = true);
void SendPacketToAll(WorldPacket *packet);
+ void YellToAll(Creature* creature, const char* text, uint32 language);
void PlaySoundToTeam(uint32 SoundID, uint32 TeamID);
void PlaySoundToAll(uint32 SoundID);
void CastSpellOnTeam(uint32 SpellID, uint32 TeamID);
@@ -423,6 +426,7 @@ class BattleGround
virtual void HandleAreaTrigger(Player* /*Source*/, uint32 /*Trigger*/) {}
// must be implemented in BG subclass if need AND call base class generic code
virtual void HandleKillPlayer(Player *player, Player *killer);
+ virtual void HandleKillUnit(Creature* /*unit*/, Player* /*killer*/);
/* Battleground events */
/* these functions will return true event is possible, but false if player is bugger */
@@ -452,6 +456,7 @@ class BattleGround
bool DelCreature(uint32 type);
bool DelObject(uint32 type);
bool AddSpiritGuide(uint32 type, float x, float y, float z, float o, uint32 team);
+ int32 GetObjectType(uint64 guid);
void DoorOpen(uint32 type);
void DoorClose(uint32 type);
diff --git a/src/game/BattleGroundAV.cpp b/src/game/BattleGroundAV.cpp
index 1feccaeae38..63511c87111 100644
--- a/src/game/BattleGroundAV.cpp
+++ b/src/game/BattleGroundAV.cpp
@@ -18,27 +18,451 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "Object.h"
#include "Player.h"
#include "BattleGround.h"
#include "BattleGroundAV.h"
#include "Creature.h"
+#include "Chat.h"
+#include "Object.h"
+#include "ObjectMgr.h"
+#include "ObjectAccessor.h"
#include "MapManager.h"
#include "Language.h"
+#include "SpellAuras.h"
+#include "Formulas.h"
BattleGroundAV::BattleGroundAV()
{
+ m_BgObjects.resize(BG_AV_OBJECT_MAX);
+ m_BgCreatures.resize(AV_CPLACE_MAX+AV_STATICCPLACE_MAX);
}
BattleGroundAV::~BattleGroundAV()
{
+}
+
+const uint16 BattleGroundAV::GetBonusHonor(uint8 kills) //TODO: move this function to Battleground.cpp (needs to find a way to get m_MaxLevel)
+{
+ return Trinity::Honor::hk_honor_at_level(m_MaxLevel, kills);
+}
+
+void BattleGroundAV::HandleKillPlayer(Player *player, Player *killer)
+{
+ if(GetStatus() != STATUS_IN_PROGRESS)
+ return;
+ BattleGround::HandleKillPlayer(player, killer);
+ UpdateScore(player->GetTeam(),-1);
+}
+
+void BattleGroundAV::HandleKillUnit(Creature *unit, Player *killer)
+{
+ sLog.outDebug("bg_av HandleKillUnit %i",unit->GetEntry());
+ if(GetStatus() != STATUS_IN_PROGRESS)
+ return;
+ uint32 entry = unit->GetEntry();
+ if(entry == BG_AV_CreatureInfo[AV_NPC_A_BOSS][0])
+ {
+ CastSpellOnTeam(23658,HORDE); //this is a spell which finishes a quest where a player has to kill the boss
+ RewardReputationToTeam(729,BG_AV_REP_BOSS,HORDE);
+ RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_BOSS),HORDE);
+ EndBattleGround(HORDE);
+ }
+ else if ( entry == BG_AV_CreatureInfo[AV_NPC_H_BOSS][0] )
+ {
+ CastSpellOnTeam(23658,ALLIANCE); //this is a spell which finishes a quest where a player has to kill the boss
+ RewardReputationToTeam(730,BG_AV_REP_BOSS,ALLIANCE);
+ RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_BOSS),ALLIANCE);
+ EndBattleGround(ALLIANCE);
+ }
+ else if(entry == BG_AV_CreatureInfo[AV_NPC_A_CAPTAIN][0])
+ {
+ if(!m_CaptainAlive[0])
+ {
+ sLog.outError("Killed a Captain twice, please report this bug, if you haven't done \".respawn\"");
+ return;
+ }
+ m_CaptainAlive[0]=false;
+ RewardReputationToTeam(729,BG_AV_REP_CAPTAIN,HORDE);
+ RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_CAPTAIN),HORDE);
+ UpdateScore(ALLIANCE,(-1)*BG_AV_RES_CAPTAIN);
+ //spawn destroyed aura
+ for(uint8 i=0; i<=9; i++)
+ SpawnBGObject(BG_AV_OBJECT_BURN_BUILDING_ALLIANCE+i,RESPAWN_IMMEDIATELY);
+ Creature* creature = GetBGCreature(AV_CPLACE_HERALD);
+ if(creature)
+ YellToAll(creature,GetTrinityString(LANG_BG_AV_A_CAPTAIN_DEAD),LANG_UNIVERSAL);
+
+ }
+ else if ( entry == BG_AV_CreatureInfo[AV_NPC_H_CAPTAIN][0] )
+ {
+ if(!m_CaptainAlive[1])
+ {
+ sLog.outError("Killed a Captain twice, please report this bug, if you haven't done \".respawn\"");
+ return;
+ }
+ m_CaptainAlive[1]=false;
+ RewardReputationToTeam(730,BG_AV_REP_CAPTAIN,ALLIANCE);
+ RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_CAPTAIN),ALLIANCE);
+ UpdateScore(HORDE,(-1)*BG_AV_RES_CAPTAIN);
+ //spawn destroyed aura
+ for(uint8 i=0; i<=9; i++)
+ SpawnBGObject(BG_AV_OBJECT_BURN_BUILDING_HORDE+i,RESPAWN_IMMEDIATELY);
+ Creature* creature = GetBGCreature(AV_CPLACE_HERALD);
+ if(creature)
+ YellToAll(creature,GetTrinityString(LANG_BG_AV_H_CAPTAIN_DEAD),LANG_UNIVERSAL);
+ }
+ else if ( entry == BG_AV_CreatureInfo[AV_NPC_N_MINE_N_4][0] || entry == BG_AV_CreatureInfo[AV_NPC_N_MINE_A_4][0] || entry == BG_AV_CreatureInfo[AV_NPC_N_MINE_H_4][0])
+ ChangeMineOwner(AV_NORTH_MINE,killer->GetTeam());
+ else if ( entry == BG_AV_CreatureInfo[AV_NPC_S_MINE_N_4][0] || entry == BG_AV_CreatureInfo[AV_NPC_S_MINE_A_4][0] || entry == BG_AV_CreatureInfo[AV_NPC_S_MINE_H_4][0])
+ ChangeMineOwner(AV_SOUTH_MINE,killer->GetTeam());
+}
+
+void BattleGroundAV::HandleQuestComplete(uint32 questid, Player *player)
+{
+ if (GetStatus() != STATUS_IN_PROGRESS)
+ return;//maybe we should log this, cause this must be a cheater or a big bug
+ uint8 team = GetTeamIndexByTeamId(player->GetTeam());
+ //TODO add reputation, events (including quest not available anymore, next quest availabe, go/npc de/spawning)and maybe honor
+ sLog.outError("BG_AV Quest %i completed",questid);
+ switch(questid)
+ {
+ case AV_QUEST_A_SCRAPS1:
+ case AV_QUEST_A_SCRAPS2:
+ case AV_QUEST_H_SCRAPS1:
+ case AV_QUEST_H_SCRAPS2:
+ m_Team_QuestStatus[team][0]+=20;
+ if(m_Team_QuestStatus[team][0] == 500 || m_Team_QuestStatus[team][0] == 1000 || m_Team_QuestStatus[team][0] == 1500) //25,50,75 turn ins
+ {
+ sLog.outDebug("BG_AV Quest %i completed starting with unit upgrading..",questid);
+ for (BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_FROSTWOLF_HUT; ++i)
+ if (m_Nodes[i].Owner == player->GetTeam() && m_Nodes[i].State == POINT_CONTROLED)
+ {
+ DePopulateNode(i);
+ PopulateNode(i);
+ //maybe this is bad, because it will instantly respawn all creatures on every grave..
+ }
+ }
+ break;
+ case AV_QUEST_A_COMMANDER1:
+ case AV_QUEST_H_COMMANDER1:
+ m_Team_QuestStatus[team][1]++;
+ RewardReputationToTeam(team,1,player->GetTeam());
+ if(m_Team_QuestStatus[team][1] == 30)
+ sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid);
+ break;
+ case AV_QUEST_A_COMMANDER2:
+ case AV_QUEST_H_COMMANDER2:
+ m_Team_QuestStatus[team][2]++;
+ RewardReputationToTeam(team,1,player->GetTeam());
+ if(m_Team_QuestStatus[team][2] == 60)
+ sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid);
+ break;
+ case AV_QUEST_A_COMMANDER3:
+ case AV_QUEST_H_COMMANDER3:
+ m_Team_QuestStatus[team][3]++;
+ RewardReputationToTeam(team,1,player->GetTeam());
+ if(m_Team_QuestStatus[team][1] == 120)
+ sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid);
+ break;
+ case AV_QUEST_A_BOSS1:
+ case AV_QUEST_H_BOSS1:
+ m_Team_QuestStatus[team][4] += 9; //you can turn in 10 or 1 item..
+ case AV_QUEST_A_BOSS2:
+ case AV_QUEST_H_BOSS2:
+ m_Team_QuestStatus[team][4]++;
+ if(m_Team_QuestStatus[team][4] >= 200)
+ sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid);
+ break;
+ case AV_QUEST_A_NEAR_MINE:
+ case AV_QUEST_H_NEAR_MINE:
+ m_Team_QuestStatus[team][5]++;
+ if(m_Team_QuestStatus[team][5] == 28)
+ {
+ sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid);
+ if(m_Team_QuestStatus[team][6] == 7)
+ sLog.outDebug("BG_AV Quest %i completed (need to implement some events here - ground assault ready",questid);
+ }
+ break;
+ case AV_QUEST_A_OTHER_MINE:
+ case AV_QUEST_H_OTHER_MINE:
+ m_Team_QuestStatus[team][6]++;
+ if(m_Team_QuestStatus[team][6] == 7)
+ {
+ sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid);
+ if(m_Team_QuestStatus[team][5] == 20)
+ sLog.outDebug("BG_AV Quest %i completed (need to implement some events here - ground assault ready",questid);
+ }
+ break;
+ case AV_QUEST_A_RIDER_HIDE:
+ case AV_QUEST_H_RIDER_HIDE:
+ m_Team_QuestStatus[team][7]++;
+ if(m_Team_QuestStatus[team][7] == 25)
+ {
+ sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid);
+ if(m_Team_QuestStatus[team][8] == 25)
+ sLog.outDebug("BG_AV Quest %i completed (need to implement some events here - rider assault ready",questid);
+ }
+ break;
+ case AV_QUEST_A_RIDER_TAME:
+ case AV_QUEST_H_RIDER_TAME:
+ m_Team_QuestStatus[team][8]++;
+ if(m_Team_QuestStatus[team][8] == 25)
+ {
+ sLog.outDebug("BG_AV Quest %i completed (need to implement some events here",questid);
+ if(m_Team_QuestStatus[team][7] == 25)
+ sLog.outDebug("BG_AV Quest %i completed (need to implement some events here - rider assault ready",questid);
+ }
+ break;
+ default:
+ sLog.outDebug("BG_AV Quest %i completed but is not interesting at all",questid);
+ return; //was no interesting quest at all
+ break;
+ }
+}
+
+
+void BattleGroundAV::UpdateScore(uint16 team, int16 points )
+{ //note: to remove reinforcementpoints points must be negative, for adding reinforcements points must be positive
+ assert( team == ALLIANCE || team == HORDE);
+ uint8 teamindex = GetTeamIndexByTeamId(team); //0=ally 1=horde
+ m_Team_Scores[teamindex] += points;
+
+ UpdateWorldState(((teamindex==BG_TEAM_HORDE)?AV_Horde_Score:AV_Alliance_Score), m_Team_Scores[teamindex]);
+ if( points < 0)
+ {
+ if( m_Team_Scores[teamindex] < 1)
+ {
+ m_Team_Scores[teamindex]=0;
+ EndBattleGround(((teamindex==BG_TEAM_HORDE)?ALLIANCE:HORDE));
+ }
+ else if(!m_IsInformedNearVictory[teamindex] && m_Team_Scores[teamindex] < SEND_MSG_NEAR_LOSE)
+ {
+ SendMessageToAll(GetTrinityString((teamindex==BG_TEAM_HORDE)?LANG_BG_AV_H_NEAR_LOSE:LANG_BG_AV_A_NEAR_LOSE));
+ PlaySoundToAll(AV_SOUND_NEAR_VICTORY);
+ m_IsInformedNearVictory[teamindex] = true;
+ }
+ }
+}
+
+Creature* BattleGroundAV::AddAVCreature(uint16 cinfoid, uint16 type )
+{
+ uint32 level;
+ bool isStatic=false;
+ Creature* creature = NULL;
+ assert(type <= AV_CPLACE_MAX + AV_STATICCPLACE_MAX);
+ if(type>=AV_CPLACE_MAX) //static
+ {
+ type-=AV_CPLACE_MAX;
+ cinfoid=int(BG_AV_StaticCreaturePos[type][4]);
+ creature = AddCreature(BG_AV_StaticCreatureInfo[cinfoid][0],(type+AV_CPLACE_MAX),BG_AV_StaticCreatureInfo[cinfoid][1],BG_AV_StaticCreaturePos[type][0],BG_AV_StaticCreaturePos[type][1],BG_AV_StaticCreaturePos[type][2],BG_AV_StaticCreaturePos[type][3]);
+ level = ( BG_AV_StaticCreatureInfo[cinfoid][2] == BG_AV_StaticCreatureInfo[cinfoid][3] ) ? BG_AV_StaticCreatureInfo[cinfoid][2] : urand(BG_AV_StaticCreatureInfo[cinfoid][2],BG_AV_StaticCreatureInfo[cinfoid][3]);
+ isStatic=true;
+ }
+ else
+ {
+ creature = AddCreature(BG_AV_CreatureInfo[cinfoid][0],type,BG_AV_CreatureInfo[cinfoid][1],BG_AV_CreaturePos[type][0],BG_AV_CreaturePos[type][1],BG_AV_CreaturePos[type][2],BG_AV_CreaturePos[type][3]);
+ level = ( BG_AV_CreatureInfo[cinfoid][2] == BG_AV_CreatureInfo[cinfoid][3] ) ? BG_AV_CreatureInfo[cinfoid][2] : urand(BG_AV_CreatureInfo[cinfoid][2],BG_AV_CreatureInfo[cinfoid][3]);
+ }
+ if(!creature)
+ return NULL;
+ if(creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_A_CAPTAIN][0] || creature->GetEntry() == BG_AV_CreatureInfo[AV_NPC_H_CAPTAIN][0])
+ creature->SetRespawnDelay(RESPAWN_ONE_DAY); // TODO: look if this can be done by database + also add this for the wingcommanders
+
+ if((isStatic && cinfoid>=10 && cinfoid<=14) || (!isStatic && ((cinfoid >= AV_NPC_A_GRAVEDEFENSE0 && cinfoid<=AV_NPC_A_GRAVEDEFENSE3) ||
+ (cinfoid>=AV_NPC_H_GRAVEDEFENSE0 && cinfoid<=AV_NPC_H_GRAVEDEFENSE3))))
+ {
+ if(!isStatic && ((cinfoid>=AV_NPC_A_GRAVEDEFENSE0 && cinfoid<=AV_NPC_A_GRAVEDEFENSE3)
+ || (cinfoid>=AV_NPC_H_GRAVEDEFENSE0 && cinfoid<=AV_NPC_H_GRAVEDEFENSE3)))
+ {
+ CreatureData &data = objmgr.NewOrExistCreatureData(creature->GetDBTableGUIDLow());
+ data.spawndist = 5;
+ }
+ //else spawndist will be 15, so creatures move maximum=10
+ creature->SetDefaultMovementType(RANDOM_MOTION_TYPE);
+ creature->GetMotionMaster()->Initialize();
+ creature->setDeathState(JUST_DIED);
+ creature->Respawn();
+ //TODO: find a way to add a motionmaster without killing the creature (i
+ //just copied this code from a gm-command
+ }
+
+ if(level != 0)
+ level += m_MaxLevel-60; //maybe we can do this more generic for custom level-range.. actually it's blizzlike
+ creature->SetLevel(level);
+ return creature;
}
void BattleGroundAV::Update(time_t diff)
{
BattleGround::Update(diff);
+ if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize())
+ {
+ ModifyStartDelayTime(diff);
+
+ if (!(m_Events & 0x01))
+ {
+ m_Events |= 0x01;
+
+ if(!SetupBattleGround())
+ {
+ EndNow();
+ return;
+ }
+
+ uint16 i;
+ sLog.outDebug("Alterac Valley: entering state STATUS_WAIT_JOIN ...");
+ // Initial Nodes
+ for(i = 0; i < BG_AV_OBJECT_MAX; i++)
+ SpawnBGObject(i, RESPAWN_ONE_DAY);
+ for(i = BG_AV_OBJECT_FLAG_A_FIRSTAID_STATION; i <= BG_AV_OBJECT_FLAG_A_STONEHEART_GRAVE ; i++){
+ SpawnBGObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+3*i,RESPAWN_IMMEDIATELY);
+ SpawnBGObject(i, RESPAWN_IMMEDIATELY);
+ }
+ for(i = BG_AV_OBJECT_FLAG_A_DUNBALDAR_SOUTH; i <= BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER ; i++)
+ SpawnBGObject(i, RESPAWN_IMMEDIATELY);
+ for(i = BG_AV_OBJECT_FLAG_H_ICEBLOOD_GRAVE; i <= BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER ; i++){
+ SpawnBGObject(i, RESPAWN_IMMEDIATELY);
+ if(i<=BG_AV_OBJECT_FLAG_H_FROSTWOLF_HUT)
+ SpawnBGObject(BG_AV_OBJECT_AURA_H_FIRSTAID_STATION+3*GetNodeThroughObject(i),RESPAWN_IMMEDIATELY);
+ }
+ for(i = BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH; i <= BG_AV_OBJECT_TFLAG_A_STONEHEART_BUNKER; i+=2)
+ {
+ SpawnBGObject(i, RESPAWN_IMMEDIATELY); //flag
+ SpawnBGObject(i+16, RESPAWN_IMMEDIATELY); //aura
+ }
+ for(i = BG_AV_OBJECT_TFLAG_H_ICEBLOOD_TOWER; i <= BG_AV_OBJECT_TFLAG_H_FROSTWOLF_WTOWER; i+=2)
+ {
+ SpawnBGObject(i, RESPAWN_IMMEDIATELY); //flag
+ SpawnBGObject(i+16, RESPAWN_IMMEDIATELY); //aura
+ }
+ //snowfall and the doors
+ for(i = BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE; i <= BG_AV_OBJECT_DOOR_A; i++)
+ SpawnBGObject(i, RESPAWN_IMMEDIATELY);
+ SpawnBGObject(BG_AV_OBJECT_AURA_N_SNOWFALL_GRAVE,RESPAWN_IMMEDIATELY);
+
+ //creatures
+ sLog.outDebug("BG_AV start poputlating nodes");
+ for(BG_AV_Nodes i= BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i )
+ {
+ if(m_Nodes[i].Owner)
+ PopulateNode(i);
+ }
+ //all creatures which don't get despawned through the script are static
+ sLog.outDebug("BG_AV: start spawning static creatures");
+ for(i=0; i < AV_STATICCPLACE_MAX; i++ )
+ AddAVCreature(0,i+AV_CPLACE_MAX);
+ //mainspiritguides:
+ sLog.outDebug("BG_AV: start spawning spiritguides creatures");
+ AddSpiritGuide(7, BG_AV_CreaturePos[7][0], BG_AV_CreaturePos[7][1], BG_AV_CreaturePos[7][2], BG_AV_CreaturePos[7][3], ALLIANCE);
+ AddSpiritGuide(8, BG_AV_CreaturePos[8][0], BG_AV_CreaturePos[8][1], BG_AV_CreaturePos[8][2], BG_AV_CreaturePos[8][3], HORDE);
+ //spawn the marshals (those who get deleted, if a tower gets destroyed)
+ sLog.outDebug("BG_AV: start spawning marshal creatures");
+ for(i=AV_NPC_A_MARSHAL_SOUTH; i<= AV_NPC_H_MARSHAL_WTOWER; i++)
+ AddAVCreature(i,AV_CPLACE_A_MARSHAL_SOUTH+(i-AV_NPC_A_MARSHAL_SOUTH));
+
+ AddAVCreature(AV_NPC_HERALD,AV_CPLACE_HERALD);
+ DoorClose(BG_AV_OBJECT_DOOR_A);
+ DoorClose(BG_AV_OBJECT_DOOR_H);
+
+ SetStartDelayTime(START_DELAY0);
+ }
+ // After 1 minute, warning is signalled
+ else if (GetStartDelayTime() <= START_DELAY1 && !(m_Events & 0x04))
+ {
+ m_Events |= 0x04;
+ SendMessageToAll(GetTrinityString(LANG_BG_AV_ONEMINTOSTART));
+ }
+ // After 1,5 minute, warning is signalled
+ else if (GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x08))
+ {
+ m_Events |= 0x08;
+ SendMessageToAll(GetTrinityString(LANG_BG_AV_HALFMINTOSTART));
+ }
+ // After 2 minutes, gates OPEN ! x)
+ else if (GetStartDelayTime() <= 0 && !(m_Events & 0x10))
+ {
+ UpdateWorldState(AV_SHOW_H_SCORE, 1);
+ UpdateWorldState(AV_SHOW_A_SCORE, 1);
+ m_Events |= 0x10;
+
+ SendMessageToAll(GetTrinityString(LANG_BG_AV_STARTED));
+ PlaySoundToAll(SOUND_BG_START);
+ SetStatus(STATUS_IN_PROGRESS);
+
+ sLog.outDebug("BG_AV: start spawning mine stuff");
+ for(uint16 i= BG_AV_OBJECT_MINE_SUPPLY_N_MIN; i<=BG_AV_OBJECT_MINE_SUPPLY_N_MAX;i++)
+ SpawnBGObject(i,RESPAWN_IMMEDIATELY);
+ for(uint16 i= BG_AV_OBJECT_MINE_SUPPLY_S_MIN; i<=BG_AV_OBJECT_MINE_SUPPLY_S_MAX;i++)
+ SpawnBGObject(i,RESPAWN_IMMEDIATELY);
+ for(uint8 mine = AV_NORTH_MINE; mine <= AV_SOUTH_MINE; mine++) //mine population
+ ChangeMineOwner(mine, AV_NEUTRAL_TEAM,true);
+ DoorOpen(BG_AV_OBJECT_DOOR_H);
+ DoorOpen(BG_AV_OBJECT_DOOR_A);
+
+
+ for(BattleGroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
+ if(Player* plr = objmgr.GetPlayer(itr->first))
+ plr->RemoveAurasDueToSpell(SPELL_PREPARATION);
+ }
+ }
+ else if(GetStatus() == STATUS_IN_PROGRESS)
+ {
+ for(uint8 i=0; i<=1;i++)//0=alliance, 1=horde
+ {
+ if(!m_CaptainAlive[i])
+ continue;
+ if(m_CaptainBuffTimer[i] > diff)
+ m_CaptainBuffTimer[i] -= diff;
+ else
+ {
+ if(i==0)
+ {
+ CastSpellOnTeam(AV_BUFF_A_CAPTAIN,ALLIANCE);
+ Creature* creature = GetBGCreature(AV_CPLACE_MAX + 61);
+ if(creature)
+ YellToAll(creature,LANG_BG_AV_A_CAPTAIN_BUFF,LANG_COMMON);
+ }
+ else
+ {
+ CastSpellOnTeam(AV_BUFF_H_CAPTAIN,HORDE);
+ Creature* creature = GetBGCreature(AV_CPLACE_MAX + 59); //TODO: make the captains a dynamic creature
+ if(creature)
+ YellToAll(creature,LANG_BG_AV_H_CAPTAIN_BUFF,LANG_ORCISH);
+ }
+ m_CaptainBuffTimer[i] = 120000 + urand(0,4)* 60000; //as far as i could see, the buff is randomly so i make 2minutes (thats the duration of the buff itself) + 0-4minutes TODO get the right times
+ }
+ }
+ //add points from mine owning, and look if he neutral team wanrts to reclaim the mine
+ m_Mine_Timer -=diff;
+ for(uint8 mine=0; mine <2; mine++)
+ {
+ if(m_Mine_Owner[mine] == ALLIANCE || m_Mine_Owner[mine] == HORDE)
+ {
+ if( m_Mine_Timer <= 0)
+ UpdateScore(m_Mine_Owner[mine],1);
+
+ if(m_Mine_Reclaim_Timer[mine] > diff)
+ m_Mine_Reclaim_Timer[mine] -= diff;
+ else{ //we don't need to set this timer to 0 cause this codepart wont get called when this thing is 0
+ ChangeMineOwner(mine,AV_NEUTRAL_TEAM);
+ }
+ }
+ }
+ if( m_Mine_Timer <= 0)
+ m_Mine_Timer=AV_MINE_TICK_TIMER; //this is at the end, cause we need to update both mines
+
+ //looks for all timers of the nodes and destroy the building (for graveyards the building wont get destroyed, it goes just to the other team
+ for(BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i < BG_AV_NODES_MAX; ++i)
+ if(m_Nodes[i].State == POINT_ASSAULTED) //maybe remove this
+ {
+ if(m_Nodes[i].Timer > diff)
+ m_Nodes[i].Timer -= diff;
+ else
+ EventPlayerDestroyedPoint( i);
+ }
+ }
}
void BattleGroundAV::AddPlayer(Player *plr)
@@ -46,15 +470,66 @@ void BattleGroundAV::AddPlayer(Player *plr)
BattleGround::AddPlayer(plr);
//create score and add it to map, default values are set in constructor
BattleGroundAVScore* sc = new BattleGroundAVScore;
-
m_PlayerScores[plr->GetGUID()] = sc;
+ if(m_MaxLevel==0)
+ m_MaxLevel=(plr->getLevel()%10 == 0)? plr->getLevel() : (plr->getLevel()-(plr->getLevel()%10))+10; //TODO: just look at the code \^_^/ --but queue-info should provide this information..
+
}
-void BattleGroundAV::RemovePlayer(Player* /*plr*/,uint64 /*guid*/)
+void BattleGroundAV::EndBattleGround(uint32 winner)
{
+ //calculate bonuskills for both teams:
+ //first towers:
+ uint8 kills[2]={0,0}; //0=ally 1=horde
+ uint8 rep[2]={0,0}; //0=ally 1=horde
+ for(BG_AV_Nodes i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_FROSTWOLF_WTOWER; ++i)
+ {
+ if(m_Nodes[i].State == POINT_CONTROLED)
+ {
+ if(m_Nodes[i].Owner == ALLIANCE)
+ {
+ rep[0] += BG_AV_REP_SURVIVING_TOWER;
+ kills[0] += BG_AV_KILL_SURVIVING_TOWER;
+ }
+ else
+ {
+ rep[0] += BG_AV_KILL_SURVIVING_TOWER;
+ kills[1] += BG_AV_KILL_SURVIVING_TOWER;
+ }
+ }
+ }
+ for(int i=0; i<=1; i++) //0=ally 1=horde
+ {
+ if(m_CaptainAlive[i])
+ {
+ kills[i] += BG_AV_KILL_SURVIVING_CAPTAIN;
+ rep[i] += BG_AV_REP_SURVIVING_CAPTAIN;
+ }
+ if(rep[i] != 0)
+ RewardReputationToTeam((i == 0)?730:729,rep[i],(i == 0)?ALLIANCE:HORDE);
+ if(kills[i] != 0)
+ RewardHonorToTeam(GetBonusHonor(kills[i]),(i == 0)?ALLIANCE:HORDE);
+ }
+
+ //TODO add enterevademode for all attacking creatures
+ BattleGround::EndBattleGround(winner);
+}
+
+void BattleGroundAV::RemovePlayer(Player* plr,uint64 /*guid*/)
+{
+ if(!plr)
+ {
+ sLog.outError("bg_AV no player at remove");
+ return;
+ }
+ //TODO search more buffs
+ plr->RemoveAurasDueToSpell(AV_BUFF_ARMOR);
+ plr->RemoveAurasDueToSpell(AV_BUFF_A_CAPTAIN);
+ plr->RemoveAurasDueToSpell(AV_BUFF_H_CAPTAIN);
}
+
void BattleGroundAV::HandleAreaTrigger(Player *Source, uint32 Trigger)
{
// this is wrong way to implement these things. On official it done by gameobject spell cast.
@@ -65,18 +540,29 @@ void BattleGroundAV::HandleAreaTrigger(Player *Source, uint32 Trigger)
switch(Trigger)
{
case 95:
- case 2606:
case 2608:
+ if(Source->GetTeam() != ALLIANCE)
+ Source->GetSession()->SendAreaTriggerMessage("Only The Alliance can use that portal");
+ else
+ Source->LeaveBattleground();
+ break;
+ case 2606:
+ if(Source->GetTeam() != HORDE)
+ Source->GetSession()->SendAreaTriggerMessage("Only The Horde can use that portal");
+ else
+ Source->LeaveBattleground();
+ break;
case 3326:
case 3327:
case 3328:
case 3329:
case 3330:
case 3331:
+ //Source->Unmount();
break;
default:
- sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
- Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger);
+ sLog.outDebug("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);
+// Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger);
break;
}
@@ -120,3 +606,842 @@ void BattleGroundAV::UpdatePlayerScore(Player* Source, uint32 type, uint32 value
break;
}
}
+
+
+
+void BattleGroundAV::EventPlayerDestroyedPoint(BG_AV_Nodes node)
+{
+
+ uint32 object = GetObjectThroughNode(node);
+ sLog.outDebug("bg_av: player destroyed point node %i object %i",node,object);
+
+ //despawn banner
+ SpawnBGObject(object, RESPAWN_ONE_DAY);
+ DestroyNode(node);
+ UpdateNodeWorldState(node);
+
+ uint32 owner = m_Nodes[node].Owner;
+ if( IsTower(node) )
+ {
+ uint8 tmp = node-BG_AV_NODES_DUNBALDAR_SOUTH;
+ //despawn marshal
+ if(m_BgCreatures[AV_CPLACE_A_MARSHAL_SOUTH + tmp])
+ DelCreature(AV_CPLACE_A_MARSHAL_SOUTH + tmp);
+ else
+ sLog.outError("BG_AV: playerdestroyedpoint: marshal %i doesn't exist",AV_CPLACE_A_MARSHAL_SOUTH + tmp);
+ //spawn destroyed aura
+ for(uint8 i=0; i<=9; i++)
+ SpawnBGObject(BG_AV_OBJECT_BURN_DUNBALDAR_SOUTH + i + (tmp * 10),RESPAWN_IMMEDIATELY);
+
+ UpdateScore((owner == ALLIANCE) ? HORDE : ALLIANCE, (-1)*BG_AV_RES_TOWER);
+ RewardReputationToTeam((owner == ALLIANCE)?730:729,BG_AV_REP_TOWER,owner);
+ RewardHonorToTeam(GetBonusHonor(BG_AV_KILL_TOWER),owner);
+
+ SpawnBGObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+GetTeamIndexByTeamId(owner)+(2*tmp),RESPAWN_ONE_DAY);
+ SpawnBGObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+GetTeamIndexByTeamId(owner)+(2*tmp),RESPAWN_ONE_DAY);
+ }
+ else
+ {
+ if( owner == ALLIANCE )
+ SpawnBGObject(object-11, RESPAWN_IMMEDIATELY);
+ else
+ SpawnBGObject(object+11, RESPAWN_IMMEDIATELY);
+ SpawnBGObject(BG_AV_OBJECT_AURA_N_FIRSTAID_STATION+3*node,RESPAWN_ONE_DAY);
+ SpawnBGObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+GetTeamIndexByTeamId(owner)+3*node,RESPAWN_IMMEDIATELY);
+ PopulateNode(node);
+ if(node == BG_AV_NODES_SNOWFALL_GRAVE) //snowfall eyecandy
+ {
+ for(uint8 i = 0; i < 4; i++)
+ {
+ SpawnBGObject(((owner==ALLIANCE)?BG_AV_OBJECT_SNOW_EYECANDY_PA : BG_AV_OBJECT_SNOW_EYECANDY_PH)+i,RESPAWN_ONE_DAY);
+ SpawnBGObject(((owner==ALLIANCE)?BG_AV_OBJECT_SNOW_EYECANDY_A : BG_AV_OBJECT_SNOW_EYECANDY_H )+i,RESPAWN_IMMEDIATELY);
+ }
+ }
+ }
+ //send a nice message to all :)
+ char buf[256];
+ if(IsTower(node))
+ sprintf(buf, GetTrinityString(LANG_BG_AV_TOWER_TAKEN) , GetNodeName(node),( owner == ALLIANCE ) ? GetTrinityString(LANG_BG_AV_ALLY) : GetTrinityString(LANG_BG_AV_HORDE) );
+ else
+ sprintf(buf, GetTrinityString(LANG_BG_AV_GRAVE_TAKEN) , GetNodeName(node),( owner == ALLIANCE ) ? GetTrinityString(LANG_BG_AV_ALLY) :GetTrinityString(LANG_BG_AV_HORDE) );
+
+ Creature* creature = GetBGCreature(AV_CPLACE_HERALD);
+ if(creature)
+ YellToAll(creature,buf,LANG_UNIVERSAL);
+}
+
+void BattleGroundAV::ChangeMineOwner(uint8 mine, uint32 team, bool initial)
+{ //mine=0 northmine mine=1 southmin
+//changing the owner results in setting respawntim to infinite for current creatures, spawning new mine owners creatures and changing the chest-objects so that the current owning team can use them
+ assert(mine == AV_NORTH_MINE || mine == AV_SOUTH_MINE);
+ if(team != ALLIANCE && team != HORDE)
+ team = AV_NEUTRAL_TEAM;
+ else
+ PlaySoundToAll((team==ALLIANCE)?AV_SOUND_ALLIANCE_GOOD:AV_SOUND_HORDE_GOOD);
+
+ if(m_Mine_Owner[mine] == team && !initial)
+ return;
+ m_Mine_PrevOwner[mine] = m_Mine_Owner[mine];
+ m_Mine_Owner[mine] = team;
+
+ if(!initial)
+ {
+ sLog.outDebug("bg_av depopulating mine %i (0=north,1=south)",mine);
+ if(mine==AV_SOUTH_MINE)
+ for(uint16 i=AV_CPLACE_MINE_S_S_MIN; i <= AV_CPLACE_MINE_S_S_MAX; i++)
+ if( m_BgCreatures[i] )
+ DelCreature(i); //TODO just set the respawntime to 999999
+ for(uint16 i=((mine==AV_NORTH_MINE)?AV_CPLACE_MINE_N_1_MIN:AV_CPLACE_MINE_S_1_MIN); i <= ((mine==AV_NORTH_MINE)?AV_CPLACE_MINE_N_3:AV_CPLACE_MINE_S_3); i++)
+ if( m_BgCreatures[i] )
+ DelCreature(i); //TODO here also
+ }
+ SendMineWorldStates(mine);
+
+ sLog.outDebug("bg_av populating mine %i (0=north,1=south)",mine);
+ uint16 miner;
+ //also neutral team exists.. after a big time, the neutral team tries to conquer the mine
+ if(mine==AV_NORTH_MINE)
+ {
+ if(team == ALLIANCE)
+ miner = AV_NPC_N_MINE_A_1;
+ else if (team == HORDE)
+ miner = AV_NPC_N_MINE_H_1;
+ else
+ miner = AV_NPC_N_MINE_N_1;
+ }
+ else
+ {
+ uint16 cinfo;
+ if(team == ALLIANCE)
+ miner = AV_NPC_S_MINE_A_1;
+ else if (team == HORDE)
+ miner = AV_NPC_S_MINE_H_1;
+ else
+ miner = AV_NPC_S_MINE_N_1;
+ //vermin
+ sLog.outDebug("spawning vermin");
+ if(team == ALLIANCE)
+ cinfo = AV_NPC_S_MINE_A_3;
+ else if (team == HORDE)
+ cinfo = AV_NPC_S_MINE_H_3;
+ else
+ cinfo = AV_NPC_S_MINE_N_S;
+ for(uint16 i=AV_CPLACE_MINE_S_S_MIN; i <= AV_CPLACE_MINE_S_S_MAX; i++)
+ AddAVCreature(cinfo,i);
+ }
+ for(uint16 i=( (mine==AV_NORTH_MINE)?AV_CPLACE_MINE_N_1_MIN:AV_CPLACE_MINE_S_1_MIN ); i <= ((mine==AV_NORTH_MINE)?AV_CPLACE_MINE_N_1_MAX:AV_CPLACE_MINE_S_1_MAX); i++)
+ AddAVCreature(miner,i);
+ //the next chooses randomly between 2 cretures
+ for(uint16 i=((mine==AV_NORTH_MINE)?AV_CPLACE_MINE_N_2_MIN:AV_CPLACE_MINE_S_2_MIN); i <= ((mine==AV_NORTH_MINE)?AV_CPLACE_MINE_N_2_MAX:AV_CPLACE_MINE_S_2_MAX); i++)
+ AddAVCreature(miner+(urand(1,2)),i);
+ AddAVCreature(miner+3,(mine==AV_NORTH_MINE)?AV_CPLACE_MINE_N_3:AV_CPLACE_MINE_S_3);
+ //because the gameobjects in this mine have changed, update all surrounding players:
+// for(uint16 i = ((mine==AV_NORTH_MINE)?BG_AV_OBJECT_MINE_SUPPLY_N_MIN:BG_AV_OBJECT_MINE_SUPPLY_N_MIN); i <= ((mine==AV_NORTH_MINE)?BG_AV_OBJECT_MINE_SUPPLY_N_MAX:BG_AV_OBJECT_MINE_SUPPLY_N_MAX); i++)
+// {
+ //TODO: add gameobject-update code
+// }
+ if(team == ALLIANCE || team == HORDE)
+ {
+ m_Mine_Reclaim_Timer[mine]=AV_MINE_RECLAIM_TIMER;
+ char buf[256];
+ sprintf(buf, GetTrinityString(LANG_BG_AV_MINE_TAKEN), GetTrinityString(( mine == AV_NORTH_MINE ) ? LANG_BG_AV_MINE_NORTH : LANG_BG_AV_MINE_SOUTH), ( team == ALLIANCE ) ? GetTrinityString(LANG_BG_AV_ALLY) : GetTrinityString(LANG_BG_AV_HORDE));
+ Creature* creature = GetBGCreature(AV_CPLACE_HERALD);
+ if(creature)
+ YellToAll(creature,buf,LANG_UNIVERSAL);
+ }
+ else
+ {
+ if(mine==AV_SOUTH_MINE) //i think this gets called all the time
+ {
+ Creature* creature = GetBGCreature(AV_CPLACE_MINE_S_3);
+ YellToAll(creature,LANG_BG_AV_S_MINE_BOSS_CLAIMS,LANG_UNIVERSAL);
+ }
+ }
+ return;
+}
+
+bool BattleGroundAV::PlayerCanDoMineQuest(int32 GOId,uint32 team)
+{
+ if(GOId == BG_AV_OBJECTID_MINE_N)
+ return (m_Mine_Owner[AV_NORTH_MINE]==team);
+ if(GOId == BG_AV_OBJECTID_MINE_S)
+ return (m_Mine_Owner[AV_SOUTH_MINE]==team);
+ return true; //cause it's no mine'object it is ok if this is true
+}
+
+void BattleGroundAV::PopulateNode(BG_AV_Nodes node)
+{
+ uint32 owner = m_Nodes[node].Owner;
+ assert(owner);
+
+ uint32 c_place = AV_CPLACE_DEFENSE_STORM_AID + ( 4 * node );
+ uint32 creatureid;
+ if(IsTower(node))
+ creatureid=(owner==ALLIANCE)?AV_NPC_A_TOWERDEFENSE:AV_NPC_H_TOWERDEFENSE;
+ else
+ {
+ uint8 team2 = GetTeamIndexByTeamId(owner);
+ if (m_Team_QuestStatus[team2][0] < 500 )
+ creatureid = ( owner == ALLIANCE )? AV_NPC_A_GRAVEDEFENSE0 : AV_NPC_H_GRAVEDEFENSE0;
+ else if ( m_Team_QuestStatus[team2][0] < 1000 )
+ creatureid = ( owner == ALLIANCE )? AV_NPC_A_GRAVEDEFENSE1 : AV_NPC_H_GRAVEDEFENSE1;
+ else if ( m_Team_QuestStatus[team2][0] < 1500 )
+ creatureid = ( owner == ALLIANCE )? AV_NPC_A_GRAVEDEFENSE2 : AV_NPC_H_GRAVEDEFENSE2;
+ else
+ creatureid = ( owner == ALLIANCE )? AV_NPC_A_GRAVEDEFENSE3 : AV_NPC_H_GRAVEDEFENSE3;
+ //spiritguide
+ if( m_BgCreatures[node] )
+ DelCreature(node);
+ if( !AddSpiritGuide(node, BG_AV_CreaturePos[node][0], BG_AV_CreaturePos[node][1], BG_AV_CreaturePos[node][2], BG_AV_CreaturePos[node][3], owner))
+ sLog.outError("AV: couldn't spawn spiritguide at node %i",node);
+
+ }
+ for(uint8 i=0; i<4; i++)
+ {
+ Creature* cr = AddAVCreature(creatureid,c_place+i);
+ }
+}
+void BattleGroundAV::DePopulateNode(BG_AV_Nodes node)
+{
+ uint32 c_place = AV_CPLACE_DEFENSE_STORM_AID + ( 4 * node );
+ for(uint8 i=0; i<4; i++)
+ if( m_BgCreatures[c_place+i] )
+ DelCreature(c_place+i);
+ //spiritguide
+ if( !IsTower(node) && m_BgCreatures[node] )
+ DelCreature(node);
+}
+
+
+const BG_AV_Nodes BattleGroundAV::GetNodeThroughObject(uint32 object)
+{
+ sLog.outDebug("bg_AV getnodethroughobject %i",object);
+ if( object <= BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER )
+ return BG_AV_Nodes(object);
+ if( object <= BG_AV_OBJECT_FLAG_C_A_FROSTWOLF_HUT )
+ return BG_AV_Nodes(object - 11);
+ if( object <= BG_AV_OBJECT_FLAG_C_A_FROSTWOLF_WTOWER )
+ return BG_AV_Nodes(object - 7);
+ if( object <= BG_AV_OBJECT_FLAG_C_H_STONEHEART_BUNKER )
+ return BG_AV_Nodes(object -22);
+ if( object <= BG_AV_OBJECT_FLAG_H_FROSTWOLF_HUT )
+ return BG_AV_Nodes(object - 33);
+ if( object <= BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER )
+ return BG_AV_Nodes(object - 29);
+ if( object == BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE )
+ return BG_AV_NODES_SNOWFALL_GRAVE;
+ sLog.outError("BattleGroundAV: ERROR! GetPlace got a wrong object :(");
+ assert(false);
+ return BG_AV_Nodes(0);
+}
+
+const uint32 BattleGroundAV::GetObjectThroughNode(BG_AV_Nodes node)
+{ //this function is the counterpart to GetNodeThroughObject()
+ sLog.outDebug("bg_AV GetObjectThroughNode %i",node);
+ if( m_Nodes[node].Owner == ALLIANCE )
+ {
+ if( m_Nodes[node].State == POINT_ASSAULTED )
+ {
+ if( node <= BG_AV_NODES_FROSTWOLF_HUT )
+ return node+11;
+ if( node >= BG_AV_NODES_ICEBLOOD_TOWER && node <= BG_AV_NODES_FROSTWOLF_WTOWER)
+ return node+7;
+ }
+ else if ( m_Nodes[node].State == POINT_CONTROLED )
+ if( node <= BG_AV_NODES_STONEHEART_BUNKER )
+ return node;
+ }
+ else if ( m_Nodes[node].Owner == HORDE )
+ {
+ if( m_Nodes[node].State == POINT_ASSAULTED )
+ if( node <= BG_AV_NODES_STONEHEART_BUNKER )
+ return node+22;
+ else if ( m_Nodes[node].State == POINT_CONTROLED )
+ {
+ if( node <= BG_AV_NODES_FROSTWOLF_HUT )
+ return node+33;
+ if( node >= BG_AV_NODES_ICEBLOOD_TOWER && node <= BG_AV_NODES_FROSTWOLF_WTOWER)
+ return node+29;
+ }
+ }
+ else if ( m_Nodes[node].Owner == AV_NEUTRAL_TEAM )
+ return BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE;
+ sLog.outError("BattleGroundAV: Error! GetPlaceNode couldn't resolve node %i",node);
+ assert(false);
+ return 0;
+}
+
+
+//called when using banner
+
+void BattleGroundAV::EventPlayerClickedOnFlag(Player *source, GameObject* target_obj)
+{
+ if(GetStatus() != STATUS_IN_PROGRESS)
+ return;
+ int32 object = GetObjectType(target_obj->GetGUID());
+ sLog.outDebug("BG_AV using gameobject %i with type %i",target_obj->GetEntry(),object);
+ if(object < 0)
+ return;
+ switch(target_obj->GetEntry())
+ {
+ case BG_AV_OBJECTID_BANNER_A:
+ case BG_AV_OBJECTID_BANNER_A_B:
+ case BG_AV_OBJECTID_BANNER_H:
+ case BG_AV_OBJECTID_BANNER_H_B:
+ case BG_AV_OBJECTID_BANNER_SNOWFALL_N:
+ EventPlayerAssaultsPoint(source, object);
+ break;
+ case BG_AV_OBJECTID_BANNER_CONT_A:
+ case BG_AV_OBJECTID_BANNER_CONT_A_B:
+ case BG_AV_OBJECTID_BANNER_CONT_H:
+ case BG_AV_OBJECTID_BANNER_CONT_H_B:
+ EventPlayerDefendsPoint(source, object);
+ break;
+ default:
+ break;
+ }
+}
+
+void BattleGroundAV::EventPlayerDefendsPoint(Player* player, uint32 object)
+{
+ assert(GetStatus() == STATUS_IN_PROGRESS);
+ BG_AV_Nodes node = GetNodeThroughObject(object);
+
+ uint32 owner = m_Nodes[node].Owner; //maybe should name it prevowner
+ uint32 team = player->GetTeam();
+
+ if(owner == player->GetTeam() || m_Nodes[node].State != POINT_ASSAULTED)
+ return;
+ if(m_Nodes[node].TotalOwner == AV_NEUTRAL_TEAM)
+ { //until snowfall doesn't belong to anyone it is better handled in assault-code
+ assert(node == BG_AV_NODES_SNOWFALL_GRAVE); //currently the only neutral grave
+ EventPlayerAssaultsPoint(player,object);
+ return;
+ }
+ sLog.outDebug("player defends point object: %i node: %i",object,node);
+ if(m_Nodes[node].PrevOwner != team)
+ {
+ sLog.outError("BG_AV: player defends point which doesn't belong to his team %i",node);
+ return;
+ }
+
+
+ //spawn new go :)
+ if(m_Nodes[node].Owner == ALLIANCE)
+ SpawnBGObject(object+22, RESPAWN_IMMEDIATELY); //spawn horde banner
+ else
+ SpawnBGObject(object-22, RESPAWN_IMMEDIATELY); //spawn alliance banner
+
+ if(!IsTower(node))
+ {
+ SpawnBGObject(BG_AV_OBJECT_AURA_N_FIRSTAID_STATION+3*node,RESPAWN_ONE_DAY);
+ SpawnBGObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+GetTeamIndexByTeamId(team)+3*node,RESPAWN_IMMEDIATELY);
+ }
+ // despawn old go
+ SpawnBGObject(object, RESPAWN_ONE_DAY);
+
+ DefendNode(node,team);
+ PopulateNode(node);
+ UpdateNodeWorldState(node);
+
+ if(IsTower(node))
+ {
+ //spawn big flag+aura on top of tower
+ SpawnBGObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == ALLIANCE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY);
+ SpawnBGObject(BG_AV_OBJECT_TAURA_H_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == HORDE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY);
+ SpawnBGObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == ALLIANCE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY);
+ SpawnBGObject(BG_AV_OBJECT_TFLAG_H_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team == HORDE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY);
+ }
+ else if(node == BG_AV_NODES_SNOWFALL_GRAVE) //snowfall eyecandy
+ {
+ for(uint8 i = 0; i < 4; i++)
+ {
+ SpawnBGObject(((owner==ALLIANCE)?BG_AV_OBJECT_SNOW_EYECANDY_PA : BG_AV_OBJECT_SNOW_EYECANDY_PH)+i,RESPAWN_ONE_DAY);
+ SpawnBGObject(((team==ALLIANCE)?BG_AV_OBJECT_SNOW_EYECANDY_A : BG_AV_OBJECT_SNOW_EYECANDY_H)+i,RESPAWN_IMMEDIATELY);
+ }
+ }
+ //send a nice message to all :)
+ char buf[256];
+ sprintf(buf, GetTrinityString(( IsTower(node) ) ? LANG_BG_AV_TOWER_DEFENDED : LANG_BG_AV_GRAVE_DEFENDED), GetNodeName(node),( team == ALLIANCE ) ? GetTrinityString(LANG_BG_AV_ALLY) : GetTrinityString(LANG_BG_AV_HORDE));
+ Creature* creature = GetBGCreature(AV_CPLACE_HERALD);
+ if(creature)
+ YellToAll(creature,buf,LANG_UNIVERSAL);
+ //update the statistic for the defending player
+ UpdatePlayerScore(player, ( IsTower(node) ) ? SCORE_TOWERS_DEFENDED : SCORE_GRAVEYARDS_DEFENDED, 1);
+ if(IsTower(node))
+ PlaySoundToAll(AV_SOUND_BOTH_TOWER_DEFEND);
+ else
+ PlaySoundToAll((team==ALLIANCE)?AV_SOUND_ALLIANCE_GOOD:AV_SOUND_HORDE_GOOD);
+}
+
+void BattleGroundAV::EventPlayerAssaultsPoint(Player* player, uint32 object)
+{
+ assert(GetStatus() == STATUS_IN_PROGRESS);
+
+ BG_AV_Nodes node = GetNodeThroughObject(object);
+ uint32 owner = m_Nodes[node].Owner; //maybe name it prevowner
+ uint32 team = player->GetTeam();
+ sLog.outDebug("bg_av: player assaults point object %i node %i",object,node);
+ if(owner == team || team == m_Nodes[node].TotalOwner)
+ return; //surely a gm used this object
+
+
+ if(node == BG_AV_NODES_SNOWFALL_GRAVE) //snowfall is a bit special in capping + it gets eyecandy stuff
+ {
+ if(object == BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE) //initial capping
+ {
+ assert(owner == AV_NEUTRAL_TEAM && m_Nodes[node].TotalOwner == AV_NEUTRAL_TEAM);
+ if( team == ALLIANCE )
+ SpawnBGObject(BG_AV_OBJECT_FLAG_C_A_SNOWFALL_GRAVE, RESPAWN_IMMEDIATELY);
+ else
+ SpawnBGObject(BG_AV_OBJECT_FLAG_C_H_SNOWFALL_GRAVE, RESPAWN_IMMEDIATELY);
+ SpawnBGObject(BG_AV_OBJECT_AURA_N_FIRSTAID_STATION+3*node,RESPAWN_IMMEDIATELY); //neutral aura spawn
+ }
+ else if(m_Nodes[node].TotalOwner == AV_NEUTRAL_TEAM) //recapping, when no team owns this node realy
+ {
+ assert(m_Nodes[node].State != POINT_CONTROLED);
+ if(team == ALLIANCE)
+ SpawnBGObject(object-11, RESPAWN_IMMEDIATELY);
+ else
+ SpawnBGObject(object+11, RESPAWN_IMMEDIATELY);
+ }
+ //eyecandy
+ uint32 spawn,despawn;
+ if(team == ALLIANCE)
+ {
+ despawn = ( m_Nodes[node].State == POINT_ASSAULTED )?BG_AV_OBJECT_SNOW_EYECANDY_PH : BG_AV_OBJECT_SNOW_EYECANDY_H;
+ spawn = BG_AV_OBJECT_SNOW_EYECANDY_PA;
+ }
+ else
+ {
+ despawn = ( m_Nodes[node].State == POINT_ASSAULTED )?BG_AV_OBJECT_SNOW_EYECANDY_PA : BG_AV_OBJECT_SNOW_EYECANDY_A;
+ spawn = BG_AV_OBJECT_SNOW_EYECANDY_PH;
+ }
+ for(uint8 i = 0; i < 4; i++)
+ {
+ SpawnBGObject(despawn+i,RESPAWN_ONE_DAY);
+ SpawnBGObject(spawn+i,RESPAWN_IMMEDIATELY);
+ }
+ }
+
+ //if snowfall gots capped it can be handled like all other graveyards
+ if( m_Nodes[node].TotalOwner != AV_NEUTRAL_TEAM)
+ {
+ assert(m_Nodes[node].Owner != AV_NEUTRAL_TEAM);
+ if(team == ALLIANCE)
+ SpawnBGObject(object-22, RESPAWN_IMMEDIATELY);
+ else
+ SpawnBGObject(object+22, RESPAWN_IMMEDIATELY);
+ if(IsTower(node))
+ { //spawning/despawning of bigflag+aura
+ SpawnBGObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team==ALLIANCE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY);
+ SpawnBGObject(BG_AV_OBJECT_TAURA_H_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team==HORDE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY);
+ SpawnBGObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team==ALLIANCE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY);
+ SpawnBGObject(BG_AV_OBJECT_TFLAG_H_DUNBALDAR_SOUTH+(2*(node-BG_AV_NODES_DUNBALDAR_SOUTH)),(team==HORDE)? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY);
+ }
+ else
+ {
+ //spawning/despawning of aura
+ SpawnBGObject(BG_AV_OBJECT_AURA_N_FIRSTAID_STATION+3*node,RESPAWN_IMMEDIATELY); //neutral aura spawn
+ SpawnBGObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+GetTeamIndexByTeamId(owner)+3*node,RESPAWN_ONE_DAY); //teeamaura despawn
+ // Those who are waiting to resurrect at this object are taken to the closest own object's graveyard
+ std::vector<uint64> ghost_list = m_ReviveQueue[m_BgCreatures[node]];
+ if( !ghost_list.empty() )
+ {
+ Player *plr;
+ WorldSafeLocsEntry const *ClosestGrave = NULL;
+ for (std::vector<uint64>::iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr)
+ {
+ plr = objmgr.GetPlayer(*ghost_list.begin());
+ if( !plr )
+ continue;
+ if(!ClosestGrave)
+ ClosestGrave = GetClosestGraveYard(plr->GetPositionX(), plr->GetPositionY(), plr->GetPositionZ(), team);
+ else
+ plr->TeleportTo(GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation());
+ }
+ m_ReviveQueue[m_BgCreatures[node]].clear();
+ }
+ }
+ DePopulateNode(node);
+ }
+
+ SpawnBGObject(object, RESPAWN_ONE_DAY); //delete old banner
+ AssaultNode(node,team);
+ UpdateNodeWorldState(node);
+
+ //send a nice message to all :)
+ char buf[256];
+ sprintf(buf, ( IsTower(node) ) ? GetTrinityString(LANG_BG_AV_TOWER_ASSAULTED) : GetTrinityString(LANG_BG_AV_GRAVE_ASSAULTED), GetNodeName(node), ( team == ALLIANCE ) ? GetTrinityString(LANG_BG_AV_ALLY) : GetTrinityString(LANG_BG_AV_HORDE ));
+ Creature* creature = GetBGCreature(AV_CPLACE_HERALD);
+ if(creature)
+ YellToAll(creature,buf,LANG_UNIVERSAL);
+ //update the statistic for the assaulting player
+ UpdatePlayerScore(player, ( IsTower(node) ) ? SCORE_TOWERS_ASSAULTED : SCORE_GRAVEYARDS_ASSAULTED, 1);
+ PlaySoundToAll((team==ALLIANCE)?AV_SOUND_ALLIANCE_ASSAULTS:AV_SOUND_HORDE_ASSAULTS);
+}
+
+void BattleGroundAV::FillInitialWorldStates(WorldPacket& data)
+{
+ bool stateok;
+ //graveyards
+ for (uint8 i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_FROSTWOLF_HUT; i++)
+ {
+ for (uint8 j =1; j <= 3; j+=2)
+ {//j=1=assaulted j=3=controled
+ stateok = (m_Nodes[i].State == j);
+ data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j,ALLIANCE)]) << uint32((m_Nodes[i].Owner == ALLIANCE && stateok)?1:0);
+ data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j,HORDE)]) << uint32((m_Nodes[i].Owner == HORDE && stateok)?1:0);
+ }
+ }
+
+ //towers
+ for (uint8 i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_MAX; i++)
+ for (uint8 j =1; j <= 3; j+=2)
+ {//j=1=assaulted j=3=controled //i dont have j=2=destroyed cause destroyed is the same like enemy-team controll
+ stateok = (m_Nodes[i].State == j || (m_Nodes[i].State == POINT_DESTROYED && j==3));
+ data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j,ALLIANCE)]) << uint32((m_Nodes[i].Owner == ALLIANCE && stateok)?1:0);
+ data << uint32(BG_AV_NodeWorldStates[i][GetWorldStateType(j,HORDE)]) << uint32((m_Nodes[i].Owner == HORDE && stateok)?1:0);
+ }
+ if(m_Nodes[BG_AV_NODES_SNOWFALL_GRAVE].Owner == AV_NEUTRAL_TEAM) //cause neutral teams aren't handled generic
+ data << uint32(AV_SNOWFALL_N) << uint32(1);
+ data << uint32(AV_Alliance_Score) << uint32(m_Team_Scores[0]);
+ data << uint32(AV_Horde_Score) << uint32(m_Team_Scores[1]);
+ if(GetStatus() == STATUS_IN_PROGRESS){ //only if game started the teamscores are displayed
+ data << uint32(AV_SHOW_A_SCORE) << uint32(1);
+ data << uint32(AV_SHOW_H_SCORE) << uint32(1);
+ }
+ else
+ {
+ data << uint32(AV_SHOW_A_SCORE) << uint32(0);
+ data << uint32(AV_SHOW_H_SCORE) << uint32(0);
+ }
+ SendMineWorldStates(AV_NORTH_MINE);
+ SendMineWorldStates(AV_SOUTH_MINE);
+}
+
+const uint8 BattleGroundAV::GetWorldStateType(uint8 state, uint16 team) //this is used for node worldstates and returns values which fit good into the worldstatesarray
+{
+ //neutral stuff cant get handled (currently its only snowfall)
+ assert(team != AV_NEUTRAL_TEAM);
+//a_c a_a h_c h_a the positions in worldstate-array
+ if(team == ALLIANCE)
+ {
+ if(state==POINT_CONTROLED || state==POINT_DESTROYED)
+ return 0;
+ if(state==POINT_ASSAULTED)
+ return 1;
+ }
+ if(team == HORDE)
+ {
+ if(state==POINT_DESTROYED || state==POINT_CONTROLED)
+ return 2;
+ if(state==POINT_ASSAULTED)
+ return 3;
+ }
+ sLog.outError("BG_AV: should update a strange worldstate state:%i team:%i",state,team);
+ return 5; //this will crash the game, but i want to know if something is wrong here
+}
+
+void BattleGroundAV::UpdateNodeWorldState(BG_AV_Nodes node)
+{
+ UpdateWorldState(BG_AV_NodeWorldStates[node][GetWorldStateType(m_Nodes[node].State,m_Nodes[node].Owner)],1);
+ if(m_Nodes[node].PrevOwner == AV_NEUTRAL_TEAM) //currently only snowfall is supported as neutral node (i don't want to make an extra row (neutral states) in worldstatesarray just for one node
+ UpdateWorldState(AV_SNOWFALL_N,0);
+ else
+ UpdateWorldState(BG_AV_NodeWorldStates[node][GetWorldStateType(m_Nodes[node].PrevState,m_Nodes[node].PrevOwner)],0);
+}
+
+void BattleGroundAV::SendMineWorldStates(uint32 mine)
+{
+ assert(mine == AV_NORTH_MINE || mine==AV_SOUTH_MINE);
+// currently i'm sure, that this works (:
+// assert(m_Mine_PrevOwner[mine] == ALLIANCE || m_Mine_PrevOwner[mine] == HORDE || m_Mine_PrevOwner[mine] == AV_NEUTRAL_TEAM);
+// assert(m_Mine_Owner[mine] == ALLIANCE || m_Mine_Owner[mine] == HORDE || m_Mine_Owner[mine] == AV_NEUTRAL_TEAM);
+
+ uint8 owner,prevowner,mine2; //those variables are needed to access the right worldstate in the BG_AV_MineWorldStates array
+ mine2 = (mine==AV_NORTH_MINE)?0:1;
+ if(m_Mine_PrevOwner[mine] == ALLIANCE)
+ prevowner = 0;
+ else if(m_Mine_PrevOwner[mine] == HORDE)
+ prevowner = 2;
+ else
+ prevowner = 1;
+ if(m_Mine_Owner[mine] == ALLIANCE)
+ owner = 0;
+ else if(m_Mine_Owner[mine] == HORDE)
+ owner = 2;
+ else
+ owner = 1;
+
+ UpdateWorldState(BG_AV_MineWorldStates[mine2][owner],1);
+ if( prevowner != owner)
+ UpdateWorldState(BG_AV_MineWorldStates[mine2][prevowner],0);
+}
+
+
+WorldSafeLocsEntry const* BattleGroundAV::GetClosestGraveYard(float x, float y, float z, uint32 team)
+{
+ WorldSafeLocsEntry const* good_entry = NULL;
+ if( GetStatus() == STATUS_IN_PROGRESS)
+ {
+ // Is there any occupied node for this team?
+ float mindist = 9999999.0f;
+ for (uint8 i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_FROSTWOLF_HUT; ++i)
+ {
+ if (m_Nodes[i].Owner != team || m_Nodes[i].State != POINT_CONTROLED)
+ continue;
+ WorldSafeLocsEntry const*entry = sWorldSafeLocsStore.LookupEntry( BG_AV_GraveyardIds[i] );
+ if( !entry )
+ continue;
+ float dist = (entry->x - x)*(entry->x - x)+(entry->y - y)*(entry->y - y);
+ if( mindist > dist )
+ {
+ mindist = dist;
+ good_entry = entry;
+ }
+ }
+ }
+ // If not, place ghost on starting location
+ if( !good_entry )
+ good_entry = sWorldSafeLocsStore.LookupEntry( BG_AV_GraveyardIds[GetTeamIndexByTeamId(team)+7] );
+
+ return good_entry;
+}
+
+
+bool BattleGroundAV::SetupBattleGround()
+{
+ // Create starting objects
+ if(
+ // alliance gates
+ !AddObject(BG_AV_OBJECT_DOOR_A, BG_AV_OBJECTID_GATE_A, BG_AV_DoorPositons[0][0],BG_AV_DoorPositons[0][1],BG_AV_DoorPositons[0][2],BG_AV_DoorPositons[0][3],0,0,sin(BG_AV_DoorPositons[0][3]/2),cos(BG_AV_DoorPositons[0][3]/2),RESPAWN_IMMEDIATELY)
+ // horde gates
+ || !AddObject(BG_AV_OBJECT_DOOR_H, BG_AV_OBJECTID_GATE_H, BG_AV_DoorPositons[1][0],BG_AV_DoorPositons[1][1],BG_AV_DoorPositons[1][2],BG_AV_DoorPositons[1][3],0,0,sin(BG_AV_DoorPositons[1][3]/2),cos(BG_AV_DoorPositons[1][3]/2),RESPAWN_IMMEDIATELY))
+ {
+ sLog.outErrorDb("BatteGroundAV: Failed to spawn some object BattleGround not created!1");
+ return false;
+ }
+
+//spawn node-objects
+ for (uint8 i = BG_AV_NODES_FIRSTAID_STATION ; i < BG_AV_NODES_MAX; ++i)
+ {
+ if( i <= BG_AV_NODES_FROSTWOLF_HUT )
+ {
+ if( !AddObject(i,BG_AV_OBJECTID_BANNER_A_B,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(i+11,BG_AV_OBJECTID_BANNER_CONT_A_B,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(i+33,BG_AV_OBJECTID_BANNER_H_B,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(i+22,BG_AV_OBJECTID_BANNER_CONT_H_B,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY)
+ //aura
+ || !AddObject(BG_AV_OBJECT_AURA_N_FIRSTAID_STATION+i*3,BG_AV_OBJECTID_AURA_N,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(BG_AV_OBJECT_AURA_A_FIRSTAID_STATION+i*3,BG_AV_OBJECTID_AURA_A,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(BG_AV_OBJECT_AURA_H_FIRSTAID_STATION+i*3,BG_AV_OBJECTID_AURA_H,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY))
+ {
+ sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!2");
+ return false;
+ }
+ }
+ else //towers
+ {
+ if( i <= BG_AV_NODES_STONEHEART_BUNKER ) //alliance towers
+ {
+ if( !AddObject(i,BG_AV_OBJECTID_BANNER_A,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(i+22,BG_AV_OBJECTID_BANNER_CONT_H,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_AURA_A,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(BG_AV_OBJECT_TAURA_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_AURA_N,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_TOWER_BANNER_A,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(BG_AV_OBJECT_TFLAG_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_TOWER_BANNER_PH,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY))
+ {
+ sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!3");
+ return false;
+ }
+ }
+ else //horde towers
+ {
+ if( !AddObject(i+7,BG_AV_OBJECTID_BANNER_CONT_A,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(i+29,BG_AV_OBJECTID_BANNER_H,BG_AV_ObjectPos[i][0],BG_AV_ObjectPos[i][1],BG_AV_ObjectPos[i][2],BG_AV_ObjectPos[i][3], 0, 0, sin(BG_AV_ObjectPos[i][3]/2), cos(BG_AV_ObjectPos[i][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_AURA_N,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(BG_AV_OBJECT_TAURA_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_AURA_H,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_TOWER_BANNER_PA,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY)
+ || !AddObject(BG_AV_OBJECT_TFLAG_H_DUNBALDAR_SOUTH+(2*(i-BG_AV_NODES_DUNBALDAR_SOUTH)),BG_AV_OBJECTID_TOWER_BANNER_H,BG_AV_ObjectPos[i+8][0],BG_AV_ObjectPos[i+8][1],BG_AV_ObjectPos[i+8][2],BG_AV_ObjectPos[i+8][3], 0, 0, sin(BG_AV_ObjectPos[i+8][3]/2), cos(BG_AV_ObjectPos[i+8][3]/2),RESPAWN_ONE_DAY))
+ {
+ sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!4");
+ return false;
+ }
+ }
+ for(uint8 j=0; j<=9; j++) //burning aura
+ {
+ if(!AddObject(BG_AV_OBJECT_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j,BG_AV_OBJECTID_FIRE,BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][0],BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][1],BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][2],BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][3], 0, 0, sin(BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_BURN_DUNBALDAR_SOUTH+((i-BG_AV_NODES_DUNBALDAR_SOUTH)*10)+j][3]/2),RESPAWN_ONE_DAY))
+ {
+ sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!5.%i",i);
+ return false;
+ }
+ }
+ }
+ }
+ for(uint8 i=0;i<2;i++) //burning aura for buildings
+ {
+ for(uint8 j=0; j<=9; j++)
+ {
+ if(j<5)
+ {
+ if(!AddObject(BG_AV_OBJECT_BURN_BUILDING_ALLIANCE+(i*10)+j,BG_AV_OBJECTID_SMOKE,BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][0],BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][1],BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][2],BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3], 0, 0, sin(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2),RESPAWN_ONE_DAY))
+ {
+ sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!6.%i",i);
+ return false;
+ }
+ }
+ else
+ {
+ if(!AddObject(BG_AV_OBJECT_BURN_BUILDING_ALLIANCE+(i*10)+j,BG_AV_OBJECTID_FIRE,BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][0],BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][1],BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][2],BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3], 0, 0, sin(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_BURN_BUILDING_A+(i*10)+j][3]/2),RESPAWN_ONE_DAY))
+ {
+ sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!7.%i",i);
+ return false;
+ }
+ }
+ }
+ }
+ for(uint16 i= 0; i<=(BG_AV_OBJECT_MINE_SUPPLY_N_MAX-BG_AV_OBJECT_MINE_SUPPLY_N_MIN);i++)
+ {
+ if(!AddObject(BG_AV_OBJECT_MINE_SUPPLY_N_MIN+i,BG_AV_OBJECTID_MINE_N,BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][0],BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][1],BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][2],BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][3], 0, 0, sin(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_N_MIN+i][3]/2),RESPAWN_ONE_DAY))
+ {
+ sLog.outError("BatteGroundAV: Failed to spawn some mine supplies BattleGround not created!7.5.%i",i);
+ return false;
+ }
+ }
+ for(uint16 i= 0 ; i<=(BG_AV_OBJECT_MINE_SUPPLY_S_MAX-BG_AV_OBJECT_MINE_SUPPLY_S_MIN);i++)
+ {
+ if(!AddObject(BG_AV_OBJECT_MINE_SUPPLY_S_MIN+i,BG_AV_OBJECTID_MINE_S,BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][0],BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][1],BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][2],BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][3], 0, 0, sin(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_MINE_SUPPLY_S_MIN+i][3]/2),RESPAWN_ONE_DAY))
+ {
+ sLog.outError("BatteGroundAV: Failed to spawn some mine supplies BattleGround not created!7.6.%i",i);
+ return false;
+ }
+ }
+
+ if(!AddObject(BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE, BG_AV_OBJECTID_BANNER_SNOWFALL_N ,BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][0],BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][1],BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][2],BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][3],0,0,sin(BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][3]/2), cos(BG_AV_ObjectPos[BG_AV_NODES_SNOWFALL_GRAVE][3]/2), RESPAWN_ONE_DAY))
+ {
+ sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!8");
+ return false;
+ }
+ for(uint8 i = 0; i < 4; i++)
+ {
+ if(!AddObject(BG_AV_OBJECT_SNOW_EYECANDY_A+i, BG_AV_OBJECTID_SNOWFALL_CANDY_A ,BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3],0,0,sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY)
+ || !AddObject(BG_AV_OBJECT_SNOW_EYECANDY_PA+i, BG_AV_OBJECTID_SNOWFALL_CANDY_PA ,BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3],0,0,sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY)
+ || !AddObject(BG_AV_OBJECT_SNOW_EYECANDY_H+i, BG_AV_OBJECTID_SNOWFALL_CANDY_H ,BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3],0,0,sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY)
+ || !AddObject(BG_AV_OBJECT_SNOW_EYECANDY_PH+i, BG_AV_OBJECTID_SNOWFALL_CANDY_PH ,BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][0],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][1],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][2],BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3],0,0,sin(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), cos(BG_AV_ObjectPos[AV_OPLACE_SNOW_1+i][3]/2), RESPAWN_ONE_DAY))
+ {
+ sLog.outError("BatteGroundAV: Failed to spawn some object BattleGround not created!9.%i",i);
+ return false;
+ }
+ }
+ return true;
+}
+
+const char* BattleGroundAV::GetNodeName(BG_AV_Nodes node)
+{
+ switch (node)
+ {
+ case BG_AV_NODES_FIRSTAID_STATION: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_STORM_AID);
+ case BG_AV_NODES_DUNBALDAR_SOUTH: return GetTrinityString(LANG_BG_AV_NODE_TOWER_DUN_S);
+ case BG_AV_NODES_DUNBALDAR_NORTH: return GetTrinityString(LANG_BG_AV_NODE_TOWER_DUN_N);
+ case BG_AV_NODES_STORMPIKE_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_STORMPIKE);
+ case BG_AV_NODES_ICEWING_BUNKER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_ICEWING);
+ case BG_AV_NODES_STONEHEART_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_STONE);
+ case BG_AV_NODES_STONEHEART_BUNKER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_STONE);
+ case BG_AV_NODES_SNOWFALL_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_SNOW);
+ case BG_AV_NODES_ICEBLOOD_TOWER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_ICE);
+ case BG_AV_NODES_ICEBLOOD_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_ICE);
+ case BG_AV_NODES_TOWER_POINT: return GetTrinityString(LANG_BG_AV_NODE_TOWER_POINT);
+ case BG_AV_NODES_FROSTWOLF_GRAVE: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_FROST);
+ case BG_AV_NODES_FROSTWOLF_ETOWER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_FROST_E);
+ case BG_AV_NODES_FROSTWOLF_WTOWER: return GetTrinityString(LANG_BG_AV_NODE_TOWER_FROST_W);
+ case BG_AV_NODES_FROSTWOLF_HUT: return GetTrinityString(LANG_BG_AV_NODE_GRAVE_FROST_HUT);
+ default:
+ {
+ sLog.outError("tried to get name for node %u%",node);
+ return "Unknown";
+ break;
+ }
+ }
+}
+
+void BattleGroundAV::AssaultNode(BG_AV_Nodes node, uint16 team)
+{
+ assert(m_Nodes[node].TotalOwner != team);
+ assert(m_Nodes[node].Owner != team);
+ assert(m_Nodes[node].State != POINT_DESTROYED);
+ assert(m_Nodes[node].State != POINT_ASSAULTED || !m_Nodes[node].TotalOwner ); //only assault an assaulted node if no totalowner exists
+ //the timer gets another time, if the previous owner was 0==Neutral
+ m_Nodes[node].Timer = (m_Nodes[node].PrevOwner)? BG_AV_CAPTIME : BG_AV_SNOWFALL_FIRSTCAP;
+ m_Nodes[node].PrevOwner = m_Nodes[node].Owner;
+ m_Nodes[node].Owner = team;
+ m_Nodes[node].PrevState = m_Nodes[node].State;
+ m_Nodes[node].State = POINT_ASSAULTED;
+}
+
+void BattleGroundAV::DestroyNode(BG_AV_Nodes node)
+{
+ assert(m_Nodes[node].State == POINT_ASSAULTED);
+
+ m_Nodes[node].TotalOwner = m_Nodes[node].Owner;
+ m_Nodes[node].PrevOwner = m_Nodes[node].Owner;
+ m_Nodes[node].PrevState = m_Nodes[node].State;
+ m_Nodes[node].State = (m_Nodes[node].Tower)? POINT_DESTROYED : POINT_CONTROLED;
+ m_Nodes[node].Timer = 0;
+}
+
+void BattleGroundAV::InitNode(BG_AV_Nodes node, uint16 team, bool tower)
+{
+ m_Nodes[node].TotalOwner = team;
+ m_Nodes[node].Owner = team;
+ m_Nodes[node].PrevOwner = 0;
+ m_Nodes[node].State = POINT_CONTROLED;
+ m_Nodes[node].PrevState = m_Nodes[node].State;
+ m_Nodes[node].State = POINT_CONTROLED;
+ m_Nodes[node].Timer = 0;
+ m_Nodes[node].Tower = tower;
+}
+
+void BattleGroundAV::DefendNode(BG_AV_Nodes node, uint16 team)
+{
+ assert(m_Nodes[node].TotalOwner == team);
+ assert(m_Nodes[node].Owner != team);
+ assert(m_Nodes[node].State != POINT_CONTROLED && m_Nodes[node].State != POINT_DESTROYED);
+ m_Nodes[node].PrevOwner = m_Nodes[node].Owner;
+ m_Nodes[node].Owner = team;
+ m_Nodes[node].PrevState = m_Nodes[node].State;
+ m_Nodes[node].State = POINT_CONTROLED;
+ m_Nodes[node].Timer = 0;
+}
+
+void BattleGroundAV::ResetBGSubclass()
+{
+ m_MaxLevel=0;
+ for(uint8 i=0; i<2; i++) //forloop for both teams (it just make 0==alliance and 1==horde also for both mines 0=north 1=south
+ {
+ for(uint8 j=0; j<9; j++)
+ m_Team_QuestStatus[i][j]=0;
+ m_Team_Scores[i]=BG_AV_SCORE_INITIAL_POINTS;
+ m_IsInformedNearVictory[i]=false;
+ m_CaptainAlive[i] = true;
+ m_CaptainBuffTimer[i] = 120000 + urand(0,4)* 60; //as far as i could see, the buff is randomly so i make 2minutes (thats the duration of the buff itself) + 0-4minutes TODO get the right times
+ m_Mine_Owner[i] = AV_NEUTRAL_TEAM;
+ m_Mine_PrevOwner[i] = m_Mine_Owner[i];
+ }
+ for(BG_AV_Nodes i = BG_AV_NODES_FIRSTAID_STATION; i <= BG_AV_NODES_STONEHEART_GRAVE; ++i) //alliance graves
+ InitNode(i,ALLIANCE,false);
+ for(BG_AV_Nodes i = BG_AV_NODES_DUNBALDAR_SOUTH; i <= BG_AV_NODES_STONEHEART_BUNKER; ++i) //alliance towers
+ InitNode(i,ALLIANCE,true);
+ for(BG_AV_Nodes i = BG_AV_NODES_ICEBLOOD_GRAVE; i <= BG_AV_NODES_FROSTWOLF_HUT; ++i) //horde graves
+ InitNode(i,HORDE,false);
+ for(BG_AV_Nodes i = BG_AV_NODES_ICEBLOOD_TOWER; i <= BG_AV_NODES_FROSTWOLF_WTOWER; ++i) //horde towers
+ InitNode(i,HORDE,true);
+ InitNode(BG_AV_NODES_SNOWFALL_GRAVE,AV_NEUTRAL_TEAM,false); //give snowfall neutral owner
+
+ m_Mine_Timer=AV_MINE_TICK_TIMER;
+ for(uint16 i = 0; i < AV_CPLACE_MAX+AV_STATICCPLACE_MAX; i++)
+ if(m_BgCreatures[i])
+ DelCreature(i);
+
+}
+
diff --git a/src/game/BattleGroundAV.h b/src/game/BattleGroundAV.h
index 5b69af9458b..e80ad47d869 100644
--- a/src/game/BattleGroundAV.h
+++ b/src/game/BattleGroundAV.h
@@ -23,6 +23,1462 @@
class BattleGround;
+#define LANG_BG_AV_A_CAPTAIN_BUFF "Begone. Uncouth scum! The Alliance shall prevail in Alterac Valley!"
+#define LANG_BG_AV_H_CAPTAIN_BUFF "Now is the time to attack! For the Horde!"
+#define LANG_BG_AV_S_MINE_BOSS_CLAIMS "Snivvle is here! Snivvle claims the Coldtooth Mine!"
+
+#define BG_AV_CAPTIME 240000 //4:00
+#define BG_AV_SNOWFALL_FIRSTCAP 300000 //5:00 but i also have seen 4:05
+
+#define BG_AV_SCORE_INITIAL_POINTS 600
+#define SEND_MSG_NEAR_LOSE 120
+
+#define BG_AV_KILL_BOSS 4
+#define BG_AV_REP_BOSS 350
+
+#define BG_AV_KILL_CAPTAIN 3
+#define BG_AV_REP_CAPTAIN 125
+#define BG_AV_RES_CAPTAIN 100
+
+#define BG_AV_KILL_TOWER 3
+#define BG_AV_REP_TOWER 12
+#define BG_AV_RES_TOWER 75
+
+#define BG_AV_GET_COMMANDER 1 //for a safely returned wingcommander
+//bonushonor at the end
+#define BG_AV_KILL_SURVIVING_TOWER 2
+#define BG_AV_REP_SURVIVING_TOWER 12
+
+#define BG_AV_KILL_SURVIVING_CAPTAIN 2
+#define BG_AV_REP_SURVIVING_CAPTAIN 125
+
+enum BG_AV_Sounds
+{ //TODO: get out if there comes a sound when neutral team captures mine
+
+/*
+8212:
+ alliance grave assault
+ alliance tower assault
+ drek "mlanzenabschaum! In meiner Burg?! Toetet sie all" - nicht immer der sound
+8333:
+ galv "sterbt fuer euch ist kein platz hier"
+
+8332:
+ bal "Verschwinde, dreckiger Abschaum! Die Allianz wird im Alteractal "
+8174:
+ horde tower assault
+ horde grave assault
+ van "es Sturmlanzenklans, euer General wird angegriffen! Ich fordere Unterst"
+8173:
+ ally grave capture/defend
+ tower destroy
+ mine capture
+ ally wins
+8192:
+ ally tower destroy(only iceblood - found a bug^^)
+ ally tower defend
+ horde tower defend
+8213
+horde:
+ grave defend/capture
+ tower destroy
+ mine capture
+ horde wins
+ */
+
+ AV_SOUND_NEAR_VICTORY = 8456, //not confirmed yet
+
+ AV_SOUND_ALLIANCE_ASSAULTS = 8212, //tower,grave + enemy boss if someone tries to attack him
+ AV_SOUND_HORDE_ASSAULTS = 8174,
+ AV_SOUND_ALLIANCE_GOOD = 8173, //if something good happens for the team: wins(maybe only through killing the boss), captures mine or grave, destroys tower and defends grave
+ AV_SOUND_HORDE_GOOD = 8213,
+ AV_SOUND_BOTH_TOWER_DEFEND = 8192,
+
+ AV_SOUND_ALLIANCE_CAPTAIN = 8232, //gets called when someone attacks them and at the beginning after 3min+rand(x)*10sec (maybe buff)
+ AV_SOUND_HORDE_CAPTAIN = 8333,
+
+
+};
+
+enum BG_AV_OTHER_VALUES
+{
+ AV_STATICCPLACE_MAX = 123,
+ AV_NORTH_MINE = 0,
+ AV_SOUTH_MINE = 1,
+ AV_MINE_TICK_TIMER = 45000,
+ AV_MINE_RECLAIM_TIMER = 1200000, //TODO: get the right value.. this is currently 20 minutes
+ AV_NEUTRAL_TEAM = 0 //this is the neutral owner of snowfall
+};
+enum BG_AV_ObjectIds
+{
+ //cause the mangos-system is a bit different, we don't use the right go-ids for every node.. if we want to be 100% like another big server, we must take one object for every node
+ //snowfall 4flags as eyecandy 179424 (alliance neutral)
+ //Banners - stolen from battleground_AB.h ;-)
+ BG_AV_OBJECTID_BANNER_A = 178925, // can only be used by horde
+ BG_AV_OBJECTID_BANNER_H = 178943, // can only be used by alliance
+ BG_AV_OBJECTID_BANNER_CONT_A = 178940, // can only be used by horde
+ BG_AV_OBJECTID_BANNER_CONT_H = 179435, // can only be used by alliance
+
+ BG_AV_OBJECTID_BANNER_A_B = 178365,
+ BG_AV_OBJECTID_BANNER_H_B = 178364,
+ BG_AV_OBJECTID_BANNER_CONT_A_B = 179286,
+ BG_AV_OBJECTID_BANNER_CONT_H_B = 179287,
+ BG_AV_OBJECTID_BANNER_SNOWFALL_N = 180418,
+
+ //snowfall eyecandy banner:
+ BG_AV_OBJECTID_SNOWFALL_CANDY_A = 179044,
+ BG_AV_OBJECTID_SNOWFALL_CANDY_PA = 179424,
+ BG_AV_OBJECTID_SNOWFALL_CANDY_H = 179064,
+ BG_AV_OBJECTID_SNOWFALL_CANDY_PH = 179425,
+
+ //banners on top of towers:
+ BG_AV_OBJECTID_TOWER_BANNER_A = 178927, //[PH] Alliance A1 Tower Banner BIG
+ BG_AV_OBJECTID_TOWER_BANNER_H = 178955, //[PH] Horde H1 Tower Banner BIG
+ BG_AV_OBJECTID_TOWER_BANNER_PA = 179446, //[PH] Alliance H1 Tower Pre-Banner BIG
+ BG_AV_OBJECTID_TOWER_BANNER_PH = 179436, //[PH] Horde A1 Tower Pre-Banner BIG
+
+ //Auras
+ BG_AV_OBJECTID_AURA_A = 180421,
+ BG_AV_OBJECTID_AURA_H = 180422,
+ BG_AV_OBJECTID_AURA_N = 180423,
+ BG_AV_OBJECTID_AURA_A_S = 180100,
+ BG_AV_OBJECTID_AURA_H_S = 180101,
+ BG_AV_OBJECTID_AURA_N_S = 180102,
+
+ BG_AV_OBJECTID_GATE_A = 180424,
+ BG_AV_OBJECTID_GATE_H = 180424,
+
+ //mine supplies
+ BG_AV_OBJECTID_MINE_N = 178785,
+ BG_AV_OBJECTID_MINE_S = 178784,
+
+ BG_AV_OBJECTID_FIRE = 179065,
+ BG_AV_OBJECTID_SMOKE = 179066
+};
+
+enum BG_AV_Nodes
+{
+ BG_AV_NODES_FIRSTAID_STATION = 0,
+ BG_AV_NODES_STORMPIKE_GRAVE = 1,
+ BG_AV_NODES_STONEHEART_GRAVE = 2,
+ BG_AV_NODES_SNOWFALL_GRAVE = 3,
+ BG_AV_NODES_ICEBLOOD_GRAVE = 4,
+ BG_AV_NODES_FROSTWOLF_GRAVE = 5,
+ BG_AV_NODES_FROSTWOLF_HUT = 6,
+ BG_AV_NODES_DUNBALDAR_SOUTH = 7,
+ BG_AV_NODES_DUNBALDAR_NORTH = 8,
+ BG_AV_NODES_ICEWING_BUNKER = 9,
+ BG_AV_NODES_STONEHEART_BUNKER = 10,
+ BG_AV_NODES_ICEBLOOD_TOWER = 11,
+ BG_AV_NODES_TOWER_POINT = 12,
+ BG_AV_NODES_FROSTWOLF_ETOWER = 13,
+ BG_AV_NODES_FROSTWOLF_WTOWER = 14,
+
+ BG_AV_NODES_MAX = 15
+};
+
+enum BG_AV_ObjectTypes
+{
+ BG_AV_OBJECT_FLAG_A_FIRSTAID_STATION = 0,
+ BG_AV_OBJECT_FLAG_A_STORMPIKE_GRAVE = 1,
+ BG_AV_OBJECT_FLAG_A_STONEHEART_GRAVE = 2,
+ BG_AV_OBJECT_FLAG_A_SNOWFALL_GRAVE = 3,
+ BG_AV_OBJECT_FLAG_A_ICEBLOOD_GRAVE = 4,
+ BG_AV_OBJECT_FLAG_A_FROSTWOLF_GRAVE = 5,
+ BG_AV_OBJECT_FLAG_A_FROSTWOLF_HUT = 6,
+ BG_AV_OBJECT_FLAG_A_DUNBALDAR_SOUTH = 7,
+ BG_AV_OBJECT_FLAG_A_DUNBALDAR_NORTH = 8,
+ BG_AV_OBJECT_FLAG_A_ICEWING_BUNKER = 9,
+ BG_AV_OBJECT_FLAG_A_STONEHEART_BUNKER = 10,
+
+ BG_AV_OBJECT_FLAG_C_A_FIRSTAID_STATION = 11,
+ BG_AV_OBJECT_FLAG_C_A_STORMPIKE_GRAVE = 12,
+ BG_AV_OBJECT_FLAG_C_A_STONEHEART_GRAVE = 13,
+ BG_AV_OBJECT_FLAG_C_A_SNOWFALL_GRAVE = 14,
+ BG_AV_OBJECT_FLAG_C_A_ICEBLOOD_GRAVE = 15,
+ BG_AV_OBJECT_FLAG_C_A_FROSTWOLF_GRAVE = 16,
+ BG_AV_OBJECT_FLAG_C_A_FROSTWOLF_HUT = 17,
+ BG_AV_OBJECT_FLAG_C_A_ICEBLOOD_TOWER = 18,
+ BG_AV_OBJECT_FLAG_C_A_TOWER_POINT = 19,
+ BG_AV_OBJECT_FLAG_C_A_FROSTWOLF_ETOWER = 20,
+ BG_AV_OBJECT_FLAG_C_A_FROSTWOLF_WTOWER = 21,
+
+ BG_AV_OBJECT_FLAG_C_H_FIRSTAID_STATION = 22,
+ BG_AV_OBJECT_FLAG_C_H_STORMPIKE_GRAVE = 23,
+ BG_AV_OBJECT_FLAG_C_H_STONEHEART_GRAVE = 24,
+ BG_AV_OBJECT_FLAG_C_H_SNOWFALL_GRAVE = 25,
+ BG_AV_OBJECT_FLAG_C_H_ICEBLOOD_GRAVE = 26,
+ BG_AV_OBJECT_FLAG_C_H_FROSTWOLF_GRAVE = 27,
+ BG_AV_OBJECT_FLAG_C_H_FROSTWOLF_HUT = 28,
+ BG_AV_OBJECT_FLAG_C_H_DUNBALDAR_SOUTH = 29,
+ BG_AV_OBJECT_FLAG_C_H_DUNBALDAR_NORTH = 30,
+ BG_AV_OBJECT_FLAG_C_H_ICEWING_BUNKER = 31,
+ BG_AV_OBJECT_FLAG_C_H_STONEHEART_BUNKER = 32,
+
+ BG_AV_OBJECT_FLAG_H_FIRSTAID_STATION = 33,
+ BG_AV_OBJECT_FLAG_H_STORMPIKE_GRAVE = 34,
+ BG_AV_OBJECT_FLAG_H_STONEHEART_GRAVE = 35,
+ BG_AV_OBJECT_FLAG_H_SNOWFALL_GRAVE = 36,
+ BG_AV_OBJECT_FLAG_H_ICEBLOOD_GRAVE = 37,
+ BG_AV_OBJECT_FLAG_H_FROSTWOLF_GRAVE = 38,
+ BG_AV_OBJECT_FLAG_H_FROSTWOLF_HUT = 39,
+ BG_AV_OBJECT_FLAG_H_ICEBLOOD_TOWER = 40,
+ BG_AV_OBJECT_FLAG_H_TOWER_POINT = 41,
+ BG_AV_OBJECT_FLAG_H_FROSTWOLF_ETOWER = 42,
+ BG_AV_OBJECT_FLAG_H_FROSTWOLF_WTOWER = 43,
+
+ BG_AV_OBJECT_FLAG_N_SNOWFALL_GRAVE = 44,
+
+ BG_AV_OBJECT_DOOR_H = 45,
+ BG_AV_OBJECT_DOOR_A = 46,
+//auras for graveyards (3auras per graveyard neutral,alliance,horde)
+ BG_AV_OBJECT_AURA_N_FIRSTAID_STATION = 47,
+ BG_AV_OBJECT_AURA_A_FIRSTAID_STATION = 48,
+ BG_AV_OBJECT_AURA_H_FIRSTAID_STATION = 49,
+ BG_AV_OBJECT_AURA_N_STORMPIKE_GRAVE = 50,
+ BG_AV_OBJECT_AURA_A_STORMPIKE_GRAVE = 51,
+ BG_AV_OBJECT_AURA_H_STORMPIKE_GRAVE = 52,
+ BG_AV_OBJECT_AURA_N_STONEHEART_GRAVE = 53,
+ BG_AV_OBJECT_AURA_A_STONEHEART_GRAVE = 54,
+ BG_AV_OBJECT_AURA_H_STONEHEART_GRAVE = 55,
+ BG_AV_OBJECT_AURA_N_SNOWFALL_GRAVE = 56,
+ BG_AV_OBJECT_AURA_A_SNOWFALL_GRAVE = 57,
+ BG_AV_OBJECT_AURA_H_SNOWFALL_GRAVE = 58,
+ BG_AV_OBJECT_AURA_N_ICEBLOOD_GRAVE = 59,
+ BG_AV_OBJECT_AURA_A_ICEBLOOD_GRAVE = 60,
+ BG_AV_OBJECT_AURA_H_ICEBLOOD_GRAVE = 61,
+ BG_AV_OBJECT_AURA_N_FROSTWOLF_GRAVE = 62,
+ BG_AV_OBJECT_AURA_A_FROSTWOLF_GRAVE = 63,
+ BG_AV_OBJECT_AURA_H_FROSTWOLF_GRAVE = 64,
+ BG_AV_OBJECT_AURA_N_FROSTWOLF_HUT = 65,
+ BG_AV_OBJECT_AURA_A_FROSTWOLF_HUT = 66,
+ BG_AV_OBJECT_AURA_H_FROSTWOLF_HUT = 67,
+
+ //big flags on top of towers 2 flags on each (contested,(alliance | horde)) + 2 auras
+ BG_AV_OBJECT_TFLAG_A_DUNBALDAR_SOUTH = 67,
+ BG_AV_OBJECT_TFLAG_H_DUNBALDAR_SOUTH = 68,
+ BG_AV_OBJECT_TFLAG_A_DUNBALDAR_NORTH = 69,
+ BG_AV_OBJECT_TFLAG_H_DUNBALDAR_NORTH = 70,
+ BG_AV_OBJECT_TFLAG_A_ICEWING_BUNKER = 71,
+ BG_AV_OBJECT_TFLAG_H_ICEWING_BUNKER = 72,
+ BG_AV_OBJECT_TFLAG_A_STONEHEART_BUNKER = 73,
+ BG_AV_OBJECT_TFLAG_H_STONEHEART_BUNKER = 74,
+ BG_AV_OBJECT_TFLAG_A_ICEBLOOD_TOWER = 75,
+ BG_AV_OBJECT_TFLAG_H_ICEBLOOD_TOWER = 76,
+ BG_AV_OBJECT_TFLAG_A_TOWER_POINT = 77,
+ BG_AV_OBJECT_TFLAG_H_TOWER_POINT = 78,
+ BG_AV_OBJECT_TFLAG_A_FROSTWOLF_ETOWER = 79,
+ BG_AV_OBJECT_TFLAG_H_FROSTWOLF_ETOWER = 80,
+ BG_AV_OBJECT_TFLAG_A_FROSTWOLF_WTOWER = 81,
+ BG_AV_OBJECT_TFLAG_H_FROSTWOLF_WTOWER = 82,
+ BG_AV_OBJECT_TAURA_A_DUNBALDAR_SOUTH = 83,
+ BG_AV_OBJECT_TAURA_H_DUNBALDAR_SOUTH = 84,
+ BG_AV_OBJECT_TAURA_A_DUNBALDAR_NORTH = 85,
+ BG_AV_OBJECT_TAURA_H_DUNBALDAR_NORTH = 86,
+ BG_AV_OBJECT_TAURA_A_ICEWING_BUNKER = 87,
+ BG_AV_OBJECT_TAURA_H_ICEWING_BUNKER = 88,
+ BG_AV_OBJECT_TAURA_A_STONEHEART_BUNKER = 89,
+ BG_AV_OBJECT_TAURA_H_STONEHEART_BUNKER = 90,
+ BG_AV_OBJECT_TAURA_A_ICEBLOOD_TOWER = 91,
+ BG_AV_OBJECT_TAURA_H_ICEBLOOD_TOWER = 92,
+ BG_AV_OBJECT_TAURA_A_TOWER_POINT = 93,
+ BG_AV_OBJECT_TAURA_H_TOWER_POINT = 94,
+ BG_AV_OBJECT_TAURA_A_FROSTWOLF_ETOWER = 95,
+ BG_AV_OBJECT_TAURA_H_FROSTWOLF_ETOWER = 96,
+ BG_AV_OBJECT_TAURA_A_FROSTWOLF_WTOWER = 97,
+ BG_AV_OBJECT_TAURA_H_FROSTWOLF_WTOWER = 98,
+
+ BG_AV_OBJECT_BURN_DUNBALDAR_SOUTH = 99,
+ BG_AV_OBJECT_BURN_DUNBALDAR_NORTH = 109,
+ BG_AV_OBJECT_BURN_ICEWING_BUNKER = 119,
+ BG_AV_OBJECT_BURN_STONEHEART_BUNKER = 129,
+ BG_AV_OBJECT_BURN_ICEBLOOD_TOWER = 139,
+ BG_AV_OBJECT_BURN_TOWER_POINT = 149,
+ BG_AV_OBJECT_BURN_FROSTWOLF_ETWOER = 159,
+ BG_AV_OBJECT_BURN_FROSTWOLF_WTOWER = 169,
+ BG_AV_OBJECT_BURN_BUILDING_ALLIANCE = 179,
+ BG_AV_OBJECT_BURN_BUILDING_HORDE = 189,
+ BG_AV_OBJECT_SNOW_EYECANDY_A = 199,
+ BG_AV_OBJECT_SNOW_EYECANDY_PA = 203,
+ BG_AV_OBJECT_SNOW_EYECANDY_H = 207,
+ BG_AV_OBJECT_SNOW_EYECANDY_PH = 211,
+ BG_AV_OBJECT_MINE_SUPPLY_N_MIN = 215,
+ BG_AV_OBJECT_MINE_SUPPLY_N_MAX = 224,
+ BG_AV_OBJECT_MINE_SUPPLY_S_MIN = 225,
+ BG_AV_OBJECT_MINE_SUPPLY_S_MAX = 236,
+
+ BG_AV_OBJECT_MAX = 237
+};
+
+
+
+enum BG_AV_OBJECTS
+{
+ AV_OPLACE_FIRSTAID_STATION = 0,
+ AV_OPLACE_STORMPIKE_GRAVE = 1,
+ AV_OPLACE_STONEHEART_GRAVE = 2,
+ AV_OPLACE_SNOWFALL_GRAVE = 3,
+ AV_OPLACE_ICEBLOOD_GRAVE = 4,
+ AV_OPLACE_FROSTWOLF_GRAVE = 5,
+ AV_OPLACE_FROSTWOLF_HUT = 6,
+ AV_OPLACE_DUNBALDAR_SOUTH = 7,
+ AV_OPLACE_DUNBALDAR_NORTH = 8,
+ AV_OPLACE_ICEWING_BUNKER = 9,
+ AV_OPLACE_STONEHEART_BUNKER = 10,
+ AV_OPLACE_ICEBLOOD_TOWER = 11,
+ AV_OPLACE_TOWER_POINT = 12,
+ AV_OPLACE_FROSTWOLF_ETOWER = 13,
+ AV_OPLACE_FROSTWOLF_WTOWER = 14,
+ AV_OPLACE_BIGBANNER_DUNBALDAR_SOUTH = 15,
+ AV_OPLACE_BIGBANNER_DUNBALDAR_NORTH = 16,
+ AV_OPLACE_BIGBANNER_ICEWING_BUNKER = 17,
+ AV_OPLACE_BIGBANNER_STONEHEART_BUNKER = 18,
+ AV_OPLACE_BIGBANNER_ICEBLOOD_TOWER = 19,
+ AV_OPLACE_BIGBANNER_TOWER_POINT = 20,
+ AV_OPLACE_BIGBANNER_FROSTWOLF_ETOWER = 21,
+ AV_OPLACE_BIGBANNER_FROSTWOLF_WTOWER = 22,
+
+ AV_OPLACE_BURN_DUNBALDAR_SOUTH = 23,
+ AV_OPLACE_BURN_DUNBALDAR_NORTH = 33,
+ AV_OPLACE_BURN_ICEWING_BUNKER = 43,
+ AV_OPLACE_BURN_STONEHEART_BUNKER = 53,
+ AV_OPLACE_BURN_ICEBLOOD_TOWER = 63,
+ AV_OPLACE_BURN_TOWER_POINT = 73,
+ AV_OPLACE_BURN_FROSTWOLF_ETOWER = 83,
+ AV_OPLACE_BURN_FROSTWOLF_WTOWER = 93,
+ AV_OPLACE_BURN_BUILDING_A = 103,
+ AV_OPLACE_BURN_BUILDING_H = 113,
+ AV_OPLACE_SNOW_1 = 123,
+ AV_OPLACE_SNOW_2 = 124,
+ AV_OPLACE_SNOW_3 = 125,
+ AV_OPLACE_SNOW_4 = 126,
+ AV_OPLACE_MINE_SUPPLY_N_MIN = 127,
+ AV_OPLACE_MINE_SUPPLY_N_MAX = 136,
+ AV_OPLACE_MINE_SUPPLY_S_MIN = 137,
+ AV_OPLACE_MINE_SUPPLY_S_MAX = 148,
+
+ AV_OPLACE_MAX = 149
+};
+const float BG_AV_ObjectPos[AV_OPLACE_MAX][4] = {
+ {638.592f,-32.422f,46.0608f,-1.62316f },//firstaid station
+ {669.007f,-294.078f,30.2909f,2.77507f },//stormpike
+ {77.8013f,-404.7f,46.7549f,-0.872665f },//stone grave
+ {-202.581f,-112.73f,78.4876f,-0.715585f },//snowfall
+ {-611.962f,-396.17f,60.8351f,2.53682f}, //iceblood grave
+ {-1082.45f,-346.823f,54.9219f,-1.53589f },//frostwolf grave
+ {-1402.21f,-307.431f,89.4424f,0.191986f },//frostwolf hut
+ {553.779f,-78.6566f,51.9378f,-1.22173f }, //dunnbaldar south
+ {674.001f,-143.125f,63.6615f,0.994838f }, //dunbaldar north
+ {203.281f,-360.366f,56.3869f,-0.925024f }, //icew
+ {-152.437f,-441.758f,40.3982f,-1.95477f }, //stone
+ {-571.88f,-262.777f,75.0087f,-0.802851f }, //ice tower
+ {-768.907f,-363.71f,90.8949f,1.07991f}, //tower point
+ {-1302.9f,-316.981f,113.867f,2.00713f }, //frostwolf etower
+ {-1297.5f,-266.767f,114.15f,3.31044f}, //frostwolf wtower
+ //bigbanner:
+ {555.848f,-84.4151f,64.4397f,3.12414f }, //duns
+ {679.339f,-136.468f,73.9626f,-2.16421f }, //dunn
+ {208.973f,-365.971f,66.7409f,-0.244346f }, //icew
+ {-155.832f,-449.401f,52.7306f,0.610865f }, //stone
+ {-572.329f,-262.476f,88.6496f,-0.575959f }, //icetower
+ {-768.199f,-363.105f,104.537f,0.10472f }, //towerp
+ {-1302.84f,-316.582f,127.516f,0.122173f }, //etower
+ {-1297.87f,-266.762f,127.796f,0.0698132f }, //wtower
+ //burning auras towers have 9*179065 captain-buildings have 5*179066+5*179065
+ //dunns
+ {562.632f,-88.1815f,61.993f,0.383972f },
+ {562.523f,-74.5028f,37.9474f,-0.0523599f },
+ {558.097f,-70.9842f,52.4876f,0.820305f },
+ {578.167f,-71.8191f,38.1514f,2.72271f },
+ {556.028f,-94.9242f,44.8191f,3.05433f },
+ {572.451f,-94.3655f,37.9443f,-1.72788f },
+ {549.263f,-79.3645f,44.8191f,0.436332f },
+ {543.513f,-94.4006f,52.4819f,0.0349066f },
+ {572.149f,-93.7862f,52.5726f,0.541052f },
+ {582.162f,-81.2375f,37.9216f,0.0872665f },
+ //dunn
+ {664.797f,-143.65f,64.1784f,-0.453786f},
+ {664.505f,-139.452f,49.6696f,-0.0349067f},
+ {676.067f,-124.319f,49.6726f,-1.01229f},
+ {693.004f,-144.025f,64.1755f,2.44346f},
+ {661.175f,-117.691f,49.645f,1.91986f},
+ {684.423f,-146.582f,63.6662f,0.994838f},
+ {682.791f,-127.769f,62.4155f,1.09956f},
+ {674.576f,-147.101f,56.5425f,-1.6057f},
+ {655.719f,-126.673f,49.8138f,2.80998f},
+ {0,0,0,0},
+ //icew
+ {231.503f,-356.688f,42.3704f,0.296706f},
+ {224.989f,-348.175f,42.5607f,1.50098f},
+ {205.782f,-351.335f,56.8998f,1.01229f},
+ {196.605f,-369.187f,56.3914f,2.46091f},
+ {210.619f,-376.938f,49.2677f,2.86234f},
+ {209.647f,-352.632f,42.3959f,-0.698132f},
+ {220.65f,-368.132f,42.3978f,-0.2618f},
+ {224.682f,-374.031f,57.0679f,0.541052f},
+ {200.26f,-359.968f,49.2677f,-2.89725f},
+ {196.619f,-378.016f,56.9131f,1.01229f},
+ //stone
+ {-155.488f,-437.356f,33.2796f,2.60054f},
+ {-163.441f,-454.188f,33.2796f,1.93732f},
+ {-143.977f,-445.148f,26.4097f,-1.8675f},
+ {-135.764f,-464.708f,26.3823f,2.25147f},
+ {-154.076f,-466.929f,41.0636f,-1.8675f},
+ {-149.908f,-460.332f,26.4083f,-2.09439f},
+ {-151.638f,-439.521f,40.3797f,0.436332f},
+ {-131.301f,-454.905f,26.5771f,2.93215f},
+ {-171.291f,-444.684f,40.9211f,2.30383f},
+ {-143.591f,-439.75f,40.9275f,-1.72788f},
+ //iceblood
+ {-572.667f,-267.923f,56.8542f,2.35619f},
+ {-561.021f,-262.689f,68.4589f,1.37881f},
+ {-572.538f,-262.649f,88.6197f,1.8326f},
+ {-574.77f,-251.45f,74.9422f,-1.18682f},
+ {-578.625f,-267.571f,68.4696f,0.506145f},
+ {-571.476f,-257.234f,63.3223f,3.10669f},
+ {-566.035f,-273.907f,52.9582f,-0.890118f},
+ {-580.948f,-259.77f,68.4696f,1.46608f},
+ {-568.318f,-267.1f,75.0008f,1.01229f},
+ {-559.621f,-268.597f,52.8986f,0.0523599f},
+ //towerp
+ {-776.072f,-368.046f,84.3558f,2.63545f},
+ {-777.564f,-368.521f,90.6701f,1.72788f},
+ {-765.461f,-357.711f,90.888f,0.314159f},
+ {-768.763f,-362.735f,104.612f,1.81514f},
+ {-760.356f,-358.896f,84.3558f,2.1293f},
+ {-771.967f,-352.838f,84.3484f,1.74533f},
+ {-773.333f,-364.653f,79.2351f,-1.64061f},
+ {-764.109f,-366.069f,70.0934f,0.383972f},
+ {-767.103f,-350.737f,68.7933f,2.80998f},
+ {-760.115f,-353.845f,68.8633f,1.79769f},
+ //froste
+ {-1304.87f,-304.525f,91.8366f,-0.680679f},
+ {-1301.77f,-310.974f,95.8252f,0.907571f},
+ {-1305.58f,-320.625f,102.166f,-0.558505f},
+ {-1294.27f,-323.468f,113.893f,-1.67552f},
+ {-1302.65f,-317.192f,127.487f,2.30383f},
+ {-1293.89f,-313.478f,107.328f,1.6057f},
+ {-1312.41f,-312.999f,107.328f,1.5708f},
+ {-1311.57f,-308.08f,91.7666f,-1.85005f},
+ {-1314.7f,-322.131f,107.36f,0.645772f},
+ {-1304.6f,-310.754f,113.859f,-0.401426f},
+ //frostw
+ {-1308.24f,-273.26f,92.0514f,-0.139626f},
+ {-1302.26f,-262.858f,95.9269f,0.418879f},
+ {-1297.28f,-267.773f,126.756f,2.23402f},
+ {-1299.08f,-256.89f,114.108f,-2.44346f},
+ {-1303.41f,-268.237f,114.151f,-1.23918f},
+ {-1304.43f,-273.682f,107.612f,0.244346f},
+ {-1309.53f,-265.951f,92.1418f,-2.49582f},
+ {-1295.55f,-263.865f,105.033f,0.925024f},
+ {-1294.71f,-281.466f,107.664f,-1.50098f},
+ {-1289.69f,-259.521f,107.612f,-2.19912f},
+
+ //the two buildings of the captains
+ //alliance
+ {-64.4987f,-289.33f,33.4616f,-2.82743f},
+ {-5.98025f,-326.144f,38.8538f,0},
+ {-2.67893f,-306.998f,33.4165f,0},
+ {-60.25f,-309.232f,50.2408f,-1.46608f},
+ {-48.7941f,-266.533f,47.7916f,2.44346f},
+ {-3.40929f,-306.288f,33.34f,0},
+ {-48.619f,-266.917f,47.8168f,0},
+ {-62.9474f,-286.212f,66.7288f,0},
+ {-5.05132f,-325.323f,38.8536f,0},
+ {-64.2677f,-289.412f,33.469f,0},
+//horde
+ {-524.276f,-199.6f,82.8733f,-1.46608f},
+ {-518.196f,-173.085f,102.43f,0},
+ {-500.732f,-145.358f,88.5337f,2.44346f},
+ {-501.084f,-150.784f,80.8506f,0},
+ {-518.309f,-163.963f,102.521f,2.96706f},
+ {-517.053f,-200.429f,80.759f,0},
+ {-514.361f,-163.864f,104.163f,0},
+ {-568.04f,-188.707f,81.55f,0},
+ {-501.775f,-151.581f,81.2027f,0},
+ {-509.975f,-191.652f,83.2978f,0},
+
+//snowfall eyecandy
+ {-191.153f,-129.868f,78.5595f,-1.25664f },
+ {-201.282f,-134.319f,78.6753f,-0.942478f },
+ {-215.981f,-91.4101f,80.8702f,-1.74533f },
+ {-200.465f,-96.418f,79.7587f,1.36136f },
+ //mine supplies
+ //irondeep
+ {870.899f,-388.434f,61.6406f,-1.22173f},
+ {825.214f,-320.174f,63.712f,-2.82743f},
+ {837.117f,-452.556f,47.2331f,-3.12414f},
+ {869.755f,-448.867f,52.5448f,-0.855212f},
+ {949.877f,-458.198f,56.4874f,0.314159f},
+ {900.35f,-479.024f,58.3553f,0.122173f},
+ {854.449f,-442.255f,50.6589f,0.401426f},
+ {886.685f,-442.358f,54.6962f,-1.22173f},
+ {817.509f,-457.331f,48.4666f,2.07694f},
+ {793.411f,-326.281f,63.1117f,-2.79253f},
+ //coldtooth
+ {-934.212f,-57.3517f,80.277f,-0.0174535f},
+ {-916.281f,-36.8579f,77.0227f,0.122173f},
+ {-902.73f,-103.868f,75.4378f,-1.58825f},
+ {-900.514f,-143.527f,75.9686f,1.8675f},
+ {-862.882f,-0.353299f,72.1526f,-2.51327f},
+ {-854.932f,-85.9184f,68.6056f,-2.04204f},
+ {-851.833f,-118.959f,63.8672f,-0.0698131f},
+ {-849.832f,-20.8421f,70.4672f,-1.81514f},
+ {-844.25f,-60.0374f,72.1031f,-2.19912f},
+ {-820.644f,-136.043f,63.1977f,2.40855f},
+ {-947.642f,-208.807f,77.0101f,1.36136f},
+ {-951.394f,-193.695f,67.634f,0.802851f}
+};
+
+const float BG_AV_DoorPositons[2][4] = {
+ {780.487f, -493.024f, 99.9553f, 3.0976f}, //alliance
+ {-1375.193f, -538.981f, 55.2824f, 0.72178f} //horde
+};
+
+
+//creaturestuff starts here
+//is related to BG_AV_CreaturePos
+enum BG_AV_CreaturePlace
+{
+ AV_CPLACE_SPIRIT_STORM_AID = 0,
+ AV_CPLACE_SPIRIT_STORM_GRAVE = 1,
+ AV_CPLACE_SPIRIT_STONE_GRAVE = 2,
+ AV_CPLACE_SPIRIT_SNOWFALL = 3,
+ AV_CPLACE_SPIRIT_ICE_GRAVE = 4,
+ AV_CPLACE_SPIRIT_FROSTWOLF = 5,
+ AV_CPLACE_SPIRIT_FROST_HUT = 6,
+ AV_CPLACE_SPIRIT_MAIN_ALLIANCE = 7,
+ AV_CPLACE_SPIRIT_MAIN_HORDE = 8,
+//i don't will add for all 4 positions a variable.. i think one is enough to compute the rest
+ AV_CPLACE_DEFENSE_STORM_AID = 9,
+ AV_CPLACE_DEFEMSE_STORM_GRAVE = 13,
+ AV_CPLACE_DEFENSE_STONE_GRAVE = 17,
+ AV_CPLACE_DEFENSE_SNOWFALL = 21,
+ AV_CPLACE_DEFENSE_FROSTWOLF = 25,
+ AV_CPLACE_DEFENSE_ICE_GRAVE = 29,
+ AV_CPLACE_DEFENSE_FROST_HUT = 33,
+
+ AV_CPLACE_DEFENSE_DUN_S = 37,
+ AV_CPLACE_DEFENSE_DUN_N = 41,
+ AV_CPLACE_DEFENSE_ICEWING = 45,
+ AV_CPLACE_DEFENSE_STONE_TOWER = 49,
+ AV_CPLACE_DEFENSE_ICE_TOWER = 53,
+ AV_CPLACE_DEFENSE_TOWERPOINT = 57,
+ AV_CPLACE_DEFENSE_FROST_E = 61,
+ AV_CPLACE_DEFENSE_FROST_t = 65,
+
+ AV_CPLACE_A_MARSHAL_SOUTH = 69,
+ AV_CPLACE_A_MARSHAL_NORTH = 70,
+ AV_CPLACE_A_MARSHAL_ICE = 71,
+ AV_CPLACE_A_MARSHAL_STONE = 72,
+ AV_CPLACE_H_MARSHAL_ICE = 73,
+ AV_CPLACE_H_MARSHAL_TOWER = 74,
+ AV_CPLACE_H_MARSHAL_ETOWER = 75,
+ AV_CPLACE_H_MARSHAL_WTOWER = 76,
+ //irondeep
+ //miner:
+ AV_CPLACE_MINE_N_1_MIN = 77,
+ AV_CPLACE_MINE_N_1_MAX = 136,
+ //special types
+ AV_CPLACE_MINE_N_2_MIN = 137,
+ AV_CPLACE_MINE_N_2_MAX = 192,
+ //boss
+ AV_CPLACE_MINE_N_3 = 193,
+ //coldtooth
+ //miner:
+ AV_CPLACE_MINE_S_1_MIN = 194,
+ AV_CPLACE_MINE_S_1_MAX = 250,
+ //special types
+ AV_CPLACE_MINE_S_2_MIN = 251,
+ AV_CPLACE_MINE_S_2_MAX = 289,
+ //vermin
+ AV_CPLACE_MINE_S_S_MIN = 290,
+ AV_CPLACE_MINE_S_S_MAX = 299,
+ //boss
+ AV_CPLACE_MINE_S_3 = 300,
+
+ //herald
+ AV_CPLACE_HERALD = 301,
+
+ AV_CPLACE_MAX = 302
+};
+
+//x, y, z, o
+const float BG_AV_CreaturePos[AV_CPLACE_MAX][4] = {
+ //spiritguides
+ {643.000000f,44.000000f,69.740196f,-0.001854f},
+ {676.000000f,-374.000000f,30.000000f,-0.001854f},
+ {73.417755f,-496.433105f,48.731918f,-0.001854f},
+ {-157.409195f,31.206272f,77.050598f,-0.001854f},
+ {-531.217834f,-405.231384f,49.551376f,-0.001854f},
+ {-1090.476807f,-253.308670f,57.672371f,-0.001854f},
+ {-1496.065063f,-333.338409f,101.134804f,-0.001854f},
+ {873.001770f,-491.283630f,96.541931f,-0.001854f},
+ {-1437.670044f,-610.088989f,51.161900f,-0.001854f},
+ //grave
+ //firstaid
+ {635.17f,-29.5594f,46.5056f,4.81711f},
+ {642.488f,-32.9437f,46.365f,4.67748f},
+ {642.326f,-27.9442f,46.9211f,4.59022f},
+ {635.945f,-33.6171f,45.7164f,4.97419f},
+ //stormpike
+ {669.272f,-297.304f,30.291f,4.66604f},
+ {674.08f,-292.328f,30.4817f,0.0918785f},
+ {667.01f,-288.532f,29.8809f,1.81583f},
+ {664.153f,-294.042f,30.2851f,3.28531f},
+ //stone
+ {81.7027f,-406.135f,47.7843f,0.598464f},
+ {78.1431f,-409.215f,48.0401f,5.05953f},
+ {73.4135f,-407.035f,46.7527f,3.34736f},
+ {78.2258f,-401.859f,46.4202f,2.05852f},
+ //snowfall
+ {-207.412f,-110.616f,78.7959f,2.43251f},
+ {-197.95f,-112.205f,78.5686f,6.22441f},
+ {-202.709f,-116.829f,78.4358f,5.13742f},
+ {-202.059f,-108.314f,78.5783f,5.91968f},
+ //ice
+ {-615.501f,-393.802f,60.4299f,3.06147f},
+ {-608.513f,-392.717f,62.5724f,2.06323f},
+ {-609.769f,-400.072f,60.7174f,5.22367f},
+ {-616.093f,-398.293f,60.5628f,3.73613f},
+ //frost
+ {-1077.7f,-340.21f,55.4682f,6.25569f},
+ {-1082.74f,-333.821f,54.7962f,2.05459f},
+ {-1090.66f,-341.267f,54.6768f,3.27746f},
+ {-1081.58f,-344.63f,55.256f,4.75636f},
+ //frost hut
+ {-1408.95f,-311.69f,89.2536f,4.49954f},
+ {-1407.15f,-305.323f,89.1993f,2.86827f},
+ {-1400.64f,-304.3f,89.7008f,1.0595f},
+ {-1400.4f,-311.35f,89.3028f,4.99434f},
+ //towers
+ //dun south - OK
+ {569.395f,-101.064f,52.8296f,2.34974f},
+ {574.85f,-92.9842f,52.5869f,3.09325f},
+ {575.411f,-83.597f,52.3626f,6.26573f},
+ {571.352f,-75.6582f,52.479f,0.523599f},
+ //dun north - OK
+ {668.60f,-122.53f,64.12f,2.34f}, //not 100% ok
+ {662.253f,-129.105f,64.1794f,2.77507f},
+ {661.209f,-138.877f,64.2251f,3.38594f},
+ {665.481f,-146.857f,64.1271f,3.75246f},
+ //icewing - OK
+ {225.228f,-368.909f,56.9983f,6.23806f},
+ {191.36f,-369.899f,57.1524f,3.24631f},
+ {215.518f,-384.019f,56.9889f,5.09636f},
+ {199.625f,-382.177f,56.8691f,4.08407f},
+ //stone
+ {-172.851f,-452.366f,40.8725f,3.31829f},
+ {-147.147f,-435.053f,40.8022f,0.599238f},
+ {-169.456f,-440.325f,40.985f,2.59101f},
+ {-163.494f,-434.904f,41.0725f,1.84174f},
+ //ice - OK
+ {-573.522f,-271.854f,75.0078f,3.9619f},
+ {-565.616f,-269.051f,74.9952f,5.02655f},
+ {-562.825f,-261.087f,74.9898f,5.95157f},
+ {-569.176f,-254.446f,74.8771f,0.820305f},
+ //towerpoint
+ {-763.04f,-371.032f,90.7933f,5.25979f},
+ {-759.764f,-358.264f,90.8681f,0.289795f},
+ {-768.808f,-353.056f,90.8811f,1.52601f},
+ {-775.944f,-362.639f,90.8949f,2.59573f},
+ //frost etower
+ {-1294.13f,-313.045f,107.328f,0.270162f},
+ {-1306.5f,-308.105f,113.767f,1.78755f},
+ {-1294.78f,-319.966f,113.79f,5.94545f},
+ {-1294.83f,-312.241f,113.799f,0.295293f},
+ //frost wtower
+ {-1300.96f,-275.111f,114.058f,4.12804f},
+ {-1302.41f,-259.256f,114.065f,1.67602f},
+ {-1287.97f,-262.087f,114.165f,6.18264f},
+ {-1291.59f,-271.166f,114.151f,5.28257f},
+
+ //alliance marshall
+ {721.104f,-7.64155f,50.7046f,3.45575f},// south
+ {723.058f,-14.1548f,50.7046f,3.40339f},// north
+ {715.691f,-4.72233f,50.2187f,3.47321f},// icewing
+ {720.046f,-19.9413f,50.2187f,3.36849f},// stone
+//horde (coords not 100% ok)
+ {-1363.99f,-221.99f,98.4053f,4.93012f},
+ {-1370.96f,-223.532f,98.4266f,4.93012f},
+ {-1378.37f,-228.614f,99.3546f,5.38565f},
+ {-1358.02f,-228.998f,98.868f,3.87768f},
+
+ //irondeep mine
+ //Irondeep Trogg
+ {971.671f,-442.657f,57.6951f,3.1765f},
+ {969.979f,-457.148f,58.1119f,4.5204f},
+ {958.692f,-333.477f,63.2276f,5.77704f},
+ {957.113f,-325.92f,61.7589f,1.13446f},
+ {948.25f,-448.268f,56.9009f,5.60251f},
+ {934.727f,-385.802f,63.0344f,3.75246f},
+ {931.751f,-403.458f,59.6737f,5.63741f},
+ {931.146f,-359.666f,66.0294f,3.9619f},
+ {929.702f,-412.401f,56.8776f,5.89921f},
+ {926.849f,-379.074f,63.5286f,2.0944f},
+ {921.972f,-358.597f,66.4313f,2.93215f},
+ {921.449f,-341.981f,67.1264f,3.4383f},
+ {921.1f,-395.812f,60.4615f,2.71695f},
+ {919.274f,-394.986f,60.3478f,2.71696f},
+ {916.852f,-393.891f,60.1726f,2.71695f},
+ {914.568f,-326.21f,66.1733f,2.25147f},
+ {913.064f,-395.773f,60.1364f,4.41568f},
+ {909.246f,-474.576f,58.2067f,0.226893f},
+ {909.246f,-474.576f,58.2901f,0.226893f},
+ {907.209f,-428.267f,59.8065f,1.8675f},
+ {905.973f,-459.528f,58.7594f,1.37189f},
+ {905.067f,-396.074f,60.2085f,5.07891f},
+ {901.809f,-457.709f,59.0116f,3.52557f},
+ {900.962f,-427.44f,59.0842f,1.50098f},
+ {897.929f,-471.742f,59.7729f,2.54818f},
+ {893.376f,-343.171f,68.1499f,5.35816f},
+ {890.584f,-406.049f,61.1925f,5.67232f},
+ {888.208f,-332.564f,68.148f,1.93732f},
+ {887.647f,-391.537f,61.8734f,1.37881f},
+ {885.109f,-343.338f,67.0867f,3.78979f},
+ {881.618f,-419.948f,53.5228f,0.593412f},
+ {878.675f,-345.36f,66.1052f,3.45651f},
+ {877.127f,-351.8f,66.5296f,5.74213f},
+ {876.778f,-345.97f,65.7724f,3.45262f},
+ {874.577f,-414.786f,52.7817f,1.67552f},
+ {868.247f,-343.136f,64.9894f,1.6057f},
+ {859.03f,-367.231f,47.4655f,0.0174533f},
+ {857.513f,-351.817f,65.1867f,4.39823f},
+ {852.632f,-372.416f,48.1657f,3.66519f},
+ {849.86f,-340.944f,66.2447f,0.401426f},
+ {847.99f,-386.287f,60.9277f,2.32374f},
+ {847.601f,-423.072f,50.0852f,4.57276f},
+ {847.135f,-411.307f,50.2106f,1.5708f},
+ {835.077f,-379.418f,48.2755f,5.93412f},
+ {834.87f,-453.304f,47.9075f,0.226893f},
+ {834.634f,-365.981f,62.8801f,1.32645f},
+ {834.354f,-355.526f,48.1491f,6.07375f},
+ {833.702f,-327.506f,65.0439f,0.331613f},
+ {833.151f,-374.228f,63.0938f,3.66519f},
+ {831.711f,-346.785f,47.2975f,0.226893f},
+ {827.874f,-413.624f,48.5818f,1.49241f},
+ {827.728f,-415.483f,48.5593f,1.49238f},
+ {827.016f,-424.543f,48.2856f,1.49236f},
+ {823.222f,-334.283f,65.6306f,4.88692f},
+ {821.892f,-464.723f,48.9451f,4.66003f},
+ {821.006f,-387.635f,49.0728f,3.15905f},
+ {817.26f,-447.432f,49.4308f,2.18166f},
+ {805.399f,-320.146f,52.7712f,0.296706f},
+ {801.405f,-328.055f,53.0195f,4.31096f},
+ //irondeep skullthumber irondeep shaman
+ {955.812f,-440.302f,55.3411f,3.19395f},
+ {937.378f,-377.816f,65.3919f,3.56047f},
+ {925.059f,-331.347f,65.7564f,3.66519f},
+ {922.918f,-396.634f,60.3942f,2.71695f},
+ {909.99f,-462.154f,59.0811f,3.7001f},
+ {907.893f,-388.787f,61.7923f,5.74213f},
+ {898.801f,-437.105f,58.5266f,0.959931f},
+ {884.237f,-407.597f,61.566f,0.820305f},
+ {880.744f,-344.683f,66.4086f,3.4644f},
+ {876.047f,-341.857f,65.8743f,4.45059f},
+ {874.674f,-402.077f,61.7573f,0.26341f},
+ {871.914f,-404.209f,62.1269f,6.06163f},
+ {871.606f,-403.665f,62.0795f,0.765774f},
+ {871.561f,-404.114f,62.1297f,0.00981727f},
+ {871.528f,-404.248f,62.1455f,0.498032f},
+ {871.493f,-404.122f,62.1331f,5.65727f},
+ {871.282f,-403.843f,62.1108f,0.788382f},
+ {868.294f,-392.395f,61.4772f,4.38685f},
+ {868.256f,-392.363f,61.4803f,0.732738f},
+ {867.804f,-392.51f,61.5089f,2.30167f},
+ {867.612f,-392.371f,61.524f,2.86149f},
+ {858.593f,-439.614f,50.2184f,0.872665f},
+ {851.471f,-362.52f,47.314f,4.06662f},
+ {846.939f,-347.279f,66.2876f,0.942478f},
+ {842.08f,-421.775f,48.2659f,1.0821f},
+ {838.358f,-371.212f,63.3299f,4.04916f},
+ {827.57f,-417.483f,48.4538f,1.49237f},
+ {827.012f,-457.397f,48.9331f,2.35619f},
+ {825.535f,-322.373f,63.9357f,4.76475f},
+ {867.635f,-443.605f,51.3347f,1.38626f},
+ {957.293f,-455.039f,56.7395f,5.79449f},
+ {950.077f,-326.672f,61.6552f,5.48033f},
+ {936.692f,-356.78f,65.9835f,2.75762f},
+ {926.475f,-419.345f,56.1833f,2.0944f},
+ {924.729f,-397.453f,60.213f,2.71695f},
+ {902.195f,-475.891f,58.312f,1.39626f},
+ {897.464f,-338.758f,68.1715f,2.94961f},
+ {884.237f,-407.597f,61.566f,0.820305f},
+ {882.517f,-344.111f,66.7887f,3.46962f},
+ {881.437f,-400.254f,61.2028f,0.263427f},
+ {880.156f,-400.678f,61.3113f,3.41373f},
+ {877.989f,-418.051f,52.9753f,4.46804f},
+ {871.212f,-404.12f,62.1433f,3.6554f},
+ {871.036f,-404.119f,62.2237f,4.50295f},
+ {857.396f,-395.766f,61.263f,4.78684f},
+ {857.276f,-395.395f,61.2418f,0.0845553f},
+ {857.231f,-394.577f,61.2174f,1.96817f},
+ {857.108f,-395.682f,61.2317f,4.87022f},
+ {856.709f,-395.28f,61.1814f,2.54913f},
+ {850.922f,-390.399f,60.8771f,2.85405f},
+ {847.556f,-388.228f,60.9438f,2.56872f},
+ {842.031f,-384.663f,61.6028f,2.56871f},
+ {832.035f,-389.301f,47.5567f,2.11185f},
+ {827.415f,-419.468f,48.3322f,1.49232f},
+ {826.402f,-349.454f,47.2722f,1.51844f},
+ {817.83f,-455.715f,48.4207f,0.925025f},
+ {808.953f,-325.964f,52.4043f,3.01942f},
+ // Morloch
+ {865.554f,-438.735f,50.7333f,2.12431f},
+ //coldtooth mine
+ //miner/digger
+ {-917.648f,-46.8922f,77.0872f,5.27089f},
+ {-912.689f,-45.4494f,76.2277f,4.60767f},
+ {-905.455f,-84.5179f,75.3642f,3.29867f},
+ {-904.332f,-111.509f,75.5925f,2.47837f},
+ {-904.27f,-160.419f,61.9876f,3.61192f},
+ {-904.023f,-90.4558f,75.3706f,3.40339f},
+ {-978.678f,-37.3136f,75.8364f,2.84489f},
+ {-973.076f,-36.5013f,77.5047f,1.0821f},
+ {-963.951f,-87.734f,81.5555f,0.575959f},
+ {-961.941f,-90.7252f,81.6629f,0.820305f},
+ {-957.623f,-186.582f,66.6021f,1.95477f},
+ {-952.476f,-179.778f,78.6771f,4.5204f},
+ {-950.427f,-115.007f,79.6127f,3.68264f},
+ {-950.25f,-151.95f,79.4598f,-1.81423f},
+ {-950.169f,-188.099f,66.6184f,5.55015f},
+ {-949.944f,-142.977f,80.5382f,2.70526f},
+ {-947.854f,-170.5f,79.7618f,0.942478f},
+ {-946.738f,-139.567f,80.0904f,2.3911f},
+ {-945.503f,-65.0654f,79.7907f,5.02655f},
+ {-943.678f,-110.986f,80.2557f,0.959931f},
+ {-942.993f,-56.9881f,79.8915f,5.65487f},
+ {-938.197f,-155.838f,61.3111f,1.65806f},
+ {-930.488f,-214.524f,72.1431f,2.1236f},
+ {-929.947f,-154.449f,61.5084f,1.67552f},
+ {-927.412f,-135.313f,61.1987f,3.29867f},
+ {-920.677f,-156.859f,62.8033f,3.15306f},
+ {-916.75f,-136.094f,62.2357f,0.0698132f},
+ {-915.319f,-132.718f,62.562f,1.16984f},
+ {-913.589f,-146.794f,76.9366f,1.8675f},
+ {-907.572f,-148.937f,76.6898f,4.76475f},
+ {-902.02f,-64.6174f,73.9707f,1.19169f},
+ {-899.489f,-61.7252f,73.2498f,5.09636f},
+ {-894.792f,-127.141f,75.3834f,6.14356f},
+ {-892.408f,-162.525f,64.1212f,2.69884f},
+ {-892.326f,-123.158f,76.0318f,5.5676f},
+ {-888.468f,-148.462f,61.8012f,1.65806f},
+ {-883.268f,-159.738f,63.5311f,5.20108f},
+ {-877.76f,-118.07f,65.215f,2.94961f},
+ {-876.792f,-128.646f,64.1045f,3.40339f},
+ {-874.901f,-36.6579f,69.4246f,2.00713f},
+ {-874.856f,-151.351f,62.7537f,3.57875f},
+ {-872.135f,-150.08f,62.7513f,3.57201f},
+ {-870.288f,-149.217f,62.5413f,3.56624f},
+ {-870.03f,-6.27443f,70.3867f,2.3911f},
+ {-869.023f,-82.2118f,69.5848f,3.22886f},
+ {-866.354f,-40.2455f,70.842f,0.0698132f},
+ {-865.305f,-152.302f,63.5044f,4.86947f},
+ {-861.926f,-79.0519f,71.4178f,0.20944f},
+ {-857.292f,-152.277f,63.2114f,4.18879f},
+ {-853.357f,-0.696194f,72.0655f,0.994838f},
+ {-850.685f,-14.2596f,70.2298f,0.20944f},
+ {-839.987f,-67.7695f,72.7916f,4.93928f},
+ {-839.199f,-57.0558f,73.4891f,1.67552f},
+ {-836.963f,-153.224f,63.3821f,4.46804f},
+ {-832.721f,-67.7555f,72.9062f,4.99164f},
+ {-821.496f,-143.095f,63.1292f,0.541052f},
+ {-818.829f,-153.004f,62.1757f,6.12611f},
+ //special
+ {-954.622f,-110.958f,80.7911f,6.24828f},
+ {-951.477f,-53.9647f,80.0235f,5.32325f},
+ {-946.812f,-126.04f,78.8601f,5.15265f},
+ {-940.689f,-140.707f,79.9225f,2.79253f},
+ {-933.954f,-159.632f,60.778f,2.56563f},
+ {-922.537f,-130.291f,61.3756f,4.95674f},
+ {-915.862f,-151.74f,76.9427f,0.942478f},
+ {-888.321f,-159.831f,62.5303f,1.20428f},
+ {-874.361f,-42.4751f,69.4316f,0.785398f},
+ {-873.19f,-50.4899f,70.0568f,-2.41288f},
+ {-868.511f,-148.386f,62.3547f,3.57875f},
+ {-868.44f,-121.649f,64.5056f,3.33358f},
+ {-868.324f,-77.7196f,71.4768f,5.41052f},
+ {-859.846f,-19.6549f,70.7304f,1.97222f},
+ {-828.05f,-150.508f,62.2019f,2.14675f},
+ {-826.254f,-58.6911f,72.0041f,3.68264f},
+ {-976.086f,-44.1775f,76.029f,1.46608f},
+ {-971.864f,-87.4223f,81.4954f,5.8294f},
+ {-966.551f,-74.1111f,80.0243f,4.2129f},
+ {-958.509f,-173.652f,77.9013f,6.24828f},
+ {-951.511f,-181.242f,65.529f,4.39823f},
+ {-940.967f,-186.243f,77.698f,1.28164f},
+ {-930.004f,-65.0898f,79.077f,0.0581657f},
+ {-920.864f,-40.2009f,78.256f,5.16617f},
+ {-919.089f,-148.021f,62.0317f,2.59327f},
+ {-901.516f,-116.329f,75.6876f,0.471239f},
+ {-897.864f,-84.4348f,74.083f,3.00197f},
+ {-897.617f,-52.0457f,71.9503f,4.36332f},
+ {-894.891f,-153.951f,61.6827f,3.23569f},
+ {-893.933f,-111.625f,75.6591f,4.22536f},
+ {-883.265f,-152.854f,61.8384f,0.0941087f},
+ {-868.293f,-147.243f,62.1097f,3.2056f},
+ {-867.501f,-11.8709f,70.018f,6.14356f},
+ {-866.699f,-147.54f,62.1646f,3.57878f},
+ {-866.566f,-91.1916f,67.4414f,4.56707f},
+ {-857.272f,-141.142f,61.7356f,4.17134f},
+ {-847.446f,-98.0061f,68.5131f,3.24631f},
+ {-837.026f,-140.729f,62.5141f,5.51524f},
+ {-824.204f,-65.053f,72.3381f,3.01942f},
+ //vermin (s.th special for this mine)
+ {-951.955f,-197.5f,77.212f,5.63741f},
+ {-944.837f,-199.608f,77.0737f,4.97419f},
+ {-933.494f,-209.063f,73.7803f,5.88176f},
+ {-929.666f,-201.308f,73.7032f,5.02655f},
+ {-978.997f,-249.356f,65.4345f,5.05464f},
+ {-974.565f,-224.828f,69.5858f,4.88846f},
+ {-946.514f,-259.239f,66.0874f,3.78132f},
+ {-918.402f,-250.439f,69.5271f,2.21352f},
+ {-910.14f,-229.959f,72.9279f,0.27677f},
+ {-851.563f,-88.6527f,68.5983f,3.61896f},
+ //boss
+ {-848.902f,-92.931f,68.6325f,3.33350},
+ //herald
+ {-48.459f,-288.802f,55.47f,1.0}
+
+};
+
+
+enum BG_AV_CreatureIds
+{
+
+ AV_NPC_A_GRAVEDEFENSE0 = 0, // stormpike Defender
+ AV_NPC_A_GRAVEDEFENSE1 = 1, // seasoned defender
+ AV_NPC_A_GRAVEDEFENSE2 = 2, // veteran defender
+ AV_NPC_A_GRAVEDEFENSE3 = 3, // champion defender
+ AV_NPC_A_TOWERDEFENSE = 4, // stormpike bowman
+ AV_NPC_A_CAPTAIN = 5, // balinda
+ AV_NPC_A_BOSS = 6, // vanndar
+
+ AV_NPC_H_GRAVEDEFENSE0 = 7, // frostwolf guardian
+ AV_NPC_H_GRAVEDEFENSE1 = 8, // seasoned guardian
+ AV_NPC_H_GRAVEDEFENSE2 = 9, // veteran guardian
+ AV_NPC_H_GRAVEDEFENSE3 = 10, // champion guardian
+ AV_NPC_H_TOWERDEFENSE = 11, // frostwolf bowman
+ AV_NPC_H_CAPTAIN = 12, // galvangar
+ AV_NPC_H_BOSS = 13, // drek thar
+
+ AV_NPC_A_MARSHAL_SOUTH = 14,
+ AV_NPC_MARSHAL_NORTH = 15,
+ AV_NPC_A_MARSHAL_ICE = 16,
+ AV_NPC_A_MARSHAL_STONE = 17,
+ AV_NPC_H_MARSHAL_ICE = 18,
+ AV_NPC_H_MARSHAL_TOWER = 19,
+ AV_NPC_MARSHAL_ETOWER = 20,
+ AV_NPC_H_MARSHAL_WTOWER= 21,
+ AV_NPC_N_MINE_N_1 = 22,
+ AV_NPC_N_MINE_N_2 = 23,
+ AV_NPC_N_MINE_N_3 = 24,
+ AV_NPC_N_MINE_N_4 = 25,
+ AV_NPC_N_MINE_A_1 = 26,
+ AV_NPC_N_MINE_A_2 = 27,
+ AV_NPC_N_MINE_A_3 = 28,
+ AV_NPC_N_MINE_A_4 = 29,
+ AV_NPC_N_MINE_H_1 = 30,
+ AV_NPC_N_MINE_H_2 = 31,
+ AV_NPC_N_MINE_H_3 = 32,
+ AV_NPC_N_MINE_H_4 = 33,
+ AV_NPC_S_MINE_N_1 = 34,
+ AV_NPC_S_MINE_N_2 = 35,
+ AV_NPC_S_MINE_N_3 = 36,
+ AV_NPC_S_MINE_N_4 = 37,
+ AV_NPC_S_MINE_N_S = 38,
+ AV_NPC_S_MINE_A_1 = 39,
+ AV_NPC_S_MINE_A_2 = 40,
+ AV_NPC_S_MINE_A_3 = 41,
+ AV_NPC_S_MINE_A_4 = 42,
+ AV_NPC_S_MINE_H_1 = 43,
+ AV_NPC_S_MINE_H_2 = 44,
+ AV_NPC_S_MINE_H_3 = 45,
+ AV_NPC_S_MINE_H_4 = 46,
+ AV_NPC_HERALD = 47,
+ AV_NPC_INFO_MAX = 48
+
+};
+
+//entry, team, minlevel, maxlevel
+//TODO this array should be removed, the only needed things are the entrys (for spawning(?) and handlekillunit)
+const uint32 BG_AV_CreatureInfo[AV_NPC_INFO_MAX][4] = {
+ { 12050, 1216, 58, 58 }, //Stormpike Defender
+ { 13326, 1216, 59, 59 }, //Seasoned Defender
+ { 13331, 1216, 60, 60 }, //Veteran Defender
+ { 13422, 1216, 61, 61 }, //Champion Defender
+ { 13358, 1216, 59, 60 }, //Stormpike Bowman //i think its 60,61 and 69,70.. but this is until now not possible TODO look if this is ok
+ { 11949,469,0,0},//not spawned with this data, but used for handlekillunit
+ { 11948,469,0,0},//not spawned with this data, but used for handlekillunit
+ { 12053, 1214, 58, 58 }, //Frostwolf Guardian
+ { 13328, 1214, 59, 59 }, //Seasoned Guardian
+ { 13332, 1214, 60, 60 }, //Veteran Guardian
+ { 13421, 1214, 61, 61 }, //Champion Guardian
+ { 13359, 1214, 59, 60 }, //Frostwolf Bowman
+ { 11947,67,0,0}, //not spawned with this data, but used for handlekillunit
+ { 11946,67,0,0}, //not spawned with this data, but used for handlekillunit
+ { 14763, 1534, 60, 60 }, //Dun Baldar South Marshal
+ { 14762, 1534, 60, 60 }, //Dun Baldar North Marshal
+ { 14764, 1534, 60, 60 }, //Icewing Marshal
+ { 14765, 1534, 60, 60 }, //Stonehearth Marshal
+
+ { 14773, 1214, 60, 60 }, //Iceblood Warmaster
+ { 14776, 1214, 60, 60 }, //Tower Point Warmaster
+ { 14772, 1214, 60, 60 }, //East Frostwolf Warmaster
+ { 14777, 1214, 60, 60 }, //West Frostwolf Warmaster
+
+ { 10987, 59, 52, 53 }, //Irondeep Trogg
+ { 11600, 59, 53, 54 }, //Irondeep Shaman
+ { 11602, 59, 54, 55 }, //Irondeep Skullthumper
+ { 11657, 59, 58, 58 }, //Morloch
+
+ {13396,469,52,53}, //irondeep alliance TODO: get the right ids
+ {13080,469,53,54},
+ {13098,469,54,55},
+ {13078,469,58,58},
+
+ {13397,67,52,53}, //irondeep horde
+ {13099,67,53,54},
+ {13081,67,54,55},
+ {13079,67,58,58},
+
+ { 11603, 59, 52, 53 }, //south mine neutral
+ { 11604, 59, 53, 54 },
+ { 11605, 59, 54, 55 },
+ { 11677, 59, 58, 58 },
+ { 10982, 59, 52, 53 }, //vermin
+
+ {13317,469,52,53}, //alliance
+ {13096,469,54,55}, //explorer
+ {13087,469,54,55}, //invader
+ {13086,469,58,58},
+
+ {13316,67,52,53}, //horde
+ {13097,67,54,55}, //surveypr
+ {13089,67,54,55}, //guard
+ {13088,67,58,58},
+ {14848,67,58,58} //Herald
+
+};
+
+//x,y,z,o,static_creature_info-id
+const float BG_AV_StaticCreaturePos[AV_STATICCPLACE_MAX][5] = { //static creatures
+ {-1235.31f,-340.777f,60.5088f,3.31613f,0 },//2225 - Zora Guthrek
+ {-1244.02f,-323.795f,61.0485f,5.21853f,1 },//3343 - Grelkor
+ {-1235.16f,-332.302f,60.2985f,2.96706f,2 },//3625 - Rarck
+ {587.303f,-42.8257f,37.5615f,5.23599f,3 },//4255 - Brogus Thunderbrew
+ {643.635f,-58.3987f,41.7405f,4.72984f,4 },//4257 - Lana Thunderbrew
+ {591.464f,-44.452f,37.6166f,5.65487f,5 },//5134 - Jonivera Farmountain
+ {608.515f,-33.3935f,42.0003f,5.41052f,6 },//5135 - Svalbrad Farmountain
+ {617.656f,-32.0701f,42.7168f,4.06662f,7 },//5139 - Kurdrum Barleybeard
+ {-1183.76f,-268.295f,72.8233f,3.28122f,8 },//10364 - Yaelika Farclaw
+ {-1187.86f,-275.31f,73.0481f,3.63028f,9 },//10367 - Shrye Ragefist
+ {-1008.42f,-368.006f,55.3426f,5.95647f,10 },//10981 - Frostwolf
+ {-1091.92f,-424.28f,53.0139f,2.93958f,10 },//10981 - Frostwolf
+ {-558.455f,-198.768f,58.1755f,4.97946f,10 },//10981 - Frostwolf
+ {-861.247f,-312.51f,55.1427f,3.35382f,10 },//10981 - Frostwolf
+ {-1003.81f,-395.913f,50.4736f,2.85631f,10 },//10981 - Frostwolf
+ {-904.5f,-289.815f,65.1222f,5.7847f,10 },//10981 - Frostwolf
+ {-1064.41f,-438.839f,51.3614f,1.88857f,10 },//10981 - Frostwolf
+ {258.814f,76.2017f,18.6468f,6.19052f,11 },//10986 - Snowblind Harpy
+ {265.838f,-315.846f,-16.5429f,3.15917f,11 },//10986 - Snowblind Harpy
+ {426.485f,-51.1927f,-5.66286f,1.60347f,11 },//10986 - Snowblind Harpy
+ {452.044f,-33.9594f,-0.044651f,2.72815f,11 },//10986 - Snowblind Harpy
+ {266.032f,-315.639f,-16.5429f,4.67962f,11 },//10986 - Snowblind Harpy
+ {532.64f,-54.5863f,20.7024f,2.93215f,11 },//10986 - Snowblind Harpy
+ {295.183f,-299.908f,-34.6123f,0.135851f,12 },//10990 - Alterac Ram
+ {421.08f,-225.006f,-23.73f,0.166754f,12 },//10990 - Alterac Ram
+ {-55.7766f,-192.498f,20.4352f,6.12221f,12 },//10990 - Alterac Ram
+ {527.887f,-477.223f,62.3559f,0.170935f,12 },//10990 - Alterac Ram
+ {389.144f,-346.508f,-30.334f,4.14117f,12 },//10990 - Alterac Ram
+ {108.121f,-322.248f,37.5655f,4.46788f,12 },//10990 - Alterac Ram
+ {507.479f,-67.9403f,10.3571f,3.26304f,12 },//10990 - Alterac Ram
+ {329.071f,-185.016f,-29.1542f,0.356943f,12 },//10990 - Alterac Ram
+ {252.449f,-422.313f,35.1404f,4.53771f,12 },//10990 - Alterac Ram
+ {358.882f,-118.061f,-24.9119f,2.29257f,12 },//10990 - Alterac Ram
+ {487.151f,-174.229f,14.7558f,4.73192f,12 },//10990 - Alterac Ram
+ {449.652f,-123.561f,6.14273f,6.12029f,12 },//10990 - Alterac Ram
+ {272.419f,-261.802f,-41.8835f,3.66559f,12 },//10990 - Alterac Ram
+ {359.021f,-210.954f,-29.3483f,4.31339f,12 },//10990 - Alterac Ram
+ {450.598f,-318.048f,-37.7548f,0.655219f,12 },//10990 - Alterac Ram
+ {509.333f,-218.2f,3.05439f,3.66292f,12 },//10990 - Alterac Ram
+ {485.771f,-223.613f,-1.53f,2.04862f,12 },//10990 - Alterac Ram
+ {486.636f,-452.172f,39.6592f,2.3341f,12 },//10990 - Alterac Ram
+ {702.783f,-257.494f,25.9777f,1.68329f,12 },//10990 - Alterac Ram
+ {460.942f,-199.263f,-6.0149f,0.380506f,12 },//10990 - Alterac Ram
+ {483.108f,-115.307f,10.1056f,3.69701f,12 },//10990 - Alterac Ram
+ {471.601f,-154.174f,14.0702f,5.5807f,12 },//10990 - Alterac Ram
+ {213.938f,-420.793f,41.2549f,5.71394f,12 },//10990 - Alterac Ram
+ {289.387f,-294.685f,-33.9073f,0.555494f,12 },//10990 - Alterac Ram
+ {155.649f,-402.891f,43.3915f,5.94838f,12 },//10990 - Alterac Ram
+ {517.184f,-295.105f,-9.78195f,6.05668f,12 },//10990 - Alterac Ram
+ {102.334f,-332.165f,38.9812f,3.31445f,12 },//10990 - Alterac Ram
+ {320.244f,-107.793f,-42.6357f,-1.00311f,12 },//10990 - Alterac Ram
+ {217.976f,110.774f,15.7603f,4.56793f,13 },//11675 - Snowblind Windcaller
+ {269.872f,6.66684f,20.7592f,0.381212f,13 },//11675 - Snowblind Windcaller
+ {313.528f,-319.041f,-27.2373f,0.554098f,13 },//11675 - Snowblind Windcaller
+ {435.441f,-39.9289f,-0.169651f,0.549454f,13 },//11675 - Snowblind Windcaller
+ {315.115f,-317.62f,-29.1123f,0.90111f,13 },//11675 - Snowblind Windcaller
+ {428.091f,-122.731f,3.40332f,6.05901f,14 },//11678 - Snowblind Ambusher
+ {235.05f,85.5705f,18.3079f,-0.914255f,14 },//11678 - Snowblind Ambusher
+ {-1553.04f,-344.342f,64.4163f,6.09933f,15 },//11839 - Wildpaw Brute
+ {-545.23f,-165.35f,57.7886f,3.01145f,16 },//11947 - Captain Galvangar
+ {722.43f,-10.9982f,50.7046f,3.42085f,17 },//11948 - Vanndar Stormpike
+ {-57.7891f,-286.597f,15.6479f,6.02139f,18 },//11949 - Captain Balinda Stonehearth
+ {930.498f,-520.755f,93.7334f,1.8326f,19 },//11997 - Stormpike Herald
+ {-776.092f,-345.161f,67.4092f,1.89257f,20 },//12051 - Frostwolf Legionnaire
+ {-1224.63f,-308.144f,65.0087f,4.01139f,20 },//12051 - Frostwolf Legionnaire
+ {-713.039f,-442.515f,82.8638f,0.68724f,20 },//12051 - Frostwolf Legionnaire
+ {-711.783f,-444.061f,82.7039f,0.683494f,20 },//12051 - Frostwolf Legionnaire
+ {587.633f,-45.9816f,37.5438f,5.81195f,21 },//12096 - Stormpike Quartermaster
+ {-1293.79f,-194.407f,72.4398f,5.84685f,22 },//12097 - Frostwolf Quartermaster
+ {446.163f,-377.119f,-1.12725f,0.209526f,23 },//12127 - Stormpike Guardsman
+ {549.348f,-399.254f,53.3537f,3.24729f,23 },//12127 - Stormpike Guardsman
+ {549.801f,-401.217f,53.8305f,3.24729f,23 },//12127 - Stormpike Guardsman
+ {192.704f,-406.874f,42.9183f,6.10696f,23 },//12127 - Stormpike Guardsman
+ {441.305f,-435.765f,28.2385f,2.14472f,23 },//12127 - Stormpike Guardsman
+ {192.982f,-404.891f,43.0132f,6.1061f,23 },//12127 - Stormpike Guardsman
+ {355.342f,-391.989f,-0.486707f,3.00643f,23 },//12127 - Stormpike Guardsman
+ {446.035f,-375.104f,-1.12725f,0.21033f,23 },//12127 - Stormpike Guardsman
+ {697.864f,-433.238f,62.7914f,1.65776f,23 },//12127 - Stormpike Guardsman
+ {610.74f,-331.585f,30.8021f,5.14253f,23 },//12127 - Stormpike Guardsman
+ {609.815f,-329.775f,30.9271f,-2.38829f,23 },//12127 - Stormpike Guardsman
+ {695.874f,-433.434f,62.8543f,1.65776f,23 },//12127 - Stormpike Guardsman
+ {443.337f,-435.283f,28.6842f,2.13768f,23 },//12127 - Stormpike Guardsman
+ {-1251.5f,-316.327f,62.6565f,5.02655f,24 },//13176 - Smith Regzar
+ {-1332.0f,-331.243f,91.2631f,1.50098f,25 },//13179 - Wing Commander Guse
+ {569.983f,-94.9992f,38.0325f,1.39626f,26 },//13216 - Gaelden Hammersmith
+ {-1244.92f,-308.916f,63.2525f,1.62316f,27 },//13218 - Grunnda Wolfheart
+ {-1319.56f,-342.675f,60.3404f,1.20428f,28 },//13236 - Primalist Thurloga
+ {647.61f,-61.1548f,41.7405f,4.24115f,29 },//13257 - Murgot Deepforge
+ {-1321.64f,-343.73f,60.4833f,1.01229f,30 },//13284 - Frostwolf Shaman
+ {-1317.61f,-342.853f,60.3726f,2.47837f,30 },//13284 - Frostwolf Shaman
+ {-1319.31f,-344.475f,60.3825f,1.72788f,30 },//13284 - Frostwolf Shaman
+ {569.963f,-42.0218f,37.7581f,4.27606f,31 },//13438 - Wing Commander Slidore
+ {729.2f,-78.812f,51.6335f,3.97935f,32 },//13442 - Arch Druid Renferal
+ {729.118f,-82.8713f,51.6335f,2.53073f,33 },//13443 - Druid of the Grove
+ {725.554f,-79.4973f,51.6335f,5.27089f,33 },//13443 - Druid of the Grove
+ {724.768f,-84.1642f,51.6335f,0.733038f,33 },//13443 - Druid of the Grove
+ {596.68f,-83.0633f,39.0051f,6.24828f,34 },//13447 - Corporal Noreg Stormpike
+ {600.032f,-2.92475f,42.0788f,5.00909f,35 },//13577 - Stormpike Ram Rider Commander
+ {610.239f,-21.8454f,43.272f,4.90438f,36 },//13617 - Stormpike Stable Master
+ {613.422f,-150.764f,33.4517f,5.55015f,37 },//13797 - Mountaineer Boombellow
+ {-1213.91f,-370.619f,56.4455f,0.837758f,38 },//13798 - Jotek
+ {704.35f,-22.9071f,50.2187f,0.785398f,39 },//13816 - Prospector Stonehewer
+ {-1271.24f,-335.766f,62.3971f,5.75959f,40 },//14185 - Najak Hexxen
+ {-1268.64f,-332.688f,62.6171f,5.28835f,41 },//14186 - Ravak Grimtotem
+ {648.363f,-65.2233f,41.7405f,3.12414f,42 },//14187 - Athramanis
+ {648.238f,-67.8931f,41.7405f,2.60054f,43 },//14188 - Dirk Swindle
+ {-1223.44f,-309.833f,64.9331f,4.0131f,44 },//14282 - Frostwolf Bloodhound
+ {-1226.4f,-307.136f,64.9706f,4.0145f,44 },//14282 - Frostwolf Bloodhound
+ {356.001f,-389.969f,-0.438796f,3.0334f,45 },//14283 - Stormpike Owl
+ {355.835f,-394.005f,-0.60149f,3.02498f,45 },//14283 - Stormpike Owl
+ {882.266f,-496.378f,96.7707f,4.83248f,45 },//14283 - Stormpike Owl
+ {878.649f,-495.917f,96.6171f,4.67693f,45 },//14283 - Stormpike Owl
+ {932.851f,-511.017f,93.6748f,3.61004f,45 },//14283 - Stormpike Owl
+ {935.806f,-513.983f,93.7436f,3.61788f,45 },//14283 - Stormpike Owl
+ {947.412f,-509.982f,95.1098f,2.82743f,46 },//14284 - Stormpike Battleguard
+ {934.557f,-512.395f,93.662f,3.61004f,46 },//14284 - Stormpike Battleguard
+ {939.42f,-502.777f,94.5887f,5.14872f,46 },//14284 - Stormpike Battleguard
+ {854.276f,-494.241f,96.8017f,5.44543f,46 },//14284 - Stormpike Battleguard
+ {776.621f,-487.775f,99.4049f,3.50811f,46 },//14284 - Stormpike Battleguard
+ {880.169f,-495.699f,96.6204f,4.8325f,46 },//14284 - Stormpike Battleguard
+ {773.651f,-497.482f,99.0408f,2.11185f,46 },//14284 - Stormpike Battleguard
+ {949.1f,-506.913f,95.4237f,3.31613f,46 },//14284 - Stormpike Battleguard
+ {-1370.9f,-219.793f,98.4258f,5.04381f,47}, //drek thar
+
+};
+
+const uint32 BG_AV_StaticCreatureInfo[51][4] = {
+ { 2225, 1215, 55, 55 }, //Zora Guthrek
+ { 3343, 1215, 55, 55 }, //Grelkor
+ { 3625, 1215, 55, 55 }, //Rarck
+ { 4255, 1217, 55, 55 }, //Brogus Thunderbrew
+ { 4257, 1217, 55, 55 }, //Lana Thunderbrew
+ { 5134, 1217, 55, 55 }, //Jonivera Farmountain
+ { 5135, 1217, 55, 55 }, //Svalbrad Farmountain
+ { 5139, 1217, 55, 55 }, //Kurdrum Barleybeard
+ { 10364, 1215, 55, 55 }, //Yaelika Farclaw
+ { 10367, 1215, 55, 55 }, //Shrye Ragefist
+ { 10981, 38, 50, 51 }, //Frostwolf
+ { 10986, 514, 52, 53 }, //Snowblind Harpy
+ { 10990, 1274, 50, 51 }, //Alterac Ram
+ { 11675, 514, 53, 53 }, //Snowblind Windcaller
+ { 11678, 14, 52, 53 }, //Snowblind Ambusher
+ { 11839, 39, 56, 56 }, //Wildpaw Brute
+ { 11947, 1214, 61, 61 }, //Captain Galvangar --TODO: doubled
+ { 11948, 1216, 63, 63 }, //Vanndar Stormpike
+ { 11949, 1216, 61, 61 }, //Captain Balinda Stonehearth
+ { 11997, 1334, 60, 60 }, //Stormpike Herald
+ { 12051, 1214, 57, 57 }, //Frostwolf Legionnaire
+ { 12096, 1217, 55, 55 }, //Stormpike Quartermaster
+ { 12097, 1215, 55, 55 }, //Frostwolf Quartermaster
+ { 12127, 1216, 57, 57 }, //Stormpike Guardsman
+ { 13176, 1215, 60, 60 }, //Smith Regzar
+ { 13179, 1215, 59, 59 }, //Wing Commander Guse
+ { 13216, 1217, 58, 58 }, //Gaelden Hammersmith
+ { 13218, 1215, 58, 58 }, //Grunnda Wolfheart
+ { 13236, 1214, 60, 60 }, //Primalist Thurloga
+ { 13257, 1216, 60, 60 }, //Murgot Deepforge
+ { 13284, 1214, 58, 58 }, //Frostwolf Shaman
+ { 13438, 1217, 58, 58 }, //Wing Commander Slidore
+ { 13442, 1216, 60, 60 }, //Arch Druid Renferal
+ { 13443, 1216, 60, 60 }, //Druid of the Grove
+ { 13447, 1216, 58, 58 }, //Corporal Noreg Stormpike
+ { 13577, 1216, 60, 60 }, //Stormpike Ram Rider Commander
+ { 13617, 1216, 60, 60 }, //Stormpike Stable Master
+ { 13797, 32, 60, 61 }, //Mountaineer Boombellow
+ { 13798, 1214, 60, 61 }, //Jotek
+ { 13816, 1216, 61, 61 }, //Prospector Stonehewer
+ { 14185, 877, 59, 59 }, //Najak Hexxen
+ { 14186, 105, 60, 60 }, //Ravak Grimtotem
+ { 14187, 1594, 60, 60 }, //Athramanis
+ { 14188, 57, 59, 59 }, //Dirk Swindle
+ { 14282, 1214, 53, 54 }, //Frostwolf Bloodhound
+ { 14283, 1216, 53, 54 }, //Stormpike Owl
+ { 14284, 1216, 61, 61 }, //Stormpike Battleguard
+ { 11946, 1214, 63, 63 }, //Drek'Thar //TODO: make the levels right (boss=0 maybe)
+ { 11948, 1216, 63, 63 }, //Vanndar Stormpike
+ { 11947, 1214, 61, 61 }, //Captain Galvangar
+ { 11949, 1216, 61, 61 } //Captain Balinda Stonehearth
+};
+
+enum BG_AV_Graveyards
+{
+ AV_GRAVE_STORM_AID = 751,
+ AV_GRAVE_STORM_GRAVE = 689,
+ AV_GRAVE_STONE_GRAVE = 729,
+ AV_GRAVE_SNOWFALL = 169,
+ AV_GRAVE_ICE_GRAVE = 749,
+ AV_GRAVE_FROSTWOLF = 690,
+ AV_GRAVE_FROST_HUT = 750,
+ AV_GRAVE_MAIN_ALLIANCE = 611,
+ AV_GRAVE_MAIN_HORDE = 610
+};
+
+
+
+const uint32 BG_AV_GraveyardIds[9]= {
+ AV_GRAVE_STORM_AID,
+ AV_GRAVE_STORM_GRAVE,
+ AV_GRAVE_STONE_GRAVE,
+ AV_GRAVE_SNOWFALL,
+ AV_GRAVE_ICE_GRAVE,
+ AV_GRAVE_FROSTWOLF,
+ AV_GRAVE_FROST_HUT,
+ AV_GRAVE_MAIN_ALLIANCE,
+ AV_GRAVE_MAIN_HORDE
+};
+
+enum BG_AV_BUFF
+{ //TODO add all other buffs here
+ AV_BUFF_ARMOR = 21163,
+ AV_BUFF_A_CAPTAIN = 23693, //the buff which the alliance captain does
+ AV_BUFF_H_CAPTAIN = 22751 //the buff which the horde captain does
+};
+enum BG_AV_States
+{
+ POINT_NEUTRAL = 0,
+ POINT_ASSAULTED = 1,
+ POINT_DESTROYED = 2,
+ POINT_CONTROLED = 3
+};
+
+enum BG_AV_WorldStates
+{
+ AV_Alliance_Score = 3127,
+ AV_Horde_Score = 3128,
+ AV_SHOW_H_SCORE = 3133,
+ AV_SHOW_A_SCORE = 3134,
+
+/*
+ //the comments behind the state shows which icon overlaps the other.. but is, until now, unused and maybe not a good solution (but give few performance (: )
+
+// Graves
+
+ // Alliance
+ //Stormpike first aid station
+ AV_AID_A_C = 1325,
+ AV_AID_A_A = 1326,
+ AV_AID_H_C = 1327,
+ AV_AID_H_A = 1328,
+ //Stormpike Graveyard
+ AV_PIKEGRAVE_A_C = 1333,
+ AV_PIKEGRAVE_A_A = 1335,
+ AV_PIKEGRAVE_H_C = 1334,
+ AV_PIKEGRAVE_H_A = 1336,
+ //Stoneheart Grave
+ AV_STONEHEART_A_C = 1302,
+ AV_STONEHEART_A_A = 1304, //over hc
+ AV_STONEHEART_H_C = 1301, //over ac
+ AV_STONEHEART_H_A = 1303, //over aa
+ //Neutral
+ //Snowfall Grave
+*/
+ AV_SNOWFALL_N = 1966, //over aa
+/*
+ AV_SNOWFALL_A_C = 1341, //over hc
+ AV_SNOWFALL_A_A = 1343, //over ha
+ AV_SNOWFALL_H_C = 1342,
+ AV_SNOWFALL_H_A = 1344, //over ac
+ //Horde
+ //Iceblood grave
+ AV_ICEBLOOD_A_C = 1346, //over hc
+ AV_ICEBLOOD_A_A = 1348, //over ac
+ AV_ICEBLOOD_H_C = 1347,
+ AV_ICEBLOOD_H_A = 1349, //over aa
+ //Frostwolf Grave
+ AV_FROSTWOLF_A_C = 1337, //over hc
+ AV_FROSTWOLF_A_A = 1339, //over ac
+ AV_FROSTWOLF_H_C = 1338,
+ AV_FROSTWOLF_H_A = 1340, //over aa
+ //Frostwolf Hut
+ AV_FROSTWOLFHUT_A_C = 1329, //over hc
+ AV_FROSTWOLFHUT_A_A = 1331, //over ha
+ AV_FROSTWOLFHUT_H_C = 1330,
+ AV_FROSTWOLFHUT_H_A = 1332, //over ac
+
+
+//Towers
+ //Alliance
+ //Dunbaldar South Bunker
+ AV_DUNS_CONTROLLED = 1361,
+ AV_DUNS_DESTROYED = 1370,
+ AV_DUNS_ASSAULTED = 1378,
+ //Dunbaldar North Bunker
+ AV_DUNN_CONTROLLED = 1362,
+ AV_DUNN_DESTROYED = 1371,
+ AV_DUNN_ASSAULTED = 1379,
+ //Icewing Bunker
+ AV_ICEWING_CONTROLLED = 1363,
+ AV_ICEWING_DESTROYED = 1372,
+ AV_ICEWING_ASSAULTED = 1380,
+ //Stoneheart Bunker
+ AV_STONEH_CONTROLLED = 1364,
+ AV_STONEH_DESTROYED = 1373,
+ AV_STONEH_ASSAULTED = 1381,
+ //Horde
+ //Iceblood Tower
+ AV_ICEBLOOD_CONTROLLED = 1385,
+ AV_ICEBLOOD_DESTROYED = 1368,
+ AV_ICEBLOOD_ASSAULTED = 1390,
+ //Tower Point
+ AV_TOWERPOINT_CONTROLLED = 1384,
+ AV_TOWERPOINT_DESTROYED = 1367, //goes over controlled
+ AV_TOWERPOINT_ASSAULTED = 1389, //goes over destroyed
+ //Frostwolf West
+ AV_FROSTWOLFW_CONTROLLED = 1382,
+ AV_FROSTWOLFW_DESTROYED = 1365, //over controlled
+ AV_FROSTWOLFW_ASSAULTED = 1387, //over destroyed
+ //Frostwolf East
+ AV_FROSTWOLFE_CONTROLLED = 1383,
+ AV_FROSTWOLFE_DESTROYED = 1366,
+ AV_FROSTWOLFE_ASSAULTED = 1388,
+
+//mines
+
+ AV_N_MINE_N = 1360,
+ AV_N_MINE_A = 1358,
+ AV_N_MINE_H = 1359,
+
+ AV_S_MINE_N = 1357,
+ AV_S_MINE_A = 1355,
+ AV_S_MINE_H = 1356,
+
+//towers assaulted by own team (unused)
+ AV_STONEH_UNUSED = 1377,
+ AV_ICEWING_UNUSED = 1376,
+ AV_DUNS_UNUSED = 1375,
+ AV_DUNN_UNUSED = 1374,
+
+ AV_ICEBLOOD_UNUSED = 1395,
+ AV_TOWERPOINT_UNUSED = 1394,
+ AV_FROSTWOLFE_UNUSED = 1393,
+ AV_FROSTWOLFW_UNUSED = 1392
+*/
+
+};
+
+//alliance_control neutral_control horde_control
+const uint32 BG_AV_MineWorldStates[2][3] = {
+ {1358, 1360,1359},
+ {1355, 1357,1356}
+};
+
+
+//alliance_control alliance_assault h_control h_assault
+const uint32 BG_AV_NodeWorldStates[16][4] = {
+ //Stormpike first aid station
+ {1325, 1326,1327,1328},
+ //Stormpike Graveyard
+ {1333,1335,1334,1336},
+ //Stoneheart Grave
+ {1302,1304,1301,1303},
+ //Snowfall Grave
+ {1341,1343,1342,1344},
+ //Iceblood grave
+ {1346,1348,1347,1349},
+ //Frostwolf Grave
+ {1337,1339,1338,1340},
+ //Frostwolf Hut
+ {1329,1331,1330,1332},
+ //Dunbaldar South Bunker
+ {1361,1375,1370,1378},
+ //Dunbaldar North Bunker
+ {1362,1374,1371,1379},
+ //Icewing Bunker
+ {1363,1376,1372,1380},
+ //Stoneheart Bunker
+ {1364,1377,1373,1381},
+ //Iceblood Tower
+ {1368,1390,1385,1395},
+ //Tower Point
+ {1367,1389,1384,1394},
+ //Frostwolf East
+ {1366,1388,1383,1393},
+ //Frostwolf West
+ {1365,1387,1382,1392},
+};
+
+enum BG_AV_QuestIds
+{
+ AV_QUEST_A_SCRAPS1 = 7223,
+ AV_QUEST_A_SCRAPS2 = 6781,
+ AV_QUEST_H_SCRAPS1 = 7224,
+ AV_QUEST_H_SCRAPS2 = 6741,
+ AV_QUEST_A_COMMANDER1 = 6942, //soldier
+ AV_QUEST_H_COMMANDER1 = 6825,
+ AV_QUEST_A_COMMANDER2 = 6941, //leutnant
+ AV_QUEST_H_COMMANDER2 = 6826,
+ AV_QUEST_A_COMMANDER3 = 6943, //commander
+ AV_QUEST_H_COMMANDER3 = 6827,
+ AV_QUEST_A_BOSS1 = 7386, // 5 cristal/blood
+ AV_QUEST_H_BOSS1 = 7385,
+ AV_QUEST_A_BOSS2 = 6881, // 1
+ AV_QUEST_H_BOSS2 = 6801,
+ AV_QUEST_A_NEAR_MINE = 5892, //the mine near start location of team
+ AV_QUEST_H_NEAR_MINE = 5893,
+ AV_QUEST_A_OTHER_MINE = 6982, //the other mine ;)
+ AV_QUEST_H_OTHER_MINE = 6985,
+ AV_QUEST_A_RIDER_HIDE = 7026,
+ AV_QUEST_H_RIDER_HIDE = 7002,
+ AV_QUEST_A_RIDER_TAME = 7027,
+ AV_QUEST_H_RIDER_TAME = 7001
+};
+
+struct BG_AV_NodeInfo
+{
+ uint16 TotalOwner;
+ uint16 Owner;
+ uint16 PrevOwner;
+ BG_AV_States State;
+ BG_AV_States PrevState;
+ int Timer;
+ bool Tower;
+};
+
+inline BG_AV_Nodes &operator++(BG_AV_Nodes &i){ return i = BG_AV_Nodes(i + 1); }
+
class BattleGroundAVScore : public BattleGroundScore
{
public:
@@ -51,11 +1507,75 @@ class BattleGroundAV : public BattleGround
void RemovePlayer(Player *plr,uint64 guid);
void HandleAreaTrigger(Player *Source, uint32 Trigger);
- //bool SetupBattleGround();
+ bool SetupBattleGround();
+ virtual void ResetBGSubclass();
- /* Scorekeeping */
- void UpdatePlayerScore(Player *Source, uint32 type, uint32 value);
+ /*general stuff*/
+ void UpdateScore(uint16 team, int16 points);
+ void UpdatePlayerScore(Player *Source, uint32 type, uint32 value);
+
+ /*handlestuff*/ //these are functions which get called from extern
+ virtual void EventPlayerClickedOnFlag(Player *source, GameObject* target_obj);
+ void HandleKillPlayer(Player* player, Player *killer);
+ void HandleKillUnit(Creature *unit, Player *killer);
+ void HandleQuestComplete(uint32 questid, Player *player);
+ bool PlayerCanDoMineQuest(int32 GOId,uint32 team);
+
+
+ void EndBattleGround(uint32 winner);
+
+ virtual WorldSafeLocsEntry const* GetClosestGraveYard(float x, float y, float z, uint32 team);
private:
+ /* Nodes occupying */
+ void EventPlayerAssaultsPoint(Player* player, uint32 object);
+ void EventPlayerDefendsPoint(Player* player, uint32 object);
+ void EventPlayerDestroyedPoint(BG_AV_Nodes node);
+
+ void AssaultNode(BG_AV_Nodes node,uint16 team);
+ void DestroyNode(BG_AV_Nodes node);
+ void InitNode(BG_AV_Nodes node, uint16 team, bool tower);
+ void DefendNode(BG_AV_Nodes node, uint16 team);
+
+ void PopulateNode(BG_AV_Nodes node);
+ void DePopulateNode(BG_AV_Nodes node);
+
+ const BG_AV_Nodes GetNodeThroughObject(uint32 object);
+ const uint32 GetObjectThroughNode(BG_AV_Nodes node);
+ const char* GetNodeName(BG_AV_Nodes node);
+ const bool IsTower(BG_AV_Nodes node) { return m_Nodes[node].Tower; }
+
+
+ /*mine*/
+ void ChangeMineOwner(uint8 mine, uint32 team, bool initial=false);
+
+ /*worldstates*/
+ void FillInitialWorldStates(WorldPacket& data);
+ const uint8 GetWorldStateType(uint8 state, uint16 team);
+ void SendMineWorldStates(uint32 mine);
+ void UpdateNodeWorldState(BG_AV_Nodes node);
+
+ /*general */
+ Creature* AddAVCreature(uint16 cinfoid, uint16 type);
+ const uint16 GetBonusHonor(uint8 kills); //TODO remove this when mangos handles this right
+
+ /*variables */
+ int32 m_Team_Scores[2];
+ uint32 m_Team_QuestStatus[2][9]; //[x][y] x=team y=questcounter
+
+ BG_AV_NodeInfo m_Nodes[BG_AV_NODES_MAX];
+
+ uint32 m_Mine_Owner[2];
+ uint32 m_Mine_PrevOwner[2]; //only for worldstates needed
+ int32 m_Mine_Timer; //ticks for both teams
+ uint32 m_Mine_Reclaim_Timer[2];
+ uint32 m_CaptainBuffTimer[2];
+ bool m_CaptainAlive[2];
+
+ uint8 m_MaxLevel; //TODO remove this when battleground-getmaxlevel() returns something usefull
+ bool m_IsInformedNearVictory[2];
+
+
};
+
#endif
diff --git a/src/game/BattleGroundEY.cpp b/src/game/BattleGroundEY.cpp
index d828d626ad2..3b545e5e65b 100644
--- a/src/game/BattleGroundEY.cpp
+++ b/src/game/BattleGroundEY.cpp
@@ -191,7 +191,7 @@ void BattleGroundEY::CheckSomeoneJoinedPoint()
++j;
continue;
}
- if (plr->isAlive() && plr->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS))
+ if (plr->isAllowUseBattleGroundObject() && plr->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS))
{
//player joined point!
//show progress bar
@@ -234,7 +234,7 @@ void BattleGroundEY::CheckSomeoneLeftPoint()
++j;
continue;
}
- if (!plr->isAlive() || !plr->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS))
+ if (!plr->isAllowUseBattleGroundObject() || !plr->IsWithinDistInMap(obj, BG_EY_POINT_RADIUS))
//move player out of point (add him to players that are out of points
{
m_PlayersNearPoint[EY_POINTS_MAX].push_back(m_PlayersNearPoint[i][j]);
diff --git a/src/game/BattleGroundMgr.cpp b/src/game/BattleGroundMgr.cpp
index 6249967bf4c..87a652f23c2 100644
--- a/src/game/BattleGroundMgr.cpp
+++ b/src/game/BattleGroundMgr.cpp
@@ -1587,7 +1587,7 @@ void BattleGroundMgr::DistributeArenaPoints()
uint32 position = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * i + 2;
CharacterDatabase.DirectPExecute("UPDATE characters SET data = CONCAT( SUBSTRING_INDEX(data,' ','%u'),' ','0',' ',SUBSTRING(data FROM (CHAR_LENGTH(SUBSTRING_INDEX(data,' ','%u')) + 2)))",position, position + 1);
}
- CharacterDatabase.DirectExecute("UPDATE arena_team_member SET points_to_add = '0', played_week = '0', wons_week = '0'");
+ CharacterDatabase.DirectExecute("UPDATE arena_team_member SET points_to_add = '0', games_week = '0', wins_week = '0'");
CharacterDatabase.DirectExecute("UPDATE arena_team_stats SET games = '0', wins = '0'");
CharacterDatabase.CommitTransaction();
diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp
index 42732a17d2b..40f3fb8e530 100644
--- a/src/game/CharacterHandler.cpp
+++ b/src/game/CharacterHandler.cpp
@@ -158,18 +158,20 @@ void WorldSession::HandleCharEnumOpcode( WorldPacket & /*recv_data*/ )
// ------- Query Without Declined Names --------
// 0 1 2 3 4 5 6 7 8
"SELECT characters.guid, characters.data, characters.name, characters.position_x, characters.position_y, characters.position_z, characters.map, characters.totaltime, characters.leveltime, "
- // 9 10 11 12
- "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level "
+ // 9 10 11 12 13
+ "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, guild_member.guildid "
"FROM characters LEFT JOIN character_pet ON characters.guid=character_pet.owner AND character_pet.slot='0' "
+ "LEFT JOIN guild_member ON characters.guid = guild_member.guid "
"WHERE characters.account = '%u' ORDER BY characters.guid"
:
// --------- Query With Declined Names ---------
// 0 1 2 3 4 5 6 7 8
"SELECT characters.guid, characters.data, characters.name, characters.position_x, characters.position_y, characters.position_z, characters.map, characters.totaltime, characters.leveltime, "
- // 9 10 11 12 13
- "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, genitive "
+ // 9 10 11 12 13 14
+ "characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, guild_member.guildid, genitive "
"FROM characters LEFT JOIN character_pet ON characters.guid = character_pet.owner AND character_pet.slot='0' "
"LEFT JOIN character_declinedname ON characters.guid = character_declinedname.guid "
+ "LEFT JOIN guild_member ON characters.guid = guild_member.guid "
"WHERE characters.account = '%u' ORDER BY characters.guid",
GetAccountId());
}
@@ -542,6 +544,22 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
DEBUG_LOG( "WORLD: Sent motd (SMSG_MOTD)" );
}
+ //QueryResult *result = CharacterDatabase.PQuery("SELECT guildid,rank FROM guild_member WHERE guid = '%u'",pCurrChar->GetGUIDLow());
+ QueryResult *resultGuild = holder->GetResult(PLAYER_LOGIN_QUERY_LOADGUILD);
+
+ if(resultGuild)
+ {
+ Field *fields = resultGuild->Fetch();
+ pCurrChar->SetInGuild(fields[0].GetUInt32());
+ pCurrChar->SetRank(fields[1].GetUInt32());
+ delete resultGuild;
+ }
+ else if(pCurrChar->GetGuildId()) // clear guild related fields in case wrong data about non existed membership
+ {
+ pCurrChar->SetInGuild(0);
+ pCurrChar->SetRank(0);
+ }
+
if(pCurrChar->GetGuildId() != 0)
{
Guild* guild = objmgr.GetGuildById(pCurrChar->GetGuildId());
@@ -569,8 +587,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
{
// remove wrong guild data
sLog.outError("Player %s (GUID: %u) marked as member not existed guild (id: %u), removing guild membership for player.",pCurrChar->GetName(),pCurrChar->GetGUIDLow(),pCurrChar->GetGuildId());
- pCurrChar->SetUInt32Value(PLAYER_GUILDID,0);
- pCurrChar->SetUInt32ValueInDB(PLAYER_GUILDID,0,pCurrChar->GetGUID());
+ pCurrChar->SetInGuild(0);
}
}
@@ -593,22 +610,6 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
}
}
- //QueryResult *result = CharacterDatabase.PQuery("SELECT guildid,rank FROM guild_member WHERE guid = '%u'",pCurrChar->GetGUIDLow());
- QueryResult *resultGuild = holder->GetResult(PLAYER_LOGIN_QUERY_LOADGUILD);
-
- if(resultGuild)
- {
- Field *fields = resultGuild->Fetch();
- pCurrChar->SetInGuild(fields[0].GetUInt32());
- pCurrChar->SetRank(fields[1].GetUInt32());
- delete resultGuild;
- }
- else if(pCurrChar->GetGuildId()) // clear guild related fields in case wrong data about non existed membership
- {
- pCurrChar->SetInGuild(0);
- pCurrChar->SetRank(0);
- }
-
if (!pCurrChar->GetMap()->Add(pCurrChar))
{
AreaTrigger const* at = objmgr.GetGoBackTrigger(pCurrChar->GetMapId());
@@ -750,7 +751,6 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
if(sWorld.getConfig(CONFIG_START_ALL_TAXI))
pCurrChar->SetTaxiCheater(true);
-
if(pCurrChar->isGameMaster())
SendNotification(LANG_GM_ON);
diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp
index 862cfc638ca..fb2032d2ac1 100644
--- a/src/game/Chat.cpp
+++ b/src/game/Chat.cpp
@@ -786,7 +786,7 @@ bool ChatHandler::ExecuteCommandInTable(ChatCommand *table, const char* text, st
{
Player* p = m_session->GetPlayer();
uint64 sel_guid = p->GetSelection();
- sLog.outCommand("Command: %s [Player: %s (Account: %u) X: %f Y: %f Z: %f Map: %u Selected: %s (GUID: %u)]",
+ sLog.outCommand(m_session->GetAccountId(),"Command: %s [Player: %s (Account: %u) X: %f Y: %f Z: %f Map: %u Selected: %s (GUID: %u)]",
fullcmd.c_str(),p->GetName(),m_session->GetAccountId(),p->GetPositionX(),p->GetPositionY(),p->GetPositionZ(),p->GetMapId(),
GetLogNameForGuid(sel_guid),GUID_LOPART(sel_guid));
}
diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp
index 8a58deb7f91..7802dcd2922 100644
--- a/src/game/Creature.cpp
+++ b/src/game/Creature.cpp
@@ -117,14 +117,36 @@ uint32 CreatureInfo::GetFirstValidModelId() const
return 0;
}
+bool AssistDelayEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/)
+{
+ Unit* victim = Unit::GetUnit(m_owner, m_victim);
+ if (victim)
+ {
+ while (!m_assistants.empty())
+ {
+ Creature* assistant = (Creature*)Unit::GetUnit(m_owner, *m_assistants.begin());
+ m_assistants.pop_front();
+
+ if (assistant && assistant->CanAssistTo(&m_owner, victim))
+ {
+ assistant->SetNoCallAssistance(true);
+ assistant->CombatStart(victim);
+ if(assistant->AI())
+ assistant->AI()->AttackStart(victim);
+ }
+ }
+ }
+ return true;
+}
+
Creature::Creature() :
Unit(), i_AI(NULL), i_AI_possessed(NULL),
lootForPickPocketed(false), lootForBody(false), m_groupLootTimer(0), lootingGroupLeaderGUID(0),
m_lootMoney(0), m_lootRecipient(0),
m_deathTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_respawnradius(0.0f),
-m_gossipOptionLoaded(false), m_emoteState(0), m_isPet(false), m_isTotem(false),
+m_gossipOptionLoaded(false), m_emoteState(0), m_isPet(false), m_isTotem(false), m_isAggressive(true),
m_regenTimer(2000), m_defaultMovementType(IDLE_MOTION_TYPE), m_equipmentId(0),
-m_AlreadyCallAssistence(false), m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false),
+m_AlreadyCallAssistance(false), m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false),
m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),m_creatureInfo(NULL), m_DBTableGuid(0)
{
m_valuesCount = UNIT_END;
@@ -147,7 +169,11 @@ Creature::~Creature()
delete i_AI;
i_AI = NULL;
- DeletePossessedAI();
+ if (i_AI_possessed)
+ {
+ delete i_AI_possessed;
+ i_AI_possessed = NULL;
+ }
}
void Creature::AddToWorld()
@@ -293,6 +319,7 @@ bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData *data )
SetUInt32Value(UNIT_FIELD_FLAGS,GetCreatureInfo()->unit_flags);
SetUInt32Value(UNIT_DYNAMIC_FLAGS,GetCreatureInfo()->dynamicflags);
+ SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->dmgschool));
SetModifierValue(UNIT_MOD_ARMOR, BASE_VALUE, float(GetCreatureInfo()->armor));
SetModifierValue(UNIT_MOD_RESISTANCE_HOLY, BASE_VALUE, float(GetCreatureInfo()->resistance1));
SetModifierValue(UNIT_MOD_RESISTANCE_FIRE, BASE_VALUE, float(GetCreatureInfo()->resistance2));
@@ -323,6 +350,12 @@ bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData *data )
if(GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER)
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ if(isTotem() || isCivilian() || GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER
+ || GetCreatureType() == CREATURE_TYPE_CRITTER)
+ m_isAggressive = false;
+ else
+ m_isAggressive = true;
+
return true;
}
@@ -555,13 +588,10 @@ void Creature::InitPossessedAI()
i_AI->OnPossess(true);
}
-void Creature::DeletePossessedAI()
+void Creature::DisablePossessedAI()
{
if (!i_AI_possessed) return;
- delete i_AI_possessed;
- i_AI_possessed = NULL;
-
// Signal the old AI that it's been re-enabled
i_AI->OnPossess(false);
}
@@ -570,6 +600,7 @@ bool Creature::Create (uint32 guidlow, Map *map, uint32 Entry, uint32 team, cons
{
SetMapId(map->GetId());
SetInstanceId(map->GetInstanceId());
+ //m_DBTableGuid = guidlow;
//oX = x; oY = y; dX = x; dY = y; m_moveTime = 0; m_startMove = 0;
const bool bResult = CreateFromProto(guidlow, Entry, team, data);
@@ -596,7 +627,6 @@ bool Creature::Create (uint32 guidlow, Map *map, uint32 Entry, uint32 team, cons
}
LoadCreaturesAddon();
}
-
return bResult;
}
@@ -1271,8 +1301,11 @@ void Creature::SelectLevel(const CreatureInfo *cinfo)
SetBaseWeaponDamage(RANGED_ATTACK, MINDAMAGE, cinfo->minrangedmg * damagemod);
SetBaseWeaponDamage(RANGED_ATTACK, MAXDAMAGE, cinfo->maxrangedmg * damagemod);
- SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, cinfo->attackpower * damagemod);
- SetModifierValue(UNIT_MOD_ATTACK_POWER_RANGED, BASE_VALUE, cinfo->rangedattackpower * damagemod);
+ // this value is not accurate, but should be close to the real value
+ SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, level * 5);
+ SetModifierValue(UNIT_MOD_ATTACK_POWER_RANGED, BASE_VALUE, level * 5);
+ //SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, cinfo->attackpower * damagemod);
+ //SetModifierValue(UNIT_MOD_ATTACK_POWER_RANGED, BASE_VALUE, cinfo->rangedattackpower * damagemod);
}
float Creature::_GetHealthMod(int32 Rank)
@@ -1410,8 +1443,6 @@ bool Creature::LoadFromDB(uint32 guid, Map *map)
SetHealth(m_deathState == ALIVE ? curhealth : 0);
SetPower(POWER_MANA,data->curmana);
- SetMeleeDamageSchool(SpellSchools(GetCreatureInfo()->dmgschool));
-
// checked at creature_template loading
m_defaultMovementType = MovementGeneratorType(data->movementType);
@@ -1538,6 +1569,19 @@ bool Creature::IsWithinSightDist(Unit const* u) const
return IsWithinDistInMap(u, sWorld.getConfig(CONFIG_SIGHT_MONSTER));
}
+bool Creature::canStartAttack(Unit const* who) const
+{
+ if(!who->isInAccessiblePlaceFor(this)
+ || !canFly() && GetDistanceZ(who) > CREATURE_Z_ATTACK_RANGE
+ || !IsWithinDistInMap(who, GetAttackDistance(who)))
+ return false;
+
+ if(!canAttack(who, false))
+ return false;
+
+ return IsWithinLOSInMap(who);
+}
+
float Creature::GetAttackDistance(Unit const* pl) const
{
float aggroRate = sWorld.getRate(RATE_CREATURE_AGGRO);
@@ -1817,13 +1861,37 @@ void Creature::DoFleeToGetAssistance(float radius) // Optional parameter
}
}
-void Creature::CallAssistence()
+Unit* Creature::SelectNearestTarget(float dist) const
{
- if( !m_AlreadyCallAssistence && getVictim() && !isPet() && !isCharmed())
+ CellPair p(Trinity::ComputeCellPair(GetPositionX(), GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+ cell.SetNoCreate();
+
+ Unit *target = NULL;
+
{
- SetNoCallAssistence(true);
+ Trinity::NearestHostileUnitInAttackDistanceCheck u_check(this, dist);
+ Trinity::UnitLastSearcher<Trinity::NearestHostileUnitInAttackDistanceCheck> searcher(target, u_check);
+
+ TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::NearestHostileUnitInAttackDistanceCheck>, WorldTypeMapContainer > world_unit_searcher(searcher);
+ TypeContainerVisitor<Trinity::UnitLastSearcher<Trinity::NearestHostileUnitInAttackDistanceCheck>, GridTypeMapContainer > grid_unit_searcher(searcher);
+
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, world_unit_searcher, *GetMap());
+ cell_lock->Visit(cell_lock, grid_unit_searcher, *GetMap());
+ }
+
+ return target;
+}
- float radius = sWorld.getConfig(CONFIG_CREATURE_FAMILY_ASSISTEMCE_RADIUS);
+void Creature::CallAssistance()
+{
+ if( !m_AlreadyCallAssistance && getVictim() && !isPet() && !isCharmed())
+ {
+ SetNoCallAssistance(true);
+
+ float radius = sWorld.getConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS);
if(radius > 0)
{
std::list<Creature*> assistList;
@@ -1843,16 +1911,49 @@ void Creature::CallAssistence()
cell_lock->Visit(cell_lock, grid_creature_searcher, *MapManager::Instance().GetMap(GetMapId(), this));
}
- for(std::list<Creature*>::iterator iter = assistList.begin(); iter != assistList.end(); ++iter)
+ if (!assistList.empty())
{
- (*iter)->SetNoCallAssistence(true);
- if((*iter)->AI())
- (*iter)->AI()->AttackStart(getVictim());
+ AssistDelayEvent *e = new AssistDelayEvent(getVictim()->GetGUID(), *this);
+ while (!assistList.empty())
+ {
+ // Pushing guids because in delay can happen some creature gets despawned => invalid pointer
+ e->AddAssistant((*assistList.begin())->GetGUID());
+ assistList.pop_front();
+ }
+ m_Events.AddEvent(e, m_Events.CalculateTime(sWorld.getConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY)));
}
}
}
}
+bool Creature::CanAssistTo(const Unit* u, const Unit* enemy) const
+{
+ if(!isAggressive())
+ return false;
+
+ // we don't need help from zombies :)
+ if( !isAlive() )
+ return false;
+
+ // skip fighting creature
+ if( isInCombat() )
+ return false;
+
+ // only from same creature faction
+ if(getFaction() != u->getFaction() )
+ return false;
+
+ // only free creature
+ if( GetCharmerOrOwnerGUID() )
+ return false;
+
+ // skip non hostile to caster enemy creatures
+ if( !IsHostileTo(enemy) )
+ return false;
+
+ return true;
+}
+
void Creature::SaveRespawnTime()
{
if(isPet() || !m_DBTableGuid)
@@ -1878,7 +1979,7 @@ bool Creature::IsOutOfThreatArea(Unit* pVictim) const
if(!pVictim->isInAccessiblePlaceFor(this))
return true;
- if(sMapStore.LookupEntry(GetMapId())->Instanceable())
+ if(sMapStore.LookupEntry(GetMapId())->IsDungeon())
return false;
float length = pVictim->GetDistance(CombatStartX,CombatStartY,CombatStartZ);
diff --git a/src/game/Creature.h b/src/game/Creature.h
index d5b6b23a025..b85c74d31b8 100644
--- a/src/game/Creature.h
+++ b/src/game/Creature.h
@@ -29,6 +29,8 @@
#include "Database/DatabaseEnv.h"
#include "Cell.h"
+#include <list>
+
struct SpellEntry;
class CreatureAI;
@@ -426,6 +428,8 @@ class TRINITY_DLL_SPEC Creature : public Unit
bool canWalk() const { return GetCreatureInfo()->InhabitType & INHABIT_GROUND; }
bool canSwim() const { return GetCreatureInfo()->InhabitType & INHABIT_WATER; }
bool canFly() const { return GetCreatureInfo()->InhabitType & INHABIT_AIR; }
+ bool isAggressive() const { return m_isAggressive; }
+ void SetAggressive(bool agg) { m_isAggressive = agg; }
///// TODO RENAME THIS!!!!!
bool isCanTrainingOf(Player* player, bool msg) const;
bool isCanIneractWithBattleMaster(Player* player, bool msg) const;
@@ -458,7 +462,7 @@ class TRINITY_DLL_SPEC Creature : public Unit
bool AIM_Initialize();
void InitPossessedAI();
- void DeletePossessedAI();
+ void DisablePossessedAI();
void AI_SendMoveToPacket(float x, float y, float z, uint32 time, uint32 MovementFlags, uint8 type);
CreatureAI* AI() { return isPossessed() && i_AI_possessed ? i_AI_possessed : i_AI; }
@@ -555,10 +559,13 @@ class TRINITY_DLL_SPEC Creature : public Unit
bool canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList) const;
bool IsWithinSightDist(Unit const* u) const;
+ bool canStartAttack(Unit const* u) const;
float GetAttackDistance(Unit const* pl) const;
- void CallAssistence();
- void SetNoCallAssistence(bool val) { m_AlreadyCallAssistence = val; }
+ Unit* SelectNearestTarget(float dist = 0) const;
+ void CallAssistance();
+ void SetNoCallAssistance(bool val) { m_AlreadyCallAssistance = val; }
+ bool CanAssistTo(const Unit* u, const Unit* enemy) const;
void DoFleeToGetAssistance(float radius = 50);
MovementGeneratorType GetDefaultMovementType() const { return m_defaultMovementType; }
@@ -607,7 +614,6 @@ class TRINITY_DLL_SPEC Creature : public Unit
void GetCombatStartPosition(float &x, float &y, float &z) { x = CombatStartX; y = CombatStartY; z = CombatStartZ; }
uint32 GetGlobalCooldown() const { return m_GlobalCooldown; }
-
protected:
bool CreateFromProto(uint32 guidlow,uint32 Entry,uint32 team, const CreatureData *data = NULL);
bool InitEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData* data=NULL);
@@ -636,6 +642,7 @@ class TRINITY_DLL_SPEC Creature : public Unit
uint8 m_emoteState;
bool m_isPet; // set only in Pet::Pet
bool m_isTotem; // set only in Totem::Totem
+ bool m_isAggressive;
void RegenerateMana();
void RegenerateHealth();
uint32 m_regenTimer;
@@ -644,7 +651,7 @@ class TRINITY_DLL_SPEC Creature : public Unit
uint32 m_DBTableGuid; ///< For new or temporary creatures is 0 for saved it is lowguid
uint32 m_equipmentId;
- bool m_AlreadyCallAssistence;
+ bool m_AlreadyCallAssistance;
bool m_regenHealth;
bool m_AI_locked;
bool m_isDeadByDefault;
@@ -655,8 +662,25 @@ class TRINITY_DLL_SPEC Creature : public Unit
float CombatStartX;
float CombatStartY;
float CombatStartZ;
+
private:
GridReference<Creature> m_gridRef;
CreatureInfo const* m_creatureInfo; // in heroic mode can different from ObjMgr::GetCreatureTemplate(GetEntry())
};
+
+class AssistDelayEvent : public BasicEvent
+{
+ public:
+ AssistDelayEvent(const uint64& victim, Unit& owner) : BasicEvent(), m_victim(victim), m_owner(owner) { }
+
+ bool Execute(uint64 e_time, uint32 p_time);
+ void AddAssistant(const uint64& guid) { m_assistants.push_back(guid); }
+ private:
+ AssistDelayEvent();
+
+ uint64 m_victim;
+ std::list<uint64> m_assistants;
+ Unit& m_owner;
+};
+
#endif
diff --git a/src/game/DynamicObject.cpp b/src/game/DynamicObject.cpp
index b61b6654167..50539796ab3 100644
--- a/src/game/DynamicObject.cpp
+++ b/src/game/DynamicObject.cpp
@@ -140,7 +140,13 @@ void DynamicObject::Delete()
// are switched to world container on creation and they are also set to active
if (isActive())
{
- GetMap()->SwitchGridContainers(this, false);
+ Map* map = GetMap();
+ if(!map)
+ {
+ sLog.outError("DynamicObject (TypeId: %u Entry: %u GUID: %u) at attempt add to move list not have valid map (Id: %u).",GetTypeId(),GetEntry(),GetGUIDLow(),GetMapId());
+ return;
+ }
+ map->SwitchGridContainers(this, false);
setActive(false);
}
SendObjectDeSpawnAnim(GetGUID());
diff --git a/src/game/Formulas.h b/src/game/Formulas.h
index 21c0b1f24fb..f9915a2001c 100644
--- a/src/game/Formulas.h
+++ b/src/game/Formulas.h
@@ -1,208 +1,208 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
- *
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
- *
- * 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
- */
-
-#ifndef TRINITY_FORMULAS_H
-#define TRINITY_FORMULAS_H
-
-#include "World.h"
-
-namespace Trinity
-{
- namespace Honor
- {
- inline uint32 hk_honor_at_level(uint32 level, uint32 count=1)
- {
- return (uint32)ceil(count*(-0.53177f + 0.59357f * exp((level +23.54042f) / 26.07859f )));
- }
- }
- namespace XP
- {
- typedef enum XPColorChar { RED, ORANGE, YELLOW, GREEN, GRAY };
-
- inline uint32 GetGrayLevel(uint32 pl_level)
- {
- if( pl_level <= 5 )
- return 0;
- else if( pl_level <= 39 )
- return pl_level - 5 - pl_level/10;
- else if( pl_level <= 59 )
- return pl_level - 1 - pl_level/5;
- else
- return pl_level - 9;
- }
-
- inline XPColorChar GetColorCode(uint32 pl_level, uint32 mob_level)
- {
- if( mob_level >= pl_level + 5 )
- return RED;
- else if( mob_level >= pl_level + 3 )
- return ORANGE;
- else if( mob_level >= pl_level - 2 )
- return YELLOW;
- else if( mob_level > GetGrayLevel(pl_level) )
- return GREEN;
- else
- return GRAY;
- }
-
- inline uint32 GetZeroDifference(uint32 pl_level)
- {
- if( pl_level < 8 ) return 5;
- if( pl_level < 10 ) return 6;
- if( pl_level < 12 ) return 7;
- if( pl_level < 16 ) return 8;
- if( pl_level < 20 ) return 9;
- if( pl_level < 30 ) return 11;
- if( pl_level < 40 ) return 12;
- if( pl_level < 45 ) return 13;
- if( pl_level < 50 ) return 14;
- if( pl_level < 55 ) return 15;
- if( pl_level < 60 ) return 16;
- return 17;
- }
-
- inline uint32 BaseGain(uint32 pl_level, uint32 mob_level, ContentLevels content)
- {
- //TODO: need modifier for CONTENT_71_80 different from CONTENT_61_70?
- const uint32 nBaseExp = content == CONTENT_1_60 ? 45 : 235;
- if( mob_level >= pl_level )
- {
- uint32 nLevelDiff = mob_level - pl_level;
- if (nLevelDiff > 4)
- nLevelDiff = 4;
- return ((pl_level*5 + nBaseExp) * (20 + nLevelDiff)/10 + 1)/2;
- }
- else
- {
- uint32 gray_level = GetGrayLevel(pl_level);
- if( mob_level > gray_level )
- {
- uint32 ZD = GetZeroDifference(pl_level);
- return (pl_level*5 + nBaseExp) * (ZD + mob_level - pl_level)/ZD;
- }
- return 0;
- }
- }
-
- inline uint32 Gain(Player *pl, Unit *u)
- {
- if(u->GetTypeId()==TYPEID_UNIT && (
- ((Creature*)u)->isTotem() || ((Creature*)u)->isPet() ||
- (((Creature*)u)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL) ))
- return 0;
-
- uint32 xp_gain= BaseGain(pl->getLevel(), u->getLevel(), GetContentLevelsForMapAndZone(pl->GetMapId(),pl->GetZoneId()));
- if( xp_gain == 0 )
- return 0;
-
- if(u->GetTypeId()==TYPEID_UNIT && ((Creature*)u)->isElite())
- xp_gain *= 2;
-
- return (uint32)(xp_gain*sWorld.getRate(RATE_XP_KILL));
- }
-
- inline uint32 xp_Diff(uint32 lvl)
- {
- if( lvl < 29 )
- return 0;
- if( lvl == 29 )
- return 1;
- if( lvl == 30 )
- return 3;
- if( lvl == 31 )
- return 6;
- else
- return (5*(lvl-30));
- }
-
- inline uint32 mxp(uint32 lvl)
- {
- if (lvl < 60)
- {
- return (45 + (5*lvl));
- }
- else
- {
- return (235 + (5*lvl));
- }
- }
-
- inline uint32 xp_to_level(uint32 lvl)
- {
- uint32 xp = 0;
- if (lvl < 60)
- {
- xp = (8*lvl + xp_Diff(lvl)) * mxp(lvl);
- }
- else if (lvl == 60)
- {
- xp = (155 + mxp(lvl) * (1344 - 70 - ((69 - lvl) * (7 + (69 - lvl) * 8 - 1)/2)));
- }
- else if (lvl < 70)
- {
- xp = (155 + mxp(lvl) * (1344 - ((69-lvl) * (7 + (69 - lvl) * 8 - 1)/2)));
- }else
- {
- // level higher than 70 is not supported
- xp = (uint32)(779700 * (pow(sWorld.getRate(RATE_XP_PAST_70), (int32)lvl - 69)));
- return ((xp < 0x7fffffff) ? xp : 0x7fffffff);
- }
-
- // The XP to Level is always rounded to the nearest 100 points (50 rounded to high).
- xp = ((xp + 50) / 100) * 100; // use additional () for prevent free association operations in C++
-
- if ((lvl > 10) && (lvl < 60)) // compute discount added in 2.3.x
- {
- uint32 discount = (lvl < 28) ? (lvl - 10) : 18;
- xp = (xp * (100 - discount)) / 100; // apply discount
- xp = (xp / 100) * 100; // floor to hundreds
- }
-
- return xp;
- }
-
- inline float xp_in_group_rate(uint32 count, bool isRaid)
- {
- if(isRaid)
- {
- // FIX ME: must apply decrease modifiers dependent from raid size
- return 1.0f;
- }
- else
- {
- switch(count)
- {
- case 0:
- case 1:
- case 2:
- return 1.0f;
- case 3:
- return 1.166f;
- case 4:
- return 1.3f;
- case 5:
- default:
- return 1.4f;
- }
- }
- }
- }
-}
-#endif
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ *
+ * 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
+ */
+
+#ifndef TRINITY_FORMULAS_H
+#define TRINITY_FORMULAS_H
+
+#include "World.h"
+
+namespace Trinity
+{
+ namespace Honor
+ {
+ inline uint32 hk_honor_at_level(uint32 level, uint32 count=1)
+ {
+ return (uint32)ceil(count*(-0.53177f + 0.59357f * exp((level +23.54042f) / 26.07859f )));
+ }
+ }
+ namespace XP
+ {
+ typedef enum XPColorChar { RED, ORANGE, YELLOW, GREEN, GRAY };
+
+ inline uint32 GetGrayLevel(uint32 pl_level)
+ {
+ if( pl_level <= 5 )
+ return 0;
+ else if( pl_level <= 39 )
+ return pl_level - 5 - pl_level/10;
+ else if( pl_level <= 59 )
+ return pl_level - 1 - pl_level/5;
+ else
+ return pl_level - 9;
+ }
+
+ inline XPColorChar GetColorCode(uint32 pl_level, uint32 mob_level)
+ {
+ if( mob_level >= pl_level + 5 )
+ return RED;
+ else if( mob_level >= pl_level + 3 )
+ return ORANGE;
+ else if( mob_level >= pl_level - 2 )
+ return YELLOW;
+ else if( mob_level > GetGrayLevel(pl_level) )
+ return GREEN;
+ else
+ return GRAY;
+ }
+
+ inline uint32 GetZeroDifference(uint32 pl_level)
+ {
+ if( pl_level < 8 ) return 5;
+ if( pl_level < 10 ) return 6;
+ if( pl_level < 12 ) return 7;
+ if( pl_level < 16 ) return 8;
+ if( pl_level < 20 ) return 9;
+ if( pl_level < 30 ) return 11;
+ if( pl_level < 40 ) return 12;
+ if( pl_level < 45 ) return 13;
+ if( pl_level < 50 ) return 14;
+ if( pl_level < 55 ) return 15;
+ if( pl_level < 60 ) return 16;
+ return 17;
+ }
+
+ inline uint32 BaseGain(uint32 pl_level, uint32 mob_level, ContentLevels content)
+ {
+ //TODO: need modifier for CONTENT_71_80 different from CONTENT_61_70?
+ const uint32 nBaseExp = content == CONTENT_1_60 ? 45 : 235;
+ if( mob_level >= pl_level )
+ {
+ uint32 nLevelDiff = mob_level - pl_level;
+ if (nLevelDiff > 4)
+ nLevelDiff = 4;
+ return ((pl_level*5 + nBaseExp) * (20 + nLevelDiff)/10 + 1)/2;
+ }
+ else
+ {
+ uint32 gray_level = GetGrayLevel(pl_level);
+ if( mob_level > gray_level )
+ {
+ uint32 ZD = GetZeroDifference(pl_level);
+ return (pl_level*5 + nBaseExp) * (ZD + mob_level - pl_level)/ZD;
+ }
+ return 0;
+ }
+ }
+
+ inline uint32 Gain(Player *pl, Unit *u)
+ {
+ if(u->GetTypeId()==TYPEID_UNIT && (
+ ((Creature*)u)->isTotem() || ((Creature*)u)->isPet() ||
+ (((Creature*)u)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL) ))
+ return 0;
+
+ uint32 xp_gain= BaseGain(pl->getLevel(), u->getLevel(), GetContentLevelsForMapAndZone(pl->GetMapId(),pl->GetZoneId()));
+ if( xp_gain == 0 )
+ return 0;
+
+ if(u->GetTypeId()==TYPEID_UNIT && ((Creature*)u)->isElite())
+ xp_gain *= 2;
+
+ return (uint32)(xp_gain*sWorld.getRate(RATE_XP_KILL));
+ }
+
+ inline uint32 xp_Diff(uint32 lvl)
+ {
+ if( lvl < 29 )
+ return 0;
+ if( lvl == 29 )
+ return 1;
+ if( lvl == 30 )
+ return 3;
+ if( lvl == 31 )
+ return 6;
+ else
+ return (5*(lvl-30));
+ }
+
+ inline uint32 mxp(uint32 lvl)
+ {
+ if (lvl < 60)
+ {
+ return (45 + (5*lvl));
+ }
+ else
+ {
+ return (235 + (5*lvl));
+ }
+ }
+
+ inline uint32 xp_to_level(uint32 lvl)
+ {
+ uint32 xp = 0;
+ if (lvl < 60)
+ {
+ xp = (8*lvl + xp_Diff(lvl)) * mxp(lvl);
+ }
+ else if (lvl == 60)
+ {
+ xp = (155 + mxp(lvl) * (1344 - 70 - ((69 - lvl) * (7 + (69 - lvl) * 8 - 1)/2)));
+ }
+ else if (lvl < 70)
+ {
+ xp = (155 + mxp(lvl) * (1344 - ((69-lvl) * (7 + (69 - lvl) * 8 - 1)/2)));
+ }else
+ {
+ // level higher than 70 is not supported
+ xp = (uint32)(779700 * (pow(sWorld.getRate(RATE_XP_PAST_70), (int32)lvl - 69)));
+ return ((xp < 0x7fffffff) ? xp : 0x7fffffff);
+ }
+
+ // The XP to Level is always rounded to the nearest 100 points (50 rounded to high).
+ xp = ((xp + 50) / 100) * 100; // use additional () for prevent free association operations in C++
+
+ if ((lvl > 10) && (lvl < 60)) // compute discount added in 2.3.x
+ {
+ uint32 discount = (lvl < 28) ? (lvl - 10) : 18;
+ xp = (xp * (100 - discount)) / 100; // apply discount
+ xp = (xp / 100) * 100; // floor to hundreds
+ }
+
+ return xp;
+ }
+
+ inline float xp_in_group_rate(uint32 count, bool isRaid)
+ {
+ if(isRaid)
+ {
+ // FIX ME: must apply decrease modifiers dependent from raid size
+ return 1.0f;
+ }
+ else
+ {
+ switch(count)
+ {
+ case 0:
+ case 1:
+ case 2:
+ return 1.0f;
+ case 3:
+ return 1.166f;
+ case 4:
+ return 1.3f;
+ case 5:
+ default:
+ return 1.4f;
+ }
+ }
+ }
+ }
+}
+#endif
diff --git a/src/game/GMTicketHandler.cpp b/src/game/GMTicketHandler.cpp
index 3a9651dc4fd..448730bd3ea 100644
--- a/src/game/GMTicketHandler.cpp
+++ b/src/game/GMTicketHandler.cpp
@@ -1,177 +1,177 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS
- *
- * Copyright (C) 2008 Trinity
- *
- * 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
- */
-
-#include "Common.h"
-#include "Language.h"
-#include "WorldPacket.h"
-#include "Log.h"
-#include "GMTicketMgr.h"
-#include "ObjectAccessor.h"
-#include "Player.h"
-#include "Chat.h"
-
-void WorldSession::SendGMTicketGetTicket(uint32 status, char const* text)
-{
- int len = text ? strlen(text) : 0;
- WorldPacket data( SMSG_GMTICKET_GETTICKET, (4+len+1+4+2+4+4) );
- data << uint32(status); // standard 0x0A, 0x06 if text present
- if(status == 6)
- {
- data << text; // ticket text
- data << uint8(0x7); // ticket category
- data << float(0); // time from ticket creation?
- data << float(0); // const
- data << float(0); // const
- data << uint8(0); // const
- data << uint8(0); // const
- }
- SendPacket( &data );
-}
-
-void WorldSession::HandleGMTicketGetTicketOpcode( WorldPacket & /*recv_data*/ )
-{
- WorldPacket data( SMSG_QUERY_TIME_RESPONSE, 4+4 );
- data << (uint32)time(NULL);
- data << (uint32)0;
- SendPacket( &data );
-
- GMTicket* ticket = ticketmgr.GetGMTicket(GetPlayer()->GetGUIDLow());
- if(ticket)
- SendGMTicketGetTicket(0x06,ticket->GetText());
- else
- SendGMTicketGetTicket(0x0A,0);
-}
-
-void WorldSession::HandleGMTicketUpdateTextOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data,1);
-
- std::string ticketText;
- recv_data >> ticketText;
-
- if(GMTicket* ticket = ticketmgr.GetGMTicket(GetPlayer()->GetGUIDLow()))
- ticket->SetText(ticketText.c_str());
- else
- sLog.outError("Ticket update: Player %s (GUID: %u) doesn't have active ticket", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow());
-}
-
-void WorldSession::HandleGMTicketDeleteOpcode( WorldPacket & /*recv_data*/ )
-{
- ticketmgr.Delete(GetPlayer()->GetGUIDLow());
-
- WorldPacket data( SMSG_GMTICKET_DELETETICKET, 4 );
- data << uint32(9);
- SendPacket( &data );
-
- SendGMTicketGetTicket(0x0A, 0);
-}
-
-void WorldSession::HandleGMTicketCreateOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 4*4+1+2*4);
-
- uint32 map;
- float x, y, z;
- std::string ticketText = "";
- uint32 unk1, unk2;
-
- recv_data >> map >> x >> y >> z; // last check 2.4.3
- recv_data >> ticketText;
-
- // recheck
- CHECK_PACKET_SIZE(recv_data,4*4+(ticketText.size()+1)+2*4);
-
- recv_data >> unk1 >> unk2;
- // note: the packet might contain more data, but the exact structure of that is unknown
-
- sLog.outDebug("TicketCreate: map %u, x %f, y %f, z %f, text %s, unk1 %u, unk2 %u", map, x, y, z, ticketText.c_str(), unk1, unk2);
-
- if(ticketmgr.GetGMTicket(GetPlayer()->GetGUIDLow()))
- {
- WorldPacket data( SMSG_GMTICKET_CREATE, 4 );
- data << uint32(1);
- SendPacket( &data );
- return;
- }
-
- ticketmgr.Create(_player->GetGUIDLow(), ticketText.c_str());
-
- WorldPacket data( SMSG_QUERY_TIME_RESPONSE, 4+4 );
- data << (uint32)time(NULL);
- data << (uint32)0;
- SendPacket( &data );
-
- data.Initialize( SMSG_GMTICKET_CREATE, 4 );
- data << uint32(2);
- SendPacket( &data );
- DEBUG_LOG("update the ticket\n");
-
- //TODO: Guard player map
- HashMapHolder<Player>::MapType &m = ObjectAccessor::Instance().GetPlayers();
- for(HashMapHolder<Player>::MapType::iterator itr = m.begin(); itr != m.end(); ++itr)
- {
- if(itr->second->GetSession()->GetSecurity() >= SEC_GAMEMASTER && itr->second->isAcceptTickets())
- ChatHandler(itr->second).PSendSysMessage(LANG_COMMAND_TICKETNEW,GetPlayer()->GetName());
- }
-}
-
-void WorldSession::HandleGMTicketSystemStatusOpcode( WorldPacket & /*recv_data*/ )
-{
- WorldPacket data( SMSG_GMTICKET_SYSTEMSTATUS,4 );
- data << uint32(1); // we can also disable ticket system by sending 0 value
-
- SendPacket( &data );
-}
-
-void WorldSession::HandleGMSurveySubmit( WorldPacket & recv_data)
-{
- // GM survey is shown after SMSG_GM_TICKET_STATUS_UPDATE with status = 3
- CHECK_PACKET_SIZE(recv_data,4+4);
- uint32 x;
- recv_data >> x; // answer range? (6 = 0-5?)
- sLog.outDebug("SURVEY: X = %u", x);
-
- uint8 result[10];
- memset(result, 0, sizeof(result));
- for( int i = 0; i < 10; ++i)
- {
- CHECK_PACKET_SIZE(recv_data,recv_data.rpos()+4);
- uint32 questionID;
- recv_data >> questionID; // GMSurveyQuestions.dbc
- if (!questionID)
- break;
-
- CHECK_PACKET_SIZE(recv_data,recv_data.rpos()+1+1);
- uint8 value;
- std::string unk_text;
- recv_data >> value; // answer
- recv_data >> unk_text; // always empty?
-
- result[i] = value;
- sLog.outDebug("SURVEY: ID %u, value %u, text %s", questionID, value, unk_text.c_str());
- }
-
- CHECK_PACKET_SIZE(recv_data,recv_data.rpos()+1);
- std::string comment;
- recv_data >> comment; // addional comment
- sLog.outDebug("SURVEY: comment %s", comment.c_str());
-
- // TODO: chart this data in some way
-}
+/*
+ * Copyright (C) 2005-2008 MaNGOS
+ *
+ * Copyright (C) 2008 Trinity
+ *
+ * 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
+ */
+
+#include "Common.h"
+#include "Language.h"
+#include "WorldPacket.h"
+#include "Log.h"
+#include "GMTicketMgr.h"
+#include "ObjectAccessor.h"
+#include "Player.h"
+#include "Chat.h"
+
+void WorldSession::SendGMTicketGetTicket(uint32 status, char const* text)
+{
+ int len = text ? strlen(text) : 0;
+ WorldPacket data( SMSG_GMTICKET_GETTICKET, (4+len+1+4+2+4+4) );
+ data << uint32(status); // standard 0x0A, 0x06 if text present
+ if(status == 6)
+ {
+ data << text; // ticket text
+ data << uint8(0x7); // ticket category
+ data << float(0); // time from ticket creation?
+ data << float(0); // const
+ data << float(0); // const
+ data << uint8(0); // const
+ data << uint8(0); // const
+ }
+ SendPacket( &data );
+}
+
+void WorldSession::HandleGMTicketGetTicketOpcode( WorldPacket & /*recv_data*/ )
+{
+ WorldPacket data( SMSG_QUERY_TIME_RESPONSE, 4+4 );
+ data << (uint32)time(NULL);
+ data << (uint32)0;
+ SendPacket( &data );
+
+ GMTicket* ticket = ticketmgr.GetGMTicket(GetPlayer()->GetGUIDLow());
+ if(ticket)
+ SendGMTicketGetTicket(0x06,ticket->GetText());
+ else
+ SendGMTicketGetTicket(0x0A,0);
+}
+
+void WorldSession::HandleGMTicketUpdateTextOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data,1);
+
+ std::string ticketText;
+ recv_data >> ticketText;
+
+ if(GMTicket* ticket = ticketmgr.GetGMTicket(GetPlayer()->GetGUIDLow()))
+ ticket->SetText(ticketText.c_str());
+ else
+ sLog.outError("Ticket update: Player %s (GUID: %u) doesn't have active ticket", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow());
+}
+
+void WorldSession::HandleGMTicketDeleteOpcode( WorldPacket & /*recv_data*/ )
+{
+ ticketmgr.Delete(GetPlayer()->GetGUIDLow());
+
+ WorldPacket data( SMSG_GMTICKET_DELETETICKET, 4 );
+ data << uint32(9);
+ SendPacket( &data );
+
+ SendGMTicketGetTicket(0x0A, 0);
+}
+
+void WorldSession::HandleGMTicketCreateOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 4*4+1+2*4);
+
+ uint32 map;
+ float x, y, z;
+ std::string ticketText = "";
+ uint32 unk1, unk2;
+
+ recv_data >> map >> x >> y >> z; // last check 2.4.3
+ recv_data >> ticketText;
+
+ // recheck
+ CHECK_PACKET_SIZE(recv_data,4*4+(ticketText.size()+1)+2*4);
+
+ recv_data >> unk1 >> unk2;
+ // note: the packet might contain more data, but the exact structure of that is unknown
+
+ sLog.outDebug("TicketCreate: map %u, x %f, y %f, z %f, text %s, unk1 %u, unk2 %u", map, x, y, z, ticketText.c_str(), unk1, unk2);
+
+ if(ticketmgr.GetGMTicket(GetPlayer()->GetGUIDLow()))
+ {
+ WorldPacket data( SMSG_GMTICKET_CREATE, 4 );
+ data << uint32(1);
+ SendPacket( &data );
+ return;
+ }
+
+ ticketmgr.Create(_player->GetGUIDLow(), ticketText.c_str());
+
+ WorldPacket data( SMSG_QUERY_TIME_RESPONSE, 4+4 );
+ data << (uint32)time(NULL);
+ data << (uint32)0;
+ SendPacket( &data );
+
+ data.Initialize( SMSG_GMTICKET_CREATE, 4 );
+ data << uint32(2);
+ SendPacket( &data );
+ DEBUG_LOG("update the ticket\n");
+
+ //TODO: Guard player map
+ HashMapHolder<Player>::MapType &m = ObjectAccessor::Instance().GetPlayers();
+ for(HashMapHolder<Player>::MapType::iterator itr = m.begin(); itr != m.end(); ++itr)
+ {
+ if(itr->second->GetSession()->GetSecurity() >= SEC_GAMEMASTER && itr->second->isAcceptTickets())
+ ChatHandler(itr->second).PSendSysMessage(LANG_COMMAND_TICKETNEW,GetPlayer()->GetName());
+ }
+}
+
+void WorldSession::HandleGMTicketSystemStatusOpcode( WorldPacket & /*recv_data*/ )
+{
+ WorldPacket data( SMSG_GMTICKET_SYSTEMSTATUS,4 );
+ data << uint32(1); // we can also disable ticket system by sending 0 value
+
+ SendPacket( &data );
+}
+
+void WorldSession::HandleGMSurveySubmit( WorldPacket & recv_data)
+{
+ // GM survey is shown after SMSG_GM_TICKET_STATUS_UPDATE with status = 3
+ CHECK_PACKET_SIZE(recv_data,4+4);
+ uint32 x;
+ recv_data >> x; // answer range? (6 = 0-5?)
+ sLog.outDebug("SURVEY: X = %u", x);
+
+ uint8 result[10];
+ memset(result, 0, sizeof(result));
+ for( int i = 0; i < 10; ++i)
+ {
+ CHECK_PACKET_SIZE(recv_data,recv_data.rpos()+4);
+ uint32 questionID;
+ recv_data >> questionID; // GMSurveyQuestions.dbc
+ if (!questionID)
+ break;
+
+ CHECK_PACKET_SIZE(recv_data,recv_data.rpos()+1+1);
+ uint8 value;
+ std::string unk_text;
+ recv_data >> value; // answer
+ recv_data >> unk_text; // always empty?
+
+ result[i] = value;
+ sLog.outDebug("SURVEY: ID %u, value %u, text %s", questionID, value, unk_text.c_str());
+ }
+
+ CHECK_PACKET_SIZE(recv_data,recv_data.rpos()+1);
+ std::string comment;
+ recv_data >> comment; // addional comment
+ sLog.outDebug("SURVEY: comment %s", comment.c_str());
+
+ // TODO: chart this data in some way
+}
diff --git a/src/game/GMTicketMgr.h b/src/game/GMTicketMgr.h
index a116f1806e2..1fd4e4c3a8f 100644
--- a/src/game/GMTicketMgr.h
+++ b/src/game/GMTicketMgr.h
@@ -1,125 +1,125 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _GMTICKETMGR_H
-#define _GMTICKETMGR_H
-
-#include "Policies/Singleton.h"
-#include "Database/DatabaseEnv.h"
-#include "Util.h"
-#include <map>
-
-class GMTicket
-{
- public:
- explicit GMTicket()
- {
- }
-
- GMTicket(uint32 guid, std::string text, time_t update) : m_guid(guid), m_text(text), m_lastUpdate(update)
- {
-
- }
-
- const char* GetText() const
- {
- return m_text.c_str();
- }
-
- uint64 GetLastUpdate() const
- {
- return m_lastUpdate;
- }
-
- void SetText(const char* text)
- {
- m_text = text ? text : "";
- m_lastUpdate = time(NULL);
-
- std::string escapedString = m_text;
- CharacterDatabase.escape_string(escapedString);
- CharacterDatabase.PExecute("UPDATE character_ticket SET ticket_text = '%s' WHERE guid = '%u'", escapedString.c_str(), m_guid);
- }
-
- void DeleteFromDB() const
- {
- CharacterDatabase.PExecute("DELETE FROM character_ticket WHERE guid = '%u' LIMIT 1", m_guid);
- }
-
- void SaveToDB() const
- {
- CharacterDatabase.BeginTransaction();
- DeleteFromDB();
-
- std::string escapedString = m_text;
- CharacterDatabase.escape_string(escapedString);
-
- CharacterDatabase.PExecute("INSERT INTO character_ticket (guid, ticket_text) VALUES ('%u', '%s')", m_guid, escapedString.c_str());
- CharacterDatabase.CommitTransaction();
- }
- private:
- uint32 m_guid;
- std::string m_text;
- time_t m_lastUpdate;
-};
-typedef std::map<uint32, GMTicket> GMTicketMap;
-
-class GMTicketMgr
-{
- public:
- GMTicketMgr() { }
- ~GMTicketMgr() { }
-
- void LoadGMTickets();
-
- GMTicket* GetGMTicket(uint32 guid)
- {
- GMTicketMap::iterator itr = m_GMTicketMap.find(guid);
- if(itr == m_GMTicketMap.end())
- return NULL;
- return &(itr->second);
- }
-
- size_t GetTicketCount() const
- {
- return m_GMTicketMap.size();
- }
-
- void Delete(uint32 guid)
- {
- GMTicketMap::iterator itr = m_GMTicketMap.find(guid);
- if(itr == m_GMTicketMap.end())
- return;
- itr->second.DeleteFromDB();
- m_GMTicketMap.erase(itr);
- }
-
- void DeleteAll();
-
- void Create(uint32 guid, const char* text)
- {
- GMTicket t = GMTicket(guid, text, time(NULL));
- t.SaveToDB();
- m_GMTicketMap[guid] = t;
- }
- private:
- GMTicketMap m_GMTicketMap;
-};
-
-#define ticketmgr Trinity::Singleton<GMTicketMgr>::Instance()
-#endif
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _GMTICKETMGR_H
+#define _GMTICKETMGR_H
+
+#include "Policies/Singleton.h"
+#include "Database/DatabaseEnv.h"
+#include "Util.h"
+#include <map>
+
+class GMTicket
+{
+ public:
+ explicit GMTicket()
+ {
+ }
+
+ GMTicket(uint32 guid, std::string text, time_t update) : m_guid(guid), m_text(text), m_lastUpdate(update)
+ {
+
+ }
+
+ const char* GetText() const
+ {
+ return m_text.c_str();
+ }
+
+ uint64 GetLastUpdate() const
+ {
+ return m_lastUpdate;
+ }
+
+ void SetText(const char* text)
+ {
+ m_text = text ? text : "";
+ m_lastUpdate = time(NULL);
+
+ std::string escapedString = m_text;
+ CharacterDatabase.escape_string(escapedString);
+ CharacterDatabase.PExecute("UPDATE character_ticket SET ticket_text = '%s' WHERE guid = '%u'", escapedString.c_str(), m_guid);
+ }
+
+ void DeleteFromDB() const
+ {
+ CharacterDatabase.PExecute("DELETE FROM character_ticket WHERE guid = '%u' LIMIT 1", m_guid);
+ }
+
+ void SaveToDB() const
+ {
+ CharacterDatabase.BeginTransaction();
+ DeleteFromDB();
+
+ std::string escapedString = m_text;
+ CharacterDatabase.escape_string(escapedString);
+
+ CharacterDatabase.PExecute("INSERT INTO character_ticket (guid, ticket_text) VALUES ('%u', '%s')", m_guid, escapedString.c_str());
+ CharacterDatabase.CommitTransaction();
+ }
+ private:
+ uint32 m_guid;
+ std::string m_text;
+ time_t m_lastUpdate;
+};
+typedef std::map<uint32, GMTicket> GMTicketMap;
+
+class GMTicketMgr
+{
+ public:
+ GMTicketMgr() { }
+ ~GMTicketMgr() { }
+
+ void LoadGMTickets();
+
+ GMTicket* GetGMTicket(uint32 guid)
+ {
+ GMTicketMap::iterator itr = m_GMTicketMap.find(guid);
+ if(itr == m_GMTicketMap.end())
+ return NULL;
+ return &(itr->second);
+ }
+
+ size_t GetTicketCount() const
+ {
+ return m_GMTicketMap.size();
+ }
+
+ void Delete(uint32 guid)
+ {
+ GMTicketMap::iterator itr = m_GMTicketMap.find(guid);
+ if(itr == m_GMTicketMap.end())
+ return;
+ itr->second.DeleteFromDB();
+ m_GMTicketMap.erase(itr);
+ }
+
+ void DeleteAll();
+
+ void Create(uint32 guid, const char* text)
+ {
+ GMTicket t = GMTicket(guid, text, time(NULL));
+ t.SaveToDB();
+ m_GMTicketMap[guid] = t;
+ }
+ private:
+ GMTicketMap m_GMTicketMap;
+};
+
+#define ticketmgr Trinity::Singleton<GMTicketMgr>::Instance()
+#endif
diff --git a/src/game/GameObject.cpp b/src/game/GameObject.cpp
index f6f89f482e5..3a11bf95c35 100644
--- a/src/game/GameObject.cpp
+++ b/src/game/GameObject.cpp
@@ -37,8 +37,9 @@
#include "CellImpl.h"
#include "InstanceData.h"
#include "BattleGround.h"
-#include "OutdoorPvPMgr.h"
#include "Util.h"
+#include "OutdoorPvPMgr.h"
+#include "BattleGroundAV.h"
GameObject::GameObject() : WorldObject()
{
@@ -754,7 +755,15 @@ bool GameObject::ActivateToQuest( Player *pTarget)const
case GAMEOBJECT_TYPE_CHEST:
{
if(LootTemplates_Gameobject.HaveQuestLootForPlayer(GetLootId(), pTarget))
+ {
+ //TODO: fix this hack
+ //look for battlegroundAV for some objects which are only activated after mine gots captured by own team
+ if(GetEntry() == BG_AV_OBJECTID_MINE_N || GetEntry() == BG_AV_OBJECTID_MINE_S)
+ if(BattleGround *bg = pTarget->GetBattleGround())
+ if(bg->GetTypeID() == BATTLEGROUND_AV && !(((BattleGroundAV*)bg)->PlayerCanDoMineQuest(GetEntry(),pTarget->GetTeam())))
+ return false;
return true;
+ }
break;
}
case GAMEOBJECT_TYPE_GOOBER:
diff --git a/src/game/GridNotifiers.cpp b/src/game/GridNotifiers.cpp
index 54ee2e67726..0c952f69649 100644
--- a/src/game/GridNotifiers.cpp
+++ b/src/game/GridNotifiers.cpp
@@ -190,7 +190,7 @@ Deliverer::Visit(DynamicObjectMapType &m)
{
// Send packet back to the caster if the caster has vision of dynamic object
Player* caster = (Player*)iter->getSource()->GetCaster();
- if (caster->GetUInt64Value(PLAYER_FARSIGHT) == iter->getSource()->GetGUID() &&
+ if (caster && caster->GetUInt64Value(PLAYER_FARSIGHT) == iter->getSource()->GetGUID() &&
(!i_dist || iter->getSource()->GetDistance(&i_source) <= i_dist))
SendPacket(caster);
}
diff --git a/src/game/GridNotifiers.h b/src/game/GridNotifiers.h
index 972c209964c..5dd863493a8 100644
--- a/src/game/GridNotifiers.h
+++ b/src/game/GridNotifiers.h
@@ -10,12 +10,12 @@
*
* 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
+ * 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
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef TRINITY_GRIDNOTIFIERS_H
@@ -476,7 +476,7 @@ namespace Trinity
return false;
}
- template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED* u) { return false; }
+ template<class NOT_INTERESTED> bool operator()(NOT_INTERESTED*) { return false; }
private:
Unit* const i_funit;
float i_range;
@@ -698,19 +698,40 @@ namespace Trinity
// Creature checks
- class InAttackDistanceFromAnyHostileCreatureCheck
+ class NearestHostileUnitInAttackDistanceCheck
{
public:
- explicit InAttackDistanceFromAnyHostileCreatureCheck(Unit* funit) : i_funit(funit) {}
- bool operator()(Creature* u)
+ explicit NearestHostileUnitInAttackDistanceCheck(Creature const* creature, float dist = 0) : m_creature(creature)
{
- if(u->isAlive() && u->IsHostileTo(i_funit) && i_funit->IsWithinDistInMap(u, u->GetAttackDistance(i_funit)))
- return true;
+ m_range = (dist == 0 ? 9999 : dist);
+ m_force = (dist == 0 ? false : true);
+ }
+ bool operator()(Unit* u)
+ {
+ // TODO: addthreat for every enemy in range?
+ if(!m_creature->IsWithinDistInMap(u, m_range))
+ return false;
- return false;
+ if(m_force)
+ {
+ if(!m_creature->canAttack(u))
+ return false;
+ }
+ else
+ {
+ if(!m_creature->canStartAttack(u))
+ return false;
+ }
+
+ m_range = m_creature->GetDistance(u);
+ return true;
}
+ float GetLastRange() const { return m_range; }
private:
- Unit* const i_funit;
+ Creature const *m_creature;
+ float m_range;
+ bool m_force;
+ NearestHostileUnitInAttackDistanceCheck(NearestHostileUnitInAttackDistanceCheck const&);
};
class NearestAssistCreatureInCreatureRangeCheck
@@ -750,32 +771,15 @@ namespace Trinity
if(u == i_funit)
return false;
- // we don't need help from zombies :)
- if( !u->isAlive() )
- return false;
-
- // skip fighting creature
- if( u->isInCombat() )
- return false;
-
- // only from same creature faction
- if(u->getFaction() != i_funit->getFaction() )
- return false;
-
- // only free creature
- if( u->GetCharmerOrOwnerGUID() )
+ if ( !u->CanAssistTo(i_funit, i_enemy) )
return false;
// too far
if( !i_funit->IsWithinDistInMap(u, i_range) )
return false;
- // skip non hostile to caster enemy creatures
- if( !u->IsHostileTo(i_enemy) )
- return false;
-
// only if see assisted creature
- if(!u->IsWithinLOSInMap(i_funit) )
+ if( !i_funit->IsWithinLOSInMap(u) )
return false;
return true;
@@ -873,7 +877,7 @@ namespace Trinity
FriendlyMissingBuffInRange(Unit const* obj, float range, uint32 spellid) : i_obj(obj), i_range(range), i_spell(spellid) {}
bool operator()(Unit* u)
{
- if(u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) &&
+ if(u->isAlive() && u->isInCombat() && /*!i_obj->IsHostileTo(u)*/ i_obj->IsFriendlyTo(u) && i_obj->IsWithinDistInMap(u, i_range) &&
!(u->HasAura(i_spell, 0) || u->HasAura(i_spell, 1) || u->HasAura(i_spell, 2)))
{
return true;
diff --git a/src/game/GridNotifiersImpl.h b/src/game/GridNotifiersImpl.h
index 80ab442bcd6..a4ad5a51bf7 100644
--- a/src/game/GridNotifiersImpl.h
+++ b/src/game/GridNotifiersImpl.h
@@ -72,7 +72,7 @@ inline void PlayerCreatureRelocationWorker(Player* pl, Creature* c)
pl->UpdateVisibilityOf(c);
// Creature AI reaction
- if(!c->hasUnitState(UNIT_STAT_CHASE | UNIT_STAT_SEARCHING | UNIT_STAT_FLEEING))
+ if(c->isAggressive() && !c->hasUnitState(UNIT_STAT_CHASE | UNIT_STAT_SEARCHING | UNIT_STAT_FLEEING))
{
if( c->AI() && c->IsWithinSightDist(pl) /*c->AI()->IsVisible(pl)*/ && !c->IsInEvadeMode() )
c->AI()->MoveInLineOfSight(pl);
@@ -81,13 +81,13 @@ inline void PlayerCreatureRelocationWorker(Player* pl, Creature* c)
inline void CreatureCreatureRelocationWorker(Creature* c1, Creature* c2)
{
- if(!c1->hasUnitState(UNIT_STAT_CHASE | UNIT_STAT_SEARCHING | UNIT_STAT_FLEEING))
+ if(c1->isAggressive() && !c1->hasUnitState(UNIT_STAT_CHASE | UNIT_STAT_SEARCHING | UNIT_STAT_FLEEING))
{
if( c1->AI() && c1->IsWithinSightDist(c2) /*c1->AI()->IsVisible(c2)*/ && !c1->IsInEvadeMode() )
c1->AI()->MoveInLineOfSight(c2);
}
- if(!c2->hasUnitState(UNIT_STAT_CHASE | UNIT_STAT_SEARCHING | UNIT_STAT_FLEEING))
+ if(c2->isAggressive() && !c2->hasUnitState(UNIT_STAT_CHASE | UNIT_STAT_SEARCHING | UNIT_STAT_FLEEING))
{
if( c2->AI() && c1->IsWithinSightDist(c2) /*c2->AI()->IsVisible(c1)*/ && !c2->IsInEvadeMode() )
c2->AI()->MoveInLineOfSight(c1);
@@ -101,7 +101,7 @@ Trinity::PlayerRelocationNotifier::Visit(CreatureMapType &m)
return;
for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
- if( iter->getSource()->isAlive())
+ if( !iter->getSource()->m_Notified && iter->getSource()->isAlive())
PlayerCreatureRelocationWorker(&i_player,iter->getSource());
}
@@ -113,7 +113,7 @@ Trinity::CreatureRelocationNotifier::Visit(PlayerMapType &m)
return;
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
- if( iter->getSource()->isAlive() && !iter->getSource()->isInFlight())
+ if( !iter->getSource()->m_Notified && iter->getSource()->isAlive() && !iter->getSource()->isInFlight())
PlayerCreatureRelocationWorker(iter->getSource(), &i_creature);
}
@@ -127,7 +127,7 @@ Trinity::CreatureRelocationNotifier::Visit(CreatureMapType &m)
for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
{
Creature* c = iter->getSource();
- if( c != &i_creature && c->isAlive())
+ if( !iter->getSource()->m_Notified && c != &i_creature && c->isAlive())
CreatureCreatureRelocationWorker(c, &i_creature);
}
}
diff --git a/src/game/GridStates.cpp b/src/game/GridStates.cpp
index 1f2df5e7c59..5cf5c8b8c11 100644
--- a/src/game/GridStates.cpp
+++ b/src/game/GridStates.cpp
@@ -10,12 +10,12 @@
*
* 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
+ * 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
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "GridStates.h"
@@ -36,7 +36,7 @@ ActiveState::Update(Map &m, NGridType &grid, GridInfo & info, const uint32 &x, c
info.UpdateTimeTracker(t_diff);
if( info.getTimeTracker().Passed() )
{
- if( grid.ActiveObjectsInGrid() == 0 && !ObjectAccessor::Instance().ActiveObjectsNearGrid(x, y, m.GetId(), m.GetInstanceId()) )
+ if( grid.ActiveObjectsInGrid() == 0 && !m.ActiveObjectsNearGrid(x, y) )
{
ObjectGridStoper stoper(grid);
stoper.StopN();
@@ -50,7 +50,7 @@ ActiveState::Update(Map &m, NGridType &grid, GridInfo & info, const uint32 &x, c
}
void
-IdleState::Update(Map &m, NGridType &grid, GridInfo &info, const uint32 &x, const uint32 &y, const uint32 &) const
+IdleState::Update(Map &m, NGridType &grid, GridInfo &, const uint32 &x, const uint32 &y, const uint32 &) const
{
m.ResetGridExpiry(grid);
grid.SetGridState(GRID_STATE_REMOVAL);
diff --git a/src/game/GuardAI.cpp b/src/game/GuardAI.cpp
index 8c6a8d3f774..8c029a5531e 100644
--- a/src/game/GuardAI.cpp
+++ b/src/game/GuardAI.cpp
@@ -52,7 +52,7 @@ void GuardAI::MoveInLineOfSight(Unit *u)
{
//Need add code to let guard support player
AttackStart(u);
- u->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ //u->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
}
}
}
diff --git a/src/game/Guild.cpp b/src/game/Guild.cpp
index 2fe6b2108b2..a4ac81f3a40 100644
--- a/src/game/Guild.cpp
+++ b/src/game/Guild.cpp
@@ -151,17 +151,13 @@ bool Guild::AddMember(uint64 plGuid, uint32 plRank)
CharacterDatabase.PExecute("INSERT INTO guild_member (guildid,guid,rank,pnote,offnote) VALUES ('%u', '%u', '%u','%s','%s')",
Id, GUID_LOPART(plGuid), newmember.RankId, dbPnote.c_str(), dbOFFnote.c_str());
+ // If player not in game data in data field will be loaded from guild tables, no need to update it!!
if(pl)
{
pl->SetInGuild(Id);
pl->SetRank(newmember.RankId);
pl->SetGuildIdInvited(0);
}
- else
- {
- Player::SetUInt32ValueInDB(PLAYER_GUILDID, Id, plGuid);
- Player::SetUInt32ValueInDB(PLAYER_GUILDRANK, newmember.RankId, plGuid);
- }
return true;
}
@@ -460,16 +456,15 @@ void Guild::DelMember(uint64 guid, bool isDisbanding)
this->SetLeader(newLeaderGUID);
newLeader = objmgr.GetPlayer(newLeaderGUID);
+
+ // If player not online data in data field will be loaded from guild tabs no need to update it !!
if(newLeader)
{
newLeader->SetRank(GR_GUILDMASTER);
newLeaderName = newLeader->GetName();
}
else
- {
- Player::SetUInt32ValueInDB(PLAYER_GUILDRANK, GR_GUILDMASTER, newLeaderGUID);
objmgr.GetPlayerNameByGUID(newLeaderGUID, newLeaderName);
- }
// when leader non-exist (at guild load with deleted leader only) not send broadcasts
if(objmgr.GetPlayerNameByGUID(guid, oldLeaderName))
@@ -500,16 +495,12 @@ void Guild::DelMember(uint64 guid, bool isDisbanding)
members.erase(GUID_LOPART(guid));
Player *player = objmgr.GetPlayer(guid);
+ // If player not online data in data field will be loaded from guild tabs no need to update it !!
if(player)
{
player->SetInGuild(0);
player->SetRank(0);
}
- else
- {
- Player::SetUInt32ValueInDB(PLAYER_GUILDID, 0, guid);
- Player::SetUInt32ValueInDB(PLAYER_GUILDRANK, GR_GUILDMASTER, guid);
- }
CharacterDatabase.PExecute("DELETE FROM guild_member WHERE guid = '%u'", GUID_LOPART(guid));
}
@@ -521,10 +512,9 @@ void Guild::ChangeRank(uint64 guid, uint32 newRank)
itr->second.RankId = newRank;
Player *player = objmgr.GetPlayer(guid);
+ // If player not online data in data field will be loaded from guild tabs no need to update it !!
if(player)
player->SetRank(newRank);
- else
- Player::SetUInt32ValueInDB(PLAYER_GUILDRANK, newRank, guid);
CharacterDatabase.PExecute( "UPDATE guild_member SET rank='%u' WHERE guid='%u'", newRank, GUID_LOPART(guid) );
}
diff --git a/src/game/GuildHandler.cpp b/src/game/GuildHandler.cpp
index 9462f7a1bb1..f29a07b89f7 100644
--- a/src/game/GuildHandler.cpp
+++ b/src/game/GuildHandler.cpp
@@ -977,14 +977,14 @@ void WorldSession::HandleGuildBankDeposit( WorldPacket & recv_data )
pGuild->SetBankMoney(pGuild->GetGuildBankMoney()+money);
GetPlayer()->ModifyMoney(-int(money));
- GetPlayer()->SaveGoldToDB();
+ GetPlayer()->SaveDataFieldToDB(); //contains money
CharacterDatabase.CommitTransaction();
// logging money
if(_player->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
{
- sLog.outCommand("GM %s (Account: %u) deposit money (Amount: %u) to guild bank (Guild ID %u)",
+ sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) deposit money (Amount: %u) to guild bank (Guild ID %u)",
_player->GetName(),_player->GetSession()->GetAccountId(),money,GuildId);
}
@@ -1033,7 +1033,7 @@ void WorldSession::HandleGuildBankWithdraw( WorldPacket & recv_data )
}
GetPlayer()->ModifyMoney(money);
- GetPlayer()->SaveGoldToDB();
+ GetPlayer()->SaveDataFieldToDB(); // contains money
CharacterDatabase.CommitTransaction();
@@ -1379,7 +1379,7 @@ void WorldSession::HandleGuildBankDepositItem( WorldPacket & recv_data )
// logging item move to bank
if(_player->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
{
- sLog.outCommand("GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
+ sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
_player->GetName(),_player->GetSession()->GetAccountId(),
pItemChar->GetProto()->Name1,pItemChar->GetEntry(),pItemChar->GetCount(),
GuildId);
@@ -1448,7 +1448,7 @@ void WorldSession::HandleGuildBankDepositItem( WorldPacket & recv_data )
// logging item move to bank (before items merge
if(_player->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
{
- sLog.outCommand("GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
+ sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
_player->GetName(),_player->GetSession()->GetAccountId(),
pItemChar->GetProto()->Name1,pItemChar->GetEntry(),SplitedAmount,GuildId);
}
@@ -1474,7 +1474,7 @@ void WorldSession::HandleGuildBankDepositItem( WorldPacket & recv_data )
// logging item move to bank
if(_player->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
{
- sLog.outCommand("GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
+ sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
_player->GetName(),_player->GetSession()->GetAccountId(),
pItemChar->GetProto()->Name1,pItemChar->GetEntry(),pItemChar->GetCount(),
GuildId);
@@ -1524,7 +1524,7 @@ void WorldSession::HandleGuildBankDepositItem( WorldPacket & recv_data )
// logging item move to bank
if(_player->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
{
- sLog.outCommand("GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
+ sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) deposit item: %s (Entry: %d Count: %u) to guild bank (Guild ID: %u )",
_player->GetName(),_player->GetSession()->GetAccountId(),
pItemChar->GetProto()->Name1,pItemChar->GetEntry(),pItemChar->GetCount(),
GuildId);
diff --git a/src/game/InstanceData.h b/src/game/InstanceData.h
index a1611a2bc1f..8fea525a6e2 100644
--- a/src/game/InstanceData.h
+++ b/src/game/InstanceData.h
@@ -64,5 +64,9 @@ class TRINITY_DLL_SPEC InstanceData
//called on creature creation
virtual void OnCreatureCreate(Creature * /*creature*/, uint32 /*creature_entry*/) {}
+
+ //All-purpose data storage 32 bit
+ virtual uint32 GetData(uint32) { return 0; }
+ virtual void SetData(uint32, uint32 data) {}
};
#endif
diff --git a/src/game/Language.h b/src/game/Language.h
index fb44f37dda5..441583c14db 100644
--- a/src/game/Language.h
+++ b/src/game/Language.h
@@ -10,12 +10,12 @@
*
* 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
+ * 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
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __TRINITY_LANGUAGE_H
@@ -80,11 +80,11 @@ enum TrinityStrings
LANG_COMMAND_INVALID_ITEM_COUNT = 52,
LANG_COMMAND_MAIL_ITEMS_LIMIT = 53,
LANG_NEW_PASSWORDS_NOT_MATCH = 54,
- LANG_PASSWORD_TOO_LONG = 55,
- LANG_MOTD_CURRENT = 56,
- LANG_USING_WORLD_DB = 57,
- LANG_USING_SCRIPT_LIB = 58,
- // Room for more level 0 59-99 not used
+ LANG_PASSWORD_TOO_LONG = 55,
+ LANG_MOTD_CURRENT = 56,
+ LANG_USING_WORLD_DB = 57,
+ LANG_USING_SCRIPT_LIB = 58,
+ // Room for more level 0 59-99 not used
// level 1 chat
LANG_GLOBAL_NOTIFY = 100,
@@ -170,7 +170,7 @@ enum TrinityStrings
LANG_SOUND_NOT_EXIST = 170,
LANG_TELEPORTED_TO_BY_CONSOLE = 171,
LANG_CONSOLE_COMMAND = 172,
- // Room for more level 1 173-199 not used
+ // Room for more level 1 173-199 not used
// level 2 chat
LANG_NO_SELECTION = 200,
@@ -326,7 +326,9 @@ enum TrinityStrings
LANG_CREATURE_FOLLOW_YOU_NOW = 340,
LANG_CREATURE_NOT_FOLLOW_YOU = 341,
LANG_CREATURE_NOT_FOLLOW_YOU_NOW = 342,
- // Room for more level 2 343-399 not used
+ LANG_CREATURE_NON_TAMEABLE = 343,
+ LANG_YOU_ALREADY_HAVE_PET = 344,
+ // Room for more level 2 345-399 not used
// level 3 chat
LANG_SCRIPTS_RELOADED = 400,
@@ -553,14 +555,14 @@ enum TrinityStrings
LANG_MOVEGENS_DISTRACT = 591,
LANG_COMMAND_LEARN_ALL_RECIPES = 592,
- LANG_BANLIST_ACCOUNTS = 593,
- LANG_BANLIST_ACCOUNTS_HEADER = 594,
- LANG_BANLIST_IPS = 595,
- LANG_BANLIST_IPS_HEADER = 596,
- LANG_GMLIST = 597,
- LANG_GMLIST_HEADER = 598,
- LANG_GMLIST_EMPTY = 599,
- // End Level 3 list, continued at 1100
+ LANG_BANLIST_ACCOUNTS = 593,
+ LANG_BANLIST_ACCOUNTS_HEADER = 594,
+ LANG_BANLIST_IPS = 595,
+ LANG_BANLIST_IPS_HEADER = 596,
+ LANG_GMLIST = 597,
+ LANG_GMLIST_HEADER = 598,
+ LANG_GMLIST_EMPTY = 599,
+ // End Level 3 list, continued at 1100
// Battleground
LANG_BG_A_WINS = 600,
@@ -644,29 +646,67 @@ enum TrinityStrings
LANG_HIS_ARENA_LEVEL_REQ_ERROR = 714,
LANG_YOUR_BG_LEVEL_REQ_ERROR = 715,
LANG_YOUR_ARENA_TEAM_FULL = 716,
- // Room for BG/ARENA 717-799 not used
-
- LANG_ARENA_YOUR_TEAM_ONLY = 730,
- LANG_ARENA_NOT_ENOUGH_PLAYERS = 731,
- LANG_ARENA_GOLD_WINS = 732,
- LANG_ARENA_GREEN_WINS = 733,
- LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING = 734,
- LANG_BG_GROUP_OFFLINE_MEMBER = 735,
- LANG_BG_GROUP_MIXED_FACTION = 736,
- LANG_BG_GROUP_MIXED_LEVELS = 737,
- LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE = 738,
- LANG_BG_GROUP_MEMBER_DESERTER = 739,
- LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS = 740,
-
- LANG_CANNOT_TELE_TO_BG = 741,
- LANG_CANNOT_SUMMON_TO_BG = 742,
- LANG_CANNOT_GO_TO_BG_GM = 743,
- LANG_CANNOT_GO_TO_BG_FROM_BG = 744,
-
- LANG_ARENA_TESTING = 745,
-
- LANG_AUTO_ANN = 746,
- LANG_ANNOUNCE_COLOR = 747,
+
+ LANG_BG_AV_ALLY = 717,
+ LANG_BG_AV_HORDE = 718,
+ LANG_BG_AV_TOWER_TAKEN = 719,
+ LANG_BG_AV_TOWER_ASSAULTED = 720,
+ LANG_BG_AV_TOWER_DEFENDED = 721,
+ LANG_BG_AV_GRAVE_TAKEN = 722,
+ LANG_BG_AV_GRAVE_DEFENDED = 723,
+ LANG_BG_AV_GRAVE_ASSAULTED = 724,
+
+ LANG_BG_AV_MINE_TAKEN = 725,
+ LANG_BG_AV_MINE_NORTH = 726,
+ LANG_BG_AV_MINE_SOUTH = 727,
+
+ LANG_BG_AV_NODE_GRAVE_STORM_AID = 728,
+ LANG_BG_AV_NODE_TOWER_DUN_S = 729,
+ LANG_BG_AV_NODE_TOWER_DUN_N = 730,
+ LANG_BG_AV_NODE_GRAVE_STORMPIKE = 731,
+ LANG_BG_AV_NODE_TOWER_ICEWING = 732,
+ LANG_BG_AV_NODE_GRAVE_STONE = 733,
+ LANG_BG_AV_NODE_TOWER_STONE = 734,
+ LANG_BG_AV_NODE_GRAVE_SNOW = 735,
+ LANG_BG_AV_NODE_TOWER_ICE = 736,
+ LANG_BG_AV_NODE_GRAVE_ICE = 737,
+ LANG_BG_AV_NODE_TOWER_POINT = 738,
+ LANG_BG_AV_NODE_GRAVE_FROST = 739,
+ LANG_BG_AV_NODE_TOWER_FROST_E = 740,
+ LANG_BG_AV_NODE_TOWER_FROST_W = 741,
+ LANG_BG_AV_NODE_GRAVE_FROST_HUT = 742,
+
+ LANG_BG_AV_ONEMINTOSTART = 743,
+ LANG_BG_AV_HALFMINTOSTART = 744,
+ LANG_BG_AV_STARTED = 745,
+ LANG_BG_AV_A_NEAR_LOSE = 746,
+ LANG_BG_AV_H_NEAR_LOSE = 747,
+ LANG_BG_AV_H_CAPTAIN_DEAD = 748,
+ LANG_BG_AV_A_CAPTAIN_DEAD = 749,
+
+ // Room for BG/ARENA 750-769 not used
+
+ LANG_ARENA_YOUR_TEAM_ONLY = 770,
+ LANG_ARENA_NOT_ENOUGH_PLAYERS = 771,
+ LANG_ARENA_GOLD_WINS = 772,
+ LANG_ARENA_GREEN_WINS = 773,
+ LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING = 774,
+ LANG_BG_GROUP_OFFLINE_MEMBER = 775,
+ LANG_BG_GROUP_MIXED_FACTION = 776,
+ LANG_BG_GROUP_MIXED_LEVELS = 777,
+ LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE = 778,
+ LANG_BG_GROUP_MEMBER_DESERTER = 779,
+ LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS = 780,
+
+ LANG_CANNOT_TELE_TO_BG = 781,
+ LANG_CANNOT_SUMMON_TO_BG = 782,
+ LANG_CANNOT_GO_TO_BG_GM = 783,
+ LANG_CANNOT_GO_TO_BG_FROM_BG = 784,
+
+ LANG_ARENA_TESTING = 785,
+
+ LANG_AUTO_ANN = 786,
+ LANG_ANNOUNCE_COLOR = 787,
// in game strings
LANG_PET_INVALID_NAME = 800,
@@ -682,43 +722,46 @@ enum TrinityStrings
// Room for in-game strings 810-999 not used
// Level 4 (CLI only commands)
- LANG_COMMAND_EXIT = 1000,
- LANG_ACCOUNT_DELETED = 1001,
- LANG_ACCOUNT_NOT_DELETED_SQL_ERROR = 1002,
- LANG_ACCOUNT_NOT_DELETED = 1003,
- LANG_ACCOUNT_CREATED = 1004,
- LANG_ACCOUNT_TOO_LONG = 1005,
- LANG_ACCOUNT_ALREADY_EXIST = 1006,
- LANG_ACCOUNT_NOT_CREATED_SQL_ERROR = 1007,
- LANG_ACCOUNT_NOT_CREATED = 1008,
- LANG_CHARACTER_DELETED = 1009,
- LANG_ACCOUNT_LIST_HEADER = 1010,
- LANG_ACCOUNT_LIST_ERROR = 1011,
- // Room for more level 4 1012-1099 not used
-
- // Level 3 (continue)
+ LANG_COMMAND_EXIT = 1000,
+ LANG_ACCOUNT_DELETED = 1001,
+ LANG_ACCOUNT_NOT_DELETED_SQL_ERROR = 1002,
+ LANG_ACCOUNT_NOT_DELETED = 1003,
+ LANG_ACCOUNT_CREATED = 1004,
+ LANG_ACCOUNT_TOO_LONG = 1005,
+ LANG_ACCOUNT_ALREADY_EXIST = 1006,
+ LANG_ACCOUNT_NOT_CREATED_SQL_ERROR = 1007,
+ LANG_ACCOUNT_NOT_CREATED = 1008,
+ LANG_CHARACTER_DELETED = 1009,
+ LANG_ACCOUNT_LIST_HEADER = 1010,
+ LANG_ACCOUNT_LIST_ERROR = 1011,
+ // Room for more level 4 1012-1099 not used
+
+ // Level 3 (continue)
LANG_ACCOUNT_SETADDON = 1100,
LANG_MOTD_NEW = 1101,
LANG_SENDMESSAGE = 1102,
LANG_EVENT_ENTRY_LIST_CONSOLE = 1103,
- LANG_CREATURE_ENTRY_LIST_CONSOLE = 1104,
- LANG_ITEM_LIST_CONSOLE = 1105,
- LANG_ITEMSET_LIST_CONSOLE = 1106,
- LANG_GO_ENTRY_LIST_CONSOLE = 1107,
- LANG_QUEST_LIST_CONSOLE = 1108,
- LANG_SKILL_LIST_CONSOLE = 1109,
- LANG_CREATURE_LIST_CONSOLE = 1110,
- LANG_GO_LIST_CONSOLE = 1111,
- LANG_FILE_OPEN_FAIL = 1112,
- LANG_ACCOUNT_CHARACTER_LIST_FULL = 1113,
- LANG_DUMP_BROKEN = 1114,
- LANG_INVALID_CHARACTER_NAME = 1115,
- LANG_INVALID_CHARACTER_GUID = 1116,
- LANG_CHARACTER_GUID_IN_USE = 1117,
- LANG_ITEMLIST_GUILD = 1118,
- // Room for more level 3 1119-1199 not used
-
- // Trinity strings 5000-9999
+ LANG_CREATURE_ENTRY_LIST_CONSOLE = 1104,
+ LANG_ITEM_LIST_CONSOLE = 1105,
+ LANG_ITEMSET_LIST_CONSOLE = 1106,
+ LANG_GO_ENTRY_LIST_CONSOLE = 1107,
+ LANG_QUEST_LIST_CONSOLE = 1108,
+ LANG_SKILL_LIST_CONSOLE = 1109,
+ LANG_CREATURE_LIST_CONSOLE = 1110,
+ LANG_GO_LIST_CONSOLE = 1111,
+ LANG_FILE_OPEN_FAIL = 1112,
+ LANG_ACCOUNT_CHARACTER_LIST_FULL = 1113,
+ LANG_DUMP_BROKEN = 1114,
+ LANG_INVALID_CHARACTER_NAME = 1115,
+ LANG_INVALID_CHARACTER_GUID = 1116,
+ LANG_CHARACTER_GUID_IN_USE = 1117,
+ LANG_ITEMLIST_GUILD = 1118,
+ LANG_MUST_MALE_OR_FEMALE = 1119,
+ LANG_YOU_CHANGE_GENDER = 1120,
+ LANG_YOUR_GENDER_CHANGED = 1121,
+ // Room for more level 3 1122-1199 not used
+
+ // Trinity strings 5000-9999
LANG_COMMAND_FREEZE = 5000,
LANG_COMMAND_FREEZE_ERROR = 5001,
LANG_COMMAND_FREEZE_WRONG = 5002,
@@ -729,9 +772,10 @@ enum TrinityStrings
LANG_INSTANCE_MUST_RAID_GRP = 5007,
LANG_INSTANCE_NOT_AS_GHOST = 5008,
LANG_COMMAND_PLAYED_TO_ALL = 5009,
- // Room for more Trinity strings 5009-9999
+ // Room for more Trinity strings 5009-9999
- // Use for not-in-svn patches 10000-10999
+ // Use for not-in-offcial-sources patches
+ // 10000-10999
// opvp hp
LANG_OPVP_HP_CAPTURE_OVERLOOK_H = 10001,
LANG_OPVP_HP_CAPTURE_OVERLOOK_A = 10002,
@@ -797,6 +841,8 @@ enum TrinityStrings
// Use for custom patches 11000-11999
- // NOT RESERVED IDS 12000-
+ // NOT RESERVED IDS 12000-1999999999
+ // `db_script_string` table index 2000000000-2000009999 (MIN_DB_SCRIPT_STRING_ID-MAX_DB_SCRIPT_STRING_ID)
+ // For other tables maybe 2000010000-2147483647 (max index)
};
#endif
diff --git a/src/game/Level2.cpp b/src/game/Level2.cpp
index cd69e327042..bb6a4473e0b 100644
--- a/src/game/Level2.cpp
+++ b/src/game/Level2.cpp
@@ -1,4242 +1,4242 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
- *
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
- *
- * 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
- */
-
-#include "Common.h"
-#include "Database/DatabaseEnv.h"
-#include "WorldPacket.h"
-#include "WorldSession.h"
-#include "World.h"
-#include "ObjectMgr.h"
-#include "Player.h"
-#include "Item.h"
-#include "GameObject.h"
-#include "Opcodes.h"
-#include "Chat.h"
-#include "ObjectAccessor.h"
-#include "MapManager.h"
-#include "Language.h"
-#include "World.h"
-#include "GameEvent.h"
-#include "SpellMgr.h"
-#include "AccountMgr.h"
-#include "GMTicketMgr.h"
-#include "WaypointManager.h"
-#include "Util.h"
-#include <cctype>
-#include <iostream>
-#include <fstream>
-#include <map>
-#include "GlobalEvents.h"
-
-#include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand
-
-static uint32 ReputationRankStrIndex[MAX_REPUTATION_RANK] =
-{
- LANG_REP_HATED, LANG_REP_HOSTILE, LANG_REP_UNFRIENDLY, LANG_REP_NEUTRAL,
- LANG_REP_FRIENDLY, LANG_REP_HONORED, LANG_REP_REVERED, LANG_REP_EXALTED
-};
-
-//mute player for some times
-bool ChatHandler::HandleMuteCommand(const char* args)
-{
- if (!*args)
- return false;
-
- char *charname = strtok((char*)args, " ");
- if (!charname)
- return false;
-
- std::string cname = charname;
-
- char *timetonotspeak = strtok(NULL, " ");
- if(!timetonotspeak)
- return false;
-
- uint32 notspeaktime = (uint32) atoi(timetonotspeak);
-
- if(!normalizePlayerName(cname))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint64 guid = objmgr.GetPlayerGUIDByName(cname.c_str());
- if(!guid)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- Player *chr = objmgr.GetPlayer(guid);
-
- // check security
- uint32 account_id = 0;
- uint32 security = 0;
-
- if (chr)
- {
- account_id = chr->GetSession()->GetAccountId();
- security = chr->GetSession()->GetSecurity();
- }
- else
- {
- account_id = objmgr.GetPlayerAccountIdByGUID(guid);
- security = accmgr.GetSecurity(account_id);
- }
-
- if(m_session && security >= m_session->GetSecurity())
- {
- SendSysMessage(LANG_YOURS_SECURITY_IS_LOW);
- SetSentErrorMessage(true);
- return false;
- }
-
- time_t mutetime = time(NULL) + notspeaktime*60;
-
- if (chr)
- chr->GetSession()->m_muteTime = mutetime;
-
- loginDatabase.PExecute("UPDATE account SET mutetime = " I64FMTD " WHERE id = '%u'",uint64(mutetime), account_id );
-
- if(chr)
- ChatHandler(chr).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notspeaktime);
-
- PSendSysMessage(LANG_YOU_DISABLE_CHAT, cname.c_str(), notspeaktime);
-
- return true;
-}
-
-//unmute player
-bool ChatHandler::HandleUnmuteCommand(const char* args)
-{
- if (!*args)
- return false;
-
- char *charname = strtok((char*)args, " ");
- if (!charname)
- return false;
-
- std::string cname = charname;
-
- if(!normalizePlayerName(cname))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint64 guid = objmgr.GetPlayerGUIDByName(cname.c_str());
- if(!guid)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- Player *chr = objmgr.GetPlayer(guid);
-
- // check security
- uint32 account_id = 0;
- uint32 security = 0;
-
- if (chr)
- {
- account_id = chr->GetSession()->GetAccountId();
- security = chr->GetSession()->GetSecurity();
- }
- else
- {
- account_id = objmgr.GetPlayerAccountIdByGUID(guid);
- security = accmgr.GetSecurity(account_id);
- }
-
- if(m_session && security >= m_session->GetSecurity())
- {
- SendSysMessage(LANG_YOURS_SECURITY_IS_LOW);
- SetSentErrorMessage(true);
- return false;
- }
-
- if (chr)
- {
- if(chr->CanSpeak())
- {
- SendSysMessage(LANG_CHAT_ALREADY_ENABLED);
- SetSentErrorMessage(true);
- return false;
- }
-
- chr->GetSession()->m_muteTime = 0;
- }
-
- loginDatabase.PExecute("UPDATE account SET mutetime = '0' WHERE id = '%u'", account_id );
-
- if(chr)
- ChatHandler(chr).PSendSysMessage(LANG_YOUR_CHAT_ENABLED);
-
- PSendSysMessage(LANG_YOU_ENABLE_CHAT, cname.c_str());
- return true;
-}
-
-bool ChatHandler::HandleTargetObjectCommand(const char* args)
-{
- Player* pl = m_session->GetPlayer();
- QueryResult *result;
- GameEvent::ActiveEvents const& activeEventsList = gameeventmgr.GetActiveEventList();
- if(*args)
- {
- int32 id = atoi((char*)args);
- if(id)
- result = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, orientation, map, (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ FROM gameobject WHERE map = '%i' AND id = '%u' ORDER BY order_ ASC LIMIT 1",
- pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(),id);
- else
- {
- std::string name = args;
- WorldDatabase.escape_string(name);
- result = WorldDatabase.PQuery(
- "SELECT guid, id, position_x, position_y, position_z, orientation, map, (POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ "
- "FROM gameobject,gameobject_template WHERE gameobject_template.entry = gameobject.id AND map = %i AND name "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'")" ORDER BY order_ ASC LIMIT 1",
- pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(),name.c_str());
- }
- }
- else
- {
- std::ostringstream eventFilter;
- eventFilter << " AND (event IS NULL ";
- bool initString = true;
-
- for (GameEvent::ActiveEvents::const_iterator itr = activeEventsList.begin(); itr != activeEventsList.end(); ++itr)
- {
- if (initString)
- {
- eventFilter << "OR event IN (" <<*itr;
- initString =false;
- }
- else
- eventFilter << "," << *itr;
- }
-
- if (!initString)
- eventFilter << "))";
- else
- eventFilter << ")";
-
- result = WorldDatabase.PQuery("SELECT gameobject.guid, id, position_x, position_y, position_z, orientation, map, "
- "(POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ FROM gameobject "
- "LEFT OUTER JOIN game_event_gameobject on gameobject.guid=game_event_gameobject.guid WHERE map = '%i' %s ORDER BY order_ ASC LIMIT 1",
- m_session->GetPlayer()->GetPositionX(), m_session->GetPlayer()->GetPositionY(), m_session->GetPlayer()->GetPositionZ(), m_session->GetPlayer()->GetMapId(),eventFilter.str().c_str());
- }
-
- if (!result)
- {
- SendSysMessage(LANG_COMMAND_TARGETOBJNOTFOUND);
- return true;
- }
-
- Field *fields = result->Fetch();
- uint32 lowguid = fields[0].GetUInt32();
- uint32 id = fields[1].GetUInt32();
- float x = fields[2].GetFloat();
- float y = fields[3].GetFloat();
- float z = fields[4].GetFloat();
- float o = fields[5].GetFloat();
- int mapid = fields[6].GetUInt16();
- delete result;
-
- GameObjectInfo const* goI = objmgr.GetGameObjectInfo(id);
-
- if (!goI)
- {
- PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id);
- return false;
- }
-
- GameObject* target = ObjectAccessor::GetGameObject(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,id,HIGHGUID_GAMEOBJECT));
-
- PSendSysMessage(LANG_GAMEOBJECT_DETAIL, lowguid, goI->name, lowguid, id, x, y, z, mapid, o);
-
- if(target)
- {
- int32 curRespawnDelay = target->GetRespawnTimeEx()-time(NULL);
- if(curRespawnDelay < 0)
- curRespawnDelay = 0;
-
- std::string curRespawnDelayStr = secsToTimeString(curRespawnDelay,true);
- std::string defRespawnDelayStr = secsToTimeString(target->GetRespawnDelay(),true);
-
- PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(),curRespawnDelayStr.c_str());
- }
- return true;
-}
-
-//teleport to gameobject
-bool ChatHandler::HandleGoObjectCommand(const char* args)
-{
- if(!*args)
- return false;
-
- Player* _player = m_session->GetPlayer();
-
- // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r
- char* cId = extractKeyFromLink((char*)args,"Hgameobject");
- if(!cId)
- return false;
-
- int32 guid = atoi(cId);
- if(!guid)
- return false;
-
- float x, y, z, ort;
- int mapid;
-
- // by DB guid
- if (GameObjectData const* go_data = objmgr.GetGOData(guid))
- {
- x = go_data->posX;
- y = go_data->posY;
- z = go_data->posZ;
- ort = go_data->orientation;
- mapid = go_data->mapid;
- }
- else
- {
- SendSysMessage(LANG_COMMAND_GOOBJNOTFOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- if(!MapManager::IsValidMapCoord(mapid,x,y,z,ort))
- {
- PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid);
- SetSentErrorMessage(true);
- return false;
- }
-
- // stop flight if need
- if(_player->isInFlight())
- {
- _player->GetMotionMaster()->MovementExpired();
- _player->m_taxi.ClearTaxiDestinations();
- }
- // save only in non-flight case
- else
- _player->SaveRecallPosition();
-
- _player->TeleportTo(mapid, x, y, z, ort);
- return true;
-}
-
-bool ChatHandler::HandleGoTriggerCommand(const char* args)
-{
- Player* _player = m_session->GetPlayer();
-
- if (!*args)
- return false;
-
- char *atId = strtok((char*)args, " ");
- if (!atId)
- return false;
-
- int32 i_atId = atoi(atId);
-
- if(!i_atId)
- return false;
-
- AreaTriggerEntry const* at = sAreaTriggerStore.LookupEntry(i_atId);
- if (!at)
- {
- PSendSysMessage(LANG_COMMAND_GOAREATRNOTFOUND,i_atId);
- SetSentErrorMessage(true);
- return false;
- }
-
- if(!MapManager::IsValidMapCoord(at->mapid,at->x,at->y,at->z))
- {
- PSendSysMessage(LANG_INVALID_TARGET_COORD,at->x,at->y,at->mapid);
- SetSentErrorMessage(true);
- return false;
- }
-
- // stop flight if need
- if(_player->isInFlight())
- {
- _player->GetMotionMaster()->MovementExpired();
- _player->m_taxi.ClearTaxiDestinations();
- }
- // save only in non-flight case
- else
- _player->SaveRecallPosition();
-
- _player->TeleportTo(at->mapid, at->x, at->y, at->z, _player->GetOrientation());
- return true;
-}
-
-bool ChatHandler::HandleGoGraveyardCommand(const char* args)
-{
- Player* _player = m_session->GetPlayer();
-
- if (!*args)
- return false;
-
- char *gyId = strtok((char*)args, " ");
- if (!gyId)
- return false;
-
- int32 i_gyId = atoi(gyId);
-
- if(!i_gyId)
- return false;
-
- WorldSafeLocsEntry const* gy = sWorldSafeLocsStore.LookupEntry(i_gyId);
- if (!gy)
- {
- PSendSysMessage(LANG_COMMAND_GRAVEYARDNOEXIST,i_gyId);
- SetSentErrorMessage(true);
- return false;
- }
-
- if(!MapManager::IsValidMapCoord(gy->map_id,gy->x,gy->y,gy->z))
- {
- PSendSysMessage(LANG_INVALID_TARGET_COORD,gy->x,gy->y,gy->map_id);
- SetSentErrorMessage(true);
- return false;
- }
-
- // stop flight if need
- if(_player->isInFlight())
- {
- _player->GetMotionMaster()->MovementExpired();
- _player->m_taxi.ClearTaxiDestinations();
- }
- // save only in non-flight case
- else
- _player->SaveRecallPosition();
-
- _player->TeleportTo(gy->map_id, gy->x, gy->y, gy->z, _player->GetOrientation());
- return true;
-}
-
-/** \brief Teleport the GM to the specified creature
- *
- * .gocreature <GUID> --> TP using creature.guid
- * .gocreature azuregos --> TP player to the mob with this name
- * Warning: If there is more than one mob with this name
- * you will be teleported to the first one that is found.
- * .gocreature id 6109 --> TP player to the mob, that has this creature_template.entry
- * Warning: If there is more than one mob with this "id"
- * you will be teleported to the first one that is found.
- */
-//teleport to creature
-bool ChatHandler::HandleGoCreatureCommand(const char* args)
-{
- if(!*args)
- return false;
- Player* _player = m_session->GetPlayer();
-
- // "id" or number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r
- char* pParam1 = extractKeyFromLink((char*)args,"Hcreature");
- if (!pParam1)
- return false;
-
- std::ostringstream whereClause;
-
- // User wants to teleport to the NPC's template entry
- if( strcmp(pParam1, "id") == 0 )
- {
- //sLog.outError("DEBUG: ID found");
-
- // Get the "creature_template.entry"
- // number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r
- char* tail = strtok(NULL,"");
- if(!tail)
- return false;
- char* cId = extractKeyFromLink(tail,"Hcreature_entry");
- if(!cId)
- return false;
-
- int32 tEntry = atoi(cId);
- //sLog.outError("DEBUG: ID value: %d", tEntry);
- if(!tEntry)
- return false;
-
- whereClause << "WHERE id = '" << tEntry << "'";
- }
- else
- {
- //sLog.outError("DEBUG: ID *not found*");
-
- int32 guid = atoi(pParam1);
-
- // Number is invalid - maybe the user specified the mob's name
- if(!guid)
- {
- std::string name = pParam1;
- WorldDatabase.escape_string(name);
- whereClause << ", creature_template WHERE creature.id = creature_template.entry AND creature_template.name "_LIKE_" '" << name << "'";
- }
- else
- {
- whereClause << "WHERE guid = '" << guid << "'";
- }
- }
- //sLog.outError("DEBUG: %s", whereClause.c_str());
-
- QueryResult *result = WorldDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map FROM creature %s", whereClause.str().c_str() );
- if (!result)
- {
- SendSysMessage(LANG_COMMAND_GOCREATNOTFOUND);
- SetSentErrorMessage(true);
- return false;
- }
- if( result->GetRowCount() > 1 )
- {
- SendSysMessage(LANG_COMMAND_GOCREATMULTIPLE);
- }
-
- Field *fields = result->Fetch();
- float x = fields[0].GetFloat();
- float y = fields[1].GetFloat();
- float z = fields[2].GetFloat();
- float ort = fields[3].GetFloat();
- int mapid = fields[4].GetUInt16();
-
- delete result;
-
- if(!MapManager::IsValidMapCoord(mapid,x,y,z,ort))
- {
- PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid);
- SetSentErrorMessage(true);
- return false;
- }
-
- // stop flight if need
- if(_player->isInFlight())
- {
- _player->GetMotionMaster()->MovementExpired();
- _player->m_taxi.ClearTaxiDestinations();
- }
- // save only in non-flight case
- else
- _player->SaveRecallPosition();
-
- _player->TeleportTo(mapid, x, y, z, ort);
- return true;
-}
-
-bool ChatHandler::HandleGUIDCommand(const char* /*args*/)
-{
- uint64 guid = m_session->GetPlayer()->GetSelection();
-
- if (guid == 0)
- {
- SendSysMessage(LANG_NO_SELECTION);
- SetSentErrorMessage(true);
- return false;
- }
-
- PSendSysMessage(LANG_OBJECT_GUID, GUID_LOPART(guid), GUID_HIPART(guid));
- return true;
-}
-
-bool ChatHandler::HandleLookupFactionCommand(const char* args)
-{
- if (!*args)
- return false;
-
- // Can be NULL at console call
- Player *target = getSelectedPlayer ();
-
- std::string namepart = args;
- std::wstring wnamepart;
-
- if (!Utf8toWStr (namepart,wnamepart))
- return false;
-
- // converting string that we try to find to lower case
- wstrToLower (wnamepart);
-
- uint32 counter = 0; // Counter for figure out that we found smth.
-
- for (uint32 id = 0; id < sFactionStore.GetNumRows(); ++id)
- {
- FactionEntry const *factionEntry = sFactionStore.LookupEntry (id);
- if (factionEntry)
- {
- FactionState const* repState = NULL;
- if(target)
- {
- FactionStateList::const_iterator repItr = target->m_factions.find (factionEntry->reputationListID);
- if(repItr != target->m_factions.end())
- repState = &repItr->second;
- }
-
- int loc = m_session ? m_session->GetSessionDbcLocale() : sWorld.GetDefaultDbcLocale();
- std::string name = factionEntry->name[loc];
- if(name.empty())
- continue;
-
- if (!Utf8FitTo(name, wnamepart))
- {
- loc = 0;
- for(; loc < MAX_LOCALE; ++loc)
- {
- if(m_session && loc==m_session->GetSessionDbcLocale())
- continue;
-
- name = factionEntry->name[loc];
- if(name.empty())
- continue;
-
- if (Utf8FitTo(name, wnamepart))
- break;
- }
- }
-
- if(loc < MAX_LOCALE)
- {
- // send faction in "id - [faction] rank reputation [visible] [at war] [own team] [unknown] [invisible] [inactive]" format
- // or "id - [faction] [no reputation]" format
- std::ostringstream ss;
- if (m_session)
- ss << id << " - |cffffffff|Hfaction:" << id << "|h[" << name << " " << localeNames[loc] << "]|h|r";
- else
- ss << id << " - " << name << " " << localeNames[loc];
-
- if (repState) // and then target!=NULL also
- {
- ReputationRank rank = target->GetReputationRank(factionEntry);
- std::string rankName = GetTrinityString(ReputationRankStrIndex[rank]);
-
- ss << " " << rankName << "|h|r (" << target->GetReputation(factionEntry) << ")";
-
- if(repState->Flags & FACTION_FLAG_VISIBLE)
- ss << GetTrinityString(LANG_FACTION_VISIBLE);
- if(repState->Flags & FACTION_FLAG_AT_WAR)
- ss << GetTrinityString(LANG_FACTION_ATWAR);
- if(repState->Flags & FACTION_FLAG_PEACE_FORCED)
- ss << GetTrinityString(LANG_FACTION_PEACE_FORCED);
- if(repState->Flags & FACTION_FLAG_HIDDEN)
- ss << GetTrinityString(LANG_FACTION_HIDDEN);
- if(repState->Flags & FACTION_FLAG_INVISIBLE_FORCED)
- ss << GetTrinityString(LANG_FACTION_INVISIBLE_FORCED);
- if(repState->Flags & FACTION_FLAG_INACTIVE)
- ss << GetTrinityString(LANG_FACTION_INACTIVE);
- }
- else
- ss << GetTrinityString(LANG_FACTION_NOREPUTATION);
-
- SendSysMessage(ss.str().c_str());
- counter++;
- }
- }
- }
-
- if (counter == 0) // if counter == 0 then we found nth
- SendSysMessage(LANG_COMMAND_FACTION_NOTFOUND);
- return true;
-}
-
-bool ChatHandler::HandleModifyRepCommand(const char * args)
-{
- if (!*args) return false;
-
- Player* target = NULL;
- target = getSelectedPlayer();
-
- if(!target)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- char* factionTxt = extractKeyFromLink((char*)args,"Hfaction");
- if(!factionTxt)
- return false;
-
- uint32 factionId = atoi(factionTxt);
-
- int32 amount = 0;
- char *rankTxt = strtok(NULL, " ");
- if (!factionTxt || !rankTxt)
- return false;
-
- amount = atoi(rankTxt);
- if ((amount == 0) && (rankTxt[0] != '-') && !isdigit(rankTxt[0]))
- {
- std::string rankStr = rankTxt;
- std::wstring wrankStr;
- if(!Utf8toWStr(rankStr,wrankStr))
- return false;
- wstrToLower( wrankStr );
-
- int r = 0;
- amount = -42000;
- for (; r < MAX_REPUTATION_RANK; ++r)
- {
- std::string rank = GetTrinityString(ReputationRankStrIndex[r]);
- if(rank.empty())
- continue;
-
- std::wstring wrank;
- if(!Utf8toWStr(rank,wrank))
- continue;
-
- wstrToLower(wrank);
-
- if(wrank.substr(0,wrankStr.size())==wrankStr)
- {
- char *deltaTxt = strtok(NULL, " ");
- if (deltaTxt)
- {
- int32 delta = atoi(deltaTxt);
- if ((delta < 0) || (delta > Player::ReputationRank_Length[r] -1))
- {
- PSendSysMessage(LANG_COMMAND_FACTION_DELTA, (Player::ReputationRank_Length[r]-1));
- SetSentErrorMessage(true);
- return false;
- }
- amount += delta;
- }
- break;
- }
- amount += Player::ReputationRank_Length[r];
- }
- if (r >= MAX_REPUTATION_RANK)
- {
- PSendSysMessage(LANG_COMMAND_FACTION_INVPARAM, rankTxt);
- SetSentErrorMessage(true);
- return false;
- }
- }
-
- FactionEntry const *factionEntry = sFactionStore.LookupEntry(factionId);
-
- if (!factionEntry)
- {
- PSendSysMessage(LANG_COMMAND_FACTION_UNKNOWN, factionId);
- SetSentErrorMessage(true);
- return false;
- }
-
- if (factionEntry->reputationListID < 0)
- {
- PSendSysMessage(LANG_COMMAND_FACTION_NOREP_ERROR, factionEntry->name[m_session->GetSessionDbcLocale()], factionId);
- SetSentErrorMessage(true);
- return false;
- }
-
- target->SetFactionReputation(factionEntry,amount);
- PSendSysMessage(LANG_COMMAND_MODIFY_REP, factionEntry->name[m_session->GetSessionDbcLocale()], factionId, target->GetName(), target->GetReputation(factionId));
- return true;
-}
-
-bool ChatHandler::HandleNameCommand(const char* args)
-{
- /* Temp. disabled
- if(!*args)
- return false;
-
- if(strlen((char*)args)>75)
- {
- PSendSysMessage(LANG_TOO_LONG_NAME, strlen((char*)args)-75);
- return true;
- }
-
- for (uint8 i = 0; i < strlen(args); i++)
- {
- if(!isalpha(args[i]) && args[i]!=' ')
- {
- SendSysMessage(LANG_CHARS_ONLY);
- return false;
- }
- }
-
- uint64 guid;
- guid = m_session->GetPlayer()->GetSelection();
- if (guid == 0)
- {
- SendSysMessage(LANG_NO_SELECTION);
- return true;
- }
-
- Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid);
-
- if(!pCreature)
- {
- SendSysMessage(LANG_SELECT_CREATURE);
- return true;
- }
-
- pCreature->SetName(args);
- uint32 idname = objmgr.AddCreatureTemplate(pCreature->GetName());
- pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname);
-
- pCreature->SaveToDB();
- */
-
- return true;
-}
-
-bool ChatHandler::HandleSubNameCommand(const char* /*args*/)
-{
- /* Temp. disabled
-
- if(!*args)
- args = "";
-
- if(strlen((char*)args)>75)
- {
-
- PSendSysMessage(LANG_TOO_LONG_SUBNAME, strlen((char*)args)-75);
- return true;
- }
-
- for (uint8 i = 0; i < strlen(args); i++)
- {
- if(!isalpha(args[i]) && args[i]!=' ')
- {
- SendSysMessage(LANG_CHARS_ONLY);
- return false;
- }
- }
- uint64 guid;
- guid = m_session->GetPlayer()->GetSelection();
- if (guid == 0)
- {
- SendSysMessage(LANG_NO_SELECTION);
- return true;
- }
-
- Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid);
-
- if(!pCreature)
- {
- SendSysMessage(LANG_SELECT_CREATURE);
- return true;
- }
-
- uint32 idname = objmgr.AddCreatureSubName(pCreature->GetName(),args,pCreature->GetUInt32Value(UNIT_FIELD_DISPLAYID));
- pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname);
-
- pCreature->SaveToDB();
- */
- return true;
-}
-
-//move item to other slot
-bool ChatHandler::HandleItemMoveCommand(const char* args)
-{
- if(!*args)
- return false;
- uint8 srcslot, dstslot;
-
- char* pParam1 = strtok((char*)args, " ");
- if (!pParam1)
- return false;
-
- char* pParam2 = strtok(NULL, " ");
- if (!pParam2)
- return false;
-
- srcslot = (uint8)atoi(pParam1);
- dstslot = (uint8)atoi(pParam2);
-
- if(srcslot==dstslot)
- return true;
-
- if(!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0,srcslot))
- return false;
-
- if(!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0,dstslot))
- return false;
-
- uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | srcslot);
- uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | dstslot);
-
- m_session->GetPlayer()->SwapItem( src, dst );
-
- return true;
-}
-
-//add spawn of creature
-bool ChatHandler::HandleNpcAddCommand(const char* args)
-{
- if(!*args)
- return false;
- char* charID = strtok((char*)args, " ");
- if (!charID)
- return false;
-
- char* team = strtok(NULL, " ");
- int32 teamval = 0;
- if (team) { teamval = atoi(team); }
- if (teamval < 0) { teamval = 0; }
-
- uint32 id = atoi(charID);
-
- Player *chr = m_session->GetPlayer();
- float x = chr->GetPositionX();
- float y = chr->GetPositionY();
- float z = chr->GetPositionZ();
- float o = chr->GetOrientation();
- Map *map = chr->GetMap();
-
- Creature* pCreature = new Creature;
- if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, id, (uint32)teamval))
- {
- delete pCreature;
- return false;
- }
-
- pCreature->Relocate(x,y,z,o);
-
- if(!pCreature->IsPositionValid())
- {
- sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
- delete pCreature;
- return false;
- }
-
- pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
-
- uint32 db_guid = pCreature->GetDBTableGUIDLow();
-
- // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
- pCreature->LoadFromDB(db_guid, map);
-
- map->Add(pCreature);
- objmgr.AddCreatureToGrid(db_guid, objmgr.GetCreatureData(db_guid));
- return true;
-}
-
-bool ChatHandler::HandleNpcDeleteCommand(const char* args)
-{
- Creature* unit = NULL;
-
- if(*args)
- {
- // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r
- char* cId = extractKeyFromLink((char*)args,"Hcreature");
- if(!cId)
- return false;
-
- uint32 lowguid = atoi(cId);
- if(!lowguid)
- return false;
-
- if (CreatureData const* cr_data = objmgr.GetCreatureData(lowguid))
- unit = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, cr_data->id, HIGHGUID_UNIT));
- }
- else
- unit = getSelectedCreature();
-
- if(!unit || unit->isPet() || unit->isTotem())
- {
- SendSysMessage(LANG_SELECT_CREATURE);
- SetSentErrorMessage(true);
- return false;
- }
-
- // Delete the creature
- unit->CombatStop();
- unit->DeleteFromDB();
- unit->CleanupsBeforeDelete();
- unit->AddObjectToRemoveList();
-
- SendSysMessage(LANG_COMMAND_DELCREATMESSAGE);
-
- return true;
-}
-
-//delete object by selection or guid
-bool ChatHandler::HandleDelObjectCommand(const char* args)
-{
- // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r
- char* cId = extractKeyFromLink((char*)args,"Hgameobject");
- if(!cId)
- return false;
-
- uint32 lowguid = atoi(cId);
- if(!lowguid)
- return false;
-
- GameObject* obj = NULL;
-
- // by DB guid
- if (GameObjectData const* go_data = objmgr.GetGOData(lowguid))
- obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id);
-
- if(!obj)
- {
- PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint64 owner_guid = obj->GetOwnerGUID();
- if(owner_guid)
- {
- Unit* owner = ObjectAccessor::GetUnit(*m_session->GetPlayer(),owner_guid);
- if(!owner && !IS_PLAYER_GUID(owner_guid))
- {
- PSendSysMessage(LANG_COMMAND_DELOBJREFERCREATURE, GUID_LOPART(owner_guid), obj->GetGUIDLow());
- SetSentErrorMessage(true);
- return false;
- }
-
- owner->RemoveGameObject(obj,false);
- }
-
- obj->SetRespawnTime(0); // not save respawn time
- obj->Delete();
- obj->DeleteFromDB();
-
- PSendSysMessage(LANG_COMMAND_DELOBJMESSAGE, obj->GetGUIDLow());
-
- return true;
-}
-
-//turn selected object
-bool ChatHandler::HandleTurnObjectCommand(const char* args)
-{
- // number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r
- char* cId = extractKeyFromLink((char*)args,"Hgameobject");
- if(!cId)
- return false;
-
- uint32 lowguid = atoi(cId);
- if(!lowguid)
- return false;
-
- GameObject* obj = NULL;
-
- // by DB guid
- if (GameObjectData const* go_data = objmgr.GetGOData(lowguid))
- obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id);
-
- if(!obj)
- {
- PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
-
- char* po = strtok(NULL, " ");
- float o;
-
- if (po)
- {
- o = (float)atof(po);
- }
- else
- {
- Player *chr = m_session->GetPlayer();
- o = chr->GetOrientation();
- }
-
- float rot2 = sin(o/2);
- float rot3 = cos(o/2);
-
- Map* map = MapManager::Instance().GetMap(obj->GetMapId(),obj);
- map->Remove(obj,false);
-
- obj->Relocate(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), o);
-
- obj->SetFloatValue(GAMEOBJECT_FACING, o);
- obj->SetFloatValue(GAMEOBJECT_ROTATION+2, rot2);
- obj->SetFloatValue(GAMEOBJECT_ROTATION+3, rot3);
-
- map->Add(obj);
-
- obj->SaveToDB();
- obj->Refresh();
-
- PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, obj->GetGUIDLow(), o);
-
- return true;
-}
-
-//move selected creature
-bool ChatHandler::HandleNpcMoveCommand(const char* args)
-{
- uint32 lowguid = 0;
-
- Creature* pCreature = getSelectedCreature();
-
- if(!pCreature)
- {
- // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r
- char* cId = extractKeyFromLink((char*)args,"Hcreature");
- if(!cId)
- return false;
-
- uint32 lowguid = atoi(cId);
-
- /* FIXME: impossibel without entry
- if(lowguid)
- pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT));
- */
-
- // Attempting creature load from DB data
- if(!pCreature)
- {
- CreatureData const* data = objmgr.GetCreatureData(lowguid);
- if(!data)
- {
- PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint32 map_id = data->mapid;
-
- if(m_session->GetPlayer()->GetMapId()!=map_id)
- {
- PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
- }
- else
- {
- lowguid = pCreature->GetDBTableGUIDLow();
- }
- }
- else
- {
- lowguid = pCreature->GetDBTableGUIDLow();
- }
-
- float x = m_session->GetPlayer()->GetPositionX();
- float y = m_session->GetPlayer()->GetPositionY();
- float z = m_session->GetPlayer()->GetPositionZ();
- float o = m_session->GetPlayer()->GetOrientation();
-
- if (pCreature)
- {
- if(CreatureData const* data = objmgr.GetCreatureData(pCreature->GetDBTableGUIDLow()))
- {
- const_cast<CreatureData*>(data)->posX = x;
- const_cast<CreatureData*>(data)->posY = y;
- const_cast<CreatureData*>(data)->posZ = z;
- const_cast<CreatureData*>(data)->orientation = o;
- }
- MapManager::Instance().GetMap(pCreature->GetMapId(),pCreature)->CreatureRelocation(pCreature,x, y, z,o);
- pCreature->GetMotionMaster()->Initialize();
- if(pCreature->isAlive()) // dead creature will reset movement generator at respawn
- {
- pCreature->setDeathState(JUST_DIED);
- pCreature->Respawn();
- }
- }
-
- WorldDatabase.PExecuteLog("UPDATE creature SET position_x = '%f', position_y = '%f', position_z = '%f', orientation = '%f' WHERE guid = '%u'", x, y, z, o, lowguid);
- PSendSysMessage(LANG_COMMAND_CREATUREMOVED);
- return true;
-}
-
-//move selected object
-bool ChatHandler::HandleMoveObjectCommand(const char* args)
-{
- // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r
- char* cId = extractKeyFromLink((char*)args,"Hgameobject");
- if(!cId)
- return false;
-
- uint32 lowguid = atoi(cId);
- if(!lowguid)
- return false;
-
- GameObject* obj = NULL;
-
- // by DB guid
- if (GameObjectData const* go_data = objmgr.GetGOData(lowguid))
- obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id);
-
- if(!obj)
- {
- PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
-
- char* px = strtok(NULL, " ");
- char* py = strtok(NULL, " ");
- char* pz = strtok(NULL, " ");
-
- if (!px)
- {
- Player *chr = m_session->GetPlayer();
-
- Map* map = MapManager::Instance().GetMap(obj->GetMapId(),obj);
- map->Remove(obj,false);
-
- obj->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), obj->GetOrientation());
- obj->SetFloatValue(GAMEOBJECT_POS_X, chr->GetPositionX());
- obj->SetFloatValue(GAMEOBJECT_POS_Y, chr->GetPositionY());
- obj->SetFloatValue(GAMEOBJECT_POS_Z, chr->GetPositionZ());
-
- map->Add(obj);
- }
- else
- {
- if(!py || !pz)
- return false;
-
- float x = (float)atof(px);
- float y = (float)atof(py);
- float z = (float)atof(pz);
-
- if(!MapManager::IsValidMapCoord(obj->GetMapId(),x,y,z))
- {
- PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,obj->GetMapId());
- SetSentErrorMessage(true);
- return false;
- }
-
- Map* map = MapManager::Instance().GetMap(obj->GetMapId(),obj);
- map->Remove(obj,false);
-
- obj->Relocate(x, y, z, obj->GetOrientation());
- obj->SetFloatValue(GAMEOBJECT_POS_X, x);
- obj->SetFloatValue(GAMEOBJECT_POS_Y, y);
- obj->SetFloatValue(GAMEOBJECT_POS_Z, z);
-
- map->Add(obj);
- }
-
- obj->SaveToDB();
- obj->Refresh();
-
- PSendSysMessage(LANG_COMMAND_MOVEOBJMESSAGE, obj->GetGUIDLow());
-
- return true;
-}
-
-//demorph player or unit
-bool ChatHandler::HandleDeMorphCommand(const char* /*args*/)
-{
- Unit *target = getSelectedUnit();
- if(!target)
- target = m_session->GetPlayer();
-
- target->DeMorph();
-
- return true;
-}
-
-//add item in vendorlist
-bool ChatHandler::HandleAddVendorItemCommand(const char* args)
-{
- if (!*args)
- return false;
-
- char* pitem = extractKeyFromLink((char*)args,"Hitem");
- if (!pitem)
- {
- SendSysMessage(LANG_COMMAND_NEEDITEMSEND);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint32 itemId = atol(pitem);
-
- char* fmaxcount = strtok(NULL, " "); //add maxcount, default: 0
- uint32 maxcount = 0;
- if (fmaxcount)
- maxcount = atol(fmaxcount);
-
- char* fincrtime = strtok(NULL, " "); //add incrtime, default: 0
- uint32 incrtime = 0;
- if (fincrtime)
- incrtime = atol(fincrtime);
-
- char* fextendedcost = strtok(NULL, " "); //add ExtendedCost, default: 0
- uint32 extendedcost = fextendedcost ? atol(fextendedcost) : 0;
-
- Creature* vendor = getSelectedCreature();
-
- uint32 vendor_entry = vendor ? vendor->GetEntry() : 0;
-
- if(!objmgr.IsVendorItemValid(vendor_entry,itemId,maxcount,incrtime,extendedcost,m_session->GetPlayer()))
- {
- SetSentErrorMessage(true);
- return false;
- }
-
- objmgr.AddVendorItem(vendor_entry,itemId,maxcount,incrtime,extendedcost);
-
- ItemPrototype const* pProto = objmgr.GetItemPrototype(itemId);
-
- PSendSysMessage(LANG_ITEM_ADDED_TO_LIST,itemId,pProto->Name1,maxcount,incrtime,extendedcost);
- return true;
-}
-
-//del item from vendor list
-bool ChatHandler::HandleDelVendorItemCommand(const char* args)
-{
- if (!*args)
- return false;
-
- Creature* vendor = getSelectedCreature();
- if (!vendor || !vendor->isVendor())
- {
- SendSysMessage(LANG_COMMAND_VENDORSELECTION);
- SetSentErrorMessage(true);
- return false;
- }
-
- char* pitem = extractKeyFromLink((char*)args,"Hitem");
- if (!pitem)
- {
- SendSysMessage(LANG_COMMAND_NEEDITEMSEND);
- SetSentErrorMessage(true);
- return false;
- }
- uint32 itemId = atol(pitem);
-
-
- if(!objmgr.RemoveVendorItem(vendor->GetEntry(),itemId))
- {
- PSendSysMessage(LANG_ITEM_NOT_IN_LIST,itemId);
- SetSentErrorMessage(true);
- return false;
- }
-
- ItemPrototype const* pProto = objmgr.GetItemPrototype(itemId);
-
- PSendSysMessage(LANG_ITEM_DELETED_FROM_LIST,itemId,pProto->Name1);
- return true;
-}
-
-//add move for creature
-bool ChatHandler::HandleNpcAddMoveCommand(const char* args)
-{
- if(!*args)
- return false;
-
- char* guid_str = strtok((char*)args, " ");
- char* wait_str = strtok((char*)NULL, " ");
-
- uint32 lowguid = atoi((char*)guid_str);
-
- Creature* pCreature = NULL;
-
- /* FIXME: impossible without entry
- if(lowguid)
- pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT));
- */
-
- // attempt check creature existence by DB data
- if(!pCreature)
- {
- CreatureData const* data = objmgr.GetCreatureData(lowguid);
- if(!data)
- {
- PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
- }
- else
- {
- // obtain real GUID for DB operations
- lowguid = pCreature->GetDBTableGUIDLow();
- }
-
- int wait = wait_str ? atoi(wait_str) : 0;
-
- if(wait < 0)
- wait = 0;
-
- Player* player = m_session->GetPlayer();
-
- WaypointMgr.AddLastNode(lowguid, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), wait, 0);
-
- // update movement type
- WorldDatabase.PExecuteLog("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE,lowguid);
- if(pCreature)
- {
- pCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE);
- pCreature->GetMotionMaster()->Initialize();
- if(pCreature->isAlive()) // dead creature will reset movement generator at respawn
- {
- pCreature->setDeathState(JUST_DIED);
- pCreature->Respawn();
- }
- pCreature->SaveToDB();
- }
-
- SendSysMessage(LANG_WAYPOINT_ADDED);
-
- return true;
-}
-
-/**
- * Set the movement type for an NPC.<br/>
- * <br/>
- * Valid movement types are:
- * <ul>
- * <li> stay - NPC wont move </li>
- * <li> random - NPC will move randomly according to the spawndist </li>
- * <li> way - NPC will move with given waypoints set </li>
- * </ul>
- * additional parameter: NODEL - so no waypoints are deleted, if you
- * change the movement type
- */
-bool ChatHandler::HandleNpcSetMoveTypeCommand(const char* args)
-{
- if(!*args)
- return false;
-
- // 3 arguments:
- // GUID (optional - you can also select the creature)
- // stay|random|way (determines the kind of movement)
- // NODEL (optional - tells the system NOT to delete any waypoints)
- // this is very handy if you want to do waypoints, that are
- // later switched on/off according to special events (like escort
- // quests, etc)
- char* guid_str = strtok((char*)args, " ");
- char* type_str = strtok((char*)NULL, " ");
- char* dontdel_str = strtok((char*)NULL, " ");
-
- bool doNotDelete = false;
-
- if(!guid_str)
- return false;
-
- uint32 lowguid = 0;
- Creature* pCreature = NULL;
-
- if( dontdel_str )
- {
- //sLog.outError("DEBUG: All 3 params are set");
-
- // All 3 params are set
- // GUID
- // type
- // doNotDEL
- if( stricmp( dontdel_str, "NODEL" ) == 0 )
- {
- //sLog.outError("DEBUG: doNotDelete = true;");
- doNotDelete = true;
- }
- }
- else
- {
- // Only 2 params - but maybe NODEL is set
- if( type_str )
- {
- sLog.outError("DEBUG: Only 2 params ");
- if( stricmp( type_str, "NODEL" ) == 0 )
- {
- //sLog.outError("DEBUG: type_str, NODEL ");
- doNotDelete = true;
- type_str = NULL;
- }
- }
- }
-
- if(!type_str) // case .setmovetype $move_type (with selected creature)
- {
- type_str = guid_str;
- pCreature = getSelectedCreature();
- if(!pCreature || pCreature->isPet())
- return false;
- lowguid = pCreature->GetDBTableGUIDLow();
- }
- else // case .setmovetype #creature_guid $move_type (with selected creature)
- {
- lowguid = atoi((char*)guid_str);
-
- /* impossible without entry
- if(lowguid)
- pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT));
- */
-
- // attempt check creature existence by DB data
- if(!pCreature)
- {
- CreatureData const* data = objmgr.GetCreatureData(lowguid);
- if(!data)
- {
- PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
- }
- else
- {
- lowguid = pCreature->GetDBTableGUIDLow();
- }
- }
-
- // now lowguid is low guid really existed creature
- // and pCreature point (maybe) to this creature or NULL
-
- MovementGeneratorType move_type;
-
- std::string type = type_str;
-
- if(type == "stay")
- move_type = IDLE_MOTION_TYPE;
- else if(type == "random")
- move_type = RANDOM_MOTION_TYPE;
- else if(type == "way")
- move_type = WAYPOINT_MOTION_TYPE;
- else
- return false;
-
- // update movement type
- if(doNotDelete == false)
- WaypointMgr.DeletePath(lowguid);
-
- if(pCreature)
- {
- pCreature->SetDefaultMovementType(move_type);
- pCreature->GetMotionMaster()->Initialize();
- if(pCreature->isAlive()) // dead creature will reset movement generator at respawn
- {
- pCreature->setDeathState(JUST_DIED);
- pCreature->Respawn();
- }
- pCreature->SaveToDB();
- }
- if( doNotDelete == false )
- {
- PSendSysMessage(LANG_MOVE_TYPE_SET,type_str);
- }
- else
- {
- PSendSysMessage(LANG_MOVE_TYPE_SET_NODEL,type_str);
- }
-
- return true;
-} // HandleNpcSetMoveTypeCommand
-
-//change level of creature or pet
-bool ChatHandler::HandleChangeLevelCommand(const char* args)
-{
- if (!*args)
- return false;
-
- uint8 lvl = (uint8) atoi((char*)args);
- if ( lvl < 1 || lvl > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) + 3)
- {
- SendSysMessage(LANG_BAD_VALUE);
- SetSentErrorMessage(true);
- return false;
- }
-
- Creature* pCreature = getSelectedCreature();
- if(!pCreature)
- {
- SendSysMessage(LANG_SELECT_CREATURE);
- SetSentErrorMessage(true);
- return false;
- }
-
- if(pCreature->isPet())
- {
- ((Pet*)pCreature)->GivePetLevel(lvl);
- }
- else
- {
- pCreature->SetMaxHealth( 100 + 30*lvl);
- pCreature->SetHealth( 100 + 30*lvl);
- pCreature->SetLevel( lvl);
- pCreature->SaveToDB();
- }
-
- return true;
-}
-
-//set npcflag of creature
-bool ChatHandler::HandleNpcFlagCommand(const char* args)
-{
- if (!*args)
- return false;
-
- uint32 npcFlags = (uint32) atoi((char*)args);
-
- Creature* pCreature = getSelectedCreature();
-
- if(!pCreature)
- {
- SendSysMessage(LANG_SELECT_CREATURE);
- SetSentErrorMessage(true);
- return false;
- }
-
- pCreature->SetUInt32Value(UNIT_NPC_FLAGS, npcFlags);
-
- WorldDatabase.PExecuteLog("UPDATE creature_template SET npcflag = '%u' WHERE entry = '%u'", npcFlags, pCreature->GetEntry());
-
- SendSysMessage(LANG_VALUE_SAVED_REJOIN);
-
- return true;
-}
-
-//set model of creature
-bool ChatHandler::HandleNpcSetModelCommand(const char* args)
-{
- if (!*args)
- return false;
-
- uint32 displayId = (uint32) atoi((char*)args);
-
- Creature *pCreature = getSelectedCreature();
-
- if(!pCreature || pCreature->isPet())
- {
- SendSysMessage(LANG_SELECT_CREATURE);
- SetSentErrorMessage(true);
- return false;
- }
-
- pCreature->SetDisplayId(displayId);
- pCreature->SetNativeDisplayId(displayId);
-
- pCreature->SaveToDB();
-
- return true;
-}
-
-//morph creature or player
-bool ChatHandler::HandleMorphCommand(const char* args)
-{
- if (!*args)
- return false;
-
- uint16 display_id = (uint16)atoi((char*)args);
-
- Unit *target = getSelectedUnit();
- if(!target)
- target = m_session->GetPlayer();
-
- target->SetDisplayId(display_id);
-
- return true;
-}
-
-//set faction of creature
-bool ChatHandler::HandleNpcFactionIdCommand(const char* args)
-{
- if (!*args)
- return false;
-
- uint32 factionId = (uint32) atoi((char*)args);
-
- if (!sFactionTemplateStore.LookupEntry(factionId))
- {
- PSendSysMessage(LANG_WRONG_FACTION, factionId);
- SetSentErrorMessage(true);
- return false;
- }
-
- Creature* pCreature = getSelectedCreature();
-
- if(!pCreature)
- {
- SendSysMessage(LANG_SELECT_CREATURE);
- SetSentErrorMessage(true);
- return false;
- }
-
- pCreature->setFaction(factionId);
-
- // faction is set in creature_template - not inside creature
-
- // update in memory
- if(CreatureInfo const *cinfo = pCreature->GetCreatureInfo())
- {
- const_cast<CreatureInfo*>(cinfo)->faction_A = factionId;
- const_cast<CreatureInfo*>(cinfo)->faction_H = factionId;
- }
-
- // and DB
- WorldDatabase.PExecuteLog("UPDATE creature_template SET faction_A = '%u', faction_H = '%u' WHERE entry = '%u'", factionId, factionId, pCreature->GetEntry());
-
- return true;
-}
-
-//kick player
-bool ChatHandler::HandleKickPlayerCommand(const char *args)
-{
- char* kickName = strtok((char*)args, " ");
- if (!kickName)
- {
- Player* player = getSelectedPlayer();
-
- if(!player)
- {
- SendSysMessage(LANG_NO_CHAR_SELECTED);
- SetSentErrorMessage(true);
- return false;
- }
-
- if(player==m_session->GetPlayer())
- {
- SendSysMessage(LANG_COMMAND_KICKSELF);
- SetSentErrorMessage(true);
- return false;
- }
-
- player->GetSession()->KickPlayer();
- }
- else
- {
- std::string name = kickName;
- if(!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- if(m_session && name==m_session->GetPlayer()->GetName())
- {
- SendSysMessage(LANG_COMMAND_KICKSELF);
- SetSentErrorMessage(true);
- return false;
- }
-
- if(sWorld.KickPlayer(name))
- {
- PSendSysMessage(LANG_COMMAND_KICKMESSAGE,name.c_str());
- }
- else
- PSendSysMessage(LANG_COMMAND_KICKNOTFOUNDPLAYER,name.c_str());
- }
-
- return true;
-}
-
-//show info of player
-bool ChatHandler::HandlePInfoCommand(const char* args)
-{
- Player* target = NULL;
- uint64 targetGUID = 0;
-
- char* px = strtok((char*)args, " ");
- char* py = NULL;
-
- std::string name;
-
- if (px)
- {
- name = px;
-
- if(name.empty())
- return false;
-
- if(!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- target = objmgr.GetPlayer(name.c_str());
- if (target)
- py = strtok(NULL, " ");
- else
- {
- targetGUID = objmgr.GetPlayerGUIDByName(name);
- if(targetGUID)
- py = strtok(NULL, " ");
- else
- py = px;
- }
- }
-
- if(!target && !targetGUID)
- {
- target = getSelectedPlayer();
- }
-
- if(!target && !targetGUID)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint32 accId = 0;
- uint32 money = 0;
- uint32 total_player_time = 0;
- uint32 level = 0;
- uint32 latency = 0;
-
- // get additional information from Player object
- if(target)
- {
- targetGUID = target->GetGUID();
- name = target->GetName(); // re-read for case getSelectedPlayer() target
- accId = target->GetSession()->GetAccountId();
- money = target->GetMoney();
- total_player_time = target->GetTotalPlayedTime();
- level = target->getLevel();
- latency = target->GetSession()->GetLatency();
- }
- // get additional information from DB
- else
- {
- QueryResult *result = CharacterDatabase.PQuery("SELECT totaltime FROM characters WHERE guid = '%u'", GUID_LOPART(targetGUID));
- if (!result)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
- Field *fields = result->Fetch();
- total_player_time = fields[0].GetUInt32();
- delete result;
-
- Tokens data;
- if (!Player::LoadValuesArrayFromDB(data,targetGUID))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- money = Player::GetUInt32ValueFromArray(data, PLAYER_FIELD_COINAGE);
- level = Player::GetUInt32ValueFromArray(data, UNIT_FIELD_LEVEL);
- accId = objmgr.GetPlayerAccountIdByGUID(targetGUID);
- }
-
- std::string username = GetTrinityString(LANG_ERROR);
- std::string last_ip = GetTrinityString(LANG_ERROR);
- uint32 security = 0;
- std::string last_login = GetTrinityString(LANG_ERROR);
-
- QueryResult* result = loginDatabase.PQuery("SELECT username,gmlevel,last_ip,last_login FROM account WHERE id = '%u'",accId);
- if(result)
- {
- Field* fields = result->Fetch();
- username = fields[0].GetCppString();
- security = fields[1].GetUInt32();
-
- if(!m_session || m_session->GetSecurity() >= security)
- {
- last_ip = fields[2].GetCppString();
- last_login = fields[3].GetCppString();
- }
- else
- {
- last_ip = "-";
- last_login = "-";
- }
-
- delete result;
- }
-
- PSendSysMessage(LANG_PINFO_ACCOUNT, (target?"":GetTrinityString(LANG_OFFLINE)), name.c_str(), GUID_LOPART(targetGUID), username.c_str(), accId, security, last_ip.c_str(), last_login.c_str(), latency);
-
- std::string timeStr = secsToTimeString(total_player_time,true,true);
- uint32 gold = money /GOLD;
- uint32 silv = (money % GOLD) / SILVER;
- uint32 copp = (money % GOLD) % SILVER;
- PSendSysMessage(LANG_PINFO_LEVEL, timeStr.c_str(), level, gold,silv,copp );
-
- if ( py && strncmp(py, "rep", 3) == 0 )
- {
- if(!target)
- {
- // rep option not implemented for offline case
- SendSysMessage(LANG_PINFO_NO_REP);
- SetSentErrorMessage(true);
- return false;
- }
-
- char* FactionName;
- for(FactionStateList::const_iterator itr = target->m_factions.begin(); itr != target->m_factions.end(); ++itr)
- {
- FactionEntry const *factionEntry = sFactionStore.LookupEntry(itr->second.ID);
- if (factionEntry)
- FactionName = factionEntry->name[m_session->GetSessionDbcLocale()];
- else
- FactionName = "#Not found#";
- ReputationRank rank = target->GetReputationRank(factionEntry);
- std::string rankName = GetTrinityString(ReputationRankStrIndex[rank]);
- std::ostringstream ss;
- ss << itr->second.ID << ": |cffffffff|Hfaction:" << itr->second.ID << "|h[" << FactionName << "]|h|r " << rankName << "|h|r (" << target->GetReputation(factionEntry) << ")";
-
- if(itr->second.Flags & FACTION_FLAG_VISIBLE)
- ss << GetTrinityString(LANG_FACTION_VISIBLE);
- if(itr->second.Flags & FACTION_FLAG_AT_WAR)
- ss << GetTrinityString(LANG_FACTION_ATWAR);
- if(itr->second.Flags & FACTION_FLAG_PEACE_FORCED)
- ss << GetTrinityString(LANG_FACTION_PEACE_FORCED);
- if(itr->second.Flags & FACTION_FLAG_HIDDEN)
- ss << GetTrinityString(LANG_FACTION_HIDDEN);
- if(itr->second.Flags & FACTION_FLAG_INVISIBLE_FORCED)
- ss << GetTrinityString(LANG_FACTION_INVISIBLE_FORCED);
- if(itr->second.Flags & FACTION_FLAG_INACTIVE)
- ss << GetTrinityString(LANG_FACTION_INACTIVE);
-
- SendSysMessage(ss.str().c_str());
- }
- }
- return true;
-}
-
-//show tickets
-void ChatHandler::ShowTicket(uint64 guid, char const* text, char const* time)
-{
- std::string name;
- if(!objmgr.GetPlayerNameByGUID(guid,name))
- name = GetTrinityString(LANG_UNKNOWN);
-
- PSendSysMessage(LANG_COMMAND_TICKETVIEW, name.c_str(),time,text);
-}
-
-//ticket commands
-bool ChatHandler::HandleTicketCommand(const char* args)
-{
- char* px = strtok((char*)args, " ");
-
- // ticket<end>
- if (!px)
- {
- if(!m_session)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- size_t count = ticketmgr.GetTicketCount();
-
- bool accept = m_session->GetPlayer()->isAcceptTickets();
-
- PSendSysMessage(LANG_COMMAND_TICKETCOUNT, count, accept ? GetTrinityString(LANG_ON) : GetTrinityString(LANG_OFF));
- return true;
- }
-
- // ticket on
- if(strncmp(px,"on",3) == 0)
- {
- if(!m_session)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- m_session->GetPlayer()->SetAcceptTicket(true);
- SendSysMessage(LANG_COMMAND_TICKETON);
- return true;
- }
-
- // ticket off
- if(strncmp(px,"off",4) == 0)
- {
- if(!m_session)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- m_session->GetPlayer()->SetAcceptTicket(false);
- SendSysMessage(LANG_COMMAND_TICKETOFF);
- return true;
- }
-
- // ticket #num
- int num = atoi(px);
- if(num > 0)
- {
- QueryResult *result = CharacterDatabase.PQuery("SELECT guid,ticket_text,ticket_lastchange FROM character_ticket ORDER BY ticket_id ASC "_OFFSET_, num-1);
-
- if(!result)
- {
- PSendSysMessage(LANG_COMMAND_TICKENOTEXIST, num);
- SetSentErrorMessage(true);
- return false;
- }
-
- Field* fields = result->Fetch();
-
- uint32 guid = fields[0].GetUInt32();
- char const* text = fields[1].GetString();
- char const* time = fields[2].GetString();
-
- ShowTicket(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER),text,time);
- delete result;
- return true;
- }
-
- std::string name = px;
-
- if(!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint64 guid = objmgr.GetPlayerGUIDByName(name);
-
- if(!guid)
- return false;
-
- // ticket $char_name
- GMTicket* ticket = ticketmgr.GetGMTicket(GUID_LOPART(guid));
- if(!ticket)
- return false;
-
- std::string time = TimeToTimestampStr(ticket->GetLastUpdate());
-
- ShowTicket(guid, ticket->GetText(), time.c_str());
-
- return true;
-}
-
-//dell all tickets
-bool ChatHandler::HandleDelTicketCommand(const char *args)
-{
- char* px = strtok((char*)args, " ");
- if (!px)
- return false;
-
- // delticket all
- if(strncmp(px,"all",4) == 0)
- {
- ticketmgr.DeleteAll();
- SendSysMessage(LANG_COMMAND_ALLTICKETDELETED);
- return true;
- }
-
- int num = (uint32)atoi(px);
-
- // delticket #num
- if(num > 0)
- {
- QueryResult* result = CharacterDatabase.PQuery("SELECT guid FROM character_ticket ORDER BY ticket_id ASC "_OFFSET_,num-1);
- if(!result)
- {
- PSendSysMessage(LANG_COMMAND_TICKENOTEXIST, num);
- SetSentErrorMessage(true);
- return false;
- }
-
- Field* fields = result->Fetch();
-
- uint32 guid = fields[0].GetUInt32();
- delete result;
-
- ticketmgr.Delete(guid);
-
- //notify player
- if(Player* pl = objmgr.GetPlayer(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)))
- {
- pl->GetSession()->SendGMTicketGetTicket(0x0A, 0);
- PSendSysMessage(LANG_COMMAND_TICKETPLAYERDEL, pl->GetName());
- }
- else
- PSendSysMessage(LANG_COMMAND_TICKETDEL);
-
- return true;
- }
-
- std::string name = px;
-
- if(!normalizePlayerName(name))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint64 guid = objmgr.GetPlayerGUIDByName(name);
-
- if(!guid)
- return false;
-
- // delticket $char_name
- ticketmgr.Delete(GUID_LOPART(guid));
-
- // notify players about ticket deleting
- if(Player* sender = objmgr.GetPlayer(guid))
- sender->GetSession()->SendGMTicketGetTicket(0x0A,0);
-
- PSendSysMessage(LANG_COMMAND_TICKETPLAYERDEL,px);
- return true;
-}
-
-//set spawn dist of creature
-bool ChatHandler::HandleNpcSpawnDistCommand(const char* args)
-{
- if(!*args)
- return false;
-
- float option = atof((char*)args);
- if (option < 0.0f)
- {
- SendSysMessage(LANG_BAD_VALUE);
- return false;
- }
-
- MovementGeneratorType mtype = IDLE_MOTION_TYPE;
- if (option >0.0f)
- mtype = RANDOM_MOTION_TYPE;
-
- Creature *pCreature = getSelectedCreature();
- uint32 u_guidlow = 0;
-
- if (pCreature)
- u_guidlow = pCreature->GetDBTableGUIDLow();
- else
- return false;
-
- pCreature->SetRespawnRadius((float)option);
- pCreature->SetDefaultMovementType(mtype);
- pCreature->GetMotionMaster()->Initialize();
- if(pCreature->isAlive()) // dead creature will reset movement generator at respawn
- {
- pCreature->setDeathState(JUST_DIED);
- pCreature->Respawn();
- }
-
- WorldDatabase.PExecuteLog("UPDATE creature SET spawndist=%f, MovementType=%i WHERE guid=%u",option,mtype,u_guidlow);
- PSendSysMessage(LANG_COMMAND_SPAWNDIST,option);
- return true;
-}
-
-bool ChatHandler::HandleNpcSpawnTimeCommand(const char* args)
-{
- if(!*args)
- return false;
-
- char* stime = strtok((char*)args, " ");
-
- if (!stime)
- return false;
-
- int i_stime = atoi((char*)stime);
-
- if (i_stime < 0)
- {
- SendSysMessage(LANG_BAD_VALUE);
- SetSentErrorMessage(true);
- return false;
- }
-
- Creature *pCreature = getSelectedCreature();
- uint32 u_guidlow = 0;
-
- if (pCreature)
- u_guidlow = pCreature->GetDBTableGUIDLow();
- else
- return false;
-
- WorldDatabase.PExecuteLog("UPDATE creature SET spawntimesecs=%i WHERE guid=%u",i_stime,u_guidlow);
- pCreature->SetRespawnDelay((uint32)i_stime);
- PSendSysMessage(LANG_COMMAND_SPAWNTIME,i_stime);
-
- return true;
-}
-
-/**
- * Add a waypoint to a creature.
- *
- * The user can either select an npc or provide its GUID.
- *
- * The user can even select a visual waypoint - then the new waypoint
- * is placed *after* the selected one - this makes insertion of new
- * waypoints possible.
- *
- * eg:
- * .wp add 12345
- * -> adds a waypoint to the npc with the GUID 12345
- *
- * .wp add
- * -> adds a waypoint to the currently selected creature
- *
- *
- * @param args if the user did not provide a GUID, it is NULL
- *
- * @return true - command did succeed, false - something went wrong
- */
-bool ChatHandler::HandleWpAddCommand(const char* args)
-{
- sLog.outDebug("DEBUG: HandleWpAddCommand");
-
- // optional
- char* guid_str = NULL;
-
- if(*args)
- {
- guid_str = strtok((char*)args, " ");
- }
-
- uint32 lowguid = 0;
- uint32 point = 0;
- Creature* target = getSelectedCreature();
- // Did player provide a GUID?
- if (!guid_str)
- {
- sLog.outDebug("DEBUG: HandleWpAddCommand - No GUID provided");
-
- // No GUID provided
- // -> Player must have selected a creature
-
- if(!target || target->isPet())
- {
- SendSysMessage(LANG_SELECT_CREATURE);
- SetSentErrorMessage(true);
- return false;
- }
- if (target->GetEntry() == VISUAL_WAYPOINT )
- {
- sLog.outDebug("DEBUG: HandleWpAddCommand - target->GetEntry() == VISUAL_WAYPOINT (1) ");
-
- QueryResult *result =
- WorldDatabase.PQuery( "SELECT id, point FROM creature_movement WHERE wpguid = %u",
- target->GetGUIDLow() );
- if(!result)
- {
- PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, target->GetGUIDLow());
- // User selected a visual spawnpoint -> get the NPC
- // Select NPC GUID
- // Since we compare float values, we have to deal with
- // some difficulties.
- // Here we search for all waypoints that only differ in one from 1 thousand
- // (0.001) - There is no other way to compare C++ floats with mySQL floats
- // See also: http://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html
- const char* maxDIFF = "0.01";
- result = WorldDatabase.PQuery( "SELECT id, point FROM creature_movement WHERE (abs(position_x - %f) <= %s ) and (abs(position_y - %f) <= %s ) and (abs(position_z - %f) <= %s )",
- target->GetPositionX(), maxDIFF, target->GetPositionY(), maxDIFF, target->GetPositionZ(), maxDIFF);
- if(!result)
- {
- PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, target->GetGUIDLow());
- SetSentErrorMessage(true);
- return false;
- }
- }
- do
- {
- Field *fields = result->Fetch();
- lowguid = fields[0].GetUInt32();
- point = fields[1].GetUInt32();
- }while( result->NextRow() );
- delete result;
-
- CreatureData const* data = objmgr.GetCreatureData(lowguid);
- if(!data)
- {
- PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
-
- target = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,data->id,HIGHGUID_UNIT));
- if(!target)
- {
- PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
- }
- else
- {
- lowguid = target->GetDBTableGUIDLow();
- }
- }
- else
- {
- sLog.outDebug("DEBUG: HandleWpAddCommand - GUID provided");
-
- // GUID provided
- // Warn if player also selected a creature
- // -> Creature selection is ignored <-
- if(target)
- {
- SendSysMessage(LANG_WAYPOINT_CREATSELECTED);
- }
- lowguid = atoi((char*)guid_str);
-
- CreatureData const* data = objmgr.GetCreatureData(lowguid);
- if(!data)
- {
- PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
-
- target = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,data->id,HIGHGUID_UNIT));
- if(!target || target->isPet())
- {
- PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
- }
- // lowguid -> GUID of the NPC
- // point -> number of the waypoint (if not 0)
- sLog.outDebug("DEBUG: HandleWpAddCommand - danach");
-
- sLog.outDebug("DEBUG: HandleWpAddCommand - point == 0");
-
- Player* player = m_session->GetPlayer();
- WaypointMgr.AddLastNode(lowguid, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), 0, 0);
-
- // update movement type
- if(target)
- {
- target->SetDefaultMovementType(WAYPOINT_MOTION_TYPE);
- target->GetMotionMaster()->Initialize();
- if(target->isAlive()) // dead creature will reset movement generator at respawn
- {
- target->setDeathState(JUST_DIED);
- target->Respawn();
- }
- target->SaveToDB();
- }
- else
- WorldDatabase.PExecuteLog("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE,lowguid);
-
- PSendSysMessage(LANG_WAYPOINT_ADDED, point, lowguid);
-
- return true;
-} // HandleWpAddCommand
-
-/**
- * .wp modify emote | spell | text | del | move | add
- *
- * add -> add a WP after the selected visual waypoint
- * User must select a visual waypoint and then issue ".wp modify add"
- *
- * emote <emoteID>
- * User has selected a visual waypoint before.
- * <emoteID> is added to this waypoint. Everytime the
- * NPC comes to this waypoint, the emote is called.
- *
- * emote <GUID> <WPNUM> <emoteID>
- * User has not selected visual waypoint before.
- * For the waypoint <WPNUM> for the NPC with <GUID>
- * an emote <emoteID> is added.
- * Everytime the NPC comes to this waypoint, the emote is called.
- *
- *
- * info <GUID> <WPNUM> -> User did not select a visual waypoint and
- */
-bool ChatHandler::HandleWpModifyCommand(const char* args)
-{
- sLog.outDebug("DEBUG: HandleWpModifyCommand");
-
- if(!*args)
- return false;
-
- // first arg: add del text emote spell waittime move
- char* show_str = strtok((char*)args, " ");
- if (!show_str)
- {
- return false;
- }
-
- std::string show = show_str;
- // Check
- // Remember: "show" must also be the name of a column!
- if( (show != "emote") && (show != "spell") && (show != "textid1") && (show != "textid2")
- && (show != "textid3") && (show != "textid4") && (show != "textid5")
- && (show != "waittime") && (show != "del") && (show != "move") && (show != "add")
- && (show != "model1") && (show != "model2") && (show != "orientation"))
- {
- return false;
- }
-
- // Next arg is: <GUID> <WPNUM> <ARGUMENT>
-
- // Did user provide a GUID
- // or did the user select a creature?
- // -> variable lowguid is filled with the GUID of the NPC
- uint32 lowguid = 0;
- uint32 point = 0;
- uint32 wpGuid = 0;
- Creature* target = getSelectedCreature();
-
- if(target)
- {
- sLog.outDebug("DEBUG: HandleWpModifyCommand - User did select an NPC");
-
- // Did the user select a visual spawnpoint?
- if (target->GetEntry() != VISUAL_WAYPOINT )
- {
- PSendSysMessage(LANG_WAYPOINT_VP_SELECT);
- SetSentErrorMessage(true);
- return false;
- }
-
- wpGuid = target->GetGUIDLow();
-
- // The visual waypoint
- QueryResult *result =
- WorldDatabase.PQuery( "SELECT id, point FROM creature_movement WHERE wpguid = %u LIMIT 1",
- target->GetGUIDLow() );
- if(!result)
- {
- PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, wpGuid);
- SetSentErrorMessage(true);
- return false;
- }
- sLog.outDebug("DEBUG: HandleWpModifyCommand - After getting wpGuid");
-
- Field *fields = result->Fetch();
- lowguid = fields[0].GetUInt32();
- point = fields[1].GetUInt32();
-
- // Cleanup memory
- sLog.outDebug("DEBUG: HandleWpModifyCommand - Cleanup memory");
- delete result;
- }
- else
- {
- // User did provide <GUID> <WPNUM>
-
- char* guid_str = strtok((char*)NULL, " ");
- if( !guid_str )
- {
- SendSysMessage(LANG_WAYPOINT_NOGUID);
- return false;
- }
- lowguid = atoi((char*)guid_str);
-
- CreatureData const* data = objmgr.GetCreatureData(lowguid);
- if(!data)
- {
- PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
-
- PSendSysMessage("DEBUG: GUID provided: %d", lowguid);
-
- char* point_str = strtok((char*)NULL, " ");
- if( !point_str )
- {
- SendSysMessage(LANG_WAYPOINT_NOWAYPOINTGIVEN);
- return false;
- }
- point = atoi((char*)point_str);
-
- PSendSysMessage("DEBUG: wpNumber provided: %d", point);
-
- // Now we need the GUID of the visual waypoint
- // -> "del", "move", "add" command
-
- QueryResult *result = WorldDatabase.PQuery( "SELECT wpguid FROM creature_movement WHERE id = '%u' AND point = '%u' LIMIT 1", lowguid, point);
- if (!result)
- {
- PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, lowguid, point);
- SetSentErrorMessage(true);
- return false;
- }
-
- Field *fields = result->Fetch();
- wpGuid = fields[0].GetUInt32();
-
- // Free memory
- delete result;
- }
-
- char* arg_str = NULL;
- // Check for argument
- if( (show.find("text") == std::string::npos ) && (show != "del") && (show != "move") && (show != "add"))
- {
- // Text is enclosed in "<>", all other arguments not
- if( show.find("text") != std::string::npos )
- arg_str = strtok((char*)NULL, "<>");
- else
- arg_str = strtok((char*)NULL, " ");
-
- if( !arg_str)
- {
- PSendSysMessage(LANG_WAYPOINT_ARGUMENTREQ, show_str);
- return false;
- }
- }
-
- sLog.outDebug("DEBUG: HandleWpModifyCommand - Parameters parsed - now execute the command");
-
- // wpGuid -> GUID of the waypoint creature
- // lowguid -> GUID of the NPC
- // point -> waypoint number
-
- // Special functions:
- // add - move - del -> no args commands
- // Add a waypoint after the selected visual
- if(show == "add" && target)
- {
- PSendSysMessage("DEBUG: wp modify add, GUID: %u", lowguid);
-
- // Get the creature for which we read the waypoint
- CreatureData const* data = objmgr.GetCreatureData(lowguid);
- if(!data)
- {
- PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
-
- Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT));
-
- if( !npcCreature )
- {
- PSendSysMessage(LANG_WAYPOINT_NPCNOTFOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- sLog.outDebug("DEBUG: HandleWpModifyCommand - add -- npcCreature");
-
- // What to do:
- // Add the visual spawnpoint (DB only)
- // Adjust the waypoints
- // Respawn the owner of the waypoints
- sLog.outDebug("DEBUG: HandleWpModifyCommand - add");
-
- Player* chr = m_session->GetPlayer();
- Map *map = chr->GetMap();
-
- if(npcCreature)
- {
- npcCreature->GetMotionMaster()->Initialize();
- if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn
- {
- npcCreature->setDeathState(JUST_DIED);
- npcCreature->Respawn();
- }
- }
-
- // create the waypoint creature
- wpGuid = 0;
- Creature* wpCreature = new Creature;
- if (!wpCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map,VISUAL_WAYPOINT,0))
- {
- PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT);
- delete wpCreature;
- }
- else
- {
- wpCreature->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation());
-
- if(!wpCreature->IsPositionValid())
- {
- sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature->GetGUIDLow(),wpCreature->GetEntry(),wpCreature->GetPositionX(),wpCreature->GetPositionY());
- delete wpCreature;
- }
- else
- {
- wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
- // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
- wpCreature->LoadFromDB(wpCreature->GetDBTableGUIDLow(), map);
- map->Add(wpCreature);
- wpGuid = wpCreature->GetGUIDLow();
- }
- }
-
- WaypointMgr.AddAfterNode(lowguid, point, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), 0, 0, wpGuid);
-
- if(!wpGuid)
- return false;
-
- PSendSysMessage(LANG_WAYPOINT_ADDED_NO, point+1);
- return true;
- } // add
-
- if(show == "del" && target)
- {
- PSendSysMessage("DEBUG: wp modify del, GUID: %u", lowguid);
-
- // Get the creature for which we read the waypoint
- CreatureData const* data = objmgr.GetCreatureData(lowguid);
- if(!data)
- {
- PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
-
- Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT));
-
- // wpCreature
- Creature* wpCreature = NULL;
- if( wpGuid != 0 )
- {
- wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT));
- wpCreature->DeleteFromDB();
- wpCreature->CleanupsBeforeDelete();
- wpCreature->AddObjectToRemoveList();
- }
-
- // What to do:
- // Remove the visual spawnpoint
- // Adjust the waypoints
- // Respawn the owner of the waypoints
-
- WaypointMgr.DeleteNode(lowguid, point);
-
- if(npcCreature)
- {
- // Any waypoints left?
- QueryResult *result2 = WorldDatabase.PQuery( "SELECT point FROM creature_movement WHERE id = '%u'",lowguid);
- if(!result2)
- {
- npcCreature->SetDefaultMovementType(RANDOM_MOTION_TYPE);
- }
- else
- {
- npcCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE);
- delete result2;
- }
- npcCreature->GetMotionMaster()->Initialize();
- if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn
- {
- npcCreature->setDeathState(JUST_DIED);
- npcCreature->Respawn();
- }
- npcCreature->SaveToDB();
- }
-
- PSendSysMessage(LANG_WAYPOINT_REMOVED);
- return true;
- } // del
-
- if(show == "move" && target)
- {
- PSendSysMessage("DEBUG: wp move, GUID: %u", lowguid);
-
- Player *chr = m_session->GetPlayer();
- Map *map = chr->GetMap();
- {
- // Get the creature for which we read the waypoint
- CreatureData const* data = objmgr.GetCreatureData(lowguid);
- if(!data)
- {
- PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
-
- Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT));
-
- // wpCreature
- Creature* wpCreature = NULL;
- // What to do:
- // Move the visual spawnpoint
- // Respawn the owner of the waypoints
- if( wpGuid != 0 )
- {
- wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT));
- wpCreature->DeleteFromDB();
- wpCreature->CleanupsBeforeDelete();
- wpCreature->AddObjectToRemoveList();
- // re-create
- Creature* wpCreature2 = new Creature;
- if (!wpCreature2->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, VISUAL_WAYPOINT, 0))
- {
- PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT);
- delete wpCreature2;
- return false;
- }
-
- wpCreature2->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation());
-
- if(!wpCreature2->IsPositionValid())
- {
- sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature2->GetGUIDLow(),wpCreature2->GetEntry(),wpCreature2->GetPositionX(),wpCreature2->GetPositionY());
- delete wpCreature2;
- return false;
- }
-
- wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
- // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
- wpCreature2->LoadFromDB(wpCreature2->GetDBTableGUIDLow(), map);
- map->Add(wpCreature2);
- //MapManager::Instance().GetMap(npcCreature->GetMapId())->Add(wpCreature2);
- }
-
- WaypointMgr.SetNodePosition(lowguid, point, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ());
-
- if(npcCreature)
- {
- npcCreature->GetMotionMaster()->Initialize();
- if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn
- {
- npcCreature->setDeathState(JUST_DIED);
- npcCreature->Respawn();
- }
- }
- PSendSysMessage(LANG_WAYPOINT_CHANGED);
- }
- return true;
- } // move
-
- // Create creature - npc that has the waypoint
- CreatureData const* data = objmgr.GetCreatureData(lowguid);
- if(!data)
- {
- PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
-
- // set in game textids not supported
- if( show == "textid1" || show == "textid2" || show == "textid3" ||
- show == "textid4" || show == "textid5" )
- {
- return false;
- }
-
- WaypointMgr.SetNodeText(lowguid, point, show_str, arg_str);
-
- Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT));
- if(npcCreature)
- {
- npcCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE);
- npcCreature->GetMotionMaster()->Initialize();
- if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn
- {
- npcCreature->setDeathState(JUST_DIED);
- npcCreature->Respawn();
- }
- }
- PSendSysMessage(LANG_WAYPOINT_CHANGED_NO, show_str);
-
- return true;
-}
-
-/**
- * .wp show info | on | off
- *
- * info -> User has selected a visual waypoint before
- *
- * info <GUID> <WPNUM> -> User did not select a visual waypoint and
- * provided the GUID of the NPC and the number of
- * the waypoint.
- *
- * on -> User has selected an NPC; all visual waypoints for this
- * NPC are added to the world
- *
- * on <GUID> -> User did not select an NPC - instead the GUID of the
- * NPC is provided. All visual waypoints for this NPC
- * are added from the world.
- *
- * off -> User has selected an NPC; all visual waypoints for this
- * NPC are removed from the world.
- *
- * on <GUID> -> User did not select an NPC - instead the GUID of the
- * NPC is provided. All visual waypoints for this NPC
- * are removed from the world.
- *
- *
- */
-bool ChatHandler::HandleWpShowCommand(const char* args)
-{
- sLog.outDebug("DEBUG: HandleWpShowCommand");
-
- if(!*args)
- return false;
-
- // first arg: on, off, first, last
- char* show_str = strtok((char*)args, " ");
- if (!show_str)
- {
- return false;
- }
- // second arg: GUID (optional, if a creature is selected)
- char* guid_str = strtok((char*)NULL, " ");
- sLog.outDebug("DEBUG: HandleWpShowCommand: show_str: %s guid_str: %s", show_str, guid_str);
- //if (!guid_str) {
- // return false;
- //}
-
- // Did user provide a GUID
- // or did the user select a creature?
- // -> variable lowguid is filled with the GUID
- Creature* target = getSelectedCreature();
- // Did player provide a GUID?
- if (!guid_str)
- {
- sLog.outDebug("DEBUG: HandleWpShowCommand: !guid_str");
- // No GUID provided
- // -> Player must have selected a creature
-
- if(!target)
- {
- SendSysMessage(LANG_SELECT_CREATURE);
- SetSentErrorMessage(true);
- return false;
- }
- }
- else
- {
- sLog.outDebug("DEBUG: HandleWpShowCommand: GUID provided");
- // GUID provided
- // Warn if player also selected a creature
- // -> Creature selection is ignored <-
- if(target)
- {
- SendSysMessage(LANG_WAYPOINT_CREATSELECTED);
- }
-
- uint32 lowguid = atoi((char*)guid_str);
-
- CreatureData const* data = objmgr.GetCreatureData(lowguid);
- if(!data)
- {
- PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
-
- target = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,data->id,HIGHGUID_UNIT));
-
- if(!target)
- {
- PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
- }
-
- uint32 lowguid = target->GetDBTableGUIDLow();
-
- std::string show = show_str;
- uint32 Maxpoint;
-
- sLog.outDebug("DEBUG: HandleWpShowCommand: lowguid: %u show: %s", lowguid, show_str);
-
- // Show info for the selected waypoint
- if(show == "info")
- {
- PSendSysMessage("DEBUG: wp info, GUID: %u", lowguid);
-
- // Check if the user did specify a visual waypoint
- if( target->GetEntry() != VISUAL_WAYPOINT )
- {
- PSendSysMessage(LANG_WAYPOINT_VP_SELECT);
- SetSentErrorMessage(true);
- return false;
- }
-
- //PSendSysMessage("wp on, GUID: %u", lowguid);
-
- //pCreature->GetPositionX();
-
- QueryResult *result =
- WorldDatabase.PQuery( "SELECT id, point, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5, model1, model2 FROM creature_movement WHERE wpguid = %u",
- target->GetGUIDLow() );
- if(!result)
- {
- // Since we compare float values, we have to deal with
- // some difficulties.
- // Here we search for all waypoints that only differ in one from 1 thousand
- // (0.001) - There is no other way to compare C++ floats with mySQL floats
- // See also: http://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html
- const char* maxDIFF = "0.01";
- PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, target->GetGUID());
-
- result = WorldDatabase.PQuery( "SELECT id, point, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5, model1, model2 FROM creature_movement WHERE (abs(position_x - %f) <= %s ) and (abs(position_y - %f) <= %s ) and (abs(position_z - %f) <= %s )",
- target->GetPositionX(), maxDIFF, target->GetPositionY(), maxDIFF, target->GetPositionZ(), maxDIFF);
- if(!result)
- {
- PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
- }
- do
- {
- Field *fields = result->Fetch();
- uint32 creGUID = fields[0].GetUInt32();
- uint32 point = fields[1].GetUInt32();
- int waittime = fields[2].GetUInt32();
- uint32 emote = fields[3].GetUInt32();
- uint32 spell = fields[4].GetUInt32();
- uint32 textid[MAX_WAYPOINT_TEXT];
- for(int i = 0; i < MAX_WAYPOINT_TEXT; ++i)
- textid[i] = fields[5+i].GetUInt32();
- uint32 model1 = fields[10].GetUInt32();
- uint32 model2 = fields[11].GetUInt32();
-
- // Get the creature for which we read the waypoint
- Creature* wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(creGUID,VISUAL_WAYPOINT,HIGHGUID_UNIT));
-
- PSendSysMessage(LANG_WAYPOINT_INFO_TITLE, point, (wpCreature ? wpCreature->GetName() : "<not found>"), creGUID);
- PSendSysMessage(LANG_WAYPOINT_INFO_WAITTIME, waittime);
- PSendSysMessage(LANG_WAYPOINT_INFO_MODEL, 1, model1);
- PSendSysMessage(LANG_WAYPOINT_INFO_MODEL, 2, model2);
- PSendSysMessage(LANG_WAYPOINT_INFO_EMOTE, emote);
- PSendSysMessage(LANG_WAYPOINT_INFO_SPELL, spell);
- for(int i = 0; i < MAX_WAYPOINT_TEXT; ++i)
- PSendSysMessage(LANG_WAYPOINT_INFO_TEXT, i+1, textid[i], (textid[i] ? GetTrinityString(textid[i]) : ""));
-
- }while( result->NextRow() );
- // Cleanup memory
- delete result;
- return true;
- }
-
- if(show == "on")
- {
- PSendSysMessage("DEBUG: wp on, GUID: %u", lowguid);
-
- QueryResult *result = WorldDatabase.PQuery( "SELECT point, position_x,position_y,position_z FROM creature_movement WHERE id = '%u'",lowguid);
- if(!result)
- {
- PSendSysMessage(LANG_WAYPOINT_NOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
- // Delete all visuals for this NPC
- QueryResult *result2 = WorldDatabase.PQuery( "SELECT wpguid FROM creature_movement WHERE id = '%u' and wpguid <> 0", lowguid);
- if(result2)
- {
- bool hasError = false;
- do
- {
- Field *fields = result2->Fetch();
- uint32 wpguid = fields[0].GetUInt32();
- Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpguid,VISUAL_WAYPOINT,HIGHGUID_UNIT));
-
- if(!pCreature)
- {
- PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, wpguid);
- hasError = true;
- WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", wpguid);
- }
- else
- {
- pCreature->DeleteFromDB();
- pCreature->CleanupsBeforeDelete();
- pCreature->AddObjectToRemoveList();
- }
-
- }while( result2->NextRow() );
- delete result2;
- if( hasError )
- {
- PSendSysMessage(LANG_WAYPOINT_TOOFAR1);
- PSendSysMessage(LANG_WAYPOINT_TOOFAR2);
- PSendSysMessage(LANG_WAYPOINT_TOOFAR3);
- }
- }
-
- do
- {
- Field *fields = result->Fetch();
- uint32 point = fields[0].GetUInt32();
- float x = fields[1].GetFloat();
- float y = fields[2].GetFloat();
- float z = fields[3].GetFloat();
-
- uint32 id = VISUAL_WAYPOINT;
-
- Player *chr = m_session->GetPlayer();
- Map *map = chr->GetMap();
- float o = chr->GetOrientation();
-
- Creature* wpCreature = new Creature;
- if (!wpCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, id, 0))
- {
- PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id);
- delete wpCreature;
- delete result;
- return false;
- }
-
- wpCreature->Relocate(x, y, z, o);
-
- if(!wpCreature->IsPositionValid())
- {
- sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature->GetGUIDLow(),wpCreature->GetEntry(),wpCreature->GetPositionX(),wpCreature->GetPositionY());
- delete wpCreature;
- delete result;
- return false;
- }
-
- wpCreature->SetVisibility(VISIBILITY_OFF);
- sLog.outDebug("DEBUG: UPDATE creature_movement SET wpguid = '%u");
- // set "wpguid" column to the visual waypoint
- WorldDatabase.PExecuteLog("UPDATE creature_movement SET wpguid = '%u' WHERE id = '%u' and point = '%u'", wpCreature->GetGUIDLow(), lowguid, point);
-
- wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
- // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
- wpCreature->LoadFromDB(wpCreature->GetDBTableGUIDLow(),map);
- map->Add(wpCreature);
- //MapManager::Instance().GetMap(wpCreature->GetMapId())->Add(wpCreature);
- }while( result->NextRow() );
-
- // Cleanup memory
- delete result;
- return true;
- }
-
- if(show == "first")
- {
- PSendSysMessage("DEBUG: wp first, GUID: %u", lowguid);
-
- QueryResult *result = WorldDatabase.PQuery( "SELECT position_x,position_y,position_z FROM creature_movement WHERE point='1' AND id = '%u'",lowguid);
- if(!result)
- {
- PSendSysMessage(LANG_WAYPOINT_NOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
-
- Field *fields = result->Fetch();
- float x = fields[0].GetFloat();
- float y = fields[1].GetFloat();
- float z = fields[2].GetFloat();
- uint32 id = VISUAL_WAYPOINT;
-
- Player *chr = m_session->GetPlayer();
- float o = chr->GetOrientation();
- Map *map = chr->GetMap();
-
- Creature* pCreature = new Creature;
- if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT),map, id, 0))
- {
- PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id);
- delete pCreature;
- delete result;
- return false;
- }
-
- pCreature->Relocate(x, y, z, o);
-
- if(!pCreature->IsPositionValid())
- {
- sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
- delete pCreature;
- delete result;
- return false;
- }
-
- pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
- pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), map);
- map->Add(pCreature);
- //player->PlayerTalkClass->SendPointOfInterest(x, y, 6, 6, 0, "First Waypoint");
-
- // Cleanup memory
- delete result;
- return true;
- }
-
- if(show == "last")
- {
- PSendSysMessage("DEBUG: wp last, GUID: %u", lowguid);
-
- QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM creature_movement WHERE id = '%u'",lowguid);
- if( result )
- {
- Maxpoint = (*result)[0].GetUInt32();
-
- delete result;
- }
- else
- Maxpoint = 0;
-
- result = WorldDatabase.PQuery( "SELECT position_x,position_y,position_z FROM creature_movement WHERE point ='%u' AND id = '%u'",Maxpoint, lowguid);
- if(!result)
- {
- PSendSysMessage(LANG_WAYPOINT_NOTFOUNDLAST, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
- Field *fields = result->Fetch();
- float x = fields[0].GetFloat();
- float y = fields[1].GetFloat();
- float z = fields[2].GetFloat();
- uint32 id = VISUAL_WAYPOINT;
-
- Player *chr = m_session->GetPlayer();
- float o = chr->GetOrientation();
- Map *map = chr->GetMap();
-
- Creature* pCreature = new Creature;
- if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, id, 0))
- {
- PSendSysMessage(LANG_WAYPOINT_NOTCREATED, id);
- delete pCreature;
- delete result;
- return false;
- }
-
- pCreature->Relocate(x, y, z, o);
-
- if(!pCreature->IsPositionValid())
- {
- sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
- delete pCreature;
- delete result;
- return false;
- }
-
- pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
- pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), map);
- map->Add(pCreature);
- //player->PlayerTalkClass->SendPointOfInterest(x, y, 6, 6, 0, "Last Waypoint");
- // Cleanup memory
- delete result;
- return true;
- }
-
- if(show == "off")
- {
- QueryResult *result = WorldDatabase.PQuery("SELECT guid FROM creature WHERE id = '%d'", VISUAL_WAYPOINT);
- if(!result)
- {
- SendSysMessage(LANG_WAYPOINT_VP_NOTFOUND);
- SetSentErrorMessage(true);
- return false;
- }
- bool hasError = false;
- do
- {
- Field *fields = result->Fetch();
- uint32 guid = fields[0].GetUInt32();
- Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(guid,VISUAL_WAYPOINT,HIGHGUID_UNIT));
-
- //Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid);
-
- if(!pCreature)
- {
- PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, guid);
- hasError = true;
- WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", guid);
- }
- else
- {
- pCreature->DeleteFromDB();
- pCreature->CleanupsBeforeDelete();
- pCreature->AddObjectToRemoveList();
- }
- }while(result->NextRow());
- // set "wpguid" column to "empty" - no visual waypoint spawned
- WorldDatabase.PExecuteLog("UPDATE creature_movement SET wpguid = '0'");
-
- if( hasError )
- {
- PSendSysMessage(LANG_WAYPOINT_TOOFAR1);
- PSendSysMessage(LANG_WAYPOINT_TOOFAR2);
- PSendSysMessage(LANG_WAYPOINT_TOOFAR3);
- }
-
- SendSysMessage(LANG_WAYPOINT_VP_ALLREMOVED);
- // Cleanup memory
- delete result;
-
- return true;
- }
-
- PSendSysMessage("DEBUG: wpshow - no valid command found");
-
- return true;
-} // HandleWpShowCommand
-
-bool ChatHandler::HandleWpExportCommand(const char *args)
-{
- if(!*args)
- return false;
-
- // Next arg is: <GUID> <ARGUMENT>
-
- // Did user provide a GUID
- // or did the user select a creature?
- // -> variable lowguid is filled with the GUID of the NPC
- uint32 lowguid = 0;
- Creature* target = getSelectedCreature();
- char* arg_str = NULL;
- if (target)
- {
- if (target->GetEntry() != VISUAL_WAYPOINT)
- lowguid = target->GetGUIDLow();
- else
- {
- QueryResult *result = WorldDatabase.PQuery( "SELECT id FROM creature_movement WHERE wpguid = %u LIMIT 1", target->GetGUIDLow() );
- if (!result)
- {
- PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, target->GetGUIDLow());
- return true;
- }
- Field *fields = result->Fetch();
- lowguid = fields[0].GetUInt32();;
- delete result;
- }
-
- arg_str = strtok((char*)args, " ");
- }
- else
- {
- // user provided <GUID>
- char* guid_str = strtok((char*)args, " ");
- if( !guid_str )
- {
- SendSysMessage(LANG_WAYPOINT_NOGUID);
- return false;
- }
- lowguid = atoi((char*)guid_str);
-
- arg_str = strtok((char*)NULL, " ");
- }
-
- if( !arg_str)
- {
- PSendSysMessage(LANG_WAYPOINT_ARGUMENTREQ, "export");
- return false;
- }
-
- PSendSysMessage("DEBUG: wp export, GUID: %u", lowguid);
-
- QueryResult *result = WorldDatabase.PQuery(
- // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- "SELECT point, position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5, id FROM creature_movement WHERE id = '%u' ORDER BY point", lowguid );
-
- if (!result)
- {
- PSendSysMessage(LANG_WAYPOINT_NOTHINGTOEXPORT);
- SetSentErrorMessage(true);
- return false;
- }
-
- std::ofstream outfile;
- outfile.open (arg_str);
-
- do
- {
- Field *fields = result->Fetch();
-
- outfile << "INSERT INTO creature_movement ";
- outfile << "( id, point, position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5 ) VALUES ";
-
- outfile << "( ";
- outfile << fields[15].GetUInt32(); // id
- outfile << ", ";
- outfile << fields[0].GetUInt32(); // point
- outfile << ", ";
- outfile << fields[1].GetFloat(); // position_x
- outfile << ", ";
- outfile << fields[2].GetFloat(); // position_y
- outfile << ", ";
- outfile << fields[3].GetUInt32(); // position_z
- outfile << ", ";
- outfile << fields[4].GetUInt32(); // orientation
- outfile << ", ";
- outfile << fields[5].GetUInt32(); // model1
- outfile << ", ";
- outfile << fields[6].GetUInt32(); // model2
- outfile << ", ";
- outfile << fields[7].GetUInt16(); // waittime
- outfile << ", ";
- outfile << fields[8].GetUInt32(); // emote
- outfile << ", ";
- outfile << fields[9].GetUInt32(); // spell
- outfile << ", ";
- outfile << fields[10].GetUInt32(); // textid1
- outfile << ", ";
- outfile << fields[11].GetUInt32(); // textid2
- outfile << ", ";
- outfile << fields[12].GetUInt32(); // textid3
- outfile << ", ";
- outfile << fields[13].GetUInt32(); // textid4
- outfile << ", ";
- outfile << fields[14].GetUInt32(); // textid5
- outfile << ");\n ";
-
- } while( result->NextRow() );
- delete result;
-
- PSendSysMessage(LANG_WAYPOINT_EXPORTED);
- outfile.close();
-
- return true;
-}
-
-bool ChatHandler::HandleWpImportCommand(const char *args)
-{
- if(!*args)
- return false;
-
- char* arg_str = strtok((char*)args, " ");
- if (!arg_str)
- return false;
-
- std::string line;
- std::ifstream infile (arg_str);
- if (infile.is_open())
- {
- while (! infile.eof() )
- {
- getline (infile,line);
- //cout << line << endl;
- QueryResult *result = WorldDatabase.Query(line.c_str());
- delete result;
- }
- infile.close();
- }
- PSendSysMessage(LANG_WAYPOINT_IMPORTED);
-
- return true;
-}
-
-//rename characters
-bool ChatHandler::HandleRenameCommand(const char* args)
-{
- Player* target = NULL;
- uint64 targetGUID = 0;
- std::string oldname;
-
- char* px = strtok((char*)args, " ");
-
- if(px)
- {
- oldname = px;
-
- if(!normalizePlayerName(oldname))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- target = objmgr.GetPlayer(oldname.c_str());
-
- if (!target)
- targetGUID = objmgr.GetPlayerGUIDByName(oldname);
- }
-
- if(!target && !targetGUID)
- {
- target = getSelectedPlayer();
- }
-
- if(!target && !targetGUID)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- if(target)
- {
- PSendSysMessage(LANG_RENAME_PLAYER, target->GetName());
- target->SetAtLoginFlag(AT_LOGIN_RENAME);
- CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '1' WHERE guid = '%u'", target->GetGUIDLow());
- }
- else
- {
- PSendSysMessage(LANG_RENAME_PLAYER_GUID, oldname.c_str(), GUID_LOPART(targetGUID));
- CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '1' WHERE guid = '%u'", GUID_LOPART(targetGUID));
- }
-
- return true;
-}
-
-//spawn go
-bool ChatHandler::HandleGameObjectCommand(const char* args)
-{
- if (!*args)
- return false;
-
- char* pParam1 = strtok((char*)args, " ");
- if (!pParam1)
- return false;
-
- uint32 id = atoi((char*)pParam1);
- if(!id)
- return false;
-
- char* spawntimeSecs = strtok(NULL, " ");
-
- const GameObjectInfo *goI = objmgr.GetGameObjectInfo(id);
-
- if (!goI)
- {
- PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id);
- SetSentErrorMessage(true);
- return false;
- }
-
- Player *chr = m_session->GetPlayer();
- float x = float(chr->GetPositionX());
- float y = float(chr->GetPositionY());
- float z = float(chr->GetPositionZ());
- float o = float(chr->GetOrientation());
- Map *map = chr->GetMap();
-
- float rot2 = sin(o/2);
- float rot3 = cos(o/2);
-
- GameObject* pGameObj = new GameObject;
- uint32 db_lowGUID = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT);
-
- if(!pGameObj->Create(db_lowGUID, goI->id, map, x, y, z, o, 0, 0, rot2, rot3, 0, 1))
- {
- delete pGameObj;
- return false;
- }
-
- if( spawntimeSecs )
- {
- uint32 value = atoi((char*)spawntimeSecs);
- pGameObj->SetRespawnTime(value);
- //sLog.outDebug("*** spawntimeSecs: %d", value);
- }
-
- // fill the gameobject data and save to the db
- pGameObj->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
-
- // this will generate a new guid if the object is in an instance
- if(!pGameObj->LoadFromDB(db_lowGUID, map))
- {
- delete pGameObj;
- return false;
- }
-
- sLog.outDebug(GetTrinityString(LANG_GAMEOBJECT_CURRENT), goI->name, db_lowGUID, x, y, z, o);
-
- map->Add(pGameObj);
-
- // TODO: is it really necessary to add both the real and DB table guid here ?
- objmgr.AddGameobjectToGrid(db_lowGUID, objmgr.GetGOData(db_lowGUID));
-
- PSendSysMessage(LANG_GAMEOBJECT_ADD,id,goI->name,db_lowGUID,x,y,z);
- return true;
-}
-
-//show animation
-bool ChatHandler::HandleAnimCommand(const char* args)
-{
- if (!*args)
- return false;
-
- uint32 anim_id = atoi((char*)args);
- m_session->GetPlayer()->HandleEmoteCommand(anim_id);
- return true;
-}
-
-//change standstate
-bool ChatHandler::HandleStandStateCommand(const char* args)
-{
- if (!*args)
- return false;
-
- uint32 anim_id = atoi((char*)args);
- m_session->GetPlayer( )->SetUInt32Value( UNIT_NPC_EMOTESTATE , anim_id );
-
- return true;
-}
-
-bool ChatHandler::HandleAddHonorCommand(const char* args)
-{
- if (!*args)
- return false;
-
- Player *target = getSelectedPlayer();
- if(!target)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- uint32 amount = (uint32)atoi(args);
- target->RewardHonor(NULL, 1, amount);
- return true;
-}
-
-bool ChatHandler::HandleHonorAddKillCommand(const char* /*args*/)
-{
- Unit *target = getSelectedUnit();
- if(!target)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- m_session->GetPlayer()->RewardHonor(target, 1);
- return true;
-}
-
-bool ChatHandler::HandleUpdateHonorFieldsCommand(const char* /*args*/)
-{
- Player *target = getSelectedPlayer();
- if(!target)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- target->UpdateHonorFields();
- return true;
-}
-
-bool ChatHandler::HandleLookupEventCommand(const char* args)
-{
- if(!*args)
- return false;
-
- std::string namepart = args;
- std::wstring wnamepart;
-
- // converting string that we try to find to lower case
- if(!Utf8toWStr(namepart,wnamepart))
- return false;
-
- wstrToLower(wnamepart);
-
- uint32 counter = 0;
-
- GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap();
- GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
-
- for(uint32 id = 0; id < events.size(); ++id )
- {
- GameEventData const& eventData = events[id];
-
- std::string descr = eventData.description;
- if(descr.empty())
- continue;
-
- if (Utf8FitTo(descr, wnamepart))
- {
- char const* active = activeEvents.find(id) != activeEvents.end() ? GetTrinityString(LANG_ACTIVE) : "";
-
- if(m_session)
- PSendSysMessage(LANG_EVENT_ENTRY_LIST_CHAT,id,id,eventData.description.c_str(),active );
- else
- PSendSysMessage(LANG_EVENT_ENTRY_LIST_CONSOLE,id,eventData.description.c_str(),active );
-
- ++counter;
- }
- }
-
- if (counter==0)
- SendSysMessage(LANG_NOEVENTFOUND);
-
- return true;
-}
-
-bool ChatHandler::HandleEventActiveListCommand(const char* args)
-{
- uint32 counter = 0;
-
- GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap();
- GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
-
- char const* active = GetTrinityString(LANG_ACTIVE);
-
- for(GameEvent::ActiveEvents::const_iterator itr = activeEvents.begin(); itr != activeEvents.end(); ++itr )
- {
- uint32 event_id = *itr;
- GameEventData const& eventData = events[event_id];
-
- if(m_session)
- PSendSysMessage(LANG_EVENT_ENTRY_LIST_CHAT,event_id,event_id,eventData.description.c_str(),active );
- else
- PSendSysMessage(LANG_EVENT_ENTRY_LIST_CONSOLE,event_id,eventData.description.c_str(),active );
-
- ++counter;
- }
-
- if (counter==0)
- SendSysMessage(LANG_NOEVENTFOUND);
-
- return true;
-}
-
-bool ChatHandler::HandleEventInfoCommand(const char* args)
-{
- if(!*args)
- return false;
-
- // id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r
- char* cId = extractKeyFromLink((char*)args,"Hgameevent");
- if(!cId)
- return false;
-
- uint32 event_id = atoi(cId);
-
- GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap();
-
- if(event_id >=events.size())
- {
- SendSysMessage(LANG_EVENT_NOT_EXIST);
- SetSentErrorMessage(true);
- return false;
- }
-
- GameEventData const& eventData = events[event_id];
- if(!eventData.isValid())
- {
- SendSysMessage(LANG_EVENT_NOT_EXIST);
- SetSentErrorMessage(true);
- return false;
- }
-
- GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
- bool active = activeEvents.find(event_id) != activeEvents.end();
- char const* activeStr = active ? GetTrinityString(LANG_ACTIVE) : "";
-
- std::string startTimeStr = TimeToTimestampStr(eventData.start);
- std::string endTimeStr = TimeToTimestampStr(eventData.end);
-
- uint32 delay = gameeventmgr.NextCheck(event_id);
- time_t nextTime = time(NULL)+delay;
- std::string nextStr = nextTime >= eventData.start && nextTime < eventData.end ? TimeToTimestampStr(time(NULL)+delay) : "-";
-
- std::string occurenceStr = secsToTimeString(eventData.occurence * MINUTE);
- std::string lengthStr = secsToTimeString(eventData.length * MINUTE);
-
- PSendSysMessage(LANG_EVENT_INFO,event_id,eventData.description.c_str(),activeStr,
- startTimeStr.c_str(),endTimeStr.c_str(),occurenceStr.c_str(),lengthStr.c_str(),
- nextStr.c_str());
- return true;
-}
-
-bool ChatHandler::HandleEventStartCommand(const char* args)
-{
- if(!*args)
- return false;
-
- // id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r
- char* cId = extractKeyFromLink((char*)args,"Hgameevent");
- if(!cId)
- return false;
-
- int32 event_id = atoi(cId);
-
- GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap();
-
- if(event_id < 1 || event_id >=events.size())
- {
- SendSysMessage(LANG_EVENT_NOT_EXIST);
- SetSentErrorMessage(true);
- return false;
- }
-
- GameEventData const& eventData = events[event_id];
- if(!eventData.isValid())
- {
- SendSysMessage(LANG_EVENT_NOT_EXIST);
- SetSentErrorMessage(true);
- return false;
- }
-
- GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
- if(activeEvents.find(event_id) != activeEvents.end())
- {
- PSendSysMessage(LANG_EVENT_ALREADY_ACTIVE,event_id);
- SetSentErrorMessage(true);
- return false;
- }
-
- gameeventmgr.StartEvent(event_id,true);
- return true;
-}
-
-bool ChatHandler::HandleEventStopCommand(const char* args)
-{
- if(!*args)
- return false;
-
- // id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r
- char* cId = extractKeyFromLink((char*)args,"Hgameevent");
- if(!cId)
- return false;
-
- int32 event_id = atoi(cId);
-
- GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap();
-
- if(event_id < 1 || event_id >=events.size())
- {
- SendSysMessage(LANG_EVENT_NOT_EXIST);
- SetSentErrorMessage(true);
- return false;
- }
-
- GameEventData const& eventData = events[event_id];
- if(!eventData.isValid())
- {
- SendSysMessage(LANG_EVENT_NOT_EXIST);
- SetSentErrorMessage(true);
- return false;
- }
-
- GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
-
- if(activeEvents.find(event_id) == activeEvents.end())
- {
- PSendSysMessage(LANG_EVENT_NOT_ACTIVE,event_id);
- SetSentErrorMessage(true);
- return false;
- }
-
- gameeventmgr.StopEvent(event_id,true);
- return true;
-}
-
-bool ChatHandler::HandleCombatStopCommand(const char* args)
-{
- Player *player;
-
- if(*args)
- {
- std::string playername = args;
-
- if(!normalizePlayerName(playername))
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- player = objmgr.GetPlayer(playername.c_str());
-
- if(!player)
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
- }
- else
- {
- player = getSelectedPlayer();
-
- if (!player)
- player = m_session->GetPlayer();
- }
-
- player->CombatStop();
- player->getHostilRefManager().deleteReferences();
- return true;
-}
-
-bool ChatHandler::HandleLearnAllCraftsCommand(const char* /*args*/)
-{
- uint32 classmask = m_session->GetPlayer()->getClassMask();
-
- for (uint32 i = 0; i < sSkillLineStore.GetNumRows(); ++i)
- {
- SkillLineEntry const *skillInfo = sSkillLineStore.LookupEntry(i);
- if( !skillInfo )
- continue;
-
- if( skillInfo->categoryId == SKILL_CATEGORY_PROFESSION || skillInfo->categoryId == SKILL_CATEGORY_SECONDARY )
- {
- for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j)
- {
- SkillLineAbilityEntry const *skillLine = sSkillLineAbilityStore.LookupEntry(j);
- if( !skillLine )
- continue;
-
- // skip racial skills
- if( skillLine->racemask != 0 )
- continue;
-
- // skip wrong class skills
- if( skillLine->classmask && (skillLine->classmask & classmask) == 0)
- continue;
-
- if( skillLine->skillId != i || skillLine->forward_spellid )
- continue;
-
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->spellId);
- if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false))
- continue;
-
- m_session->GetPlayer()->learnSpell(skillLine->spellId);
- }
- }
- }
-
- SendSysMessage(LANG_COMMAND_LEARN_ALL_CRAFT);
- return true;
-}
-
-bool ChatHandler::HandleLearnAllRecipesCommand(const char* args)
-{
- // Learns all recipes of specified profession and sets skill to max
- // Example: .learn all_recipes enchanting
-
- Player* target = getSelectedPlayer();
- if( !target )
- {
- SendSysMessage(LANG_PLAYER_NOT_FOUND);
- return false;
- }
-
- if (!*args)
- return false;
-
- std::wstring wnamepart;
-
- if(!Utf8toWStr(args,wnamepart))
- return false;
-
- uint32 counter = 0; // Counter for figure out that we found smth.
-
- // converting string that we try to find to lower case
- wstrToLower( wnamepart );
-
- uint32 classmask = m_session->GetPlayer()->getClassMask();
-
- for (uint32 i = 0; i < sSkillLineStore.GetNumRows(); ++i)
- {
- SkillLineEntry const *skillInfo = sSkillLineStore.LookupEntry(i);
- if( !skillInfo )
- continue;
-
- if( skillInfo->categoryId != SKILL_CATEGORY_PROFESSION &&
- skillInfo->categoryId != SKILL_CATEGORY_SECONDARY )
- continue;
-
- int loc = m_session->GetSessionDbcLocale();
- std::string name = skillInfo->name[loc];
-
- if(Utf8FitTo(name, wnamepart))
- {
- for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j)
- {
- SkillLineAbilityEntry const *skillLine = sSkillLineAbilityStore.LookupEntry(j);
- if( !skillLine )
- continue;
-
- if( skillLine->skillId != i || skillLine->forward_spellid )
- continue;
-
- // skip racial skills
- if( skillLine->racemask != 0 )
- continue;
-
- // skip wrong class skills
- if( skillLine->classmask && (skillLine->classmask & classmask) == 0)
- continue;
-
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->spellId);
- if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false))
- continue;
-
- if( !target->HasSpell(spellInfo->Id) )
- m_session->GetPlayer()->learnSpell(skillLine->spellId);
- }
-
- uint16 maxLevel = target->GetPureMaxSkillValue(skillInfo->id);
- target->SetSkill(skillInfo->id, maxLevel, maxLevel);
- PSendSysMessage(LANG_COMMAND_LEARN_ALL_RECIPES, name.c_str());
- return true;
- }
- }
-
- return false;
-}
-
-bool ChatHandler::HandleLookupPlayerIpCommand(const char* args)
-{
-
- if (!*args)
- return false;
-
- std::string ip = strtok ((char*)args, " ");
- char* limit_str = strtok (NULL, " ");
- int32 limit = limit_str ? atoi (limit_str) : -1;
-
- loginDatabase.escape_string (ip);
-
- QueryResult* result = loginDatabase.PQuery ("SELECT id,username FROM account WHERE last_ip = '%s'", ip.c_str ());
-
- return LookupPlayerSearchCommand (result,limit);
-}
-
-bool ChatHandler::HandleLookupPlayerAccountCommand(const char* args)
-{
- if (!*args)
- return false;
-
- std::string account = strtok ((char*)args, " ");
- char* limit_str = strtok (NULL, " ");
- int32 limit = limit_str ? atoi (limit_str) : -1;
-
- if (!AccountMgr::normilizeString (account))
- return false;
-
- loginDatabase.escape_string (account);
-
- QueryResult* result = loginDatabase.PQuery ("SELECT id,username FROM account WHERE username = '%s'", account.c_str ());
-
- return LookupPlayerSearchCommand (result,limit);
-}
-
-bool ChatHandler::HandleLookupPlayerEmailCommand(const char* args)
-{
-
- if (!*args)
- return false;
-
- std::string email = strtok ((char*)args, " ");
- char* limit_str = strtok (NULL, " ");
- int32 limit = limit_str ? atoi (limit_str) : -1;
-
- loginDatabase.escape_string (email);
-
- QueryResult* result = loginDatabase.PQuery ("SELECT id,username FROM account WHERE email = '%s'", email.c_str ());
-
- return LookupPlayerSearchCommand (result,limit);
-}
-
-bool ChatHandler::LookupPlayerSearchCommand(QueryResult* result, int32 limit)
-{
- if(!result)
- {
- PSendSysMessage(LANG_NO_PLAYERS_FOUND);
- SetSentErrorMessage(true);
- return false;
- }
-
- int i =0;
- do
- {
- Field* fields = result->Fetch();
- uint32 acc_id = fields[0].GetUInt32();
- std::string acc_name = fields[1].GetCppString();
-
- QueryResult* chars = CharacterDatabase.PQuery("SELECT guid,name FROM characters WHERE account = '%u'", acc_id);
- if(chars)
- {
- PSendSysMessage(LANG_LOOKUP_PLAYER_ACCOUNT,acc_name.c_str(),acc_id);
-
- uint64 guid = 0;
- std::string name;
-
- do
- {
- Field* charfields = chars->Fetch();
- guid = charfields[0].GetUInt64();
- name = charfields[1].GetCppString();
-
- PSendSysMessage(LANG_LOOKUP_PLAYER_CHARACTER,name.c_str(),guid);
- ++i;
-
- } while( chars->NextRow() && ( limit == -1 || i < limit ) );
-
- delete chars;
- }
- } while(result->NextRow());
-
- delete result;
-
- return true;
-}
-
-/// Triggering corpses expire check in world
-bool ChatHandler::HandleServerCorpsesCommand(const char* /*args*/)
-{
- CorpsesErase();
- return true;
-}
-
-bool ChatHandler::HandleRepairitemsCommand(const char* /*args*/)
-{
- Player *target = getSelectedPlayer();
-
- if(!target)
- {
- PSendSysMessage(LANG_NO_CHAR_SELECTED);
- SetSentErrorMessage(true);
- return false;
- }
-
- // Repair items
- target->DurabilityRepairAll(false, 0, false);
-
- PSendSysMessage(LANG_YOU_REPAIR_ITEMS, target->GetName());
- if(needReportToTarget(target))
- ChatHandler(target).PSendSysMessage(LANG_YOUR_ITEMS_REPAIRED, GetName());
- return true;
-}
-
-bool ChatHandler::HandleNpcFollowCommand(const char* /*args*/)
-{
- Player *player = m_session->GetPlayer();
- Creature *creature = getSelectedCreature();
-
- if(!creature)
- {
- PSendSysMessage(LANG_SELECT_CREATURE);
- SetSentErrorMessage(true);
- return false;
- }
-
- // Follow player - Using pet's default dist and angle
- creature->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
-
- PSendSysMessage(LANG_CREATURE_FOLLOW_YOU_NOW, creature->GetName());
- return true;
-}
-
-bool ChatHandler::HandleNpcUnFollowCommand(const char* /*args*/)
-{
- Player *player = m_session->GetPlayer();
- Creature *creature = getSelectedCreature();
-
- if(!creature)
- {
- PSendSysMessage(LANG_SELECT_CREATURE);
- SetSentErrorMessage(true);
- return false;
- }
-
- if (creature->GetMotionMaster()->empty() ||
- creature->GetMotionMaster()->GetCurrentMovementGeneratorType ()!=TARGETED_MOTION_TYPE)
- {
- PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU);
- SetSentErrorMessage(true);
- return false;
- }
-
- TargetedMovementGenerator<Creature> const* mgen
- = static_cast<TargetedMovementGenerator<Creature> const*>((creature->GetMotionMaster()->top()));
-
- if(mgen->GetTarget()!=player)
- {
- PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU);
- SetSentErrorMessage(true);
- return false;
- }
-
- // reset movement
- creature->GetMotionMaster()->MovementExpired(true);
-
- PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU_NOW, creature->GetName());
- return true;
-}
-
-bool ChatHandler::HandleCreatePetCommand(const char* args)
-{
- Player *player = m_session->GetPlayer();
- Creature *creatureTarget = getSelectedCreature();
-
- if(!creatureTarget || creatureTarget->isPet() || creatureTarget->GetTypeId() == TYPEID_PLAYER)
- {
- PSendSysMessage(LANG_SELECT_CREATURE);
- SetSentErrorMessage(true);
- return false;
- }
-
- CreatureInfo const* cInfo = objmgr.GetCreatureTemplate(creatureTarget->GetEntry());
- // Creatures with family 0 crashes the server
- if(cInfo->family == 0)
- {
- PSendSysMessage("This creature cannot be tamed. (family id: 0).");
- SetSentErrorMessage(true);
- return false;
- }
-
- if(player->GetPetGUID())
- {
- PSendSysMessage("You already have a pet");
- SetSentErrorMessage(true);
- return false;
- }
-
- // Everything looks OK, create new pet
- Pet* pet = new Pet(HUNTER_PET);
-
- if(!pet->CreateBaseAtCreature(creatureTarget))
- {
- delete pet;
- PSendSysMessage("Error 1");
- return false;
- }
-
- creatureTarget->setDeathState(JUST_DIED);
- creatureTarget->RemoveCorpse();
- creatureTarget->SetHealth(0); // just for nice GM-mode view
-
- pet->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, player->GetGUID());
- pet->SetUInt64Value(UNIT_FIELD_CREATEDBY, player->GetGUID());
- pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, player->getFaction());
-
- if(!pet->InitStatsForLevel(creatureTarget->getLevel()))
- {
- sLog.outError("ERROR: InitStatsForLevel() in EffectTameCreature failed! Pet deleted.");
- PSendSysMessage("Error 2");
- return false;
- }
-
- // prepare visual effect for levelup
- pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel()-1);
-
- pet->GetCharmInfo()->SetPetNumber(objmgr.GeneratePetNumber(), true);
- // this enables pet details window (Shift+P)
- pet->AIM_Initialize();
- pet->InitPetCreateSpells();
- pet->SetHealth(pet->GetMaxHealth());
-
- MapManager::Instance().GetMap(pet->GetMapId(), pet)->Add((Creature*)pet);
-
- // visual effect for levelup
- pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel());
-
- player->SetPet(pet);
- pet->SavePetToDB(PET_SAVE_AS_CURRENT);
- player->PetSpellInitialize();
-
- return true;
-}
-
-bool ChatHandler::HandlePetLearnCommand(const char* args)
-{
- if(!*args)
- return false;
-
- Player *plr = m_session->GetPlayer();
- Pet *pet = plr->GetPet();
-
- if(!pet)
- {
- PSendSysMessage("You have no pet");
- SetSentErrorMessage(true);
- return false;
- }
-
- uint32 spellId = extractSpellIdFromLink((char*)args);
-
- if(!spellId || !sSpellStore.LookupEntry(spellId))
- return false;
-
- // Check if pet already has it
- if(pet->HasSpell(spellId))
- {
- PSendSysMessage("Pet already has spell: %u", spellId);
- SetSentErrorMessage(true);
- return false;
- }
-
- // Check if spell is valid
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId);
- if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo))
- {
- PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spellId);
- SetSentErrorMessage(true);
- return false;
- }
-
- pet->learnSpell(spellId);
-
- PSendSysMessage("Pet has learned spell %u", spellId);
- return true;
-}
-
-bool ChatHandler::HandlePetUnlearnCommand(const char *args)
-{
- if(!*args)
- return false;
-
- Player *plr = m_session->GetPlayer();
- Pet *pet = plr->GetPet();
-
- if(!pet)
- {
- PSendSysMessage("You have no pet");
- SetSentErrorMessage(true);
- return false;
- }
-
- uint32 spellId = extractSpellIdFromLink((char*)args);
-
- if(pet->HasSpell(spellId))
- pet->removeSpell(spellId);
- else
- PSendSysMessage("Pet doesn't have that spell");
-
- return true;
-}
-
-bool ChatHandler::HandlePetTpCommand(const char *args)
-{
- if(!*args)
- return false;
-
- Player *plr = m_session->GetPlayer();
- Pet *pet = plr->GetPet();
-
- if(!pet)
- {
- PSendSysMessage("You have no pet");
- SetSentErrorMessage(true);
- return false;
- }
-
- uint32 tp = atol(args);
-
- pet->SetTP(tp);
-
- PSendSysMessage("Pet's tp changed to %u", tp);
- return true;
-}
-
-bool ChatHandler::HandleActivateObjectCommand(const char *args)
-{
- if(!*args)
- return false;
-
- char* cId = extractKeyFromLink((char*)args,"Hgameobject");
- if(!cId)
- return false;
-
- uint32 lowguid = atoi(cId);
- if(!lowguid)
- return false;
-
- GameObject* obj = NULL;
-
- // by DB guid
- if (GameObjectData const* go_data = objmgr.GetGOData(lowguid))
- obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id);
-
- if(!obj)
- {
- PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid);
- SetSentErrorMessage(true);
- return false;
- }
-
- // Activate
- obj->SetLootState(GO_READY);
- obj->UseDoorOrButton(10000);
-
- PSendSysMessage("Object activated!");
-
- return true;
-}
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ *
+ * 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
+ */
+
+#include "Common.h"
+#include "Database/DatabaseEnv.h"
+#include "WorldPacket.h"
+#include "WorldSession.h"
+#include "World.h"
+#include "ObjectMgr.h"
+#include "Player.h"
+#include "Item.h"
+#include "GameObject.h"
+#include "Opcodes.h"
+#include "Chat.h"
+#include "ObjectAccessor.h"
+#include "MapManager.h"
+#include "Language.h"
+#include "World.h"
+#include "GameEvent.h"
+#include "SpellMgr.h"
+#include "AccountMgr.h"
+#include "GMTicketMgr.h"
+#include "WaypointManager.h"
+#include "Util.h"
+#include <cctype>
+#include <iostream>
+#include <fstream>
+#include <map>
+#include "GlobalEvents.h"
+
+#include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand
+
+static uint32 ReputationRankStrIndex[MAX_REPUTATION_RANK] =
+{
+ LANG_REP_HATED, LANG_REP_HOSTILE, LANG_REP_UNFRIENDLY, LANG_REP_NEUTRAL,
+ LANG_REP_FRIENDLY, LANG_REP_HONORED, LANG_REP_REVERED, LANG_REP_EXALTED
+};
+
+//mute player for some times
+bool ChatHandler::HandleMuteCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ char *charname = strtok((char*)args, " ");
+ if (!charname)
+ return false;
+
+ std::string cname = charname;
+
+ char *timetonotspeak = strtok(NULL, " ");
+ if(!timetonotspeak)
+ return false;
+
+ uint32 notspeaktime = (uint32) atoi(timetonotspeak);
+
+ if(!normalizePlayerName(cname))
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint64 guid = objmgr.GetPlayerGUIDByName(cname.c_str());
+ if(!guid)
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Player *chr = objmgr.GetPlayer(guid);
+
+ // check security
+ uint32 account_id = 0;
+ uint32 security = 0;
+
+ if (chr)
+ {
+ account_id = chr->GetSession()->GetAccountId();
+ security = chr->GetSession()->GetSecurity();
+ }
+ else
+ {
+ account_id = objmgr.GetPlayerAccountIdByGUID(guid);
+ security = accmgr.GetSecurity(account_id);
+ }
+
+ if(m_session && security >= m_session->GetSecurity())
+ {
+ SendSysMessage(LANG_YOURS_SECURITY_IS_LOW);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ time_t mutetime = time(NULL) + notspeaktime*60;
+
+ if (chr)
+ chr->GetSession()->m_muteTime = mutetime;
+
+ loginDatabase.PExecute("UPDATE account SET mutetime = " I64FMTD " WHERE id = '%u'",uint64(mutetime), account_id );
+
+ if(chr)
+ ChatHandler(chr).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notspeaktime);
+
+ PSendSysMessage(LANG_YOU_DISABLE_CHAT, cname.c_str(), notspeaktime);
+
+ return true;
+}
+
+//unmute player
+bool ChatHandler::HandleUnmuteCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ char *charname = strtok((char*)args, " ");
+ if (!charname)
+ return false;
+
+ std::string cname = charname;
+
+ if(!normalizePlayerName(cname))
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint64 guid = objmgr.GetPlayerGUIDByName(cname.c_str());
+ if(!guid)
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Player *chr = objmgr.GetPlayer(guid);
+
+ // check security
+ uint32 account_id = 0;
+ uint32 security = 0;
+
+ if (chr)
+ {
+ account_id = chr->GetSession()->GetAccountId();
+ security = chr->GetSession()->GetSecurity();
+ }
+ else
+ {
+ account_id = objmgr.GetPlayerAccountIdByGUID(guid);
+ security = accmgr.GetSecurity(account_id);
+ }
+
+ if(m_session && security >= m_session->GetSecurity())
+ {
+ SendSysMessage(LANG_YOURS_SECURITY_IS_LOW);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if (chr)
+ {
+ if(chr->CanSpeak())
+ {
+ SendSysMessage(LANG_CHAT_ALREADY_ENABLED);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ chr->GetSession()->m_muteTime = 0;
+ }
+
+ loginDatabase.PExecute("UPDATE account SET mutetime = '0' WHERE id = '%u'", account_id );
+
+ if(chr)
+ ChatHandler(chr).PSendSysMessage(LANG_YOUR_CHAT_ENABLED);
+
+ PSendSysMessage(LANG_YOU_ENABLE_CHAT, cname.c_str());
+ return true;
+}
+
+bool ChatHandler::HandleTargetObjectCommand(const char* args)
+{
+ Player* pl = m_session->GetPlayer();
+ QueryResult *result;
+ GameEvent::ActiveEvents const& activeEventsList = gameeventmgr.GetActiveEventList();
+ if(*args)
+ {
+ int32 id = atoi((char*)args);
+ if(id)
+ result = WorldDatabase.PQuery("SELECT guid, id, position_x, position_y, position_z, orientation, map, (POW(position_x - '%f', 2) + POW(position_y - '%f', 2) + POW(position_z - '%f', 2)) AS order_ FROM gameobject WHERE map = '%i' AND id = '%u' ORDER BY order_ ASC LIMIT 1",
+ pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(),id);
+ else
+ {
+ std::string name = args;
+ WorldDatabase.escape_string(name);
+ result = WorldDatabase.PQuery(
+ "SELECT guid, id, position_x, position_y, position_z, orientation, map, (POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ "
+ "FROM gameobject,gameobject_template WHERE gameobject_template.entry = gameobject.id AND map = %i AND name "_LIKE_" "_CONCAT3_("'%%'","'%s'","'%%'")" ORDER BY order_ ASC LIMIT 1",
+ pl->GetPositionX(), pl->GetPositionY(), pl->GetPositionZ(), pl->GetMapId(),name.c_str());
+ }
+ }
+ else
+ {
+ std::ostringstream eventFilter;
+ eventFilter << " AND (event IS NULL ";
+ bool initString = true;
+
+ for (GameEvent::ActiveEvents::const_iterator itr = activeEventsList.begin(); itr != activeEventsList.end(); ++itr)
+ {
+ if (initString)
+ {
+ eventFilter << "OR event IN (" <<*itr;
+ initString =false;
+ }
+ else
+ eventFilter << "," << *itr;
+ }
+
+ if (!initString)
+ eventFilter << "))";
+ else
+ eventFilter << ")";
+
+ result = WorldDatabase.PQuery("SELECT gameobject.guid, id, position_x, position_y, position_z, orientation, map, "
+ "(POW(position_x - %f, 2) + POW(position_y - %f, 2) + POW(position_z - %f, 2)) AS order_ FROM gameobject "
+ "LEFT OUTER JOIN game_event_gameobject on gameobject.guid=game_event_gameobject.guid WHERE map = '%i' %s ORDER BY order_ ASC LIMIT 1",
+ m_session->GetPlayer()->GetPositionX(), m_session->GetPlayer()->GetPositionY(), m_session->GetPlayer()->GetPositionZ(), m_session->GetPlayer()->GetMapId(),eventFilter.str().c_str());
+ }
+
+ if (!result)
+ {
+ SendSysMessage(LANG_COMMAND_TARGETOBJNOTFOUND);
+ return true;
+ }
+
+ Field *fields = result->Fetch();
+ uint32 lowguid = fields[0].GetUInt32();
+ uint32 id = fields[1].GetUInt32();
+ float x = fields[2].GetFloat();
+ float y = fields[3].GetFloat();
+ float z = fields[4].GetFloat();
+ float o = fields[5].GetFloat();
+ int mapid = fields[6].GetUInt16();
+ delete result;
+
+ GameObjectInfo const* goI = objmgr.GetGameObjectInfo(id);
+
+ if (!goI)
+ {
+ PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id);
+ return false;
+ }
+
+ GameObject* target = ObjectAccessor::GetGameObject(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,id,HIGHGUID_GAMEOBJECT));
+
+ PSendSysMessage(LANG_GAMEOBJECT_DETAIL, lowguid, goI->name, lowguid, id, x, y, z, mapid, o);
+
+ if(target)
+ {
+ int32 curRespawnDelay = target->GetRespawnTimeEx()-time(NULL);
+ if(curRespawnDelay < 0)
+ curRespawnDelay = 0;
+
+ std::string curRespawnDelayStr = secsToTimeString(curRespawnDelay,true);
+ std::string defRespawnDelayStr = secsToTimeString(target->GetRespawnDelay(),true);
+
+ PSendSysMessage(LANG_COMMAND_RAWPAWNTIMES, defRespawnDelayStr.c_str(),curRespawnDelayStr.c_str());
+ }
+ return true;
+}
+
+//teleport to gameobject
+bool ChatHandler::HandleGoObjectCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ Player* _player = m_session->GetPlayer();
+
+ // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r
+ char* cId = extractKeyFromLink((char*)args,"Hgameobject");
+ if(!cId)
+ return false;
+
+ int32 guid = atoi(cId);
+ if(!guid)
+ return false;
+
+ float x, y, z, ort;
+ int mapid;
+
+ // by DB guid
+ if (GameObjectData const* go_data = objmgr.GetGOData(guid))
+ {
+ x = go_data->posX;
+ y = go_data->posY;
+ z = go_data->posZ;
+ ort = go_data->orientation;
+ mapid = go_data->mapid;
+ }
+ else
+ {
+ SendSysMessage(LANG_COMMAND_GOOBJNOTFOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if(!MapManager::IsValidMapCoord(mapid,x,y,z,ort))
+ {
+ PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ // stop flight if need
+ if(_player->isInFlight())
+ {
+ _player->GetMotionMaster()->MovementExpired();
+ _player->m_taxi.ClearTaxiDestinations();
+ }
+ // save only in non-flight case
+ else
+ _player->SaveRecallPosition();
+
+ _player->TeleportTo(mapid, x, y, z, ort);
+ return true;
+}
+
+bool ChatHandler::HandleGoTriggerCommand(const char* args)
+{
+ Player* _player = m_session->GetPlayer();
+
+ if (!*args)
+ return false;
+
+ char *atId = strtok((char*)args, " ");
+ if (!atId)
+ return false;
+
+ int32 i_atId = atoi(atId);
+
+ if(!i_atId)
+ return false;
+
+ AreaTriggerEntry const* at = sAreaTriggerStore.LookupEntry(i_atId);
+ if (!at)
+ {
+ PSendSysMessage(LANG_COMMAND_GOAREATRNOTFOUND,i_atId);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if(!MapManager::IsValidMapCoord(at->mapid,at->x,at->y,at->z))
+ {
+ PSendSysMessage(LANG_INVALID_TARGET_COORD,at->x,at->y,at->mapid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ // stop flight if need
+ if(_player->isInFlight())
+ {
+ _player->GetMotionMaster()->MovementExpired();
+ _player->m_taxi.ClearTaxiDestinations();
+ }
+ // save only in non-flight case
+ else
+ _player->SaveRecallPosition();
+
+ _player->TeleportTo(at->mapid, at->x, at->y, at->z, _player->GetOrientation());
+ return true;
+}
+
+bool ChatHandler::HandleGoGraveyardCommand(const char* args)
+{
+ Player* _player = m_session->GetPlayer();
+
+ if (!*args)
+ return false;
+
+ char *gyId = strtok((char*)args, " ");
+ if (!gyId)
+ return false;
+
+ int32 i_gyId = atoi(gyId);
+
+ if(!i_gyId)
+ return false;
+
+ WorldSafeLocsEntry const* gy = sWorldSafeLocsStore.LookupEntry(i_gyId);
+ if (!gy)
+ {
+ PSendSysMessage(LANG_COMMAND_GRAVEYARDNOEXIST,i_gyId);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if(!MapManager::IsValidMapCoord(gy->map_id,gy->x,gy->y,gy->z))
+ {
+ PSendSysMessage(LANG_INVALID_TARGET_COORD,gy->x,gy->y,gy->map_id);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ // stop flight if need
+ if(_player->isInFlight())
+ {
+ _player->GetMotionMaster()->MovementExpired();
+ _player->m_taxi.ClearTaxiDestinations();
+ }
+ // save only in non-flight case
+ else
+ _player->SaveRecallPosition();
+
+ _player->TeleportTo(gy->map_id, gy->x, gy->y, gy->z, _player->GetOrientation());
+ return true;
+}
+
+/** \brief Teleport the GM to the specified creature
+ *
+ * .gocreature <GUID> --> TP using creature.guid
+ * .gocreature azuregos --> TP player to the mob with this name
+ * Warning: If there is more than one mob with this name
+ * you will be teleported to the first one that is found.
+ * .gocreature id 6109 --> TP player to the mob, that has this creature_template.entry
+ * Warning: If there is more than one mob with this "id"
+ * you will be teleported to the first one that is found.
+ */
+//teleport to creature
+bool ChatHandler::HandleGoCreatureCommand(const char* args)
+{
+ if(!*args)
+ return false;
+ Player* _player = m_session->GetPlayer();
+
+ // "id" or number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r
+ char* pParam1 = extractKeyFromLink((char*)args,"Hcreature");
+ if (!pParam1)
+ return false;
+
+ std::ostringstream whereClause;
+
+ // User wants to teleport to the NPC's template entry
+ if( strcmp(pParam1, "id") == 0 )
+ {
+ //sLog.outError("DEBUG: ID found");
+
+ // Get the "creature_template.entry"
+ // number or [name] Shift-click form |color|Hcreature_entry:creature_id|h[name]|h|r
+ char* tail = strtok(NULL,"");
+ if(!tail)
+ return false;
+ char* cId = extractKeyFromLink(tail,"Hcreature_entry");
+ if(!cId)
+ return false;
+
+ int32 tEntry = atoi(cId);
+ //sLog.outError("DEBUG: ID value: %d", tEntry);
+ if(!tEntry)
+ return false;
+
+ whereClause << "WHERE id = '" << tEntry << "'";
+ }
+ else
+ {
+ //sLog.outError("DEBUG: ID *not found*");
+
+ int32 guid = atoi(pParam1);
+
+ // Number is invalid - maybe the user specified the mob's name
+ if(!guid)
+ {
+ std::string name = pParam1;
+ WorldDatabase.escape_string(name);
+ whereClause << ", creature_template WHERE creature.id = creature_template.entry AND creature_template.name "_LIKE_" '" << name << "'";
+ }
+ else
+ {
+ whereClause << "WHERE guid = '" << guid << "'";
+ }
+ }
+ //sLog.outError("DEBUG: %s", whereClause.c_str());
+
+ QueryResult *result = WorldDatabase.PQuery("SELECT position_x,position_y,position_z,orientation,map FROM creature %s", whereClause.str().c_str() );
+ if (!result)
+ {
+ SendSysMessage(LANG_COMMAND_GOCREATNOTFOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ if( result->GetRowCount() > 1 )
+ {
+ SendSysMessage(LANG_COMMAND_GOCREATMULTIPLE);
+ }
+
+ Field *fields = result->Fetch();
+ float x = fields[0].GetFloat();
+ float y = fields[1].GetFloat();
+ float z = fields[2].GetFloat();
+ float ort = fields[3].GetFloat();
+ int mapid = fields[4].GetUInt16();
+
+ delete result;
+
+ if(!MapManager::IsValidMapCoord(mapid,x,y,z,ort))
+ {
+ PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,mapid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ // stop flight if need
+ if(_player->isInFlight())
+ {
+ _player->GetMotionMaster()->MovementExpired();
+ _player->m_taxi.ClearTaxiDestinations();
+ }
+ // save only in non-flight case
+ else
+ _player->SaveRecallPosition();
+
+ _player->TeleportTo(mapid, x, y, z, ort);
+ return true;
+}
+
+bool ChatHandler::HandleGUIDCommand(const char* /*args*/)
+{
+ uint64 guid = m_session->GetPlayer()->GetSelection();
+
+ if (guid == 0)
+ {
+ SendSysMessage(LANG_NO_SELECTION);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ PSendSysMessage(LANG_OBJECT_GUID, GUID_LOPART(guid), GUID_HIPART(guid));
+ return true;
+}
+
+bool ChatHandler::HandleLookupFactionCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ // Can be NULL at console call
+ Player *target = getSelectedPlayer ();
+
+ std::string namepart = args;
+ std::wstring wnamepart;
+
+ if (!Utf8toWStr (namepart,wnamepart))
+ return false;
+
+ // converting string that we try to find to lower case
+ wstrToLower (wnamepart);
+
+ uint32 counter = 0; // Counter for figure out that we found smth.
+
+ for (uint32 id = 0; id < sFactionStore.GetNumRows(); ++id)
+ {
+ FactionEntry const *factionEntry = sFactionStore.LookupEntry (id);
+ if (factionEntry)
+ {
+ FactionState const* repState = NULL;
+ if(target)
+ {
+ FactionStateList::const_iterator repItr = target->m_factions.find (factionEntry->reputationListID);
+ if(repItr != target->m_factions.end())
+ repState = &repItr->second;
+ }
+
+ int loc = m_session ? m_session->GetSessionDbcLocale() : sWorld.GetDefaultDbcLocale();
+ std::string name = factionEntry->name[loc];
+ if(name.empty())
+ continue;
+
+ if (!Utf8FitTo(name, wnamepart))
+ {
+ loc = 0;
+ for(; loc < MAX_LOCALE; ++loc)
+ {
+ if(m_session && loc==m_session->GetSessionDbcLocale())
+ continue;
+
+ name = factionEntry->name[loc];
+ if(name.empty())
+ continue;
+
+ if (Utf8FitTo(name, wnamepart))
+ break;
+ }
+ }
+
+ if(loc < MAX_LOCALE)
+ {
+ // send faction in "id - [faction] rank reputation [visible] [at war] [own team] [unknown] [invisible] [inactive]" format
+ // or "id - [faction] [no reputation]" format
+ std::ostringstream ss;
+ if (m_session)
+ ss << id << " - |cffffffff|Hfaction:" << id << "|h[" << name << " " << localeNames[loc] << "]|h|r";
+ else
+ ss << id << " - " << name << " " << localeNames[loc];
+
+ if (repState) // and then target!=NULL also
+ {
+ ReputationRank rank = target->GetReputationRank(factionEntry);
+ std::string rankName = GetTrinityString(ReputationRankStrIndex[rank]);
+
+ ss << " " << rankName << "|h|r (" << target->GetReputation(factionEntry) << ")";
+
+ if(repState->Flags & FACTION_FLAG_VISIBLE)
+ ss << GetTrinityString(LANG_FACTION_VISIBLE);
+ if(repState->Flags & FACTION_FLAG_AT_WAR)
+ ss << GetTrinityString(LANG_FACTION_ATWAR);
+ if(repState->Flags & FACTION_FLAG_PEACE_FORCED)
+ ss << GetTrinityString(LANG_FACTION_PEACE_FORCED);
+ if(repState->Flags & FACTION_FLAG_HIDDEN)
+ ss << GetTrinityString(LANG_FACTION_HIDDEN);
+ if(repState->Flags & FACTION_FLAG_INVISIBLE_FORCED)
+ ss << GetTrinityString(LANG_FACTION_INVISIBLE_FORCED);
+ if(repState->Flags & FACTION_FLAG_INACTIVE)
+ ss << GetTrinityString(LANG_FACTION_INACTIVE);
+ }
+ else
+ ss << GetTrinityString(LANG_FACTION_NOREPUTATION);
+
+ SendSysMessage(ss.str().c_str());
+ counter++;
+ }
+ }
+ }
+
+ if (counter == 0) // if counter == 0 then we found nth
+ SendSysMessage(LANG_COMMAND_FACTION_NOTFOUND);
+ return true;
+}
+
+bool ChatHandler::HandleModifyRepCommand(const char * args)
+{
+ if (!*args) return false;
+
+ Player* target = NULL;
+ target = getSelectedPlayer();
+
+ if(!target)
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ char* factionTxt = extractKeyFromLink((char*)args,"Hfaction");
+ if(!factionTxt)
+ return false;
+
+ uint32 factionId = atoi(factionTxt);
+
+ int32 amount = 0;
+ char *rankTxt = strtok(NULL, " ");
+ if (!factionTxt || !rankTxt)
+ return false;
+
+ amount = atoi(rankTxt);
+ if ((amount == 0) && (rankTxt[0] != '-') && !isdigit(rankTxt[0]))
+ {
+ std::string rankStr = rankTxt;
+ std::wstring wrankStr;
+ if(!Utf8toWStr(rankStr,wrankStr))
+ return false;
+ wstrToLower( wrankStr );
+
+ int r = 0;
+ amount = -42000;
+ for (; r < MAX_REPUTATION_RANK; ++r)
+ {
+ std::string rank = GetTrinityString(ReputationRankStrIndex[r]);
+ if(rank.empty())
+ continue;
+
+ std::wstring wrank;
+ if(!Utf8toWStr(rank,wrank))
+ continue;
+
+ wstrToLower(wrank);
+
+ if(wrank.substr(0,wrankStr.size())==wrankStr)
+ {
+ char *deltaTxt = strtok(NULL, " ");
+ if (deltaTxt)
+ {
+ int32 delta = atoi(deltaTxt);
+ if ((delta < 0) || (delta > Player::ReputationRank_Length[r] -1))
+ {
+ PSendSysMessage(LANG_COMMAND_FACTION_DELTA, (Player::ReputationRank_Length[r]-1));
+ SetSentErrorMessage(true);
+ return false;
+ }
+ amount += delta;
+ }
+ break;
+ }
+ amount += Player::ReputationRank_Length[r];
+ }
+ if (r >= MAX_REPUTATION_RANK)
+ {
+ PSendSysMessage(LANG_COMMAND_FACTION_INVPARAM, rankTxt);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ }
+
+ FactionEntry const *factionEntry = sFactionStore.LookupEntry(factionId);
+
+ if (!factionEntry)
+ {
+ PSendSysMessage(LANG_COMMAND_FACTION_UNKNOWN, factionId);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if (factionEntry->reputationListID < 0)
+ {
+ PSendSysMessage(LANG_COMMAND_FACTION_NOREP_ERROR, factionEntry->name[m_session->GetSessionDbcLocale()], factionId);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ target->SetFactionReputation(factionEntry,amount);
+ PSendSysMessage(LANG_COMMAND_MODIFY_REP, factionEntry->name[m_session->GetSessionDbcLocale()], factionId, target->GetName(), target->GetReputation(factionId));
+ return true;
+}
+
+bool ChatHandler::HandleNameCommand(const char* args)
+{
+ /* Temp. disabled
+ if(!*args)
+ return false;
+
+ if(strlen((char*)args)>75)
+ {
+ PSendSysMessage(LANG_TOO_LONG_NAME, strlen((char*)args)-75);
+ return true;
+ }
+
+ for (uint8 i = 0; i < strlen(args); i++)
+ {
+ if(!isalpha(args[i]) && args[i]!=' ')
+ {
+ SendSysMessage(LANG_CHARS_ONLY);
+ return false;
+ }
+ }
+
+ uint64 guid;
+ guid = m_session->GetPlayer()->GetSelection();
+ if (guid == 0)
+ {
+ SendSysMessage(LANG_NO_SELECTION);
+ return true;
+ }
+
+ Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid);
+
+ if(!pCreature)
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ return true;
+ }
+
+ pCreature->SetName(args);
+ uint32 idname = objmgr.AddCreatureTemplate(pCreature->GetName());
+ pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname);
+
+ pCreature->SaveToDB();
+ */
+
+ return true;
+}
+
+bool ChatHandler::HandleSubNameCommand(const char* /*args*/)
+{
+ /* Temp. disabled
+
+ if(!*args)
+ args = "";
+
+ if(strlen((char*)args)>75)
+ {
+
+ PSendSysMessage(LANG_TOO_LONG_SUBNAME, strlen((char*)args)-75);
+ return true;
+ }
+
+ for (uint8 i = 0; i < strlen(args); i++)
+ {
+ if(!isalpha(args[i]) && args[i]!=' ')
+ {
+ SendSysMessage(LANG_CHARS_ONLY);
+ return false;
+ }
+ }
+ uint64 guid;
+ guid = m_session->GetPlayer()->GetSelection();
+ if (guid == 0)
+ {
+ SendSysMessage(LANG_NO_SELECTION);
+ return true;
+ }
+
+ Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid);
+
+ if(!pCreature)
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ return true;
+ }
+
+ uint32 idname = objmgr.AddCreatureSubName(pCreature->GetName(),args,pCreature->GetUInt32Value(UNIT_FIELD_DISPLAYID));
+ pCreature->SetUInt32Value(OBJECT_FIELD_ENTRY, idname);
+
+ pCreature->SaveToDB();
+ */
+ return true;
+}
+
+//move item to other slot
+bool ChatHandler::HandleItemMoveCommand(const char* args)
+{
+ if(!*args)
+ return false;
+ uint8 srcslot, dstslot;
+
+ char* pParam1 = strtok((char*)args, " ");
+ if (!pParam1)
+ return false;
+
+ char* pParam2 = strtok(NULL, " ");
+ if (!pParam2)
+ return false;
+
+ srcslot = (uint8)atoi(pParam1);
+ dstslot = (uint8)atoi(pParam2);
+
+ if(srcslot==dstslot)
+ return true;
+
+ if(!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0,srcslot))
+ return false;
+
+ if(!m_session->GetPlayer()->IsValidPos(INVENTORY_SLOT_BAG_0,dstslot))
+ return false;
+
+ uint16 src = ((INVENTORY_SLOT_BAG_0 << 8) | srcslot);
+ uint16 dst = ((INVENTORY_SLOT_BAG_0 << 8) | dstslot);
+
+ m_session->GetPlayer()->SwapItem( src, dst );
+
+ return true;
+}
+
+//add spawn of creature
+bool ChatHandler::HandleNpcAddCommand(const char* args)
+{
+ if(!*args)
+ return false;
+ char* charID = strtok((char*)args, " ");
+ if (!charID)
+ return false;
+
+ char* team = strtok(NULL, " ");
+ int32 teamval = 0;
+ if (team) { teamval = atoi(team); }
+ if (teamval < 0) { teamval = 0; }
+
+ uint32 id = atoi(charID);
+
+ Player *chr = m_session->GetPlayer();
+ float x = chr->GetPositionX();
+ float y = chr->GetPositionY();
+ float z = chr->GetPositionZ();
+ float o = chr->GetOrientation();
+ Map *map = chr->GetMap();
+
+ Creature* pCreature = new Creature;
+ if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, id, (uint32)teamval))
+ {
+ delete pCreature;
+ return false;
+ }
+
+ pCreature->Relocate(x,y,z,o);
+
+ if(!pCreature->IsPositionValid())
+ {
+ sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
+ delete pCreature;
+ return false;
+ }
+
+ pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
+
+ uint32 db_guid = pCreature->GetDBTableGUIDLow();
+
+ // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
+ pCreature->LoadFromDB(db_guid, map);
+
+ map->Add(pCreature);
+ objmgr.AddCreatureToGrid(db_guid, objmgr.GetCreatureData(db_guid));
+ return true;
+}
+
+bool ChatHandler::HandleNpcDeleteCommand(const char* args)
+{
+ Creature* unit = NULL;
+
+ if(*args)
+ {
+ // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r
+ char* cId = extractKeyFromLink((char*)args,"Hcreature");
+ if(!cId)
+ return false;
+
+ uint32 lowguid = atoi(cId);
+ if(!lowguid)
+ return false;
+
+ if (CreatureData const* cr_data = objmgr.GetCreatureData(lowguid))
+ unit = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, cr_data->id, HIGHGUID_UNIT));
+ }
+ else
+ unit = getSelectedCreature();
+
+ if(!unit || unit->isPet() || unit->isTotem())
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ // Delete the creature
+ unit->CombatStop();
+ unit->DeleteFromDB();
+ unit->CleanupsBeforeDelete();
+ unit->AddObjectToRemoveList();
+
+ SendSysMessage(LANG_COMMAND_DELCREATMESSAGE);
+
+ return true;
+}
+
+//delete object by selection or guid
+bool ChatHandler::HandleDelObjectCommand(const char* args)
+{
+ // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r
+ char* cId = extractKeyFromLink((char*)args,"Hgameobject");
+ if(!cId)
+ return false;
+
+ uint32 lowguid = atoi(cId);
+ if(!lowguid)
+ return false;
+
+ GameObject* obj = NULL;
+
+ // by DB guid
+ if (GameObjectData const* go_data = objmgr.GetGOData(lowguid))
+ obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id);
+
+ if(!obj)
+ {
+ PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint64 owner_guid = obj->GetOwnerGUID();
+ if(owner_guid)
+ {
+ Unit* owner = ObjectAccessor::GetUnit(*m_session->GetPlayer(),owner_guid);
+ if(!owner && !IS_PLAYER_GUID(owner_guid))
+ {
+ PSendSysMessage(LANG_COMMAND_DELOBJREFERCREATURE, GUID_LOPART(owner_guid), obj->GetGUIDLow());
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ owner->RemoveGameObject(obj,false);
+ }
+
+ obj->SetRespawnTime(0); // not save respawn time
+ obj->Delete();
+ obj->DeleteFromDB();
+
+ PSendSysMessage(LANG_COMMAND_DELOBJMESSAGE, obj->GetGUIDLow());
+
+ return true;
+}
+
+//turn selected object
+bool ChatHandler::HandleTurnObjectCommand(const char* args)
+{
+ // number or [name] Shift-click form |color|Hgameobject:go_id|h[name]|h|r
+ char* cId = extractKeyFromLink((char*)args,"Hgameobject");
+ if(!cId)
+ return false;
+
+ uint32 lowguid = atoi(cId);
+ if(!lowguid)
+ return false;
+
+ GameObject* obj = NULL;
+
+ // by DB guid
+ if (GameObjectData const* go_data = objmgr.GetGOData(lowguid))
+ obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id);
+
+ if(!obj)
+ {
+ PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ char* po = strtok(NULL, " ");
+ float o;
+
+ if (po)
+ {
+ o = (float)atof(po);
+ }
+ else
+ {
+ Player *chr = m_session->GetPlayer();
+ o = chr->GetOrientation();
+ }
+
+ float rot2 = sin(o/2);
+ float rot3 = cos(o/2);
+
+ Map* map = MapManager::Instance().GetMap(obj->GetMapId(),obj);
+ map->Remove(obj,false);
+
+ obj->Relocate(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), o);
+
+ obj->SetFloatValue(GAMEOBJECT_FACING, o);
+ obj->SetFloatValue(GAMEOBJECT_ROTATION+2, rot2);
+ obj->SetFloatValue(GAMEOBJECT_ROTATION+3, rot3);
+
+ map->Add(obj);
+
+ obj->SaveToDB();
+ obj->Refresh();
+
+ PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, obj->GetGUIDLow(), o);
+
+ return true;
+}
+
+//move selected creature
+bool ChatHandler::HandleNpcMoveCommand(const char* args)
+{
+ uint32 lowguid = 0;
+
+ Creature* pCreature = getSelectedCreature();
+
+ if(!pCreature)
+ {
+ // number or [name] Shift-click form |color|Hcreature:creature_guid|h[name]|h|r
+ char* cId = extractKeyFromLink((char*)args,"Hcreature");
+ if(!cId)
+ return false;
+
+ uint32 lowguid = atoi(cId);
+
+ /* FIXME: impossibel without entry
+ if(lowguid)
+ pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT));
+ */
+
+ // Attempting creature load from DB data
+ if(!pCreature)
+ {
+ CreatureData const* data = objmgr.GetCreatureData(lowguid);
+ if(!data)
+ {
+ PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint32 map_id = data->mapid;
+
+ if(m_session->GetPlayer()->GetMapId()!=map_id)
+ {
+ PSendSysMessage(LANG_COMMAND_CREATUREATSAMEMAP, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ }
+ else
+ {
+ lowguid = pCreature->GetDBTableGUIDLow();
+ }
+ }
+ else
+ {
+ lowguid = pCreature->GetDBTableGUIDLow();
+ }
+
+ float x = m_session->GetPlayer()->GetPositionX();
+ float y = m_session->GetPlayer()->GetPositionY();
+ float z = m_session->GetPlayer()->GetPositionZ();
+ float o = m_session->GetPlayer()->GetOrientation();
+
+ if (pCreature)
+ {
+ if(CreatureData const* data = objmgr.GetCreatureData(pCreature->GetDBTableGUIDLow()))
+ {
+ const_cast<CreatureData*>(data)->posX = x;
+ const_cast<CreatureData*>(data)->posY = y;
+ const_cast<CreatureData*>(data)->posZ = z;
+ const_cast<CreatureData*>(data)->orientation = o;
+ }
+ MapManager::Instance().GetMap(pCreature->GetMapId(),pCreature)->CreatureRelocation(pCreature,x, y, z,o);
+ pCreature->GetMotionMaster()->Initialize();
+ if(pCreature->isAlive()) // dead creature will reset movement generator at respawn
+ {
+ pCreature->setDeathState(JUST_DIED);
+ pCreature->Respawn();
+ }
+ }
+
+ WorldDatabase.PExecuteLog("UPDATE creature SET position_x = '%f', position_y = '%f', position_z = '%f', orientation = '%f' WHERE guid = '%u'", x, y, z, o, lowguid);
+ PSendSysMessage(LANG_COMMAND_CREATUREMOVED);
+ return true;
+}
+
+//move selected object
+bool ChatHandler::HandleMoveObjectCommand(const char* args)
+{
+ // number or [name] Shift-click form |color|Hgameobject:go_guid|h[name]|h|r
+ char* cId = extractKeyFromLink((char*)args,"Hgameobject");
+ if(!cId)
+ return false;
+
+ uint32 lowguid = atoi(cId);
+ if(!lowguid)
+ return false;
+
+ GameObject* obj = NULL;
+
+ // by DB guid
+ if (GameObjectData const* go_data = objmgr.GetGOData(lowguid))
+ obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id);
+
+ if(!obj)
+ {
+ PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ char* px = strtok(NULL, " ");
+ char* py = strtok(NULL, " ");
+ char* pz = strtok(NULL, " ");
+
+ if (!px)
+ {
+ Player *chr = m_session->GetPlayer();
+
+ Map* map = MapManager::Instance().GetMap(obj->GetMapId(),obj);
+ map->Remove(obj,false);
+
+ obj->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), obj->GetOrientation());
+ obj->SetFloatValue(GAMEOBJECT_POS_X, chr->GetPositionX());
+ obj->SetFloatValue(GAMEOBJECT_POS_Y, chr->GetPositionY());
+ obj->SetFloatValue(GAMEOBJECT_POS_Z, chr->GetPositionZ());
+
+ map->Add(obj);
+ }
+ else
+ {
+ if(!py || !pz)
+ return false;
+
+ float x = (float)atof(px);
+ float y = (float)atof(py);
+ float z = (float)atof(pz);
+
+ if(!MapManager::IsValidMapCoord(obj->GetMapId(),x,y,z))
+ {
+ PSendSysMessage(LANG_INVALID_TARGET_COORD,x,y,obj->GetMapId());
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Map* map = MapManager::Instance().GetMap(obj->GetMapId(),obj);
+ map->Remove(obj,false);
+
+ obj->Relocate(x, y, z, obj->GetOrientation());
+ obj->SetFloatValue(GAMEOBJECT_POS_X, x);
+ obj->SetFloatValue(GAMEOBJECT_POS_Y, y);
+ obj->SetFloatValue(GAMEOBJECT_POS_Z, z);
+
+ map->Add(obj);
+ }
+
+ obj->SaveToDB();
+ obj->Refresh();
+
+ PSendSysMessage(LANG_COMMAND_MOVEOBJMESSAGE, obj->GetGUIDLow());
+
+ return true;
+}
+
+//demorph player or unit
+bool ChatHandler::HandleDeMorphCommand(const char* /*args*/)
+{
+ Unit *target = getSelectedUnit();
+ if(!target)
+ target = m_session->GetPlayer();
+
+ target->DeMorph();
+
+ return true;
+}
+
+//add item in vendorlist
+bool ChatHandler::HandleAddVendorItemCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ char* pitem = extractKeyFromLink((char*)args,"Hitem");
+ if (!pitem)
+ {
+ SendSysMessage(LANG_COMMAND_NEEDITEMSEND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint32 itemId = atol(pitem);
+
+ char* fmaxcount = strtok(NULL, " "); //add maxcount, default: 0
+ uint32 maxcount = 0;
+ if (fmaxcount)
+ maxcount = atol(fmaxcount);
+
+ char* fincrtime = strtok(NULL, " "); //add incrtime, default: 0
+ uint32 incrtime = 0;
+ if (fincrtime)
+ incrtime = atol(fincrtime);
+
+ char* fextendedcost = strtok(NULL, " "); //add ExtendedCost, default: 0
+ uint32 extendedcost = fextendedcost ? atol(fextendedcost) : 0;
+
+ Creature* vendor = getSelectedCreature();
+
+ uint32 vendor_entry = vendor ? vendor->GetEntry() : 0;
+
+ if(!objmgr.IsVendorItemValid(vendor_entry,itemId,maxcount,incrtime,extendedcost,m_session->GetPlayer()))
+ {
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ objmgr.AddVendorItem(vendor_entry,itemId,maxcount,incrtime,extendedcost);
+
+ ItemPrototype const* pProto = objmgr.GetItemPrototype(itemId);
+
+ PSendSysMessage(LANG_ITEM_ADDED_TO_LIST,itemId,pProto->Name1,maxcount,incrtime,extendedcost);
+ return true;
+}
+
+//del item from vendor list
+bool ChatHandler::HandleDelVendorItemCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ Creature* vendor = getSelectedCreature();
+ if (!vendor || !vendor->isVendor())
+ {
+ SendSysMessage(LANG_COMMAND_VENDORSELECTION);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ char* pitem = extractKeyFromLink((char*)args,"Hitem");
+ if (!pitem)
+ {
+ SendSysMessage(LANG_COMMAND_NEEDITEMSEND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ uint32 itemId = atol(pitem);
+
+
+ if(!objmgr.RemoveVendorItem(vendor->GetEntry(),itemId))
+ {
+ PSendSysMessage(LANG_ITEM_NOT_IN_LIST,itemId);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ ItemPrototype const* pProto = objmgr.GetItemPrototype(itemId);
+
+ PSendSysMessage(LANG_ITEM_DELETED_FROM_LIST,itemId,pProto->Name1);
+ return true;
+}
+
+//add move for creature
+bool ChatHandler::HandleNpcAddMoveCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ char* guid_str = strtok((char*)args, " ");
+ char* wait_str = strtok((char*)NULL, " ");
+
+ uint32 lowguid = atoi((char*)guid_str);
+
+ Creature* pCreature = NULL;
+
+ /* FIXME: impossible without entry
+ if(lowguid)
+ pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT));
+ */
+
+ // attempt check creature existence by DB data
+ if(!pCreature)
+ {
+ CreatureData const* data = objmgr.GetCreatureData(lowguid);
+ if(!data)
+ {
+ PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ }
+ else
+ {
+ // obtain real GUID for DB operations
+ lowguid = pCreature->GetDBTableGUIDLow();
+ }
+
+ int wait = wait_str ? atoi(wait_str) : 0;
+
+ if(wait < 0)
+ wait = 0;
+
+ Player* player = m_session->GetPlayer();
+
+ WaypointMgr.AddLastNode(lowguid, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), wait, 0);
+
+ // update movement type
+ WorldDatabase.PExecuteLog("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE,lowguid);
+ if(pCreature)
+ {
+ pCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE);
+ pCreature->GetMotionMaster()->Initialize();
+ if(pCreature->isAlive()) // dead creature will reset movement generator at respawn
+ {
+ pCreature->setDeathState(JUST_DIED);
+ pCreature->Respawn();
+ }
+ pCreature->SaveToDB();
+ }
+
+ SendSysMessage(LANG_WAYPOINT_ADDED);
+
+ return true;
+}
+
+/**
+ * Set the movement type for an NPC.<br/>
+ * <br/>
+ * Valid movement types are:
+ * <ul>
+ * <li> stay - NPC wont move </li>
+ * <li> random - NPC will move randomly according to the spawndist </li>
+ * <li> way - NPC will move with given waypoints set </li>
+ * </ul>
+ * additional parameter: NODEL - so no waypoints are deleted, if you
+ * change the movement type
+ */
+bool ChatHandler::HandleNpcSetMoveTypeCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ // 3 arguments:
+ // GUID (optional - you can also select the creature)
+ // stay|random|way (determines the kind of movement)
+ // NODEL (optional - tells the system NOT to delete any waypoints)
+ // this is very handy if you want to do waypoints, that are
+ // later switched on/off according to special events (like escort
+ // quests, etc)
+ char* guid_str = strtok((char*)args, " ");
+ char* type_str = strtok((char*)NULL, " ");
+ char* dontdel_str = strtok((char*)NULL, " ");
+
+ bool doNotDelete = false;
+
+ if(!guid_str)
+ return false;
+
+ uint32 lowguid = 0;
+ Creature* pCreature = NULL;
+
+ if( dontdel_str )
+ {
+ //sLog.outError("DEBUG: All 3 params are set");
+
+ // All 3 params are set
+ // GUID
+ // type
+ // doNotDEL
+ if( stricmp( dontdel_str, "NODEL" ) == 0 )
+ {
+ //sLog.outError("DEBUG: doNotDelete = true;");
+ doNotDelete = true;
+ }
+ }
+ else
+ {
+ // Only 2 params - but maybe NODEL is set
+ if( type_str )
+ {
+ sLog.outError("DEBUG: Only 2 params ");
+ if( stricmp( type_str, "NODEL" ) == 0 )
+ {
+ //sLog.outError("DEBUG: type_str, NODEL ");
+ doNotDelete = true;
+ type_str = NULL;
+ }
+ }
+ }
+
+ if(!type_str) // case .setmovetype $move_type (with selected creature)
+ {
+ type_str = guid_str;
+ pCreature = getSelectedCreature();
+ if(!pCreature || pCreature->isPet())
+ return false;
+ lowguid = pCreature->GetDBTableGUIDLow();
+ }
+ else // case .setmovetype #creature_guid $move_type (with selected creature)
+ {
+ lowguid = atoi((char*)guid_str);
+
+ /* impossible without entry
+ if(lowguid)
+ pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_GUID(lowguid,HIGHGUID_UNIT));
+ */
+
+ // attempt check creature existence by DB data
+ if(!pCreature)
+ {
+ CreatureData const* data = objmgr.GetCreatureData(lowguid);
+ if(!data)
+ {
+ PSendSysMessage(LANG_COMMAND_CREATGUIDNOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ }
+ else
+ {
+ lowguid = pCreature->GetDBTableGUIDLow();
+ }
+ }
+
+ // now lowguid is low guid really existed creature
+ // and pCreature point (maybe) to this creature or NULL
+
+ MovementGeneratorType move_type;
+
+ std::string type = type_str;
+
+ if(type == "stay")
+ move_type = IDLE_MOTION_TYPE;
+ else if(type == "random")
+ move_type = RANDOM_MOTION_TYPE;
+ else if(type == "way")
+ move_type = WAYPOINT_MOTION_TYPE;
+ else
+ return false;
+
+ // update movement type
+ if(doNotDelete == false)
+ WaypointMgr.DeletePath(lowguid);
+
+ if(pCreature)
+ {
+ pCreature->SetDefaultMovementType(move_type);
+ pCreature->GetMotionMaster()->Initialize();
+ if(pCreature->isAlive()) // dead creature will reset movement generator at respawn
+ {
+ pCreature->setDeathState(JUST_DIED);
+ pCreature->Respawn();
+ }
+ pCreature->SaveToDB();
+ }
+ if( doNotDelete == false )
+ {
+ PSendSysMessage(LANG_MOVE_TYPE_SET,type_str);
+ }
+ else
+ {
+ PSendSysMessage(LANG_MOVE_TYPE_SET_NODEL,type_str);
+ }
+
+ return true;
+} // HandleNpcSetMoveTypeCommand
+
+//change level of creature or pet
+bool ChatHandler::HandleChangeLevelCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ uint8 lvl = (uint8) atoi((char*)args);
+ if ( lvl < 1 || lvl > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) + 3)
+ {
+ SendSysMessage(LANG_BAD_VALUE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Creature* pCreature = getSelectedCreature();
+ if(!pCreature)
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if(pCreature->isPet())
+ {
+ ((Pet*)pCreature)->GivePetLevel(lvl);
+ }
+ else
+ {
+ pCreature->SetMaxHealth( 100 + 30*lvl);
+ pCreature->SetHealth( 100 + 30*lvl);
+ pCreature->SetLevel( lvl);
+ pCreature->SaveToDB();
+ }
+
+ return true;
+}
+
+//set npcflag of creature
+bool ChatHandler::HandleNpcFlagCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ uint32 npcFlags = (uint32) atoi((char*)args);
+
+ Creature* pCreature = getSelectedCreature();
+
+ if(!pCreature)
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ pCreature->SetUInt32Value(UNIT_NPC_FLAGS, npcFlags);
+
+ WorldDatabase.PExecuteLog("UPDATE creature_template SET npcflag = '%u' WHERE entry = '%u'", npcFlags, pCreature->GetEntry());
+
+ SendSysMessage(LANG_VALUE_SAVED_REJOIN);
+
+ return true;
+}
+
+//set model of creature
+bool ChatHandler::HandleNpcSetModelCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ uint32 displayId = (uint32) atoi((char*)args);
+
+ Creature *pCreature = getSelectedCreature();
+
+ if(!pCreature || pCreature->isPet())
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ pCreature->SetDisplayId(displayId);
+ pCreature->SetNativeDisplayId(displayId);
+
+ pCreature->SaveToDB();
+
+ return true;
+}
+
+//morph creature or player
+bool ChatHandler::HandleMorphCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ uint16 display_id = (uint16)atoi((char*)args);
+
+ Unit *target = getSelectedUnit();
+ if(!target)
+ target = m_session->GetPlayer();
+
+ target->SetDisplayId(display_id);
+
+ return true;
+}
+
+//set faction of creature
+bool ChatHandler::HandleNpcFactionIdCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ uint32 factionId = (uint32) atoi((char*)args);
+
+ if (!sFactionTemplateStore.LookupEntry(factionId))
+ {
+ PSendSysMessage(LANG_WRONG_FACTION, factionId);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Creature* pCreature = getSelectedCreature();
+
+ if(!pCreature)
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ pCreature->setFaction(factionId);
+
+ // faction is set in creature_template - not inside creature
+
+ // update in memory
+ if(CreatureInfo const *cinfo = pCreature->GetCreatureInfo())
+ {
+ const_cast<CreatureInfo*>(cinfo)->faction_A = factionId;
+ const_cast<CreatureInfo*>(cinfo)->faction_H = factionId;
+ }
+
+ // and DB
+ WorldDatabase.PExecuteLog("UPDATE creature_template SET faction_A = '%u', faction_H = '%u' WHERE entry = '%u'", factionId, factionId, pCreature->GetEntry());
+
+ return true;
+}
+
+//kick player
+bool ChatHandler::HandleKickPlayerCommand(const char *args)
+{
+ char* kickName = strtok((char*)args, " ");
+ if (!kickName)
+ {
+ Player* player = getSelectedPlayer();
+
+ if(!player)
+ {
+ SendSysMessage(LANG_NO_CHAR_SELECTED);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if(player==m_session->GetPlayer())
+ {
+ SendSysMessage(LANG_COMMAND_KICKSELF);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ player->GetSession()->KickPlayer();
+ }
+ else
+ {
+ std::string name = kickName;
+ if(!normalizePlayerName(name))
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if(m_session && name==m_session->GetPlayer()->GetName())
+ {
+ SendSysMessage(LANG_COMMAND_KICKSELF);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if(sWorld.KickPlayer(name))
+ {
+ PSendSysMessage(LANG_COMMAND_KICKMESSAGE,name.c_str());
+ }
+ else
+ PSendSysMessage(LANG_COMMAND_KICKNOTFOUNDPLAYER,name.c_str());
+ }
+
+ return true;
+}
+
+//show info of player
+bool ChatHandler::HandlePInfoCommand(const char* args)
+{
+ Player* target = NULL;
+ uint64 targetGUID = 0;
+
+ char* px = strtok((char*)args, " ");
+ char* py = NULL;
+
+ std::string name;
+
+ if (px)
+ {
+ name = px;
+
+ if(name.empty())
+ return false;
+
+ if(!normalizePlayerName(name))
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ target = objmgr.GetPlayer(name.c_str());
+ if (target)
+ py = strtok(NULL, " ");
+ else
+ {
+ targetGUID = objmgr.GetPlayerGUIDByName(name);
+ if(targetGUID)
+ py = strtok(NULL, " ");
+ else
+ py = px;
+ }
+ }
+
+ if(!target && !targetGUID)
+ {
+ target = getSelectedPlayer();
+ }
+
+ if(!target && !targetGUID)
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint32 accId = 0;
+ uint32 money = 0;
+ uint32 total_player_time = 0;
+ uint32 level = 0;
+ uint32 latency = 0;
+
+ // get additional information from Player object
+ if(target)
+ {
+ targetGUID = target->GetGUID();
+ name = target->GetName(); // re-read for case getSelectedPlayer() target
+ accId = target->GetSession()->GetAccountId();
+ money = target->GetMoney();
+ total_player_time = target->GetTotalPlayedTime();
+ level = target->getLevel();
+ latency = target->GetSession()->GetLatency();
+ }
+ // get additional information from DB
+ else
+ {
+ QueryResult *result = CharacterDatabase.PQuery("SELECT totaltime FROM characters WHERE guid = '%u'", GUID_LOPART(targetGUID));
+ if (!result)
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ Field *fields = result->Fetch();
+ total_player_time = fields[0].GetUInt32();
+ delete result;
+
+ Tokens data;
+ if (!Player::LoadValuesArrayFromDB(data,targetGUID))
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ money = Player::GetUInt32ValueFromArray(data, PLAYER_FIELD_COINAGE);
+ level = Player::GetUInt32ValueFromArray(data, UNIT_FIELD_LEVEL);
+ accId = objmgr.GetPlayerAccountIdByGUID(targetGUID);
+ }
+
+ std::string username = GetTrinityString(LANG_ERROR);
+ std::string last_ip = GetTrinityString(LANG_ERROR);
+ uint32 security = 0;
+ std::string last_login = GetTrinityString(LANG_ERROR);
+
+ QueryResult* result = loginDatabase.PQuery("SELECT username,gmlevel,last_ip,last_login FROM account WHERE id = '%u'",accId);
+ if(result)
+ {
+ Field* fields = result->Fetch();
+ username = fields[0].GetCppString();
+ security = fields[1].GetUInt32();
+
+ if(!m_session || m_session->GetSecurity() >= security)
+ {
+ last_ip = fields[2].GetCppString();
+ last_login = fields[3].GetCppString();
+ }
+ else
+ {
+ last_ip = "-";
+ last_login = "-";
+ }
+
+ delete result;
+ }
+
+ PSendSysMessage(LANG_PINFO_ACCOUNT, (target?"":GetTrinityString(LANG_OFFLINE)), name.c_str(), GUID_LOPART(targetGUID), username.c_str(), accId, security, last_ip.c_str(), last_login.c_str(), latency);
+
+ std::string timeStr = secsToTimeString(total_player_time,true,true);
+ uint32 gold = money /GOLD;
+ uint32 silv = (money % GOLD) / SILVER;
+ uint32 copp = (money % GOLD) % SILVER;
+ PSendSysMessage(LANG_PINFO_LEVEL, timeStr.c_str(), level, gold,silv,copp );
+
+ if ( py && strncmp(py, "rep", 3) == 0 )
+ {
+ if(!target)
+ {
+ // rep option not implemented for offline case
+ SendSysMessage(LANG_PINFO_NO_REP);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ char* FactionName;
+ for(FactionStateList::const_iterator itr = target->m_factions.begin(); itr != target->m_factions.end(); ++itr)
+ {
+ FactionEntry const *factionEntry = sFactionStore.LookupEntry(itr->second.ID);
+ if (factionEntry)
+ FactionName = factionEntry->name[m_session->GetSessionDbcLocale()];
+ else
+ FactionName = "#Not found#";
+ ReputationRank rank = target->GetReputationRank(factionEntry);
+ std::string rankName = GetTrinityString(ReputationRankStrIndex[rank]);
+ std::ostringstream ss;
+ ss << itr->second.ID << ": |cffffffff|Hfaction:" << itr->second.ID << "|h[" << FactionName << "]|h|r " << rankName << "|h|r (" << target->GetReputation(factionEntry) << ")";
+
+ if(itr->second.Flags & FACTION_FLAG_VISIBLE)
+ ss << GetTrinityString(LANG_FACTION_VISIBLE);
+ if(itr->second.Flags & FACTION_FLAG_AT_WAR)
+ ss << GetTrinityString(LANG_FACTION_ATWAR);
+ if(itr->second.Flags & FACTION_FLAG_PEACE_FORCED)
+ ss << GetTrinityString(LANG_FACTION_PEACE_FORCED);
+ if(itr->second.Flags & FACTION_FLAG_HIDDEN)
+ ss << GetTrinityString(LANG_FACTION_HIDDEN);
+ if(itr->second.Flags & FACTION_FLAG_INVISIBLE_FORCED)
+ ss << GetTrinityString(LANG_FACTION_INVISIBLE_FORCED);
+ if(itr->second.Flags & FACTION_FLAG_INACTIVE)
+ ss << GetTrinityString(LANG_FACTION_INACTIVE);
+
+ SendSysMessage(ss.str().c_str());
+ }
+ }
+ return true;
+}
+
+//show tickets
+void ChatHandler::ShowTicket(uint64 guid, char const* text, char const* time)
+{
+ std::string name;
+ if(!objmgr.GetPlayerNameByGUID(guid,name))
+ name = GetTrinityString(LANG_UNKNOWN);
+
+ PSendSysMessage(LANG_COMMAND_TICKETVIEW, name.c_str(),time,text);
+}
+
+//ticket commands
+bool ChatHandler::HandleTicketCommand(const char* args)
+{
+ char* px = strtok((char*)args, " ");
+
+ // ticket<end>
+ if (!px)
+ {
+ if(!m_session)
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ size_t count = ticketmgr.GetTicketCount();
+
+ bool accept = m_session->GetPlayer()->isAcceptTickets();
+
+ PSendSysMessage(LANG_COMMAND_TICKETCOUNT, count, accept ? GetTrinityString(LANG_ON) : GetTrinityString(LANG_OFF));
+ return true;
+ }
+
+ // ticket on
+ if(strncmp(px,"on",3) == 0)
+ {
+ if(!m_session)
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ m_session->GetPlayer()->SetAcceptTicket(true);
+ SendSysMessage(LANG_COMMAND_TICKETON);
+ return true;
+ }
+
+ // ticket off
+ if(strncmp(px,"off",4) == 0)
+ {
+ if(!m_session)
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ m_session->GetPlayer()->SetAcceptTicket(false);
+ SendSysMessage(LANG_COMMAND_TICKETOFF);
+ return true;
+ }
+
+ // ticket #num
+ int num = atoi(px);
+ if(num > 0)
+ {
+ QueryResult *result = CharacterDatabase.PQuery("SELECT guid,ticket_text,ticket_lastchange FROM character_ticket ORDER BY ticket_id ASC "_OFFSET_, num-1);
+
+ if(!result)
+ {
+ PSendSysMessage(LANG_COMMAND_TICKENOTEXIST, num);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Field* fields = result->Fetch();
+
+ uint32 guid = fields[0].GetUInt32();
+ char const* text = fields[1].GetString();
+ char const* time = fields[2].GetString();
+
+ ShowTicket(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER),text,time);
+ delete result;
+ return true;
+ }
+
+ std::string name = px;
+
+ if(!normalizePlayerName(name))
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint64 guid = objmgr.GetPlayerGUIDByName(name);
+
+ if(!guid)
+ return false;
+
+ // ticket $char_name
+ GMTicket* ticket = ticketmgr.GetGMTicket(GUID_LOPART(guid));
+ if(!ticket)
+ return false;
+
+ std::string time = TimeToTimestampStr(ticket->GetLastUpdate());
+
+ ShowTicket(guid, ticket->GetText(), time.c_str());
+
+ return true;
+}
+
+//dell all tickets
+bool ChatHandler::HandleDelTicketCommand(const char *args)
+{
+ char* px = strtok((char*)args, " ");
+ if (!px)
+ return false;
+
+ // delticket all
+ if(strncmp(px,"all",4) == 0)
+ {
+ ticketmgr.DeleteAll();
+ SendSysMessage(LANG_COMMAND_ALLTICKETDELETED);
+ return true;
+ }
+
+ int num = (uint32)atoi(px);
+
+ // delticket #num
+ if(num > 0)
+ {
+ QueryResult* result = CharacterDatabase.PQuery("SELECT guid FROM character_ticket ORDER BY ticket_id ASC "_OFFSET_,num-1);
+ if(!result)
+ {
+ PSendSysMessage(LANG_COMMAND_TICKENOTEXIST, num);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Field* fields = result->Fetch();
+
+ uint32 guid = fields[0].GetUInt32();
+ delete result;
+
+ ticketmgr.Delete(guid);
+
+ //notify player
+ if(Player* pl = objmgr.GetPlayer(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)))
+ {
+ pl->GetSession()->SendGMTicketGetTicket(0x0A, 0);
+ PSendSysMessage(LANG_COMMAND_TICKETPLAYERDEL, pl->GetName());
+ }
+ else
+ PSendSysMessage(LANG_COMMAND_TICKETDEL);
+
+ return true;
+ }
+
+ std::string name = px;
+
+ if(!normalizePlayerName(name))
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint64 guid = objmgr.GetPlayerGUIDByName(name);
+
+ if(!guid)
+ return false;
+
+ // delticket $char_name
+ ticketmgr.Delete(GUID_LOPART(guid));
+
+ // notify players about ticket deleting
+ if(Player* sender = objmgr.GetPlayer(guid))
+ sender->GetSession()->SendGMTicketGetTicket(0x0A,0);
+
+ PSendSysMessage(LANG_COMMAND_TICKETPLAYERDEL,px);
+ return true;
+}
+
+//set spawn dist of creature
+bool ChatHandler::HandleNpcSpawnDistCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ float option = atof((char*)args);
+ if (option < 0.0f)
+ {
+ SendSysMessage(LANG_BAD_VALUE);
+ return false;
+ }
+
+ MovementGeneratorType mtype = IDLE_MOTION_TYPE;
+ if (option >0.0f)
+ mtype = RANDOM_MOTION_TYPE;
+
+ Creature *pCreature = getSelectedCreature();
+ uint32 u_guidlow = 0;
+
+ if (pCreature)
+ u_guidlow = pCreature->GetDBTableGUIDLow();
+ else
+ return false;
+
+ pCreature->SetRespawnRadius((float)option);
+ pCreature->SetDefaultMovementType(mtype);
+ pCreature->GetMotionMaster()->Initialize();
+ if(pCreature->isAlive()) // dead creature will reset movement generator at respawn
+ {
+ pCreature->setDeathState(JUST_DIED);
+ pCreature->Respawn();
+ }
+
+ WorldDatabase.PExecuteLog("UPDATE creature SET spawndist=%f, MovementType=%i WHERE guid=%u",option,mtype,u_guidlow);
+ PSendSysMessage(LANG_COMMAND_SPAWNDIST,option);
+ return true;
+}
+
+bool ChatHandler::HandleNpcSpawnTimeCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ char* stime = strtok((char*)args, " ");
+
+ if (!stime)
+ return false;
+
+ int i_stime = atoi((char*)stime);
+
+ if (i_stime < 0)
+ {
+ SendSysMessage(LANG_BAD_VALUE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Creature *pCreature = getSelectedCreature();
+ uint32 u_guidlow = 0;
+
+ if (pCreature)
+ u_guidlow = pCreature->GetDBTableGUIDLow();
+ else
+ return false;
+
+ WorldDatabase.PExecuteLog("UPDATE creature SET spawntimesecs=%i WHERE guid=%u",i_stime,u_guidlow);
+ pCreature->SetRespawnDelay((uint32)i_stime);
+ PSendSysMessage(LANG_COMMAND_SPAWNTIME,i_stime);
+
+ return true;
+}
+
+/**
+ * Add a waypoint to a creature.
+ *
+ * The user can either select an npc or provide its GUID.
+ *
+ * The user can even select a visual waypoint - then the new waypoint
+ * is placed *after* the selected one - this makes insertion of new
+ * waypoints possible.
+ *
+ * eg:
+ * .wp add 12345
+ * -> adds a waypoint to the npc with the GUID 12345
+ *
+ * .wp add
+ * -> adds a waypoint to the currently selected creature
+ *
+ *
+ * @param args if the user did not provide a GUID, it is NULL
+ *
+ * @return true - command did succeed, false - something went wrong
+ */
+bool ChatHandler::HandleWpAddCommand(const char* args)
+{
+ sLog.outDebug("DEBUG: HandleWpAddCommand");
+
+ // optional
+ char* guid_str = NULL;
+
+ if(*args)
+ {
+ guid_str = strtok((char*)args, " ");
+ }
+
+ uint32 lowguid = 0;
+ uint32 point = 0;
+ Creature* target = getSelectedCreature();
+ // Did player provide a GUID?
+ if (!guid_str)
+ {
+ sLog.outDebug("DEBUG: HandleWpAddCommand - No GUID provided");
+
+ // No GUID provided
+ // -> Player must have selected a creature
+
+ if(!target || target->isPet())
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ if (target->GetEntry() == VISUAL_WAYPOINT )
+ {
+ sLog.outDebug("DEBUG: HandleWpAddCommand - target->GetEntry() == VISUAL_WAYPOINT (1) ");
+
+ QueryResult *result =
+ WorldDatabase.PQuery( "SELECT id, point FROM creature_movement WHERE wpguid = %u",
+ target->GetGUIDLow() );
+ if(!result)
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, target->GetGUIDLow());
+ // User selected a visual spawnpoint -> get the NPC
+ // Select NPC GUID
+ // Since we compare float values, we have to deal with
+ // some difficulties.
+ // Here we search for all waypoints that only differ in one from 1 thousand
+ // (0.001) - There is no other way to compare C++ floats with mySQL floats
+ // See also: http://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html
+ const char* maxDIFF = "0.01";
+ result = WorldDatabase.PQuery( "SELECT id, point FROM creature_movement WHERE (abs(position_x - %f) <= %s ) and (abs(position_y - %f) <= %s ) and (abs(position_z - %f) <= %s )",
+ target->GetPositionX(), maxDIFF, target->GetPositionY(), maxDIFF, target->GetPositionZ(), maxDIFF);
+ if(!result)
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, target->GetGUIDLow());
+ SetSentErrorMessage(true);
+ return false;
+ }
+ }
+ do
+ {
+ Field *fields = result->Fetch();
+ lowguid = fields[0].GetUInt32();
+ point = fields[1].GetUInt32();
+ }while( result->NextRow() );
+ delete result;
+
+ CreatureData const* data = objmgr.GetCreatureData(lowguid);
+ if(!data)
+ {
+ PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ target = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,data->id,HIGHGUID_UNIT));
+ if(!target)
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ }
+ else
+ {
+ lowguid = target->GetDBTableGUIDLow();
+ }
+ }
+ else
+ {
+ sLog.outDebug("DEBUG: HandleWpAddCommand - GUID provided");
+
+ // GUID provided
+ // Warn if player also selected a creature
+ // -> Creature selection is ignored <-
+ if(target)
+ {
+ SendSysMessage(LANG_WAYPOINT_CREATSELECTED);
+ }
+ lowguid = atoi((char*)guid_str);
+
+ CreatureData const* data = objmgr.GetCreatureData(lowguid);
+ if(!data)
+ {
+ PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ target = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,data->id,HIGHGUID_UNIT));
+ if(!target || target->isPet())
+ {
+ PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ }
+ // lowguid -> GUID of the NPC
+ // point -> number of the waypoint (if not 0)
+ sLog.outDebug("DEBUG: HandleWpAddCommand - danach");
+
+ sLog.outDebug("DEBUG: HandleWpAddCommand - point == 0");
+
+ Player* player = m_session->GetPlayer();
+ WaypointMgr.AddLastNode(lowguid, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), 0, 0);
+
+ // update movement type
+ if(target)
+ {
+ target->SetDefaultMovementType(WAYPOINT_MOTION_TYPE);
+ target->GetMotionMaster()->Initialize();
+ if(target->isAlive()) // dead creature will reset movement generator at respawn
+ {
+ target->setDeathState(JUST_DIED);
+ target->Respawn();
+ }
+ target->SaveToDB();
+ }
+ else
+ WorldDatabase.PExecuteLog("UPDATE creature SET MovementType = '%u' WHERE guid = '%u'", WAYPOINT_MOTION_TYPE,lowguid);
+
+ PSendSysMessage(LANG_WAYPOINT_ADDED, point, lowguid);
+
+ return true;
+} // HandleWpAddCommand
+
+/**
+ * .wp modify emote | spell | text | del | move | add
+ *
+ * add -> add a WP after the selected visual waypoint
+ * User must select a visual waypoint and then issue ".wp modify add"
+ *
+ * emote <emoteID>
+ * User has selected a visual waypoint before.
+ * <emoteID> is added to this waypoint. Everytime the
+ * NPC comes to this waypoint, the emote is called.
+ *
+ * emote <GUID> <WPNUM> <emoteID>
+ * User has not selected visual waypoint before.
+ * For the waypoint <WPNUM> for the NPC with <GUID>
+ * an emote <emoteID> is added.
+ * Everytime the NPC comes to this waypoint, the emote is called.
+ *
+ *
+ * info <GUID> <WPNUM> -> User did not select a visual waypoint and
+ */
+bool ChatHandler::HandleWpModifyCommand(const char* args)
+{
+ sLog.outDebug("DEBUG: HandleWpModifyCommand");
+
+ if(!*args)
+ return false;
+
+ // first arg: add del text emote spell waittime move
+ char* show_str = strtok((char*)args, " ");
+ if (!show_str)
+ {
+ return false;
+ }
+
+ std::string show = show_str;
+ // Check
+ // Remember: "show" must also be the name of a column!
+ if( (show != "emote") && (show != "spell") && (show != "textid1") && (show != "textid2")
+ && (show != "textid3") && (show != "textid4") && (show != "textid5")
+ && (show != "waittime") && (show != "del") && (show != "move") && (show != "add")
+ && (show != "model1") && (show != "model2") && (show != "orientation"))
+ {
+ return false;
+ }
+
+ // Next arg is: <GUID> <WPNUM> <ARGUMENT>
+
+ // Did user provide a GUID
+ // or did the user select a creature?
+ // -> variable lowguid is filled with the GUID of the NPC
+ uint32 lowguid = 0;
+ uint32 point = 0;
+ uint32 wpGuid = 0;
+ Creature* target = getSelectedCreature();
+
+ if(target)
+ {
+ sLog.outDebug("DEBUG: HandleWpModifyCommand - User did select an NPC");
+
+ // Did the user select a visual spawnpoint?
+ if (target->GetEntry() != VISUAL_WAYPOINT )
+ {
+ PSendSysMessage(LANG_WAYPOINT_VP_SELECT);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ wpGuid = target->GetGUIDLow();
+
+ // The visual waypoint
+ QueryResult *result =
+ WorldDatabase.PQuery( "SELECT id, point FROM creature_movement WHERE wpguid = %u LIMIT 1",
+ target->GetGUIDLow() );
+ if(!result)
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, wpGuid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ sLog.outDebug("DEBUG: HandleWpModifyCommand - After getting wpGuid");
+
+ Field *fields = result->Fetch();
+ lowguid = fields[0].GetUInt32();
+ point = fields[1].GetUInt32();
+
+ // Cleanup memory
+ sLog.outDebug("DEBUG: HandleWpModifyCommand - Cleanup memory");
+ delete result;
+ }
+ else
+ {
+ // User did provide <GUID> <WPNUM>
+
+ char* guid_str = strtok((char*)NULL, " ");
+ if( !guid_str )
+ {
+ SendSysMessage(LANG_WAYPOINT_NOGUID);
+ return false;
+ }
+ lowguid = atoi((char*)guid_str);
+
+ CreatureData const* data = objmgr.GetCreatureData(lowguid);
+ if(!data)
+ {
+ PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ PSendSysMessage("DEBUG: GUID provided: %d", lowguid);
+
+ char* point_str = strtok((char*)NULL, " ");
+ if( !point_str )
+ {
+ SendSysMessage(LANG_WAYPOINT_NOWAYPOINTGIVEN);
+ return false;
+ }
+ point = atoi((char*)point_str);
+
+ PSendSysMessage("DEBUG: wpNumber provided: %d", point);
+
+ // Now we need the GUID of the visual waypoint
+ // -> "del", "move", "add" command
+
+ QueryResult *result = WorldDatabase.PQuery( "SELECT wpguid FROM creature_movement WHERE id = '%u' AND point = '%u' LIMIT 1", lowguid, point);
+ if (!result)
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, lowguid, point);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Field *fields = result->Fetch();
+ wpGuid = fields[0].GetUInt32();
+
+ // Free memory
+ delete result;
+ }
+
+ char* arg_str = NULL;
+ // Check for argument
+ if( (show.find("text") == std::string::npos ) && (show != "del") && (show != "move") && (show != "add"))
+ {
+ // Text is enclosed in "<>", all other arguments not
+ if( show.find("text") != std::string::npos )
+ arg_str = strtok((char*)NULL, "<>");
+ else
+ arg_str = strtok((char*)NULL, " ");
+
+ if( !arg_str)
+ {
+ PSendSysMessage(LANG_WAYPOINT_ARGUMENTREQ, show_str);
+ return false;
+ }
+ }
+
+ sLog.outDebug("DEBUG: HandleWpModifyCommand - Parameters parsed - now execute the command");
+
+ // wpGuid -> GUID of the waypoint creature
+ // lowguid -> GUID of the NPC
+ // point -> waypoint number
+
+ // Special functions:
+ // add - move - del -> no args commands
+ // Add a waypoint after the selected visual
+ if(show == "add" && target)
+ {
+ PSendSysMessage("DEBUG: wp modify add, GUID: %u", lowguid);
+
+ // Get the creature for which we read the waypoint
+ CreatureData const* data = objmgr.GetCreatureData(lowguid);
+ if(!data)
+ {
+ PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT));
+
+ if( !npcCreature )
+ {
+ PSendSysMessage(LANG_WAYPOINT_NPCNOTFOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ sLog.outDebug("DEBUG: HandleWpModifyCommand - add -- npcCreature");
+
+ // What to do:
+ // Add the visual spawnpoint (DB only)
+ // Adjust the waypoints
+ // Respawn the owner of the waypoints
+ sLog.outDebug("DEBUG: HandleWpModifyCommand - add");
+
+ Player* chr = m_session->GetPlayer();
+ Map *map = chr->GetMap();
+
+ if(npcCreature)
+ {
+ npcCreature->GetMotionMaster()->Initialize();
+ if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn
+ {
+ npcCreature->setDeathState(JUST_DIED);
+ npcCreature->Respawn();
+ }
+ }
+
+ // create the waypoint creature
+ wpGuid = 0;
+ Creature* wpCreature = new Creature;
+ if (!wpCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map,VISUAL_WAYPOINT,0))
+ {
+ PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT);
+ delete wpCreature;
+ }
+ else
+ {
+ wpCreature->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation());
+
+ if(!wpCreature->IsPositionValid())
+ {
+ sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature->GetGUIDLow(),wpCreature->GetEntry(),wpCreature->GetPositionX(),wpCreature->GetPositionY());
+ delete wpCreature;
+ }
+ else
+ {
+ wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
+ // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
+ wpCreature->LoadFromDB(wpCreature->GetDBTableGUIDLow(), map);
+ map->Add(wpCreature);
+ wpGuid = wpCreature->GetGUIDLow();
+ }
+ }
+
+ WaypointMgr.AddAfterNode(lowguid, point, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), 0, 0, wpGuid);
+
+ if(!wpGuid)
+ return false;
+
+ PSendSysMessage(LANG_WAYPOINT_ADDED_NO, point+1);
+ return true;
+ } // add
+
+ if(show == "del" && target)
+ {
+ PSendSysMessage("DEBUG: wp modify del, GUID: %u", lowguid);
+
+ // Get the creature for which we read the waypoint
+ CreatureData const* data = objmgr.GetCreatureData(lowguid);
+ if(!data)
+ {
+ PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT));
+
+ // wpCreature
+ Creature* wpCreature = NULL;
+ if( wpGuid != 0 )
+ {
+ wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT));
+ wpCreature->DeleteFromDB();
+ wpCreature->CleanupsBeforeDelete();
+ wpCreature->AddObjectToRemoveList();
+ }
+
+ // What to do:
+ // Remove the visual spawnpoint
+ // Adjust the waypoints
+ // Respawn the owner of the waypoints
+
+ WaypointMgr.DeleteNode(lowguid, point);
+
+ if(npcCreature)
+ {
+ // Any waypoints left?
+ QueryResult *result2 = WorldDatabase.PQuery( "SELECT point FROM creature_movement WHERE id = '%u'",lowguid);
+ if(!result2)
+ {
+ npcCreature->SetDefaultMovementType(RANDOM_MOTION_TYPE);
+ }
+ else
+ {
+ npcCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE);
+ delete result2;
+ }
+ npcCreature->GetMotionMaster()->Initialize();
+ if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn
+ {
+ npcCreature->setDeathState(JUST_DIED);
+ npcCreature->Respawn();
+ }
+ npcCreature->SaveToDB();
+ }
+
+ PSendSysMessage(LANG_WAYPOINT_REMOVED);
+ return true;
+ } // del
+
+ if(show == "move" && target)
+ {
+ PSendSysMessage("DEBUG: wp move, GUID: %u", lowguid);
+
+ Player *chr = m_session->GetPlayer();
+ Map *map = chr->GetMap();
+ {
+ // Get the creature for which we read the waypoint
+ CreatureData const* data = objmgr.GetCreatureData(lowguid);
+ if(!data)
+ {
+ PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT));
+
+ // wpCreature
+ Creature* wpCreature = NULL;
+ // What to do:
+ // Move the visual spawnpoint
+ // Respawn the owner of the waypoints
+ if( wpGuid != 0 )
+ {
+ wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpGuid, VISUAL_WAYPOINT, HIGHGUID_UNIT));
+ wpCreature->DeleteFromDB();
+ wpCreature->CleanupsBeforeDelete();
+ wpCreature->AddObjectToRemoveList();
+ // re-create
+ Creature* wpCreature2 = new Creature;
+ if (!wpCreature2->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, VISUAL_WAYPOINT, 0))
+ {
+ PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT);
+ delete wpCreature2;
+ return false;
+ }
+
+ wpCreature2->Relocate(chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation());
+
+ if(!wpCreature2->IsPositionValid())
+ {
+ sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature2->GetGUIDLow(),wpCreature2->GetEntry(),wpCreature2->GetPositionX(),wpCreature2->GetPositionY());
+ delete wpCreature2;
+ return false;
+ }
+
+ wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
+ // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
+ wpCreature2->LoadFromDB(wpCreature2->GetDBTableGUIDLow(), map);
+ map->Add(wpCreature2);
+ //MapManager::Instance().GetMap(npcCreature->GetMapId())->Add(wpCreature2);
+ }
+
+ WaypointMgr.SetNodePosition(lowguid, point, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ());
+
+ if(npcCreature)
+ {
+ npcCreature->GetMotionMaster()->Initialize();
+ if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn
+ {
+ npcCreature->setDeathState(JUST_DIED);
+ npcCreature->Respawn();
+ }
+ }
+ PSendSysMessage(LANG_WAYPOINT_CHANGED);
+ }
+ return true;
+ } // move
+
+ // Create creature - npc that has the waypoint
+ CreatureData const* data = objmgr.GetCreatureData(lowguid);
+ if(!data)
+ {
+ PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ // set in game textids not supported
+ if( show == "textid1" || show == "textid2" || show == "textid3" ||
+ show == "textid4" || show == "textid5" )
+ {
+ return false;
+ }
+
+ WaypointMgr.SetNodeText(lowguid, point, show_str, arg_str);
+
+ Creature* npcCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), MAKE_NEW_GUID(lowguid, data->id, HIGHGUID_UNIT));
+ if(npcCreature)
+ {
+ npcCreature->SetDefaultMovementType(WAYPOINT_MOTION_TYPE);
+ npcCreature->GetMotionMaster()->Initialize();
+ if(npcCreature->isAlive()) // dead creature will reset movement generator at respawn
+ {
+ npcCreature->setDeathState(JUST_DIED);
+ npcCreature->Respawn();
+ }
+ }
+ PSendSysMessage(LANG_WAYPOINT_CHANGED_NO, show_str);
+
+ return true;
+}
+
+/**
+ * .wp show info | on | off
+ *
+ * info -> User has selected a visual waypoint before
+ *
+ * info <GUID> <WPNUM> -> User did not select a visual waypoint and
+ * provided the GUID of the NPC and the number of
+ * the waypoint.
+ *
+ * on -> User has selected an NPC; all visual waypoints for this
+ * NPC are added to the world
+ *
+ * on <GUID> -> User did not select an NPC - instead the GUID of the
+ * NPC is provided. All visual waypoints for this NPC
+ * are added from the world.
+ *
+ * off -> User has selected an NPC; all visual waypoints for this
+ * NPC are removed from the world.
+ *
+ * on <GUID> -> User did not select an NPC - instead the GUID of the
+ * NPC is provided. All visual waypoints for this NPC
+ * are removed from the world.
+ *
+ *
+ */
+bool ChatHandler::HandleWpShowCommand(const char* args)
+{
+ sLog.outDebug("DEBUG: HandleWpShowCommand");
+
+ if(!*args)
+ return false;
+
+ // first arg: on, off, first, last
+ char* show_str = strtok((char*)args, " ");
+ if (!show_str)
+ {
+ return false;
+ }
+ // second arg: GUID (optional, if a creature is selected)
+ char* guid_str = strtok((char*)NULL, " ");
+ sLog.outDebug("DEBUG: HandleWpShowCommand: show_str: %s guid_str: %s", show_str, guid_str);
+ //if (!guid_str) {
+ // return false;
+ //}
+
+ // Did user provide a GUID
+ // or did the user select a creature?
+ // -> variable lowguid is filled with the GUID
+ Creature* target = getSelectedCreature();
+ // Did player provide a GUID?
+ if (!guid_str)
+ {
+ sLog.outDebug("DEBUG: HandleWpShowCommand: !guid_str");
+ // No GUID provided
+ // -> Player must have selected a creature
+
+ if(!target)
+ {
+ SendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ }
+ else
+ {
+ sLog.outDebug("DEBUG: HandleWpShowCommand: GUID provided");
+ // GUID provided
+ // Warn if player also selected a creature
+ // -> Creature selection is ignored <-
+ if(target)
+ {
+ SendSysMessage(LANG_WAYPOINT_CREATSELECTED);
+ }
+
+ uint32 lowguid = atoi((char*)guid_str);
+
+ CreatureData const* data = objmgr.GetCreatureData(lowguid);
+ if(!data)
+ {
+ PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ target = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(lowguid,data->id,HIGHGUID_UNIT));
+
+ if(!target)
+ {
+ PSendSysMessage(LANG_WAYPOINT_CREATNOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ }
+
+ uint32 lowguid = target->GetDBTableGUIDLow();
+
+ std::string show = show_str;
+ uint32 Maxpoint;
+
+ sLog.outDebug("DEBUG: HandleWpShowCommand: lowguid: %u show: %s", lowguid, show_str);
+
+ // Show info for the selected waypoint
+ if(show == "info")
+ {
+ PSendSysMessage("DEBUG: wp info, GUID: %u", lowguid);
+
+ // Check if the user did specify a visual waypoint
+ if( target->GetEntry() != VISUAL_WAYPOINT )
+ {
+ PSendSysMessage(LANG_WAYPOINT_VP_SELECT);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ //PSendSysMessage("wp on, GUID: %u", lowguid);
+
+ //pCreature->GetPositionX();
+
+ QueryResult *result =
+ WorldDatabase.PQuery( "SELECT id, point, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5, model1, model2 FROM creature_movement WHERE wpguid = %u",
+ target->GetGUIDLow() );
+ if(!result)
+ {
+ // Since we compare float values, we have to deal with
+ // some difficulties.
+ // Here we search for all waypoints that only differ in one from 1 thousand
+ // (0.001) - There is no other way to compare C++ floats with mySQL floats
+ // See also: http://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html
+ const char* maxDIFF = "0.01";
+ PSendSysMessage(LANG_WAYPOINT_NOTFOUNDSEARCH, target->GetGUID());
+
+ result = WorldDatabase.PQuery( "SELECT id, point, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5, model1, model2 FROM creature_movement WHERE (abs(position_x - %f) <= %s ) and (abs(position_y - %f) <= %s ) and (abs(position_z - %f) <= %s )",
+ target->GetPositionX(), maxDIFF, target->GetPositionY(), maxDIFF, target->GetPositionZ(), maxDIFF);
+ if(!result)
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ }
+ do
+ {
+ Field *fields = result->Fetch();
+ uint32 creGUID = fields[0].GetUInt32();
+ uint32 point = fields[1].GetUInt32();
+ int waittime = fields[2].GetUInt32();
+ uint32 emote = fields[3].GetUInt32();
+ uint32 spell = fields[4].GetUInt32();
+ uint32 textid[MAX_WAYPOINT_TEXT];
+ for(int i = 0; i < MAX_WAYPOINT_TEXT; ++i)
+ textid[i] = fields[5+i].GetUInt32();
+ uint32 model1 = fields[10].GetUInt32();
+ uint32 model2 = fields[11].GetUInt32();
+
+ // Get the creature for which we read the waypoint
+ Creature* wpCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(creGUID,VISUAL_WAYPOINT,HIGHGUID_UNIT));
+
+ PSendSysMessage(LANG_WAYPOINT_INFO_TITLE, point, (wpCreature ? wpCreature->GetName() : "<not found>"), creGUID);
+ PSendSysMessage(LANG_WAYPOINT_INFO_WAITTIME, waittime);
+ PSendSysMessage(LANG_WAYPOINT_INFO_MODEL, 1, model1);
+ PSendSysMessage(LANG_WAYPOINT_INFO_MODEL, 2, model2);
+ PSendSysMessage(LANG_WAYPOINT_INFO_EMOTE, emote);
+ PSendSysMessage(LANG_WAYPOINT_INFO_SPELL, spell);
+ for(int i = 0; i < MAX_WAYPOINT_TEXT; ++i)
+ PSendSysMessage(LANG_WAYPOINT_INFO_TEXT, i+1, textid[i], (textid[i] ? GetTrinityString(textid[i]) : ""));
+
+ }while( result->NextRow() );
+ // Cleanup memory
+ delete result;
+ return true;
+ }
+
+ if(show == "on")
+ {
+ PSendSysMessage("DEBUG: wp on, GUID: %u", lowguid);
+
+ QueryResult *result = WorldDatabase.PQuery( "SELECT point, position_x,position_y,position_z FROM creature_movement WHERE id = '%u'",lowguid);
+ if(!result)
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ // Delete all visuals for this NPC
+ QueryResult *result2 = WorldDatabase.PQuery( "SELECT wpguid FROM creature_movement WHERE id = '%u' and wpguid <> 0", lowguid);
+ if(result2)
+ {
+ bool hasError = false;
+ do
+ {
+ Field *fields = result2->Fetch();
+ uint32 wpguid = fields[0].GetUInt32();
+ Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(wpguid,VISUAL_WAYPOINT,HIGHGUID_UNIT));
+
+ if(!pCreature)
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, wpguid);
+ hasError = true;
+ WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", wpguid);
+ }
+ else
+ {
+ pCreature->DeleteFromDB();
+ pCreature->CleanupsBeforeDelete();
+ pCreature->AddObjectToRemoveList();
+ }
+
+ }while( result2->NextRow() );
+ delete result2;
+ if( hasError )
+ {
+ PSendSysMessage(LANG_WAYPOINT_TOOFAR1);
+ PSendSysMessage(LANG_WAYPOINT_TOOFAR2);
+ PSendSysMessage(LANG_WAYPOINT_TOOFAR3);
+ }
+ }
+
+ do
+ {
+ Field *fields = result->Fetch();
+ uint32 point = fields[0].GetUInt32();
+ float x = fields[1].GetFloat();
+ float y = fields[2].GetFloat();
+ float z = fields[3].GetFloat();
+
+ uint32 id = VISUAL_WAYPOINT;
+
+ Player *chr = m_session->GetPlayer();
+ Map *map = chr->GetMap();
+ float o = chr->GetOrientation();
+
+ Creature* wpCreature = new Creature;
+ if (!wpCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, id, 0))
+ {
+ PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id);
+ delete wpCreature;
+ delete result;
+ return false;
+ }
+
+ wpCreature->Relocate(x, y, z, o);
+
+ if(!wpCreature->IsPositionValid())
+ {
+ sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",wpCreature->GetGUIDLow(),wpCreature->GetEntry(),wpCreature->GetPositionX(),wpCreature->GetPositionY());
+ delete wpCreature;
+ delete result;
+ return false;
+ }
+
+ wpCreature->SetVisibility(VISIBILITY_OFF);
+ sLog.outDebug("DEBUG: UPDATE creature_movement SET wpguid = '%u");
+ // set "wpguid" column to the visual waypoint
+ WorldDatabase.PExecuteLog("UPDATE creature_movement SET wpguid = '%u' WHERE id = '%u' and point = '%u'", wpCreature->GetGUIDLow(), lowguid, point);
+
+ wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
+ // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells();
+ wpCreature->LoadFromDB(wpCreature->GetDBTableGUIDLow(),map);
+ map->Add(wpCreature);
+ //MapManager::Instance().GetMap(wpCreature->GetMapId())->Add(wpCreature);
+ }while( result->NextRow() );
+
+ // Cleanup memory
+ delete result;
+ return true;
+ }
+
+ if(show == "first")
+ {
+ PSendSysMessage("DEBUG: wp first, GUID: %u", lowguid);
+
+ QueryResult *result = WorldDatabase.PQuery( "SELECT position_x,position_y,position_z FROM creature_movement WHERE point='1' AND id = '%u'",lowguid);
+ if(!result)
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Field *fields = result->Fetch();
+ float x = fields[0].GetFloat();
+ float y = fields[1].GetFloat();
+ float z = fields[2].GetFloat();
+ uint32 id = VISUAL_WAYPOINT;
+
+ Player *chr = m_session->GetPlayer();
+ float o = chr->GetOrientation();
+ Map *map = chr->GetMap();
+
+ Creature* pCreature = new Creature;
+ if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT),map, id, 0))
+ {
+ PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id);
+ delete pCreature;
+ delete result;
+ return false;
+ }
+
+ pCreature->Relocate(x, y, z, o);
+
+ if(!pCreature->IsPositionValid())
+ {
+ sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
+ delete pCreature;
+ delete result;
+ return false;
+ }
+
+ pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
+ pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), map);
+ map->Add(pCreature);
+ //player->PlayerTalkClass->SendPointOfInterest(x, y, 6, 6, 0, "First Waypoint");
+
+ // Cleanup memory
+ delete result;
+ return true;
+ }
+
+ if(show == "last")
+ {
+ PSendSysMessage("DEBUG: wp last, GUID: %u", lowguid);
+
+ QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM creature_movement WHERE id = '%u'",lowguid);
+ if( result )
+ {
+ Maxpoint = (*result)[0].GetUInt32();
+
+ delete result;
+ }
+ else
+ Maxpoint = 0;
+
+ result = WorldDatabase.PQuery( "SELECT position_x,position_y,position_z FROM creature_movement WHERE point ='%u' AND id = '%u'",Maxpoint, lowguid);
+ if(!result)
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTFOUNDLAST, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ Field *fields = result->Fetch();
+ float x = fields[0].GetFloat();
+ float y = fields[1].GetFloat();
+ float z = fields[2].GetFloat();
+ uint32 id = VISUAL_WAYPOINT;
+
+ Player *chr = m_session->GetPlayer();
+ float o = chr->GetOrientation();
+ Map *map = chr->GetMap();
+
+ Creature* pCreature = new Creature;
+ if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, id, 0))
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTCREATED, id);
+ delete pCreature;
+ delete result;
+ return false;
+ }
+
+ pCreature->Relocate(x, y, z, o);
+
+ if(!pCreature->IsPositionValid())
+ {
+ sLog.outError("ERROR: Creature (guidlow %d, entry %d) not created. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
+ delete pCreature;
+ delete result;
+ return false;
+ }
+
+ pCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
+ pCreature->LoadFromDB(pCreature->GetDBTableGUIDLow(), map);
+ map->Add(pCreature);
+ //player->PlayerTalkClass->SendPointOfInterest(x, y, 6, 6, 0, "Last Waypoint");
+ // Cleanup memory
+ delete result;
+ return true;
+ }
+
+ if(show == "off")
+ {
+ QueryResult *result = WorldDatabase.PQuery("SELECT guid FROM creature WHERE id = '%d'", VISUAL_WAYPOINT);
+ if(!result)
+ {
+ SendSysMessage(LANG_WAYPOINT_VP_NOTFOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ bool hasError = false;
+ do
+ {
+ Field *fields = result->Fetch();
+ uint32 guid = fields[0].GetUInt32();
+ Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(),MAKE_NEW_GUID(guid,VISUAL_WAYPOINT,HIGHGUID_UNIT));
+
+ //Creature* pCreature = ObjectAccessor::GetCreature(*m_session->GetPlayer(), guid);
+
+ if(!pCreature)
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTREMOVED, guid);
+ hasError = true;
+ WorldDatabase.PExecuteLog("DELETE FROM creature WHERE guid = '%u'", guid);
+ }
+ else
+ {
+ pCreature->DeleteFromDB();
+ pCreature->CleanupsBeforeDelete();
+ pCreature->AddObjectToRemoveList();
+ }
+ }while(result->NextRow());
+ // set "wpguid" column to "empty" - no visual waypoint spawned
+ WorldDatabase.PExecuteLog("UPDATE creature_movement SET wpguid = '0'");
+
+ if( hasError )
+ {
+ PSendSysMessage(LANG_WAYPOINT_TOOFAR1);
+ PSendSysMessage(LANG_WAYPOINT_TOOFAR2);
+ PSendSysMessage(LANG_WAYPOINT_TOOFAR3);
+ }
+
+ SendSysMessage(LANG_WAYPOINT_VP_ALLREMOVED);
+ // Cleanup memory
+ delete result;
+
+ return true;
+ }
+
+ PSendSysMessage("DEBUG: wpshow - no valid command found");
+
+ return true;
+} // HandleWpShowCommand
+
+bool ChatHandler::HandleWpExportCommand(const char *args)
+{
+ if(!*args)
+ return false;
+
+ // Next arg is: <GUID> <ARGUMENT>
+
+ // Did user provide a GUID
+ // or did the user select a creature?
+ // -> variable lowguid is filled with the GUID of the NPC
+ uint32 lowguid = 0;
+ Creature* target = getSelectedCreature();
+ char* arg_str = NULL;
+ if (target)
+ {
+ if (target->GetEntry() != VISUAL_WAYPOINT)
+ lowguid = target->GetGUIDLow();
+ else
+ {
+ QueryResult *result = WorldDatabase.PQuery( "SELECT id FROM creature_movement WHERE wpguid = %u LIMIT 1", target->GetGUIDLow() );
+ if (!result)
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTFOUNDDBPROBLEM, target->GetGUIDLow());
+ return true;
+ }
+ Field *fields = result->Fetch();
+ lowguid = fields[0].GetUInt32();;
+ delete result;
+ }
+
+ arg_str = strtok((char*)args, " ");
+ }
+ else
+ {
+ // user provided <GUID>
+ char* guid_str = strtok((char*)args, " ");
+ if( !guid_str )
+ {
+ SendSysMessage(LANG_WAYPOINT_NOGUID);
+ return false;
+ }
+ lowguid = atoi((char*)guid_str);
+
+ arg_str = strtok((char*)NULL, " ");
+ }
+
+ if( !arg_str)
+ {
+ PSendSysMessage(LANG_WAYPOINT_ARGUMENTREQ, "export");
+ return false;
+ }
+
+ PSendSysMessage("DEBUG: wp export, GUID: %u", lowguid);
+
+ QueryResult *result = WorldDatabase.PQuery(
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ "SELECT point, position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5, id FROM creature_movement WHERE id = '%u' ORDER BY point", lowguid );
+
+ if (!result)
+ {
+ PSendSysMessage(LANG_WAYPOINT_NOTHINGTOEXPORT);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ std::ofstream outfile;
+ outfile.open (arg_str);
+
+ do
+ {
+ Field *fields = result->Fetch();
+
+ outfile << "INSERT INTO creature_movement ";
+ outfile << "( id, point, position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5 ) VALUES ";
+
+ outfile << "( ";
+ outfile << fields[15].GetUInt32(); // id
+ outfile << ", ";
+ outfile << fields[0].GetUInt32(); // point
+ outfile << ", ";
+ outfile << fields[1].GetFloat(); // position_x
+ outfile << ", ";
+ outfile << fields[2].GetFloat(); // position_y
+ outfile << ", ";
+ outfile << fields[3].GetUInt32(); // position_z
+ outfile << ", ";
+ outfile << fields[4].GetUInt32(); // orientation
+ outfile << ", ";
+ outfile << fields[5].GetUInt32(); // model1
+ outfile << ", ";
+ outfile << fields[6].GetUInt32(); // model2
+ outfile << ", ";
+ outfile << fields[7].GetUInt16(); // waittime
+ outfile << ", ";
+ outfile << fields[8].GetUInt32(); // emote
+ outfile << ", ";
+ outfile << fields[9].GetUInt32(); // spell
+ outfile << ", ";
+ outfile << fields[10].GetUInt32(); // textid1
+ outfile << ", ";
+ outfile << fields[11].GetUInt32(); // textid2
+ outfile << ", ";
+ outfile << fields[12].GetUInt32(); // textid3
+ outfile << ", ";
+ outfile << fields[13].GetUInt32(); // textid4
+ outfile << ", ";
+ outfile << fields[14].GetUInt32(); // textid5
+ outfile << ");\n ";
+
+ } while( result->NextRow() );
+ delete result;
+
+ PSendSysMessage(LANG_WAYPOINT_EXPORTED);
+ outfile.close();
+
+ return true;
+}
+
+bool ChatHandler::HandleWpImportCommand(const char *args)
+{
+ if(!*args)
+ return false;
+
+ char* arg_str = strtok((char*)args, " ");
+ if (!arg_str)
+ return false;
+
+ std::string line;
+ std::ifstream infile (arg_str);
+ if (infile.is_open())
+ {
+ while (! infile.eof() )
+ {
+ getline (infile,line);
+ //cout << line << endl;
+ QueryResult *result = WorldDatabase.Query(line.c_str());
+ delete result;
+ }
+ infile.close();
+ }
+ PSendSysMessage(LANG_WAYPOINT_IMPORTED);
+
+ return true;
+}
+
+//rename characters
+bool ChatHandler::HandleRenameCommand(const char* args)
+{
+ Player* target = NULL;
+ uint64 targetGUID = 0;
+ std::string oldname;
+
+ char* px = strtok((char*)args, " ");
+
+ if(px)
+ {
+ oldname = px;
+
+ if(!normalizePlayerName(oldname))
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ target = objmgr.GetPlayer(oldname.c_str());
+
+ if (!target)
+ targetGUID = objmgr.GetPlayerGUIDByName(oldname);
+ }
+
+ if(!target && !targetGUID)
+ {
+ target = getSelectedPlayer();
+ }
+
+ if(!target && !targetGUID)
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if(target)
+ {
+ PSendSysMessage(LANG_RENAME_PLAYER, target->GetName());
+ target->SetAtLoginFlag(AT_LOGIN_RENAME);
+ CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '1' WHERE guid = '%u'", target->GetGUIDLow());
+ }
+ else
+ {
+ PSendSysMessage(LANG_RENAME_PLAYER_GUID, oldname.c_str(), GUID_LOPART(targetGUID));
+ CharacterDatabase.PExecute("UPDATE characters SET at_login = at_login | '1' WHERE guid = '%u'", GUID_LOPART(targetGUID));
+ }
+
+ return true;
+}
+
+//spawn go
+bool ChatHandler::HandleGameObjectCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ char* pParam1 = strtok((char*)args, " ");
+ if (!pParam1)
+ return false;
+
+ uint32 id = atoi((char*)pParam1);
+ if(!id)
+ return false;
+
+ char* spawntimeSecs = strtok(NULL, " ");
+
+ const GameObjectInfo *goI = objmgr.GetGameObjectInfo(id);
+
+ if (!goI)
+ {
+ PSendSysMessage(LANG_GAMEOBJECT_NOT_EXIST,id);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ Player *chr = m_session->GetPlayer();
+ float x = float(chr->GetPositionX());
+ float y = float(chr->GetPositionY());
+ float z = float(chr->GetPositionZ());
+ float o = float(chr->GetOrientation());
+ Map *map = chr->GetMap();
+
+ float rot2 = sin(o/2);
+ float rot3 = cos(o/2);
+
+ GameObject* pGameObj = new GameObject;
+ uint32 db_lowGUID = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT);
+
+ if(!pGameObj->Create(db_lowGUID, goI->id, map, x, y, z, o, 0, 0, rot2, rot3, 0, 1))
+ {
+ delete pGameObj;
+ return false;
+ }
+
+ if( spawntimeSecs )
+ {
+ uint32 value = atoi((char*)spawntimeSecs);
+ pGameObj->SetRespawnTime(value);
+ //sLog.outDebug("*** spawntimeSecs: %d", value);
+ }
+
+ // fill the gameobject data and save to the db
+ pGameObj->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()));
+
+ // this will generate a new guid if the object is in an instance
+ if(!pGameObj->LoadFromDB(db_lowGUID, map))
+ {
+ delete pGameObj;
+ return false;
+ }
+
+ sLog.outDebug(GetTrinityString(LANG_GAMEOBJECT_CURRENT), goI->name, db_lowGUID, x, y, z, o);
+
+ map->Add(pGameObj);
+
+ // TODO: is it really necessary to add both the real and DB table guid here ?
+ objmgr.AddGameobjectToGrid(db_lowGUID, objmgr.GetGOData(db_lowGUID));
+
+ PSendSysMessage(LANG_GAMEOBJECT_ADD,id,goI->name,db_lowGUID,x,y,z);
+ return true;
+}
+
+//show animation
+bool ChatHandler::HandleAnimCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ uint32 anim_id = atoi((char*)args);
+ m_session->GetPlayer()->HandleEmoteCommand(anim_id);
+ return true;
+}
+
+//change standstate
+bool ChatHandler::HandleStandStateCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ uint32 anim_id = atoi((char*)args);
+ m_session->GetPlayer( )->SetUInt32Value( UNIT_NPC_EMOTESTATE , anim_id );
+
+ return true;
+}
+
+bool ChatHandler::HandleAddHonorCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ Player *target = getSelectedPlayer();
+ if(!target)
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint32 amount = (uint32)atoi(args);
+ target->RewardHonor(NULL, 1, amount);
+ return true;
+}
+
+bool ChatHandler::HandleHonorAddKillCommand(const char* /*args*/)
+{
+ Unit *target = getSelectedUnit();
+ if(!target)
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ m_session->GetPlayer()->RewardHonor(target, 1);
+ return true;
+}
+
+bool ChatHandler::HandleUpdateHonorFieldsCommand(const char* /*args*/)
+{
+ Player *target = getSelectedPlayer();
+ if(!target)
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ target->UpdateHonorFields();
+ return true;
+}
+
+bool ChatHandler::HandleLookupEventCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ std::string namepart = args;
+ std::wstring wnamepart;
+
+ // converting string that we try to find to lower case
+ if(!Utf8toWStr(namepart,wnamepart))
+ return false;
+
+ wstrToLower(wnamepart);
+
+ uint32 counter = 0;
+
+ GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap();
+ GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
+
+ for(uint32 id = 0; id < events.size(); ++id )
+ {
+ GameEventData const& eventData = events[id];
+
+ std::string descr = eventData.description;
+ if(descr.empty())
+ continue;
+
+ if (Utf8FitTo(descr, wnamepart))
+ {
+ char const* active = activeEvents.find(id) != activeEvents.end() ? GetTrinityString(LANG_ACTIVE) : "";
+
+ if(m_session)
+ PSendSysMessage(LANG_EVENT_ENTRY_LIST_CHAT,id,id,eventData.description.c_str(),active );
+ else
+ PSendSysMessage(LANG_EVENT_ENTRY_LIST_CONSOLE,id,eventData.description.c_str(),active );
+
+ ++counter;
+ }
+ }
+
+ if (counter==0)
+ SendSysMessage(LANG_NOEVENTFOUND);
+
+ return true;
+}
+
+bool ChatHandler::HandleEventActiveListCommand(const char* args)
+{
+ uint32 counter = 0;
+
+ GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap();
+ GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
+
+ char const* active = GetTrinityString(LANG_ACTIVE);
+
+ for(GameEvent::ActiveEvents::const_iterator itr = activeEvents.begin(); itr != activeEvents.end(); ++itr )
+ {
+ uint32 event_id = *itr;
+ GameEventData const& eventData = events[event_id];
+
+ if(m_session)
+ PSendSysMessage(LANG_EVENT_ENTRY_LIST_CHAT,event_id,event_id,eventData.description.c_str(),active );
+ else
+ PSendSysMessage(LANG_EVENT_ENTRY_LIST_CONSOLE,event_id,eventData.description.c_str(),active );
+
+ ++counter;
+ }
+
+ if (counter==0)
+ SendSysMessage(LANG_NOEVENTFOUND);
+
+ return true;
+}
+
+bool ChatHandler::HandleEventInfoCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ // id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r
+ char* cId = extractKeyFromLink((char*)args,"Hgameevent");
+ if(!cId)
+ return false;
+
+ uint32 event_id = atoi(cId);
+
+ GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap();
+
+ if(event_id >=events.size())
+ {
+ SendSysMessage(LANG_EVENT_NOT_EXIST);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ GameEventData const& eventData = events[event_id];
+ if(!eventData.isValid())
+ {
+ SendSysMessage(LANG_EVENT_NOT_EXIST);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
+ bool active = activeEvents.find(event_id) != activeEvents.end();
+ char const* activeStr = active ? GetTrinityString(LANG_ACTIVE) : "";
+
+ std::string startTimeStr = TimeToTimestampStr(eventData.start);
+ std::string endTimeStr = TimeToTimestampStr(eventData.end);
+
+ uint32 delay = gameeventmgr.NextCheck(event_id);
+ time_t nextTime = time(NULL)+delay;
+ std::string nextStr = nextTime >= eventData.start && nextTime < eventData.end ? TimeToTimestampStr(time(NULL)+delay) : "-";
+
+ std::string occurenceStr = secsToTimeString(eventData.occurence * MINUTE);
+ std::string lengthStr = secsToTimeString(eventData.length * MINUTE);
+
+ PSendSysMessage(LANG_EVENT_INFO,event_id,eventData.description.c_str(),activeStr,
+ startTimeStr.c_str(),endTimeStr.c_str(),occurenceStr.c_str(),lengthStr.c_str(),
+ nextStr.c_str());
+ return true;
+}
+
+bool ChatHandler::HandleEventStartCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ // id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r
+ char* cId = extractKeyFromLink((char*)args,"Hgameevent");
+ if(!cId)
+ return false;
+
+ int32 event_id = atoi(cId);
+
+ GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap();
+
+ if(event_id < 1 || event_id >=events.size())
+ {
+ SendSysMessage(LANG_EVENT_NOT_EXIST);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ GameEventData const& eventData = events[event_id];
+ if(!eventData.isValid())
+ {
+ SendSysMessage(LANG_EVENT_NOT_EXIST);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
+ if(activeEvents.find(event_id) != activeEvents.end())
+ {
+ PSendSysMessage(LANG_EVENT_ALREADY_ACTIVE,event_id);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ gameeventmgr.StartEvent(event_id,true);
+ return true;
+}
+
+bool ChatHandler::HandleEventStopCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ // id or [name] Shift-click form |color|Hgameevent:id|h[name]|h|r
+ char* cId = extractKeyFromLink((char*)args,"Hgameevent");
+ if(!cId)
+ return false;
+
+ int32 event_id = atoi(cId);
+
+ GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap();
+
+ if(event_id < 1 || event_id >=events.size())
+ {
+ SendSysMessage(LANG_EVENT_NOT_EXIST);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ GameEventData const& eventData = events[event_id];
+ if(!eventData.isValid())
+ {
+ SendSysMessage(LANG_EVENT_NOT_EXIST);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ GameEvent::ActiveEvents const& activeEvents = gameeventmgr.GetActiveEventList();
+
+ if(activeEvents.find(event_id) == activeEvents.end())
+ {
+ PSendSysMessage(LANG_EVENT_NOT_ACTIVE,event_id);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ gameeventmgr.StopEvent(event_id,true);
+ return true;
+}
+
+bool ChatHandler::HandleCombatStopCommand(const char* args)
+{
+ Player *player;
+
+ if(*args)
+ {
+ std::string playername = args;
+
+ if(!normalizePlayerName(playername))
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ player = objmgr.GetPlayer(playername.c_str());
+
+ if(!player)
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ }
+ else
+ {
+ player = getSelectedPlayer();
+
+ if (!player)
+ player = m_session->GetPlayer();
+ }
+
+ player->CombatStop();
+ player->getHostilRefManager().deleteReferences();
+ return true;
+}
+
+bool ChatHandler::HandleLearnAllCraftsCommand(const char* /*args*/)
+{
+ uint32 classmask = m_session->GetPlayer()->getClassMask();
+
+ for (uint32 i = 0; i < sSkillLineStore.GetNumRows(); ++i)
+ {
+ SkillLineEntry const *skillInfo = sSkillLineStore.LookupEntry(i);
+ if( !skillInfo )
+ continue;
+
+ if( skillInfo->categoryId == SKILL_CATEGORY_PROFESSION || skillInfo->categoryId == SKILL_CATEGORY_SECONDARY )
+ {
+ for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j)
+ {
+ SkillLineAbilityEntry const *skillLine = sSkillLineAbilityStore.LookupEntry(j);
+ if( !skillLine )
+ continue;
+
+ // skip racial skills
+ if( skillLine->racemask != 0 )
+ continue;
+
+ // skip wrong class skills
+ if( skillLine->classmask && (skillLine->classmask & classmask) == 0)
+ continue;
+
+ if( skillLine->skillId != i || skillLine->forward_spellid )
+ continue;
+
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->spellId);
+ if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false))
+ continue;
+
+ m_session->GetPlayer()->learnSpell(skillLine->spellId);
+ }
+ }
+ }
+
+ SendSysMessage(LANG_COMMAND_LEARN_ALL_CRAFT);
+ return true;
+}
+
+bool ChatHandler::HandleLearnAllRecipesCommand(const char* args)
+{
+ // Learns all recipes of specified profession and sets skill to max
+ // Example: .learn all_recipes enchanting
+
+ Player* target = getSelectedPlayer();
+ if( !target )
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ return false;
+ }
+
+ if (!*args)
+ return false;
+
+ std::wstring wnamepart;
+
+ if(!Utf8toWStr(args,wnamepart))
+ return false;
+
+ uint32 counter = 0; // Counter for figure out that we found smth.
+
+ // converting string that we try to find to lower case
+ wstrToLower( wnamepart );
+
+ uint32 classmask = m_session->GetPlayer()->getClassMask();
+
+ for (uint32 i = 0; i < sSkillLineStore.GetNumRows(); ++i)
+ {
+ SkillLineEntry const *skillInfo = sSkillLineStore.LookupEntry(i);
+ if( !skillInfo )
+ continue;
+
+ if( skillInfo->categoryId != SKILL_CATEGORY_PROFESSION &&
+ skillInfo->categoryId != SKILL_CATEGORY_SECONDARY )
+ continue;
+
+ int loc = m_session->GetSessionDbcLocale();
+ std::string name = skillInfo->name[loc];
+
+ if(Utf8FitTo(name, wnamepart))
+ {
+ for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j)
+ {
+ SkillLineAbilityEntry const *skillLine = sSkillLineAbilityStore.LookupEntry(j);
+ if( !skillLine )
+ continue;
+
+ if( skillLine->skillId != i || skillLine->forward_spellid )
+ continue;
+
+ // skip racial skills
+ if( skillLine->racemask != 0 )
+ continue;
+
+ // skip wrong class skills
+ if( skillLine->classmask && (skillLine->classmask & classmask) == 0)
+ continue;
+
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(skillLine->spellId);
+ if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false))
+ continue;
+
+ if( !target->HasSpell(spellInfo->Id) )
+ m_session->GetPlayer()->learnSpell(skillLine->spellId);
+ }
+
+ uint16 maxLevel = target->GetPureMaxSkillValue(skillInfo->id);
+ target->SetSkill(skillInfo->id, maxLevel, maxLevel);
+ PSendSysMessage(LANG_COMMAND_LEARN_ALL_RECIPES, name.c_str());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ChatHandler::HandleLookupPlayerIpCommand(const char* args)
+{
+
+ if (!*args)
+ return false;
+
+ std::string ip = strtok ((char*)args, " ");
+ char* limit_str = strtok (NULL, " ");
+ int32 limit = limit_str ? atoi (limit_str) : -1;
+
+ loginDatabase.escape_string (ip);
+
+ QueryResult* result = loginDatabase.PQuery ("SELECT id,username FROM account WHERE last_ip = '%s'", ip.c_str ());
+
+ return LookupPlayerSearchCommand (result,limit);
+}
+
+bool ChatHandler::HandleLookupPlayerAccountCommand(const char* args)
+{
+ if (!*args)
+ return false;
+
+ std::string account = strtok ((char*)args, " ");
+ char* limit_str = strtok (NULL, " ");
+ int32 limit = limit_str ? atoi (limit_str) : -1;
+
+ if (!AccountMgr::normilizeString (account))
+ return false;
+
+ loginDatabase.escape_string (account);
+
+ QueryResult* result = loginDatabase.PQuery ("SELECT id,username FROM account WHERE username = '%s'", account.c_str ());
+
+ return LookupPlayerSearchCommand (result,limit);
+}
+
+bool ChatHandler::HandleLookupPlayerEmailCommand(const char* args)
+{
+
+ if (!*args)
+ return false;
+
+ std::string email = strtok ((char*)args, " ");
+ char* limit_str = strtok (NULL, " ");
+ int32 limit = limit_str ? atoi (limit_str) : -1;
+
+ loginDatabase.escape_string (email);
+
+ QueryResult* result = loginDatabase.PQuery ("SELECT id,username FROM account WHERE email = '%s'", email.c_str ());
+
+ return LookupPlayerSearchCommand (result,limit);
+}
+
+bool ChatHandler::LookupPlayerSearchCommand(QueryResult* result, int32 limit)
+{
+ if(!result)
+ {
+ PSendSysMessage(LANG_NO_PLAYERS_FOUND);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ int i =0;
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 acc_id = fields[0].GetUInt32();
+ std::string acc_name = fields[1].GetCppString();
+
+ QueryResult* chars = CharacterDatabase.PQuery("SELECT guid,name FROM characters WHERE account = '%u'", acc_id);
+ if(chars)
+ {
+ PSendSysMessage(LANG_LOOKUP_PLAYER_ACCOUNT,acc_name.c_str(),acc_id);
+
+ uint64 guid = 0;
+ std::string name;
+
+ do
+ {
+ Field* charfields = chars->Fetch();
+ guid = charfields[0].GetUInt64();
+ name = charfields[1].GetCppString();
+
+ PSendSysMessage(LANG_LOOKUP_PLAYER_CHARACTER,name.c_str(),guid);
+ ++i;
+
+ } while( chars->NextRow() && ( limit == -1 || i < limit ) );
+
+ delete chars;
+ }
+ } while(result->NextRow());
+
+ delete result;
+
+ return true;
+}
+
+/// Triggering corpses expire check in world
+bool ChatHandler::HandleServerCorpsesCommand(const char* /*args*/)
+{
+ CorpsesErase();
+ return true;
+}
+
+bool ChatHandler::HandleRepairitemsCommand(const char* /*args*/)
+{
+ Player *target = getSelectedPlayer();
+
+ if(!target)
+ {
+ PSendSysMessage(LANG_NO_CHAR_SELECTED);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ // Repair items
+ target->DurabilityRepairAll(false, 0, false);
+
+ PSendSysMessage(LANG_YOU_REPAIR_ITEMS, target->GetName());
+ if(needReportToTarget(target))
+ ChatHandler(target).PSendSysMessage(LANG_YOUR_ITEMS_REPAIRED, GetName());
+ return true;
+}
+
+bool ChatHandler::HandleNpcFollowCommand(const char* /*args*/)
+{
+ Player *player = m_session->GetPlayer();
+ Creature *creature = getSelectedCreature();
+
+ if(!creature)
+ {
+ PSendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ // Follow player - Using pet's default dist and angle
+ creature->GetMotionMaster()->MoveFollow(player, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
+
+ PSendSysMessage(LANG_CREATURE_FOLLOW_YOU_NOW, creature->GetName());
+ return true;
+}
+
+bool ChatHandler::HandleNpcUnFollowCommand(const char* /*args*/)
+{
+ Player *player = m_session->GetPlayer();
+ Creature *creature = getSelectedCreature();
+
+ if(!creature)
+ {
+ PSendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if (creature->GetMotionMaster()->empty() ||
+ creature->GetMotionMaster()->GetCurrentMovementGeneratorType ()!=TARGETED_MOTION_TYPE)
+ {
+ PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ TargetedMovementGenerator<Creature> const* mgen
+ = static_cast<TargetedMovementGenerator<Creature> const*>((creature->GetMotionMaster()->top()));
+
+ if(mgen->GetTarget()!=player)
+ {
+ PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ // reset movement
+ creature->GetMotionMaster()->MovementExpired(true);
+
+ PSendSysMessage(LANG_CREATURE_NOT_FOLLOW_YOU_NOW, creature->GetName());
+ return true;
+}
+
+bool ChatHandler::HandleCreatePetCommand(const char* args)
+{
+ Player *player = m_session->GetPlayer();
+ Creature *creatureTarget = getSelectedCreature();
+
+ if(!creatureTarget || creatureTarget->isPet() || creatureTarget->GetTypeId() == TYPEID_PLAYER)
+ {
+ PSendSysMessage(LANG_SELECT_CREATURE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ CreatureInfo const* cInfo = objmgr.GetCreatureTemplate(creatureTarget->GetEntry());
+ // Creatures with family 0 crashes the server
+ if(cInfo->family == 0)
+ {
+ PSendSysMessage("This creature cannot be tamed. (family id: 0).");
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ if(player->GetPetGUID())
+ {
+ PSendSysMessage("You already have a pet");
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ // Everything looks OK, create new pet
+ Pet* pet = new Pet(HUNTER_PET);
+
+ if(!pet->CreateBaseAtCreature(creatureTarget))
+ {
+ delete pet;
+ PSendSysMessage("Error 1");
+ return false;
+ }
+
+ creatureTarget->setDeathState(JUST_DIED);
+ creatureTarget->RemoveCorpse();
+ creatureTarget->SetHealth(0); // just for nice GM-mode view
+
+ pet->SetUInt64Value(UNIT_FIELD_SUMMONEDBY, player->GetGUID());
+ pet->SetUInt64Value(UNIT_FIELD_CREATEDBY, player->GetGUID());
+ pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, player->getFaction());
+
+ if(!pet->InitStatsForLevel(creatureTarget->getLevel()))
+ {
+ sLog.outError("ERROR: InitStatsForLevel() in EffectTameCreature failed! Pet deleted.");
+ PSendSysMessage("Error 2");
+ return false;
+ }
+
+ // prepare visual effect for levelup
+ pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel()-1);
+
+ pet->GetCharmInfo()->SetPetNumber(objmgr.GeneratePetNumber(), true);
+ // this enables pet details window (Shift+P)
+ pet->AIM_Initialize();
+ pet->InitPetCreateSpells();
+ pet->SetHealth(pet->GetMaxHealth());
+
+ MapManager::Instance().GetMap(pet->GetMapId(), pet)->Add((Creature*)pet);
+
+ // visual effect for levelup
+ pet->SetUInt32Value(UNIT_FIELD_LEVEL,creatureTarget->getLevel());
+
+ player->SetPet(pet);
+ pet->SavePetToDB(PET_SAVE_AS_CURRENT);
+ player->PetSpellInitialize();
+
+ return true;
+}
+
+bool ChatHandler::HandlePetLearnCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ Player *plr = m_session->GetPlayer();
+ Pet *pet = plr->GetPet();
+
+ if(!pet)
+ {
+ PSendSysMessage("You have no pet");
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint32 spellId = extractSpellIdFromLink((char*)args);
+
+ if(!spellId || !sSpellStore.LookupEntry(spellId))
+ return false;
+
+ // Check if pet already has it
+ if(pet->HasSpell(spellId))
+ {
+ PSendSysMessage("Pet already has spell: %u", spellId);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ // Check if spell is valid
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(spellId);
+ if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo))
+ {
+ PSendSysMessage(LANG_COMMAND_SPELL_BROKEN,spellId);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ pet->learnSpell(spellId);
+
+ PSendSysMessage("Pet has learned spell %u", spellId);
+ return true;
+}
+
+bool ChatHandler::HandlePetUnlearnCommand(const char *args)
+{
+ if(!*args)
+ return false;
+
+ Player *plr = m_session->GetPlayer();
+ Pet *pet = plr->GetPet();
+
+ if(!pet)
+ {
+ PSendSysMessage("You have no pet");
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint32 spellId = extractSpellIdFromLink((char*)args);
+
+ if(pet->HasSpell(spellId))
+ pet->removeSpell(spellId);
+ else
+ PSendSysMessage("Pet doesn't have that spell");
+
+ return true;
+}
+
+bool ChatHandler::HandlePetTpCommand(const char *args)
+{
+ if(!*args)
+ return false;
+
+ Player *plr = m_session->GetPlayer();
+ Pet *pet = plr->GetPet();
+
+ if(!pet)
+ {
+ PSendSysMessage("You have no pet");
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint32 tp = atol(args);
+
+ pet->SetTP(tp);
+
+ PSendSysMessage("Pet's tp changed to %u", tp);
+ return true;
+}
+
+bool ChatHandler::HandleActivateObjectCommand(const char *args)
+{
+ if(!*args)
+ return false;
+
+ char* cId = extractKeyFromLink((char*)args,"Hgameobject");
+ if(!cId)
+ return false;
+
+ uint32 lowguid = atoi(cId);
+ if(!lowguid)
+ return false;
+
+ GameObject* obj = NULL;
+
+ // by DB guid
+ if (GameObjectData const* go_data = objmgr.GetGOData(lowguid))
+ obj = GetObjectGlobalyWithGuidOrNearWithDbGuid(lowguid,go_data->id);
+
+ if(!obj)
+ {
+ PSendSysMessage(LANG_COMMAND_OBJNOTFOUND, lowguid);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ // Activate
+ obj->SetLootState(GO_READY);
+ obj->UseDoorOrButton(10000);
+
+ PSendSysMessage("Object activated!");
+
+ return true;
+}
diff --git a/src/game/Level3.cpp b/src/game/Level3.cpp
index 1fb799cde6b..42aa9393399 100644
--- a/src/game/Level3.cpp
+++ b/src/game/Level3.cpp
@@ -4406,7 +4406,7 @@ static bool HandleResetStatsOrLevelHelper(Player* player)
player->m_form = FORM_NONE;
player->SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, DEFAULT_WORLD_OBJECT_SIZE );
- player->SetFloatValue(UNIT_FIELD_COMBATREACH, 1.5f );
+ player->SetFloatValue(UNIT_FIELD_COMBATREACH, DEFAULT_WORLD_OBJECT_SIZE );
player->setFactionForRace(player->getRace());
@@ -5673,9 +5673,23 @@ bool ChatHandler::HandleWritePDumpCommand(const char *args)
if(!file || !p2)
return false;
- uint32 guid = objmgr.GetPlayerGUIDByName(p2);
- if(!guid)
+ uint32 guid;
+ // character name can't start from number
+ if (isNumeric(p2[0]))
guid = atoi(p2);
+ else
+ {
+ std::string name = p2;
+
+ if (!normalizePlayerName (name))
+ {
+ SendSysMessage (LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage (true);
+ return false;
+ }
+
+ guid = objmgr.GetPlayerGUIDByName(name);
+ }
if(!objmgr.GetPlayerAccountIdByGUID(guid))
{
@@ -6548,31 +6562,11 @@ bool ChatHandler::HandleSendMessageCommand(const char* args)
return true;
}
-bool ChatHandler::HandlePlayAllCommand(const char* args)
+bool ChatHandler::HandleModifyGenderCommand(const char *args)
{
if(!*args)
return false;
- uint32 soundId = atoi((char*)args);
-
- if(!sSoundEntriesStore.LookupEntry(soundId))
- {
- PSendSysMessage(LANG_SOUND_NOT_EXIST, soundId);
- SetSentErrorMessage(true);
- return false;
- }
-
- WorldPacket data(SMSG_PLAY_SOUND, 4);
- data << uint32(soundId) << m_session->GetPlayer()->GetGUID();
- sWorld.SendGlobalMessage(&data);
-
- PSendSysMessage(LANG_COMMAND_PLAYED_TO_ALL, soundId);
- return true;
-}
-
-bool ChatHandler::HandleModifyGenderCommand(const char *args)
-{
- if(!*args) return false;
Player *player = getSelectedPlayer();
if(!player)
@@ -6582,54 +6576,75 @@ bool ChatHandler::HandleModifyGenderCommand(const char *args)
return false;
}
- std::string gender = (char*)args;
+ char const* gender_str = (char*)args;
+ int gender_len = strlen(gender_str);
+
uint32 displayId = player->GetNativeDisplayId();
+ char const* gender_full = NULL;
+ uint32 new_displayId = displayId;
+ Gender gender;
- if(gender == "male") // MALE
+ if(!strncmp(gender_str,"male",gender_len)) // MALE
{
if(player->getGender() == GENDER_MALE)
- {
- PSendSysMessage("%s is already male", player->GetName());
- SetSentErrorMessage(true);
- return false;
- }
-
- // Set gender
- player->SetByteValue(UNIT_FIELD_BYTES_0, 2, GENDER_MALE);
- // Change display ID
- player->SetDisplayId(player->getRace() == RACE_BLOODELF ? displayId+1 : displayId-1);
- player->SetNativeDisplayId(player->getRace() == RACE_BLOODELF ? displayId+1 : displayId-1);
+ return true;
- ChatHandler(player).PSendSysMessage("Gender changed. You are now a man!");
- PSendSysMessage("Gender changed for %s", player->GetName());
- return true;
+ gender_full = "male";
+ new_displayId = player->getRace() == RACE_BLOODELF ? displayId+1 : displayId-1;
+ gender = GENDER_MALE;
}
- else if(gender == "female") // FEMALE
+ else if (!strncmp(gender_str,"female",gender_len)) // FEMALE
{
if(player->getGender() == GENDER_FEMALE)
- {
- PSendSysMessage("%s is already female", player->GetName());
- SetSentErrorMessage(true);
- return false;
- }
-
- // Set gender
- player->SetByteValue(UNIT_FIELD_BYTES_0, 2, GENDER_FEMALE);
- // Change display ID
- player->SetDisplayId(player->getRace() == RACE_BLOODELF ? displayId-1 : displayId+1);
- player->SetNativeDisplayId(player->getRace() == RACE_BLOODELF ? displayId-1 : displayId+1);
+ return true;
- ChatHandler(player).PSendSysMessage("Gender changed. You are now a woman!");
- PSendSysMessage("Gender changed for %s", player->GetName());
- return true;
+ gender_full = "female";
+ new_displayId = player->getRace() == RACE_BLOODELF ? displayId-1 : displayId+1;
+ gender = GENDER_FEMALE;
}
else
{
- PSendSysMessage("You must use male or female as gender.");
+ SendSysMessage(LANG_MUST_MALE_OR_FEMALE);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ // Set gender
+ player->SetByteValue(UNIT_FIELD_BYTES_0, 2, gender);
+
+ // Change display ID
+ player->SetDisplayId(new_displayId);
+ player->SetNativeDisplayId(new_displayId);
+
+ PSendSysMessage(LANG_YOU_CHANGE_GENDER, player->GetName(),gender_full);
+ if (needReportToTarget(player))
+ ChatHandler(player).PSendSysMessage(LANG_YOUR_GENDER_CHANGED, gender_full,GetName());
+ return true;
+}
+
+/*------------------------------------------
+ *-------------TRINITY----------------------
+ *-------------------------------------*/
+
+bool ChatHandler::HandlePlayAllCommand(const char* args)
+{
+ if(!*args)
+ return false;
+
+ uint32 soundId = atoi((char*)args);
+
+ if(!sSoundEntriesStore.LookupEntry(soundId))
+ {
+ PSendSysMessage(LANG_SOUND_NOT_EXIST, soundId);
SetSentErrorMessage(true);
return false;
}
+ WorldPacket data(SMSG_PLAY_SOUND, 4);
+ data << uint32(soundId) << m_session->GetPlayer()->GetGUID();
+ sWorld.SendGlobalMessage(&data);
+
+ PSendSysMessage(LANG_COMMAND_PLAYED_TO_ALL, soundId);
return true;
}
diff --git a/src/game/LootHandler.cpp b/src/game/LootHandler.cpp
index 4894b3aabeb..a4a8a7a1f01 100644
--- a/src/game/LootHandler.cpp
+++ b/src/game/LootHandler.cpp
@@ -70,6 +70,16 @@ void WorldSession::HandleAutostoreLootItemOpcode( WorldPacket & recv_data )
loot = &pItem->loot;
}
+ else if (IS_CORPSE_GUID(lguid))
+ {
+ Corpse *bones = ObjectAccessor::GetCorpse(*player, lguid);
+ if (!bones)
+ {
+ player->SendLootRelease(lguid);
+ return;
+ }
+ loot = &bones->loot;
+ }
else
{
Creature* pCreature =
diff --git a/src/game/Mail.cpp b/src/game/Mail.cpp
index 6605cc78057..57d90178869 100644
--- a/src/game/Mail.cpp
+++ b/src/game/Mail.cpp
@@ -232,7 +232,7 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data )
if( GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
{
- sLog.outCommand("GM %s (Account: %u) mail item: %s (Entry: %u Count: %u) to player: %s (Account: %u)",
+ sLog.outCommand(GetAccountId(), "GM %s (Account: %u) mail item: %s (Entry: %u Count: %u) to player: %s (Account: %u)",
GetPlayerName(), GetAccountId(), mailItem.item->GetProto()->Name1, mailItem.item->GetEntry(), mailItem.item->GetCount(), receiver.c_str(), rc_account);
}
@@ -251,7 +251,7 @@ void WorldSession::HandleSendMail(WorldPacket & recv_data )
if(money > 0 && GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE))
{
- sLog.outCommand("GM %s (Account: %u) mail money: %u to player: %s (Account: %u)",
+ sLog.outCommand(GetAccountId(),"GM %s (Account: %u) mail money: %u to player: %s (Account: %u)",
GetPlayerName(), GetAccountId(), money, receiver.c_str(), rc_account);
}
}
@@ -460,7 +460,7 @@ void WorldSession::HandleTakeItem(WorldPacket & recv_data )
if(!objmgr.GetPlayerNameByGUID(sender_guid,sender_name))
sender_name = objmgr.GetTrinityStringForDBCLocale(LANG_UNKNOWN);
}
- sLog.outCommand("GM %s (Account: %u) receive mail item: %s (Entry: %u Count: %u) and send COD money: %u to player: %s (Account: %u)",
+ sLog.outCommand(GetAccountId(),"GM %s (Account: %u) receive mail item: %s (Entry: %u Count: %u) and send COD money: %u to player: %s (Account: %u)",
GetPlayerName(),GetAccountId(),it->GetProto()->Name1,it->GetEntry(),it->GetCount(),m->COD,sender_name.c_str(),sender_accId);
}
else if(!receive)
@@ -519,7 +519,7 @@ void WorldSession::HandleTakeMoney(WorldPacket & recv_data )
// save money and mail to prevent cheating
CharacterDatabase.BeginTransaction();
- pl->SetUInt32ValueInDB(PLAYER_FIELD_COINAGE,pl->GetMoney(),pl->GetGUID());
+ pl->SaveDataFieldToDB(); // contains money
pl->_SaveMail();
CharacterDatabase.CommitTransaction();
}
diff --git a/src/game/Map.cpp b/src/game/Map.cpp
index 3804560b662..c807c6ab1a1 100644
--- a/src/game/Map.cpp
+++ b/src/game/Map.cpp
@@ -466,7 +466,8 @@ bool Map::Add(Player *player)
UpdatePlayerVisibility(player,cell,p);
UpdateObjectsVisibilityFor(player,cell,p);
- AddNotifier(player,cell,p);
+ //AddNotifier(player,cell,p);
+ AddUnitToNotify(player);
return true;
}
@@ -496,7 +497,9 @@ Map::Add(T *obj)
UpdateObjectVisibility(obj,cell,p);
- AddNotifier(obj,cell,p);
+ //AddNotifier(obj,cell,p);
+ if(obj->GetTypeId() == TYPEID_UNIT || obj->GetTypeId() == TYPEID_PLAYER)
+ AddUnitToNotify((Unit*)obj);
}
void Map::MessageBroadcast(Player *player, WorldPacket *msg, bool to_self, bool to_possessor)
@@ -594,23 +597,100 @@ bool Map::loaded(const GridPair &p) const
return ( getNGrid(p.x_coord, p.y_coord) && isGridObjectDataLoaded(p.x_coord, p.y_coord) );
}
-void Map::Update(const uint32 &t_diff)
+/*void Map::UpdateActiveCells(const float &x, const float &y, const uint32 &t_diff)
{
- resetMarkedCells();
+ CellPair standing_cell(Trinity::ComputeCellPair(x, y));
+ // Check for correctness of standing_cell, it also avoids problems with update_cell
+ if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
+ return;
+
+ // will this reduce the speed?
Trinity::ObjectUpdater updater(t_diff);
// for creature
TypeContainerVisitor<Trinity::ObjectUpdater, GridTypeMapContainer > grid_object_update(updater);
// for pets
TypeContainerVisitor<Trinity::ObjectUpdater, WorldTypeMapContainer > world_object_update(updater);
+ // the overloaded operators handle range checking
+ // so ther's no need for range checking inside the loop
+ CellPair begin_cell(standing_cell), end_cell(standing_cell);
+ begin_cell << 1; begin_cell -= 1; // upper left
+ end_cell >> 1; end_cell += 1; // lower right
+
+ for(uint32 x = begin_cell.x_coord; x <= end_cell.x_coord; ++x)
+ {
+ for(uint32 y = begin_cell.y_coord; y <= end_cell.y_coord; ++y)
+ {
+ // marked cells are those that have been visited
+ // don't visit the same cell twice
+ uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
+ if(!isCellMarked(cell_id))
+ {
+ markCell(cell_id);
+ CellPair pair(x,y);
+ Cell cell(pair);
+ cell.data.Part.reserved = CENTER_DISTRICT;
+ cell.SetNoCreate();
+ CellLock<NullGuard> cell_lock(cell, pair);
+ cell_lock->Visit(cell_lock, grid_object_update, *this);
+ cell_lock->Visit(cell_lock, world_object_update, *this);
+ }
+ }
+ }
+}*/
+
+void Map::Update(const uint32 &t_diff)
+{
+ for(std::vector<uint64>::iterator iter = i_unitsToNotify.begin(); iter != i_unitsToNotify.end(); ++iter)
+ {
+ Unit *unit = ObjectAccessor::GetObjectInWorld(*iter, (Unit*)NULL);
+ if(!unit) continue;
+ unit->m_Notified = true;
+ if(!unit->IsInWorld())
+ continue;
+ CellPair val = Trinity::ComputeCellPair(unit->GetPositionX(), unit->GetPositionY());
+ Cell cell(val);
+ if(unit->GetTypeId() == TYPEID_PLAYER)
+ PlayerRelocationNotify((Player*)unit, cell, val);
+ else
+ CreatureRelocationNotify((Creature*)unit, cell, val);
+ }
+ for(std::vector<uint64>::iterator iter = i_unitsToNotify.begin(); iter != i_unitsToNotify.end(); ++iter)
+ {
+ if(Unit *unit = ObjectAccessor::GetObjectInWorld(*iter, (Unit*)NULL))
+ {
+ unit->m_IsInNotifyList = false;
+ unit->m_Notified = false;
+ }
+ }
+ i_unitsToNotify.clear();
+
+ resetMarkedCells();
+
+ //TODO: is there a better way to update activeobjects?
+ std::vector<WorldObject*> activeObjects;
for(MapRefManager::iterator iter = m_mapRefManager.begin(); iter != m_mapRefManager.end(); ++iter)
{
Player* plr = iter->getSource();
- if(!plr->IsInWorld())
- continue;
+ if(plr->IsInWorld())
+ activeObjects.push_back(plr);
+ }
+ for(std::set<WorldObject *>::iterator iter = i_activeObjects.begin(); iter != i_activeObjects.end(); ++iter)
+ {
+ if((*iter)->IsInWorld())
+ activeObjects.push_back(*iter);
+ }
- CellPair standing_cell(Trinity::ComputeCellPair(plr->GetPositionX(), plr->GetPositionY()));
+ Trinity::ObjectUpdater updater(t_diff);
+ // for creature
+ TypeContainerVisitor<Trinity::ObjectUpdater, GridTypeMapContainer > grid_object_update(updater);
+ // for pets
+ TypeContainerVisitor<Trinity::ObjectUpdater, WorldTypeMapContainer > world_object_update(updater);
+
+ for(std::vector<WorldObject*>::iterator iter = activeObjects.begin(); iter != activeObjects.end(); ++iter)
+ {
+ CellPair standing_cell(Trinity::ComputeCellPair((*iter)->GetPositionX(), (*iter)->GetPositionY()));
// Check for correctness of standing_cell, it also avoids problems with update_cell
if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
@@ -642,8 +722,9 @@ void Map::Update(const uint32 &t_diff)
}
}
}
- }
+ // UpdateActiveCells((*iter)->GetPositionX(), (*iter)->GetPositionY(), t_diff);
+ }
// Don't unload grids if it's battleground, since we may have manually added GOs,creatures, those doesn't load from DB at grid re-load !
// This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended
@@ -662,6 +743,13 @@ void Map::Update(const uint32 &t_diff)
void Map::Remove(Player *player, bool remove)
{
+ // this may be called during Map::Update
+ // after decrement+unlink, ++m_mapRefIter will continue correctly
+ // when the first element of the list is being removed
+ // nocheck_prev will return the padding element of the RefManager
+ // instead of NULL in the case of prev
+ if(m_mapRefIter == player->GetMapRef())
+ m_mapRefIter = m_mapRefIter->nocheck_prev();
player->GetMapRef().unlink();
CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
if(p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
@@ -784,7 +872,8 @@ Map::PlayerRelocation(Player *player, float x, float y, float z, float orientati
if(player->isPossessedByPlayer())
UpdateObjectsVisibilityFor((Player*)player->GetCharmer(), new_cell, new_val);
- PlayerRelocationNotify(player,new_cell,new_val);
+ //PlayerRelocationNotify(player,new_cell,new_val);
+ AddUnitToNotify(player);
NGridType* newGrid = getNGrid(new_cell.GridX(), new_cell.GridY());
if( !same_cell && newGrid->GetGridState()!= GRID_STATE_ACTIVE )
{
@@ -812,8 +901,13 @@ Map::CreatureRelocation(Creature *creature, float x, float y, float z, float ang
#endif
AddCreatureToMoveList(creature,x,y,z,ang);
// in diffcell/diffgrid case notifiers called at finishing move creature in Map::MoveAllCreaturesInMoveList
- if(creature->isPossessedByPlayer())
- EnsureGridLoadedForPlayer(new_cell, (Player*)creature->GetCharmer(), false);
+ if(creature->isActive())
+ {
+ if(creature->isPossessedByPlayer())
+ EnsureGridLoadedForPlayer(new_cell, (Player*)creature->GetCharmer(), false);
+ else
+ EnsureGridLoadedForPlayer(new_cell, NULL, false);
+ }
}
else
{
@@ -822,7 +916,8 @@ Map::CreatureRelocation(Creature *creature, float x, float y, float z, float ang
if(creature->isPossessedByPlayer())
UpdateObjectsVisibilityFor((Player*)creature->GetCharmer(), new_cell, new_val);
- CreatureRelocationNotify(creature,new_cell,new_val);
+ //CreatureRelocationNotify(creature,new_cell,new_val);
+ AddUnitToNotify(creature);
}
assert(CheckGridIntegrity(creature,true));
}
@@ -854,7 +949,8 @@ void Map::MoveAllCreaturesInMoveList()
{
// update pos
c->Relocate(cm.x, cm.y, cm.z, cm.ang);
- CreatureRelocationNotify(c,new_cell,new_cell.cellPair());
+ //CreatureRelocationNotify(c,new_cell,new_cell.cellPair());
+ AddUnitToNotify(c);
}
else
{
@@ -949,7 +1045,8 @@ bool Map::CreatureRespawnRelocation(Creature *c)
{
c->Relocate(resp_x, resp_y, resp_z, resp_o);
c->GetMotionMaster()->Initialize(); // prevent possible problems with default move generators
- CreatureRelocationNotify(c,resp_cell,resp_cell.cellPair());
+ //CreatureRelocationNotify(c,resp_cell,resp_cell.cellPair());
+ AddUnitToNotify(c);
return true;
}
else
@@ -1508,6 +1605,36 @@ bool Map::PlayersNearGrid(uint32 x, uint32 y) const
return false;
}
+bool Map::ActiveObjectsNearGrid(uint32 x, uint32 y) const
+{
+ CellPair cell_min(x*MAX_NUMBER_OF_CELLS, y*MAX_NUMBER_OF_CELLS);
+ CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS);
+ cell_min << 2;
+ cell_min -= 2;
+ cell_max >> 2;
+ cell_max += 2;
+
+ for(MapRefManager::const_iterator iter = m_mapRefManager.begin(); iter != m_mapRefManager.end(); ++iter)
+ {
+ Player* plr = iter->getSource();
+
+ CellPair p = Trinity::ComputeCellPair(plr->GetPositionX(), plr->GetPositionY());
+ if( (cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) &&
+ (cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord) )
+ return true;
+ }
+
+ for(std::set<WorldObject*>::const_iterator itr = i_activeObjects.begin(); itr != i_activeObjects.end(); ++itr)
+ {
+ CellPair p = Trinity::ComputeCellPair((*itr)->GetPositionX(), (*itr)->GetPositionY());
+ if( (cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) &&
+ (cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord) )
+ return true;
+ }
+
+ return false;
+}
+
template void Map::Add(Corpse *);
template void Map::Add(Creature *);
template void Map::Add(GameObject *);
@@ -1658,6 +1785,8 @@ bool InstanceMap::Add(Player *player)
}
if(i_data) i_data->OnPlayerEnter(player);
+ // for normal instances cancel the reset schedule when the
+ // first player enters (no players yet)
SetResetSchedule(false);
player->SendInitWorldStates();
@@ -1684,11 +1813,12 @@ void InstanceMap::Update(const uint32& t_diff)
void InstanceMap::Remove(Player *player, bool remove)
{
sLog.outDetail("MAP: Removing player '%s' from instance '%u' of map '%s' before relocating to other map", player->GetName(), GetInstanceId(), GetMapName());
- SetResetSchedule(true);
//if last player set unload timer
if(!m_unloadTimer && m_mapRefManager.getSize() == 1)
m_unloadTimer = m_unloadWhenEmpty ? MIN_UNLOAD_DELAY : std::max(sWorld.getConfig(CONFIG_INSTANCE_UNLOAD_DELAY), (uint32)MIN_UNLOAD_DELAY);
Map::Remove(player, remove);
+ // for normal instances schedule the reset after all players have left
+ SetResetSchedule(true);
}
Creature * Map::GetCreatureInMap(uint64 guid)
@@ -1923,3 +2053,14 @@ void BattleGroundMap::UnloadAll(bool pForce)
Map::UnloadAll(pForce);
}
+
+/*--------------------------TRINITY-------------------------*/
+
+void Map::AddUnitToNotify(Unit* u)
+{
+ if(!u->m_IsInNotifyList)
+ {
+ i_unitsToNotify.push_back(u->GetGUID());
+ u->m_IsInNotifyList = true;
+ }
+} \ No newline at end of file
diff --git a/src/game/Map.h b/src/game/Map.h
index 6e0e9cb37a9..167a34dcccd 100644
--- a/src/game/Map.h
+++ b/src/game/Map.h
@@ -242,6 +242,11 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O
bool HavePlayers() const { return !m_mapRefManager.isEmpty(); }
uint32 GetPlayersCountExceptGMs() const;
bool PlayersNearGrid(uint32 x,uint32 y) const;
+ bool ActiveObjectsNearGrid(uint32 x, uint32 y) const;
+
+ void AddActiveObject(WorldObject* obj) { i_activeObjects.insert(obj); }
+ void RemoveActiveObject(WorldObject* obj) { i_activeObjects.erase(obj); }
+ void AddUnitToNotify(Unit* unit);
void SendToPlayers(WorldPacket const* data) const;
@@ -287,6 +292,7 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O
inline void setNGrid(NGridType* grid, uint32 x, uint32 y);
+ void UpdateActiveCells(const float &x, const float &y, const uint32 &t_diff);
protected:
typedef Trinity::ObjectLevelLockable<Map, ZThread::Mutex>::Lock Guard;
@@ -297,6 +303,7 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O
uint32 m_unloadTimer;
MapRefManager m_mapRefManager;
+ MapRefManager::iterator m_mapRefIter;
private:
typedef GridReadGuard ReadGuard;
typedef GridWriteGuard WriteGuard;
@@ -307,6 +314,8 @@ class TRINITY_DLL_SPEC Map : public GridRefManager<NGridType>, public Trinity::O
time_t i_gridExpiry;
+ std::set<WorldObject *> i_activeObjects;
+ std::vector<uint64> i_unitsToNotify;
std::set<WorldObject *> i_objectsToRemove;
// Type specific code for add/remove to/from grid
diff --git a/src/game/MapRefManager.h b/src/game/MapRefManager.h
index da0c81a9138..bfd0ca12eda 100644
--- a/src/game/MapRefManager.h
+++ b/src/game/MapRefManager.h
@@ -1,44 +1,44 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _MAPREFMANAGER
-#define _MAPREFMANAGER
-
-#include "Utilities/LinkedReference/RefManager.h"
-
-class MapReference;
-
-class MapRefManager : public RefManager<Map, Player>
-{
- public:
- typedef LinkedListHead::Iterator< MapReference > iterator;
- typedef LinkedListHead::Iterator< MapReference const > const_iterator;
-
- MapReference* getFirst() { return (MapReference*)RefManager<Map, Player>::getFirst(); }
- MapReference const* getFirst() const { return (MapReference const*)RefManager<Map, Player>::getFirst(); }
- MapReference* getLast() { return (MapReference*)RefManager<Map, Player>::getLast(); }
- MapReference const* getLast() const { return (MapReference const*)RefManager<Map, Player>::getLast(); }
-
- iterator begin() { return iterator(getFirst()); }
- iterator end() { return iterator(NULL); }
- iterator rbegin() { return iterator(getLast()); }
- iterator rend() { return iterator(NULL); }
- const_iterator begin() const { return const_iterator(getFirst()); }
- const_iterator end() const { return const_iterator(getLast()); }
-};
-#endif
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _MAPREFMANAGER
+#define _MAPREFMANAGER
+
+#include "Utilities/LinkedReference/RefManager.h"
+
+class MapReference;
+
+class MapRefManager : public RefManager<Map, Player>
+{
+ public:
+ typedef LinkedListHead::Iterator< MapReference > iterator;
+ typedef LinkedListHead::Iterator< MapReference const > const_iterator;
+
+ MapReference* getFirst() { return (MapReference*)RefManager<Map, Player>::getFirst(); }
+ MapReference const* getFirst() const { return (MapReference const*)RefManager<Map, Player>::getFirst(); }
+ MapReference* getLast() { return (MapReference*)RefManager<Map, Player>::getLast(); }
+ MapReference const* getLast() const { return (MapReference const*)RefManager<Map, Player>::getLast(); }
+
+ iterator begin() { return iterator(getFirst()); }
+ iterator end() { return iterator(NULL); }
+ iterator rbegin() { return iterator(getLast()); }
+ iterator rend() { return iterator(NULL); }
+ const_iterator begin() const { return const_iterator(getFirst()); }
+ const_iterator end() const { return const_iterator(NULL); }
+};
+#endif
diff --git a/src/game/MapReference.h b/src/game/MapReference.h
index b41796ea91b..5300d1aa4a7 100644
--- a/src/game/MapReference.h
+++ b/src/game/MapReference.h
@@ -1,50 +1,52 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _MAPREFERENCE_H
-#define _MAPREFERENCE_H
-
-#include "Utilities/LinkedReference/Reference.h"
-#include "Map.h"
-
-class TRINITY_DLL_SPEC MapReference : public Reference<Map, Player>
-{
- protected:
- void targetObjectBuildLink()
- {
- // called from link()
- getTarget()->m_mapRefManager.insertFirst(this);
- getTarget()->m_mapRefManager.incSize();
- }
- void targetObjectDestroyLink()
- {
- // called from unlink()
- if(isValid()) getTarget()->m_mapRefManager.decSize();
- }
- void sourceObjectDestroyLink()
- {
- // called from invalidate()
- getTarget()->m_mapRefManager.decSize();
- }
- public:
- MapReference() : Reference<Map, Player>() {}
- ~MapReference() { unlink(); }
- MapReference *next() { return (MapReference*)Reference<Map, Player>::next(); }
- MapReference const *next() const { return (MapReference const*)Reference<Map, Player>::next(); }
-};
-#endif
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _MAPREFERENCE_H
+#define _MAPREFERENCE_H
+
+#include "Utilities/LinkedReference/Reference.h"
+#include "Map.h"
+
+class TRINITY_DLL_SPEC MapReference : public Reference<Map, Player>
+{
+ protected:
+ void targetObjectBuildLink()
+ {
+ // called from link()
+ getTarget()->m_mapRefManager.insertFirst(this);
+ getTarget()->m_mapRefManager.incSize();
+ }
+ void targetObjectDestroyLink()
+ {
+ // called from unlink()
+ if(isValid()) getTarget()->m_mapRefManager.decSize();
+ }
+ void sourceObjectDestroyLink()
+ {
+ // called from invalidate()
+ getTarget()->m_mapRefManager.decSize();
+ }
+ public:
+ MapReference() : Reference<Map, Player>() {}
+ ~MapReference() { unlink(); }
+ MapReference *next() { return (MapReference*)Reference<Map, Player>::next(); }
+ MapReference const *next() const { return (MapReference const*)Reference<Map, Player>::next(); }
+ MapReference *nockeck_prev() { return (MapReference*)Reference<Map, Player>::nocheck_prev(); }
+ MapReference const *nocheck_prev() const { return (MapReference const*)Reference<Map, Player>::nocheck_prev(); }
+};
+#endif
diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp
index 7196b57eac2..e63a92c27b1 100644
--- a/src/game/MiscHandler.cpp
+++ b/src/game/MiscHandler.cpp
@@ -279,13 +279,6 @@ void WorldSession::HandleLogoutRequestOpcode( WorldPacket & /*recv_data*/ )
if (uint64 lguid = GetPlayer()->GetLootGUID())
DoLootRelease(lguid);
- //instant logout for admins, gm's, mod's
- if( GetSecurity() > SEC_PLAYER )
- {
- LogoutPlayer(true);
- return;
- }
-
//Can not logout if...
if( GetPlayer()->isInCombat() || //...is in combat
GetPlayer()->duel || //...is in Duel
@@ -302,8 +295,9 @@ void WorldSession::HandleLogoutRequestOpcode( WorldPacket & /*recv_data*/ )
return;
}
- //instant logout in taverns/cities or on taxi or if its enabled in Trinityd.conf
- if(GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) || GetPlayer()->isInFlight() || sWorld.getConfig(CONFIG_INSTANT_LOGOUT))
+ //instant logout in taverns/cities or on taxi or for admins, gm's, mod's if its enabled in mangosd.conf
+ if (GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) || GetPlayer()->isInFlight() ||
+ GetSecurity() >= sWorld.getConfig(CONFIG_INSTANT_LOGOUT))
{
LogoutPlayer(true);
return;
@@ -671,9 +665,9 @@ void WorldSession::HandleCorpseReclaimOpcode(WorldPacket &recv_data)
if (GetPlayer()->isAlive())
return;
- if (BattleGround * bg = _player->GetBattleGround())
- if(bg->isArena())
- return;
+ // do not allow corpse reclaim in arena
+ if (GetPlayer()->InArena())
+ return;
// body not released yet
if(!GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
@@ -1275,14 +1269,12 @@ void WorldSession::HandleWhoisOpcode(WorldPacket& recv_data)
return;
}
- if(charname.empty())
+ if(charname.empty() || !normalizePlayerName (charname))
{
SendNotification(LANG_NEED_CHARACTER_NAME);
return;
}
- normalizePlayerName (charname);
-
Player *plr = objmgr.GetPlayer(charname.c_str());
if(!plr)
diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp
index 78cabe07bab..cdc922aa84c 100644
--- a/src/game/MovementHandler.cpp
+++ b/src/game/MovementHandler.cpp
@@ -10,12 +10,12 @@
*
* 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
+ * 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
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Common.h"
@@ -50,15 +50,6 @@ void WorldSession::HandleMoveWorldportAckOpcode()
return;
}
- if(!sWorld.IsAllowedMap(loc.mapid) && (GetSecurity() < SEC_GAMEMASTER))
- {
- if(sWorld.IsAllowedMap(GetPlayer()->m_homebindMapId))
- GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation());
- else
- LogoutPlayer(false);
- return;
- }
-
// get the destination map entry, not the current one, this will fix homebind and reset greeting
MapEntry const* mEntry = sMapStore.LookupEntry(loc.mapid);
InstanceTemplate const* mInstance = objmgr.GetInstanceTemplate(loc.mapid);
@@ -83,7 +74,7 @@ void WorldSession::HandleMoveWorldportAckOpcode()
GetPlayer()->SendInitialPacketsBeforeAddToMap();
// the CanEnter checks are done in TeleporTo but conditions may change
// while the player is in transit, for example the map may get full
- if(!MapManager::Instance().GetMap(GetPlayer()->GetMapId(), GetPlayer())->Add(GetPlayer()))
+ if(!GetPlayer()->GetMap()->Add(GetPlayer()))
{
sLog.outDebug("WORLD: teleport of player %s (%d) to location %d,%f,%f,%f,%f failed", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), loc.mapid, loc.x, loc.y, loc.z, loc.o);
// teleport the player home
diff --git a/src/game/Object.cpp b/src/game/Object.cpp
index ea59a448f7f..cc754f32bd3 100644
--- a/src/game/Object.cpp
+++ b/src/game/Object.cpp
@@ -990,36 +990,37 @@ WorldObject::WorldObject()
WorldObject::~WorldObject()
{
- if(m_isActive && IsInWorld())
- ObjectAccessor::Instance().RemoveActiveObject(this);
+ if(m_isActive && !isType(TYPEMASK_PLAYER) && IsInWorld())
+ GetMap()->RemoveActiveObject(this);
}
void WorldObject::setActive(bool isActive)
{
// if already in the same activity state as we try to set, do nothing
- if(isActive == m_isActive)
+ if(isActive == m_isActive || isType(TYPEMASK_PLAYER))
return;
+
m_isActive = isActive;
if(IsInWorld())
{
if(isActive)
- ObjectAccessor::Instance().AddActiveObject(this);
+ GetMap()->AddActiveObject(this);
else
- ObjectAccessor::Instance().RemoveActiveObject(this);
+ GetMap()->RemoveActiveObject(this);
}
}
void WorldObject::AddToWorld()
{
Object::AddToWorld();
- if(m_isActive)
- ObjectAccessor::Instance().AddActiveObject(this);
+ if(m_isActive && !isType(TYPEMASK_PLAYER))
+ GetMap()->AddActiveObject(this);
}
void WorldObject::RemoveFromWorld()
{
- if(m_isActive)
- ObjectAccessor::Instance().RemoveActiveObject(this);
+ if(m_isActive && !isType(TYPEMASK_PLAYER))
+ GetMap()->RemoveActiveObject(this);
Object::RemoveFromWorld();
}
diff --git a/src/game/Object.h b/src/game/Object.h
index 2d8f3a134e6..43ecca2afb0 100644
--- a/src/game/Object.h
+++ b/src/game/Object.h
@@ -455,7 +455,7 @@ class TRINITY_DLL_SPEC WorldObject : public Object
Creature* SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime);
GameObject* SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime);
bool isActive() const { return m_isActive; }
- virtual void setActive(bool isActive);
+ void setActive(bool isActive);
protected:
explicit WorldObject();
std::string m_name;
diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp
index 8a7e8fbfa2c..82e01e6529a 100644
--- a/src/game/ObjectAccessor.cpp
+++ b/src/game/ObjectAccessor.cpp
@@ -487,22 +487,10 @@ ObjectAccessor::ConvertCorpseForPlayer(uint64 player_guid)
}
void
-ObjectAccessor::AddActiveObject( WorldObject * obj )
-{
- i_activeobjects.insert(obj);
-}
-
-void
-ObjectAccessor::RemoveActiveObject( WorldObject * obj )
-{
- i_activeobjects.erase(obj);
-}
-
-void
ObjectAccessor::Update(uint32 diff)
{
-
- {
+/* {
+ //Player update now in MapManager -> UpdatePlayers
// player update might remove the player from grid, and that causes crashes. We HAVE to update players first, and then the active objects.
HashMapHolder<Player>::MapType& playerMap = HashMapHolder<Player>::GetContainer();
for(HashMapHolder<Player>::MapType::iterator iter = playerMap.begin(); iter != playerMap.end(); ++iter)
@@ -513,6 +501,7 @@ ObjectAccessor::Update(uint32 diff)
}
}
+ // TODO: move this to Map::Update
// clone the active object list, because update might remove from it
std::set<WorldObject *> activeobjects(i_activeobjects);
@@ -571,6 +560,28 @@ ObjectAccessor::Update(uint32 diff)
}
}
}
+ }*/
+
+ UpdateDataMapType update_players;
+ {
+ Guard guard(i_updateGuard);
+ while(!i_objects.empty())
+ {
+ Object* obj = *i_objects.begin();
+ i_objects.erase(i_objects.begin());
+ if (!obj || !obj->IsInWorld())
+ continue;
+ _buildUpdateObject(obj, update_players);
+ obj->ClearUpdateMask(false);
+ }
+ }
+
+ WorldPacket packet; // here we allocate a std::vector with a size of 0x10000
+ for(UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter)
+ {
+ iter->second.BuildPacket(&packet);
+ iter->first->GetSession()->SendPacket(&packet);
+ packet.clear(); // clean the string
}
}
@@ -583,30 +594,6 @@ ObjectAccessor::UpdatePlayers(uint32 diff)
iter->second->Update(diff);
}
-bool
-ObjectAccessor::ActiveObjectsNearGrid(uint32 x, uint32 y, uint32 m_id, uint32 i_id) const
-{
- CellPair cell_min(x*MAX_NUMBER_OF_CELLS, y*MAX_NUMBER_OF_CELLS);
- CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS);
- cell_min << 2;
- cell_min -= 2;
- cell_max >> 2;
- cell_max += 2;
-
- for(std::set<WorldObject*>::const_iterator itr = i_activeobjects.begin(); itr != i_activeobjects.end(); ++itr)
- {
- if( m_id != (*itr)->GetMapId() || i_id != (*itr)->GetInstanceId() )
- continue;
-
- CellPair p = Trinity::ComputeCellPair((*itr)->GetPositionX(), (*itr)->GetPositionY());
- if( (cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) &&
- (cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord) )
- return true;
- }
-
- return false;
-}
-
void
ObjectAccessor::WorldObjectChangeAccumulator::Visit(PlayerMapType &m)
{
diff --git a/src/game/ObjectAccessor.h b/src/game/ObjectAccessor.h
index 89ea6d1e43d..21ede723da5 100644
--- a/src/game/ObjectAccessor.h
+++ b/src/game/ObjectAccessor.h
@@ -194,16 +194,11 @@ class TRINITY_DLL_DECL ObjectAccessor : public Trinity::Singleton<ObjectAccessor
void AddCorpsesToGrid(GridPair const& gridpair,GridType& grid,Map* map);
Corpse* ConvertCorpseForPlayer(uint64 player_guid);
- bool ActiveObjectsNearGrid(uint32 x,uint32 y,uint32 m_id,uint32 i_id) const;
-
static void UpdateObject(Object* obj, Player* exceptPlayer);
static void _buildUpdateObject(Object* obj, UpdateDataMapType &);
static void UpdateObjectVisibility(WorldObject* obj);
static void UpdateVisibilityForPlayer(Player* player);
-
- void AddActiveObject(WorldObject*);
- void RemoveActiveObject(WorldObject*);
private:
struct WorldObjectChangeAccumulator
{
@@ -228,7 +223,6 @@ class TRINITY_DLL_DECL ObjectAccessor : public Trinity::Singleton<ObjectAccessor
static void _buildPacket(Player *, Object *, UpdateDataMapType &);
void _update(void);
std::set<Object *> i_objects;
- std::set<WorldObject *> i_activeobjects;
LockType i_playerGuard;
LockType i_updateGuard;
LockType i_corpseGuard;
diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp
index fab835a1f8f..54f92b5fccf 100644
--- a/src/game/ObjectMgr.cpp
+++ b/src/game/ObjectMgr.cpp
@@ -1,7505 +1,7517 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
- *
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
- *
- * 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
- */
-
-#include "Common.h"
-#include "Database/DatabaseEnv.h"
-#include "Database/SQLStorage.h"
-#include "Database/SQLStorageImpl.h"
-
-#include "Log.h"
-#include "MapManager.h"
-#include "ObjectMgr.h"
-#include "SpellMgr.h"
-#include "UpdateMask.h"
-#include "World.h"
-#include "WorldSession.h"
-#include "Group.h"
-#include "Guild.h"
-#include "ArenaTeam.h"
-#include "Transports.h"
-#include "ProgressBar.h"
-#include "Policies/SingletonImp.h"
-#include "Language.h"
-#include "GameEvent.h"
-#include "Spell.h"
-#include "Chat.h"
-#include "AccountMgr.h"
-#include "InstanceSaveMgr.h"
-#include "SpellAuras.h"
-#include "Util.h"
-
-INSTANTIATE_SINGLETON_1(ObjectMgr);
-
-ScriptMapMap sQuestEndScripts;
-ScriptMapMap sQuestStartScripts;
-ScriptMapMap sSpellScripts;
-ScriptMapMap sGameObjectScripts;
-ScriptMapMap sEventScripts;
-
-bool normalizePlayerName(std::string& name)
-{
- if(name.empty())
- return false;
-
- wchar_t wstr_buf[MAX_INTERNAL_PLAYER_NAME+1];
- size_t wstr_len = MAX_INTERNAL_PLAYER_NAME;
-
- if(!Utf8toWStr(name,&wstr_buf[0],wstr_len))
- return false;
-
- wstr_buf[0] = wcharToUpper(wstr_buf[0]);
- for(size_t i = 1; i < wstr_len; ++i)
- wstr_buf[i] = wcharToLower(wstr_buf[i]);
-
- if(!WStrToUtf8(wstr_buf,wstr_len,name))
- return false;
-
- return true;
-}
-
-LanguageDesc lang_description[LANGUAGES_COUNT] =
-{
- { LANG_ADDON, 0, 0 },
- { LANG_UNIVERSAL, 0, 0 },
- { LANG_ORCISH, 669, SKILL_LANG_ORCISH },
- { LANG_DARNASSIAN, 671, SKILL_LANG_DARNASSIAN },
- { LANG_TAURAHE, 670, SKILL_LANG_TAURAHE },
- { LANG_DWARVISH, 672, SKILL_LANG_DWARVEN },
- { LANG_COMMON, 668, SKILL_LANG_COMMON },
- { LANG_DEMONIC, 815, SKILL_LANG_DEMON_TONGUE },
- { LANG_TITAN, 816, SKILL_LANG_TITAN },
- { LANG_THALASSIAN, 813, SKILL_LANG_THALASSIAN },
- { LANG_DRACONIC, 814, SKILL_LANG_DRACONIC },
- { LANG_KALIMAG, 817, SKILL_LANG_OLD_TONGUE },
- { LANG_GNOMISH, 7340, SKILL_LANG_GNOMISH },
- { LANG_TROLL, 7341, SKILL_LANG_TROLL },
- { LANG_GUTTERSPEAK, 17737, SKILL_LANG_GUTTERSPEAK },
- { LANG_DRAENEI, 29932, SKILL_LANG_DRAENEI },
- { LANG_ZOMBIE, 0, 0 },
- { LANG_GNOMISH_BINARY, 0, 0 },
- { LANG_GOBLIN_BINARY, 0, 0 }
-};
-
-LanguageDesc const* GetLanguageDescByID(uint32 lang)
-{
- for(int i = 0; i < LANGUAGES_COUNT; ++i)
- {
- if(uint32(lang_description[i].lang_id) == lang)
- return &lang_description[i];
- }
-
- return NULL;
-}
-
-ObjectMgr::ObjectMgr()
-{
- m_hiCharGuid = 1;
- m_hiCreatureGuid = 1;
- m_hiPetGuid = 1;
- m_hiItemGuid = 1;
- m_hiGoGuid = 1;
- m_hiDoGuid = 1;
- m_hiCorpseGuid = 1;
- m_hiPetNumber = 1;
- m_ItemTextId = 1;
- m_mailid = 1;
- m_auctionid = 1;
- m_guildId = 1;
- m_arenaTeamId = 1;
-
- mGuildBankTabPrice.resize(GUILD_BANK_MAX_TABS);
- mGuildBankTabPrice[0] = 100;
- mGuildBankTabPrice[1] = 250;
- mGuildBankTabPrice[2] = 500;
- mGuildBankTabPrice[3] = 1000;
- mGuildBankTabPrice[4] = 2500;
- mGuildBankTabPrice[5] = 5000;
-
- // Only zero condition left, others will be added while loading DB tables
- mConditions.resize(1);
-}
-
-ObjectMgr::~ObjectMgr()
-{
- for( QuestMap::iterator i = mQuestTemplates.begin( ); i != mQuestTemplates.end( ); ++ i )
- {
- delete i->second;
- }
- mQuestTemplates.clear( );
-
- for( GossipTextMap::iterator i = mGossipText.begin( ); i != mGossipText.end( ); ++ i )
- {
- delete i->second;
- }
- mGossipText.clear( );
-
- mAreaTriggers.clear();
-
- for(PetLevelInfoMap::iterator i = petInfo.begin( ); i != petInfo.end( ); ++ i )
- {
- delete[] i->second;
- }
- petInfo.clear();
-
- // free only if loaded
- for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
- delete[] playerClassInfo[class_].levelInfo;
-
- for (int race = 0; race < MAX_RACES; ++race)
- for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
- delete[] playerInfo[race][class_].levelInfo;
-
- // free group and guild objects
- for (GroupSet::iterator itr = mGroupSet.begin(); itr != mGroupSet.end(); ++itr)
- delete (*itr);
- for (GuildSet::iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); ++itr)
- delete (*itr);
-
- for (CachePlayerInfoMap::iterator itr = m_mPlayerInfoMap.begin(); itr != m_mPlayerInfoMap.end(); ++itr)
- delete itr->second;
-
- for(ItemMap::iterator itr = mAitems.begin(); itr != mAitems.end(); ++itr)
- delete itr->second;
-
- for (CacheVendorItemMap::iterator itr = m_mCacheVendorItemMap.begin(); itr != m_mCacheVendorItemMap.end(); ++itr)
- itr->second.Clear();
-
- for (CacheTrainerSpellMap::iterator itr = m_mCacheTrainerSpellMap.begin(); itr != m_mCacheTrainerSpellMap.end(); ++itr)
- itr->second.Clear();
-}
-
-void ObjectMgr::LoadPlayerInfoInCache()
-{
- QueryResult *result = CharacterDatabase.PQuery("SELECT guid, name, data, class FROM characters");
- if(!result)
- {
- sLog.outError( "Loading Player Cache failed.");
- return;
- }
-
- PCachePlayerInfo pPPlayerInfo = NULL;
- Field *fields = NULL;
- Tokens tdata;
- barGoLink bar( result->GetRowCount() );
- do
- {
- bar.step();
- fields = result->Fetch();
- pPPlayerInfo = new CachePlayerInfo();
-
- pPPlayerInfo->sPlayerName = fields[1].GetString();
-
- tdata.clear();
- tdata = StrSplit(fields[2].GetCppString(), " ");
-
- pPPlayerInfo->unLevel = Player::GetUInt32ValueFromArray(tdata,UNIT_FIELD_LEVEL);
- pPPlayerInfo->unfield = Player::GetUInt32ValueFromArray(tdata,UNIT_FIELD_BYTES_0);
-
- pPPlayerInfo->unArenaInfoId0 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 0 * 6);
- pPPlayerInfo->unArenaInfoId1 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 * 6);
- pPPlayerInfo->unArenaInfoId2 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 2 * 6);
-
- pPPlayerInfo->unArenaInfoSlot0 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 0 * 6 + 5);
- pPPlayerInfo->unArenaInfoSlot1 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 * 6 + 5);
- pPPlayerInfo->unArenaInfoSlot2 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 2 * 6 + 5);
-
- pPPlayerInfo->unClass = (uint32)fields[3].GetUInt32();
- m_mPlayerInfoMap[fields[0].GetUInt32()] = pPPlayerInfo;
- }
- while (result->NextRow());
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded info about %d players", m_mPlayerInfoMap.size());
-}
-
-PCachePlayerInfo ObjectMgr::GetPlayerInfoFromCache(uint32 unPlayerGuid) const
-{
- //Now m_mPlayerInfoMap is using only for search, but when dinamic inserting/removing
- //will be implemented we should lock it to prevent simultaneous access.
- //Inserting - when new created player is saving
- //Removing - when player has been deleted
- CachePlayerInfoMap::const_iterator ipos = m_mPlayerInfoMap.find(unPlayerGuid);
- return ipos == m_mPlayerInfoMap.end() ? NULL : ipos->second;
-}
-
-Group * ObjectMgr::GetGroupByLeader(const uint64 &guid) const
-{
- for(GroupSet::const_iterator itr = mGroupSet.begin(); itr != mGroupSet.end(); ++itr)
- if ((*itr)->GetLeaderGUID() == guid)
- return *itr;
-
- return NULL;
-}
-
-Guild * ObjectMgr::GetGuildById(const uint32 GuildId) const
-{
- for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); itr++)
- if ((*itr)->GetId() == GuildId)
- return *itr;
-
- return NULL;
-}
-
-Guild * ObjectMgr::GetGuildByName(std::string guildname) const
-{
- for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); itr++)
- if ((*itr)->GetName() == guildname)
- return *itr;
-
- return NULL;
-}
-
-std::string ObjectMgr::GetGuildNameById(const uint32 GuildId) const
-{
- for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); itr++)
- if ((*itr)->GetId() == GuildId)
- return (*itr)->GetName();
-
- return "";
-}
-
-Guild* ObjectMgr::GetGuildByLeader(const uint64 &guid) const
-{
- for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); ++itr)
- if( (*itr)->GetLeader() == guid)
- return *itr;
-
- return NULL;
-}
-
-ArenaTeam* ObjectMgr::GetArenaTeamById(const uint32 ArenaTeamId) const
-{
- for(ArenaTeamSet::const_iterator itr = mArenaTeamSet.begin(); itr != mArenaTeamSet.end(); itr++)
- if ((*itr)->GetId() == ArenaTeamId)
- return *itr;
-
- return NULL;
-}
-
-ArenaTeam* ObjectMgr::GetArenaTeamByName(std::string arenateamname) const
-{
- for(ArenaTeamSet::const_iterator itr = mArenaTeamSet.begin(); itr != mArenaTeamSet.end(); itr++)
- if ((*itr)->GetName() == arenateamname)
- return *itr;
-
- return NULL;
-}
-
-ArenaTeam* ObjectMgr::GetArenaTeamByCapitan(uint64 const& guid) const
-{
- for(ArenaTeamSet::const_iterator itr = mArenaTeamSet.begin(); itr != mArenaTeamSet.end(); itr++)
- if ((*itr)->GetCaptain() == guid)
- return *itr;
-
- return NULL;
-}
-
-AuctionHouseObject * ObjectMgr::GetAuctionsMap( uint32 location )
-{
- switch ( location )
- {
- case 6: //horde
- return & mHordeAuctions;
- break;
- case 2: //alliance
- return & mAllianceAuctions;
- break;
- default: //neutral
- return & mNeutralAuctions;
- }
-}
-
-uint32 ObjectMgr::GetAuctionCut(uint32 location, uint32 highBid)
-{
- if (location == 7 && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
- return (uint32) (0.15f * highBid * sWorld.getRate(RATE_AUCTION_CUT));
- else
- return (uint32) (0.05f * highBid * sWorld.getRate(RATE_AUCTION_CUT));
-}
-
-uint32 ObjectMgr::GetAuctionDeposit(uint32 location, uint32 time, Item *pItem)
-{
- float percentance; // in 0..1
- if ( location == 7 && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
- percentance = 0.75f;
- else
- percentance = 0.15f;
-
- percentance *= sWorld.getRate(RATE_AUCTION_DEPOSIT);
-
- return uint32( percentance * pItem->GetProto()->SellPrice * pItem->GetCount() * (time / MIN_AUCTION_TIME ) );
-}
-
-/// the sum of outbid is (1% from current bid)*5, if bid is very small, it is 1c
-uint32 ObjectMgr::GetAuctionOutBid(uint32 currentBid)
-{
- uint32 outbid = (currentBid / 100) * 5;
- if (!outbid)
- outbid = 1;
- return outbid;
-}
-
-//does not clear ram
-void ObjectMgr::SendAuctionWonMail( AuctionEntry *auction )
-{
- Item *pItem = GetAItem(auction->item_guidlow);
- if(!pItem)
- return;
-
- uint64 bidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER);
- Player *bidder = GetPlayer(bidder_guid);
-
- uint32 bidder_accId = 0;
-
- // data for gm.log
- if( sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
- {
- uint32 bidder_security = 0;
- std::string bidder_name;
- if (bidder)
- {
- bidder_accId = bidder->GetSession()->GetAccountId();
- bidder_security = bidder->GetSession()->GetSecurity();
- bidder_name = bidder->GetName();
- }
- else
- {
- bidder_accId = GetPlayerAccountIdByGUID(bidder_guid);
- bidder_security = accmgr.GetSecurity(bidder_accId);
-
- if(bidder_security > SEC_PLAYER ) // not do redundant DB requests
- {
- if(!GetPlayerNameByGUID(bidder_guid,bidder_name))
- bidder_name = GetTrinityStringForDBCLocale(LANG_UNKNOWN);
- }
- }
-
- if( bidder_security > SEC_PLAYER )
- {
- std::string owner_name;
- if(!GetPlayerNameByGUID(auction->owner,owner_name))
- owner_name = GetTrinityStringForDBCLocale(LANG_UNKNOWN);
-
- uint32 owner_accid = GetPlayerAccountIdByGUID(auction->owner);
-
- sLog.outCommand("GM %s (Account: %u) won item in auction: %s (Entry: %u Count: %u) and pay money: %u. Original owner %s (Account: %u)",
- bidder_name.c_str(),bidder_accId,pItem->GetProto()->Name1,pItem->GetEntry(),pItem->GetCount(),auction->bid,owner_name.c_str(),owner_accid);
- }
- }
- else if(!bidder)
- bidder_accId = GetPlayerAccountIdByGUID(bidder_guid);
-
- // receiver exist
- if(bidder || bidder_accId)
- {
- std::ostringstream msgAuctionWonSubject;
- msgAuctionWonSubject << auction->item_template << ":0:" << AUCTION_WON;
-
- std::ostringstream msgAuctionWonBody;
- msgAuctionWonBody.width(16);
- msgAuctionWonBody << std::right << std::hex << auction->owner;
- msgAuctionWonBody << std::dec << ":" << auction->bid << ":" << auction->buyout;
- sLog.outDebug( "AuctionWon body string : %s", msgAuctionWonBody.str().c_str() );
-
- //prepare mail data... :
- uint32 itemTextId = CreateItemText( msgAuctionWonBody.str() );
-
- // set owner to bidder (to prevent delete item with sender char deleting)
- // owner in `data` will set at mail receive and item extracting
- CharacterDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'",auction->bidder,pItem->GetGUIDLow());
- CharacterDatabase.CommitTransaction();
-
- MailItemsInfo mi;
- mi.AddItem(auction->item_guidlow, auction->item_template, pItem);
-
- if (bidder)
- bidder->GetSession()->SendAuctionBidderNotification( auction->location, auction->Id, bidder_guid, 0, 0, auction->item_template);
- else
- RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !!
-
- // will delete item or place to receiver mail list
- WorldSession::SendMailTo(bidder, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, auction->bidder, msgAuctionWonSubject.str(), itemTextId, &mi, 0, 0, MAIL_CHECK_MASK_AUCTION);
- }
- // receiver not exist
- else
- {
- CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid='%u'", pItem->GetGUIDLow());
- RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !!
- delete pItem;
- }
-}
-
-void ObjectMgr::SendAuctionSalePendingMail( AuctionEntry * auction )
-{
- uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER);
- Player *owner = GetPlayer(owner_guid);
-
- // owner exist (online or offline)
- if(owner || GetPlayerAccountIdByGUID(owner_guid))
- {
- std::ostringstream msgAuctionSalePendingSubject;
- msgAuctionSalePendingSubject << auction->item_template << ":0:" << AUCTION_SALE_PENDING;
-
- std::ostringstream msgAuctionSalePendingBody;
- uint32 auctionCut = GetAuctionCut(auction->location, auction->bid);
-
- time_t distrTime = time(NULL) + HOUR;
-
- msgAuctionSalePendingBody.width(16);
- msgAuctionSalePendingBody << std::right << std::hex << auction->bidder;
- msgAuctionSalePendingBody << std::dec << ":" << auction->bid << ":" << auction->buyout;
- msgAuctionSalePendingBody << ":" << auction->deposit << ":" << auctionCut << ":0:";
- msgAuctionSalePendingBody << secsToTimeBitFields(distrTime);
-
- sLog.outDebug("AuctionSalePending body string : %s", msgAuctionSalePendingBody.str().c_str());
-
- uint32 itemTextId = CreateItemText( msgAuctionSalePendingBody.str() );
-
- WorldSession::SendMailTo(owner, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, auction->owner, msgAuctionSalePendingSubject.str(), itemTextId, NULL, 0, 0, MAIL_CHECK_MASK_AUCTION);
- }
-}
-
-//call this method to send mail to auction owner, when auction is successful, it does not clear ram
-void ObjectMgr::SendAuctionSuccessfulMail( AuctionEntry * auction )
-{
- uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER);
- Player *owner = GetPlayer(owner_guid);
-
- uint32 owner_accId = 0;
- if(!owner)
- owner_accId = GetPlayerAccountIdByGUID(owner_guid);
-
- // owner exist
- if(owner || owner_accId)
- {
- std::ostringstream msgAuctionSuccessfulSubject;
- msgAuctionSuccessfulSubject << auction->item_template << ":0:" << AUCTION_SUCCESSFUL;
-
- std::ostringstream auctionSuccessfulBody;
- uint32 auctionCut = GetAuctionCut(auction->location, auction->bid);
-
- auctionSuccessfulBody.width(16);
- auctionSuccessfulBody << std::right << std::hex << auction->bidder;
- auctionSuccessfulBody << std::dec << ":" << auction->bid << ":" << auction->buyout;
- auctionSuccessfulBody << ":" << auction->deposit << ":" << auctionCut;
-
- sLog.outDebug("AuctionSuccessful body string : %s", auctionSuccessfulBody.str().c_str());
-
- uint32 itemTextId = CreateItemText( auctionSuccessfulBody.str() );
-
- uint32 profit = auction->bid + auction->deposit - auctionCut;
-
- if (owner)
- {
- //send auction owner notification, bidder must be current!
- owner->GetSession()->SendAuctionOwnerNotification( auction );
- }
-
- WorldSession::SendMailTo(owner, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, auction->owner, msgAuctionSuccessfulSubject.str(), itemTextId, NULL, profit, 0, MAIL_CHECK_MASK_AUCTION, HOUR);
- }
-}
-
-//does not clear ram
-void ObjectMgr::SendAuctionExpiredMail( AuctionEntry * auction )
-{ //return an item in auction to its owner by mail
- Item *pItem = GetAItem(auction->item_guidlow);
- if(!pItem)
- {
- sLog.outError("Auction item (GUID: %u) not found, and lost.",auction->item_guidlow);
- return;
- }
-
- uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER);
- Player *owner = GetPlayer(owner_guid);
-
- uint32 owner_accId = 0;
- if(!owner)
- owner_accId = GetPlayerAccountIdByGUID(owner_guid);
-
- // owner exist
- if(owner || owner_accId)
- {
- std::ostringstream subject;
- subject << auction->item_template << ":0:" << AUCTION_EXPIRED;
-
- if ( owner )
- owner->GetSession()->SendAuctionOwnerNotification( auction );
- else
- RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !!
-
- MailItemsInfo mi;
- mi.AddItem(auction->item_guidlow, auction->item_template, pItem);
-
- // will delete item or place to receiver mail list
- WorldSession::SendMailTo(owner, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, GUID_LOPART(owner_guid), subject.str(), 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE);
- }
- // owner not found
- else
- {
- CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid='%u'",pItem->GetGUIDLow());
- RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !!
- delete pItem;
- }
-}
-
-CreatureInfo const* ObjectMgr::GetCreatureTemplate(uint32 id)
-{
- return sCreatureStorage.LookupEntry<CreatureInfo>(id);
-}
-
-void ObjectMgr::LoadCreatureLocales()
-{
- mCreatureLocaleMap.clear(); // need for reload case
-
- QueryResult *result = WorldDatabase.Query("SELECT entry,name_loc1,subname_loc1,name_loc2,subname_loc2,name_loc3,subname_loc3,name_loc4,subname_loc4,name_loc5,subname_loc5,name_loc6,subname_loc6,name_loc7,subname_loc7,name_loc8,subname_loc8 FROM locales_creature");
-
- if(!result)
- {
- barGoLink bar(1);
-
- bar.step();
-
- sLog.outString("");
- sLog.outString(">> Loaded 0 creature locale strings. DB table `locales_creature` is empty.");
- return;
- }
-
- barGoLink bar(result->GetRowCount());
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- uint32 entry = fields[0].GetUInt32();
-
- CreatureLocale& data = mCreatureLocaleMap[entry];
-
- for(int i = 1; i < MAX_LOCALE; ++i)
- {
- std::string str = fields[1+2*(i-1)].GetCppString();
- if(!str.empty())
- {
- int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
- {
- if(data.Name.size() <= idx)
- data.Name.resize(idx+1);
-
- data.Name[idx] = str;
- }
- }
- str = fields[1+2*(i-1)+1].GetCppString();
- if(!str.empty())
- {
- int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
- {
- if(data.SubName.size() <= idx)
- data.SubName.resize(idx+1);
-
- data.SubName[idx] = str;
- }
- }
- }
- } while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u creature locale strings", mCreatureLocaleMap.size() );
-}
-
-void ObjectMgr::LoadNpcOptionLocales()
-{
- mNpcOptionLocaleMap.clear(); // need for reload case
-
- QueryResult *result = WorldDatabase.Query("SELECT entry,"
- "option_text_loc1,box_text_loc1,option_text_loc2,box_text_loc2,"
- "option_text_loc3,box_text_loc3,option_text_loc4,box_text_loc4,"
- "option_text_loc5,box_text_loc5,option_text_loc6,box_text_loc6,"
- "option_text_loc7,box_text_loc7,option_text_loc8,box_text_loc8 "
- "FROM locales_npc_option");
-
- if(!result)
- {
- barGoLink bar(1);
-
- bar.step();
-
- sLog.outString("");
- sLog.outString(">> Loaded 0 npc_option locale strings. DB table `locales_npc_option` is empty.");
- return;
- }
-
- barGoLink bar(result->GetRowCount());
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- uint32 entry = fields[0].GetUInt32();
-
- NpcOptionLocale& data = mNpcOptionLocaleMap[entry];
-
- for(int i = 1; i < MAX_LOCALE; ++i)
- {
- std::string str = fields[1+2*(i-1)].GetCppString();
- if(!str.empty())
- {
- int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
- {
- if(data.OptionText.size() <= idx)
- data.OptionText.resize(idx+1);
-
- data.OptionText[idx] = str;
- }
- }
- str = fields[1+2*(i-1)+1].GetCppString();
- if(!str.empty())
- {
- int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
- {
- if(data.BoxText.size() <= idx)
- data.BoxText.resize(idx+1);
-
- data.BoxText[idx] = str;
- }
- }
- }
- } while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u npc_option locale strings", mNpcOptionLocaleMap.size() );
-}
-
-struct SQLCreatureLoader : public SQLStorageLoaderBase<SQLCreatureLoader>
-{
- template<class D>
- void convert_from_str(uint32 field_pos, char *src, D &dst)
- {
- dst = D(objmgr.GetScriptId(src));
- }
-};
-
-void ObjectMgr::LoadCreatureTemplates()
-{
- SQLCreatureLoader loader;
- loader.Load(sCreatureStorage);
-
- sLog.outString( ">> Loaded %u creature definitions", sCreatureStorage.RecordCount );
- sLog.outString();
-
- std::set<uint32> heroicEntries; // already loaded heroic value in creatures
- std::set<uint32> hasHeroicEntries; // already loaded creatures with heroic entry values
-
- // check data correctness
- for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i)
- {
- CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i);
- if(!cInfo)
- continue;
-
- if(cInfo->HeroicEntry)
- {
- CreatureInfo const* heroicInfo = GetCreatureTemplate(cInfo->HeroicEntry);
- if(!heroicInfo)
- {
- sLog.outErrorDb("Creature (Entry: %u) have `heroic_entry`=%u but creature entry %u not exist.",cInfo->HeroicEntry,cInfo->HeroicEntry);
- continue;
- }
-
- if(heroicEntries.find(i)!=heroicEntries.end())
- {
- sLog.outErrorDb("Creature (Entry: %u) listed as heroic but have value in `heroic_entry`.",i);
- continue;
- }
-
- if(heroicEntries.find(cInfo->HeroicEntry)!=heroicEntries.end())
- {
- sLog.outErrorDb("Creature (Entry: %u) already listed as heroic for another entry.",cInfo->HeroicEntry);
- continue;
- }
-
- if(hasHeroicEntries.find(cInfo->HeroicEntry)!=hasHeroicEntries.end())
- {
- sLog.outErrorDb("Creature (Entry: %u) have `heroic_entry`=%u but creature entry %u have heroic entry also.",i,cInfo->HeroicEntry,cInfo->HeroicEntry);
- continue;
- }
-
- if(cInfo->npcflag != heroicInfo->npcflag)
- {
- sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `npcflag` in heroic mode.",i);
- continue;
- }
-
- if(cInfo->classNum != heroicInfo->classNum)
- {
- sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `classNum` in heroic mode.",i);
- continue;
- }
-
- if(cInfo->race != heroicInfo->race)
- {
- sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `race` in heroic mode.",i);
- continue;
- }
-
- if(cInfo->trainer_type != heroicInfo->trainer_type)
- {
- sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `trainer_type` in heroic mode.",i);
- continue;
- }
-
- if(cInfo->trainer_spell != heroicInfo->trainer_spell)
- {
- sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `trainer_spell` in heroic mode.",i);
- continue;
- }
-
- hasHeroicEntries.insert(i);
- heroicEntries.insert(cInfo->HeroicEntry);
- }
-
- FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_A);
- if(!factionTemplate)
- sLog.outErrorDb("Creature (Entry: %u) has non-existing faction_A template (%u)", cInfo->Entry, cInfo->faction_A);
-
- factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_H);
- if(!factionTemplate)
- sLog.outErrorDb("Creature (Entry: %u) has non-existing faction_H template (%u)", cInfo->Entry, cInfo->faction_H);
-
- // check model ids, supplying and sending non-existent ids to the client might crash them
- if(cInfo->Modelid1 && !sCreatureModelStorage.LookupEntry<CreatureModelInfo>(cInfo->Modelid1))
- {
- sLog.outErrorDb("Creature (Entry: %u) has non-existing modelId_A (%u), setting it to 0", cInfo->Entry, cInfo->Modelid1);
- const_cast<CreatureInfo*>(cInfo)->Modelid1 = 0;
- }
- if(cInfo->Modelid2 && !sCreatureModelStorage.LookupEntry<CreatureModelInfo>(cInfo->Modelid2))
- {
- sLog.outErrorDb("Creature (Entry: %u) has non-existing modelId_A2 (%u), setting it to 0", cInfo->Entry, cInfo->Modelid2);
- const_cast<CreatureInfo*>(cInfo)->Modelid2 = 0;
- }
- if(cInfo->Modelid3 && !sCreatureModelStorage.LookupEntry<CreatureModelInfo>(cInfo->Modelid3))
- {
- sLog.outErrorDb("Creature (Entry: %u) has non-existing modelId_H (%u), setting it to 0", cInfo->Entry, cInfo->Modelid3);
- const_cast<CreatureInfo*>(cInfo)->Modelid3 = 0;
- }
- if(cInfo->Modelid4 && !sCreatureModelStorage.LookupEntry<CreatureModelInfo>(cInfo->Modelid4))
- {
- sLog.outErrorDb("Creature (Entry: %u) has non-existing modelId_H2 (%u), setting it to 0", cInfo->Entry, cInfo->Modelid4);
- const_cast<CreatureInfo*>(cInfo)->Modelid4 = 0;
- }
-
- if(cInfo->dmgschool >= MAX_SPELL_SCHOOL)
- {
- sLog.outErrorDb("Creature (Entry: %u) has invalid spell school value (%u) in `dmgschool`",cInfo->Entry,cInfo->dmgschool);
- const_cast<CreatureInfo*>(cInfo)->dmgschool = SPELL_SCHOOL_NORMAL;
- }
-
- if(cInfo->baseattacktime == 0)
- const_cast<CreatureInfo*>(cInfo)->baseattacktime = BASE_ATTACK_TIME;
-
- if(cInfo->rangeattacktime == 0)
- const_cast<CreatureInfo*>(cInfo)->rangeattacktime = BASE_ATTACK_TIME;
-
- if((cInfo->npcflag & UNIT_NPC_FLAG_TRAINER) && cInfo->trainer_type >= MAX_TRAINER_TYPE)
- sLog.outErrorDb("Creature (Entry: %u) has wrong trainer type %u",cInfo->Entry,cInfo->trainer_type);
-
- if(cInfo->InhabitType <= 0 || cInfo->InhabitType > INHABIT_ANYWHERE)
- {
- sLog.outErrorDb("Creature (Entry: %u) has wrong value (%u) in `InhabitType`, creature will not correctly walk/swim/fly",cInfo->Entry,cInfo->InhabitType);
- const_cast<CreatureInfo*>(cInfo)->InhabitType = INHABIT_ANYWHERE;
- }
-
- if(cInfo->PetSpellDataId)
- {
- CreatureSpellDataEntry const* spellDataId = sCreatureSpellDataStore.LookupEntry(cInfo->PetSpellDataId);
- if(!spellDataId)
- sLog.outErrorDb("Creature (Entry: %u) has non-existing PetSpellDataId (%u)", cInfo->Entry, cInfo->PetSpellDataId);
- }
-
- if(cInfo->MovementType >= MAX_DB_MOTION_TYPE)
- {
- sLog.outErrorDb("Creature (Entry: %u) has wrong movement generator type (%u), ignore and set to IDLE.",cInfo->Entry,cInfo->MovementType);
- const_cast<CreatureInfo*>(cInfo)->MovementType = IDLE_MOTION_TYPE;
- }
-
- if(cInfo->equipmentId > 0) // 0 no equipment
- {
- if(!GetEquipmentInfo(cInfo->equipmentId))
- {
- sLog.outErrorDb("Table `creature_template` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", cInfo->Entry, cInfo->equipmentId);
- const_cast<CreatureInfo*>(cInfo)->equipmentId = 0;
- }
- }
-
- /// if not set custom creature scale then load scale from CreatureDisplayInfo.dbc
- if(cInfo->scale <= 0.0f)
- {
- uint32 modelid = cInfo->GetFirstValidModelId();
- CreatureDisplayInfoEntry const* ScaleEntry = sCreatureDisplayInfoStore.LookupEntry(modelid);
- const_cast<CreatureInfo*>(cInfo)->scale = ScaleEntry ? ScaleEntry->scale : 1.0f;
- }
- }
-}
-
-void ObjectMgr::ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr)
-{
- // Now add the auras, format "spellid effectindex spellid effectindex..."
- char *p,*s;
- std::vector<int> val;
- s=p=(char*)reinterpret_cast<char const*>(addon->auras);
- if(p)
- {
- while (p[0]!=0)
- {
- ++p;
- if (p[0]==' ')
- {
- val.push_back(atoi(s));
- s=++p;
- }
- }
- if (p!=s)
- val.push_back(atoi(s));
-
- // free char* loaded memory
- delete[] (char*)reinterpret_cast<char const*>(addon->auras);
-
- // wrong list
- if (val.size()%2)
- {
- addon->auras = NULL;
- sLog.outErrorDb("Creature (%s: %u) has wrong `auras` data in `%s`.",guidEntryStr,addon->guidOrEntry,table);
- return;
- }
- }
-
- // empty list
- if(val.empty())
- {
- addon->auras = NULL;
- return;
- }
-
- // replace by new structures array
- const_cast<CreatureDataAddonAura*&>(addon->auras) = new CreatureDataAddonAura[val.size()/2+1];
-
- int i=0;
- for(int j=0;j<val.size()/2;++j)
- {
- CreatureDataAddonAura& cAura = const_cast<CreatureDataAddonAura&>(addon->auras[i]);
- cAura.spell_id = (uint32)val[2*j+0];
- cAura.effect_idx = (uint32)val[2*j+1];
- if ( cAura.effect_idx > 2 )
- {
- sLog.outErrorDb("Creature (%s: %u) has wrong effect %u for spell %u in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,cAura.effect_idx,cAura.spell_id,table);
- continue;
- }
- SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(cAura.spell_id);
- if (!AdditionalSpellInfo)
- {
- sLog.outErrorDb("Creature (%s: %u) has wrong spell %u defined in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,cAura.spell_id,table);
- continue;
- }
-
- if (!AdditionalSpellInfo->Effect[cAura.effect_idx] || !AdditionalSpellInfo->EffectApplyAuraName[cAura.effect_idx])
- {
- sLog.outErrorDb("Creature (%s: %u) has not aura effect %u of spell %u defined in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,cAura.effect_idx,cAura.spell_id,table);
- continue;
- }
-
- ++i;
- }
-
- // fill terminator element (after last added)
- CreatureDataAddonAura& endAura = const_cast<CreatureDataAddonAura&>(addon->auras[i]);
- endAura.spell_id = 0;
- endAura.effect_idx = 0;
-}
-
-void ObjectMgr::LoadCreatureAddons()
-{
- sCreatureInfoAddonStorage.Load();
-
- sLog.outString( ">> Loaded %u creature template addons", sCreatureInfoAddonStorage.RecordCount );
- sLog.outString();
-
- // check data correctness and convert 'auras'
- for(uint32 i = 1; i < sCreatureInfoAddonStorage.MaxEntry; ++i)
- {
- CreatureDataAddon const* addon = sCreatureInfoAddonStorage.LookupEntry<CreatureDataAddon>(i);
- if(!addon)
- continue;
-
- ConvertCreatureAddonAuras(const_cast<CreatureDataAddon*>(addon), "creature_template_addon", "Entry");
-
- if(!sCreatureStorage.LookupEntry<CreatureInfo>(addon->guidOrEntry))
- sLog.outErrorDb("Creature (Entry: %u) does not exist but has a record in `creature_template_addon`",addon->guidOrEntry);
- }
-
- sCreatureDataAddonStorage.Load();
-
- sLog.outString( ">> Loaded %u creature addons", sCreatureDataAddonStorage.RecordCount );
- sLog.outString();
-
- // check data correctness and convert 'auras'
- for(uint32 i = 1; i < sCreatureDataAddonStorage.MaxEntry; ++i)
- {
- CreatureDataAddon const* addon = sCreatureDataAddonStorage.LookupEntry<CreatureDataAddon>(i);
- if(!addon)
- continue;
-
- ConvertCreatureAddonAuras(const_cast<CreatureDataAddon*>(addon), "creature_addon", "GUIDLow");
-
- if(mCreatureDataMap.find(addon->guidOrEntry)==mCreatureDataMap.end())
- sLog.outErrorDb("Creature (GUID: %u) does not exist but has a record in `creature_addon`",addon->guidOrEntry);
- }
-}
-
-EquipmentInfo const* ObjectMgr::GetEquipmentInfo(uint32 entry)
-{
- return sEquipmentStorage.LookupEntry<EquipmentInfo>(entry);
-}
-
-void ObjectMgr::LoadEquipmentTemplates()
-{
- sEquipmentStorage.Load();
-
- sLog.outString( ">> Loaded %u equipment template", sEquipmentStorage.RecordCount );
- sLog.outString();
-}
-
-CreatureModelInfo const* ObjectMgr::GetCreatureModelInfo(uint32 modelid)
-{
- return sCreatureModelStorage.LookupEntry<CreatureModelInfo>(modelid);
-}
-
-uint32 ObjectMgr::ChooseDisplayId(uint32 team, const CreatureInfo *cinfo, const CreatureData *data)
-{
- // Load creature model (display id)
- uint32 display_id = 0;
-
- if (!data || data->displayid == 0) // use defaults from the template
- {
- display_id = cinfo->GetRandomValidModelId();
- } else display_id = data->displayid; // overwritten from creature data
-
- return display_id;
-}
-
-CreatureModelInfo const* ObjectMgr::GetCreatureModelRandomGender(uint32 display_id)
-{
- CreatureModelInfo const *minfo = GetCreatureModelInfo(display_id);
- if(!minfo)
- return NULL;
-
- // If a model for another gender exists, 50% chance to use it
- if(minfo->modelid_other_gender != 0 && urand(0,1) == 0)
- {
- CreatureModelInfo const *minfo_tmp = GetCreatureModelInfo(minfo->modelid_other_gender);
- if(!minfo_tmp)
- {
- sLog.outErrorDb("Model (Entry: %u) has modelid_other_gender %u not found in table `creature_model_info`. ", minfo->modelid, minfo->modelid_other_gender);
- return minfo; // not fatal, just use the previous one
- }
- else
- return minfo_tmp;
- }
- else
- return minfo;
-}
-
-void ObjectMgr::LoadCreatureModelInfo()
-{
- sCreatureModelStorage.Load();
-
- sLog.outString( ">> Loaded %u creature model based info", sCreatureModelStorage.RecordCount );
- sLog.outString();
-
- // check if combat_reach is valid
- for(uint32 i = 1; i < sCreatureModelStorage.MaxEntry; ++i)
- {
- CreatureModelInfo const* mInfo = sCreatureModelStorage.LookupEntry<CreatureModelInfo>(i);
- if(!mInfo)
- continue;
-
- if(mInfo->combat_reach < 0.5f)
- {
- //sLog.outErrorDb("Creature model (Entry: %u) has invalid combat reach (%f), setting it to 0.5", mInfo->modelid, mInfo->combat_reach);
- const_cast<CreatureModelInfo*>(mInfo)->combat_reach = 0.5f;
- }
- }
-}
-
-void ObjectMgr::LoadCreatures()
-{
- uint32 count = 0;
- // 0 1 2 3
- QueryResult *result = WorldDatabase.Query("SELECT creature.guid, id, map, modelid,"
- // 4 5 6 7 8 9 10 11
- "equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, currentwaypoint,"
- // 12 13 14 15 16 17
- "curhealth, curmana, DeathState, MovementType, spawnMask, event "
- "FROM creature LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid");
-
- if(!result)
- {
- barGoLink bar(1);
-
- bar.step();
-
- sLog.outString("");
- sLog.outErrorDb(">> Loaded 0 creature. DB table `creature` is empty.");
- return;
- }
-
- // build single time for check creature data
- std::set<uint32> heroicCreatures;
- for(uint32 i = 0; i < sCreatureStorage.MaxEntry; ++i)
- if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
- if(cInfo->HeroicEntry)
- heroicCreatures.insert(cInfo->HeroicEntry);
-
- barGoLink bar(result->GetRowCount());
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- uint32 guid = fields[0].GetUInt32();
-
- CreatureData& data = mCreatureDataMap[guid];
-
- data.id = fields[ 1].GetUInt32();
- data.mapid = fields[ 2].GetUInt32();
- data.displayid = fields[ 3].GetUInt32();
- data.equipmentId = fields[ 4].GetUInt32();
- data.posX = fields[ 5].GetFloat();
- data.posY = fields[ 6].GetFloat();
- data.posZ = fields[ 7].GetFloat();
- data.orientation = fields[ 8].GetFloat();
- data.spawntimesecs = fields[ 9].GetUInt32();
- data.spawndist = fields[10].GetFloat();
- data.currentwaypoint= fields[11].GetUInt32();
- data.curhealth = fields[12].GetUInt32();
- data.curmana = fields[13].GetUInt32();
- data.is_dead = fields[14].GetBool();
- data.movementType = fields[15].GetUInt8();
- data.spawnMask = fields[16].GetUInt8();
- int16 gameEvent = fields[17].GetInt16();
-
- CreatureInfo const* cInfo = GetCreatureTemplate(data.id);
- if(!cInfo)
- {
- sLog.outErrorDb("Table `creature` have creature (GUID: %u) with not existed creature entry %u, skipped.",guid,data.id );
- continue;
- }
-
- if(heroicCreatures.find(data.id)!=heroicCreatures.end())
- {
- sLog.outErrorDb("Table `creature` have creature (GUID: %u) that listed as heroic template in `creature_template_substitution`, skipped.",guid,data.id );
- continue;
- }
-
- if(data.equipmentId > 0) // -1 no equipment, 0 use default
- {
- if(!GetEquipmentInfo(data.equipmentId))
- {
- sLog.outErrorDb("Table `creature` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", data.id, data.equipmentId);
- data.equipmentId = -1;
- }
- }
-
- if(cInfo->RegenHealth && data.curhealth < cInfo->minhealth)
- {
- sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`RegenHealth`=1 and low current health (%u), `creature_template`.`minhealth`=%u.",guid,data.id,data.curhealth, cInfo->minhealth );
- data.curhealth = cInfo->minhealth;
- }
-
- if(data.curmana < cInfo->minmana)
- {
- sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with low current mana (%u), `creature_template`.`minmana`=%u.",guid,data.id,data.curmana, cInfo->minmana );
- data.curmana = cInfo->minmana;
- }
-
- if(data.spawndist < 0.0f)
- {
- sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `spawndist`< 0, set to 0.",guid,data.id );
- data.spawndist = 0.0f;
- }
- else if(data.movementType == RANDOM_MOTION_TYPE)
- {
- if(data.spawndist == 0.0f)
- {
- sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `MovementType`=1 (random movement) but with `spawndist`=0, replace by idle movement type (0).",guid,data.id );
- data.movementType = IDLE_MOTION_TYPE;
- }
- }
- else if(data.movementType == IDLE_MOTION_TYPE)
- {
- if(data.spawndist != 0.0f)
- {
- sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `MovementType`=0 (idle) have `spawndist`<>0, set to 0.",guid,data.id );
- data.spawndist = 0.0f;
- }
- }
-
- if (gameEvent==0) // if not this is to be managed by GameEvent System
- AddCreatureToGrid(guid, &data);
- ++count;
-
- } while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u creatures", mCreatureDataMap.size() );
-}
-
-void ObjectMgr::AddCreatureToGrid(uint32 guid, CreatureData const* data)
-{
- uint8 mask = data->spawnMask;
- for(uint8 i = 0; mask != 0; i++, mask >>= 1)
- {
- if(mask & 1)
- {
- CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY);
- uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
-
- CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id];
- cell_guids.creatures.insert(guid);
- }
- }
-}
-
-void ObjectMgr::RemoveCreatureFromGrid(uint32 guid, CreatureData const* data)
-{
- uint8 mask = data->spawnMask;
- for(uint8 i = 0; mask != 0; i++, mask >>= 1)
- {
- if(mask & 1)
- {
- CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY);
- uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
-
- CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id];
- cell_guids.creatures.erase(guid);
- }
- }
-}
-
-void ObjectMgr::LoadGameobjects()
-{
- uint32 count = 0;
-
- // 0 1 2 3 4 5 6
- QueryResult *result = WorldDatabase.Query("SELECT gameobject.guid, id, map, position_x, position_y, position_z, orientation,"
- // 7 8 9 10 11 12 13 14 15
- "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, event "
- "FROM gameobject LEFT OUTER JOIN game_event_gameobject ON gameobject.guid = game_event_gameobject.guid");
-
- if(!result)
- {
- barGoLink bar(1);
-
- bar.step();
-
- sLog.outString();
- sLog.outErrorDb(">> Loaded 0 gameobjects. DB table `gameobject` is empty.");
- return;
- }
-
- barGoLink bar(result->GetRowCount());
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- uint32 guid = fields[0].GetUInt32();
-
- GameObjectData& data = mGameObjectDataMap[guid];
-
- data.id = fields[ 1].GetUInt32();
- data.mapid = fields[ 2].GetUInt32();
- data.posX = fields[ 3].GetFloat();
- data.posY = fields[ 4].GetFloat();
- data.posZ = fields[ 5].GetFloat();
- data.orientation = fields[ 6].GetFloat();
- data.rotation0 = fields[ 7].GetFloat();
- data.rotation1 = fields[ 8].GetFloat();
- data.rotation2 = fields[ 9].GetFloat();
- data.rotation3 = fields[10].GetFloat();
- data.spawntimesecs = fields[11].GetInt32();
- data.animprogress = fields[12].GetUInt32();
- data.go_state = fields[13].GetUInt32();
- data.ArtKit = 0;
- data.spawnMask = fields[14].GetUInt8();
- int16 gameEvent = fields[15].GetInt16();
-
- GameObjectInfo const* gInfo = GetGameObjectInfo(data.id);
- if(!gInfo)
- {
- sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u) with not existed gameobject entry %u, skipped.",guid,data.id );
- continue;
- }
-
- if (gameEvent==0) // if not this is to be managed by GameEvent System
- AddGameobjectToGrid(guid, &data);
- ++count;
-
- } while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u gameobjects", mGameObjectDataMap.size());
-}
-
-void ObjectMgr::AddGameobjectToGrid(uint32 guid, GameObjectData const* data)
-{
- uint8 mask = data->spawnMask;
- for(uint8 i = 0; mask != 0; i++, mask >>= 1)
- {
- if(mask & 1)
- {
- CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY);
- uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
-
- CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id];
- cell_guids.gameobjects.insert(guid);
- }
- }
-}
-
-void ObjectMgr::RemoveGameobjectFromGrid(uint32 guid, GameObjectData const* data)
-{
- uint8 mask = data->spawnMask;
- for(uint8 i = 0; mask != 0; i++, mask >>= 1)
- {
- if(mask & 1)
- {
- CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY);
- uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
-
- CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id];
- cell_guids.gameobjects.erase(guid);
- }
- }
-}
-
-void ObjectMgr::LoadCreatureRespawnTimes()
-{
- // remove outdated data
- WorldDatabase.DirectExecute("DELETE FROM creature_respawn WHERE respawntime <= UNIX_TIMESTAMP(NOW())");
-
- uint32 count = 0;
-
- QueryResult *result = WorldDatabase.Query("SELECT guid,respawntime,instance FROM creature_respawn");
-
- if(!result)
- {
- barGoLink bar(1);
-
- bar.step();
-
- sLog.outString();
- sLog.outString(">> Loaded 0 creature respawn time.");
- return;
- }
-
- barGoLink bar(result->GetRowCount());
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- uint32 loguid = fields[0].GetUInt32();
- uint64 respawn_time = fields[1].GetUInt64();
- uint32 instance = fields[2].GetUInt32();
-
- mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)] = time_t(respawn_time);
-
- ++count;
- } while (result->NextRow());
-
- delete result;
-
- sLog.outString( ">> Loaded %u creature respawn times", mCreatureRespawnTimes.size() );
- sLog.outString();
-}
-
-void ObjectMgr::LoadGameobjectRespawnTimes()
-{
- // remove outdated data
- WorldDatabase.DirectExecute("DELETE FROM gameobject_respawn WHERE respawntime <= UNIX_TIMESTAMP(NOW())");
-
- uint32 count = 0;
-
- QueryResult *result = WorldDatabase.Query("SELECT guid,respawntime,instance FROM gameobject_respawn");
-
- if(!result)
- {
- barGoLink bar(1);
-
- bar.step();
-
- sLog.outString();
- sLog.outString(">> Loaded 0 gameobject respawn time.");
- return;
- }
-
- barGoLink bar(result->GetRowCount());
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- uint32 loguid = fields[0].GetUInt32();
- uint64 respawn_time = fields[1].GetUInt64();
- uint32 instance = fields[2].GetUInt32();
-
- mGORespawnTimes[MAKE_PAIR64(loguid,instance)] = time_t(respawn_time);
-
- ++count;
- } while (result->NextRow());
-
- delete result;
-
- sLog.outString( ">> Loaded %u gameobject respawn times", mGORespawnTimes.size() );
- sLog.outString();
-}
-
-// name must be checked to correctness (if received) before call this function
-uint64 ObjectMgr::GetPlayerGUIDByName(std::string name) const
-{
- uint64 guid = 0;
-
- CharacterDatabase.escape_string(name);
-
- // Player name safe to sending to DB (checked at login) and this function using
- QueryResult *result = CharacterDatabase.PQuery("SELECT guid FROM characters WHERE name = '%s'", name.c_str());
- if(result)
- {
- guid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER);
-
- delete result;
- }
-
- return guid;
-}
-
-bool ObjectMgr::GetPlayerNameByGUID(const uint64 &guid, std::string &name) const
-{
- // prevent DB access for online player
- if(Player* player = GetPlayer(guid))
- {
- name = player->GetName();
- return true;
- }
-
- PCachePlayerInfo pInfo = GetPlayerInfoFromCache(GUID_LOPART(guid));
- if(pInfo)
- {
- name = pInfo->sPlayerName.c_str();
- return true;
- }
-
- QueryResult *result = CharacterDatabase.PQuery("SELECT name FROM characters WHERE guid = '%u'", GUID_LOPART(guid));
-
- if(result)
- {
- name = (*result)[0].GetCppString();
- delete result;
- return true;
- }
-
- return false;
-}
-
-uint32 ObjectMgr::GetPlayerTeamByGUID(const uint64 &guid) const
-{
- QueryResult *result = CharacterDatabase.PQuery("SELECT race FROM characters WHERE guid = '%u'", GUID_LOPART(guid));
-
- if(result)
- {
- uint8 race = (*result)[0].GetUInt8();
- delete result;
- return Player::TeamForRace(race);
- }
-
- return 0;
-}
-
-uint32 ObjectMgr::GetPlayerAccountIdByGUID(const uint64 &guid) const
-{
- QueryResult *result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE guid = '%u'", GUID_LOPART(guid));
- if(result)
- {
- uint32 acc = (*result)[0].GetUInt32();
- delete result;
- return acc;
- }
-
- return 0;
-}
-
-uint32 ObjectMgr::GetPlayerAccountIdByPlayerName(std::string name) const
-{
- QueryResult *result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name = '%s'", name.c_str());
- if(result)
- {
- uint32 acc = (*result)[0].GetUInt32();
- delete result;
- return acc;
- }
-
- return 0;
-}
-
-void ObjectMgr::LoadAuctions()
-{
- QueryResult *result = CharacterDatabase.Query("SELECT COUNT(*) FROM auctionhouse");
- if( !result )
- return;
-
- Field *fields = result->Fetch();
- uint32 AuctionCount=fields[0].GetUInt32();
- delete result;
-
- if(!AuctionCount)
- return;
-
- result = CharacterDatabase.Query( "SELECT id,auctioneerguid,itemguid,item_template,itemowner,buyoutprice,time,buyguid,lastbid,startbid,deposit,location FROM auctionhouse" );
- if( !result )
- return;
-
- barGoLink bar( AuctionCount );
-
- AuctionEntry *aItem;
-
- do
- {
- fields = result->Fetch();
-
- bar.step();
-
- aItem = new AuctionEntry;
- aItem->Id = fields[0].GetUInt32();
- aItem->auctioneer = fields[1].GetUInt32();
- aItem->item_guidlow = fields[2].GetUInt32();
- aItem->item_template = fields[3].GetUInt32();
- aItem->owner = fields[4].GetUInt32();
- aItem->buyout = fields[5].GetUInt32();
- aItem->time = fields[6].GetUInt32();
- aItem->bidder = fields[7].GetUInt32();
- aItem->bid = fields[8].GetUInt32();
- aItem->startbid = fields[9].GetUInt32();
- aItem->deposit = fields[10].GetUInt32();
- aItem->location = fields[11].GetUInt8();
- //check if sold item exists
- if ( GetAItem( aItem->item_guidlow ) )
- {
- GetAuctionsMap( aItem->location )->AddAuction(aItem);
- }
- else
- {
- CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE id = '%u'",aItem->Id);
- sLog.outError("Auction %u has not a existing item : %u", aItem->Id, aItem->item_guidlow);
- delete aItem;
- }
- } while (result->NextRow());
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u auctions", AuctionCount );
- sLog.outString();
-}
-
-void ObjectMgr::LoadItemLocales()
-{
- mItemLocaleMap.clear(); // need for reload case
-
- QueryResult *result = WorldDatabase.Query("SELECT entry,name_loc1,description_loc1,name_loc2,description_loc2,name_loc3,description_loc3,name_loc4,description_loc4,name_loc5,description_loc5,name_loc6,description_loc6,name_loc7,description_loc7,name_loc8,description_loc8 FROM locales_item");
-
- if(!result)
- {
- barGoLink bar(1);
-
- bar.step();
-
- sLog.outString("");
- sLog.outString(">> Loaded 0 Item locale strings. DB table `locales_item` is empty.");
- return;
- }
-
- barGoLink bar(result->GetRowCount());
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- uint32 entry = fields[0].GetUInt32();
-
- ItemLocale& data = mItemLocaleMap[entry];
-
- for(int i = 1; i < MAX_LOCALE; ++i)
- {
- std::string str = fields[1+2*(i-1)].GetCppString();
- if(!str.empty())
- {
- int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
- {
- if(data.Name.size() <= idx)
- data.Name.resize(idx+1);
-
- data.Name[idx] = str;
- }
- }
-
- str = fields[1+2*(i-1)+1].GetCppString();
- if(!str.empty())
- {
- int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
- {
- if(data.Description.size() <= idx)
- data.Description.resize(idx+1);
-
- data.Description[idx] = str;
- }
- }
- }
- } while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u Item locale strings", mItemLocaleMap.size() );
-}
-
-struct SQLItemLoader : public SQLStorageLoaderBase<SQLItemLoader>
-{
- template<class D>
- void convert_from_str(uint32 field_pos, char *src, D &dst)
- {
- dst = D(objmgr.GetScriptId(src));
- }
-};
-
-void ObjectMgr::LoadItemPrototypes()
-{
- SQLItemLoader loader;
- loader.Load(sItemStorage);
- sLog.outString( ">> Loaded %u item prototypes", sItemStorage.RecordCount );
- sLog.outString();
-
- // check data correctness
- for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i)
- {
- ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype >(i);
- ItemEntry const *dbcitem = sItemStore.LookupEntry(i);
- if(!proto)
- {
- /* to many errors, and possible not all items really used in game
- if (dbcitem)
- sLog.outErrorDb("Item (Entry: %u) doesn't exists in DB, but must exist.",i);
- */
- continue;
- }
-
- if(dbcitem)
- {
- if(proto->InventoryType != dbcitem->InventoryType)
- {
- sLog.outErrorDb("Item (Entry: %u) not correct %u inventory type, must be %u (still using DB value).",i,proto->InventoryType,dbcitem->InventoryType);
- // It safe let use InventoryType from DB
- }
-
- if(proto->DisplayInfoID != dbcitem->DisplayId)
- {
- sLog.outErrorDb("Item (Entry: %u) not correct %u display id, must be %u (using it).",i,proto->DisplayInfoID,dbcitem->DisplayId);
- const_cast<ItemPrototype*>(proto)->DisplayInfoID = dbcitem->DisplayId;
- }
- if(proto->Sheath != dbcitem->Sheath)
- {
- sLog.outErrorDb("Item (Entry: %u) not correct %u sheath, must be %u (using it).",i,proto->Sheath,dbcitem->Sheath);
- const_cast<ItemPrototype*>(proto)->Sheath = dbcitem->Sheath;
- }
- }
- else
- {
- sLog.outErrorDb("Item (Entry: %u) not correct (not listed in list of existed items).",i);
- }
-
- if(proto->Class >= MAX_ITEM_CLASS)
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong Class value (%u)",i,proto->Class);
- const_cast<ItemPrototype*>(proto)->Class = ITEM_CLASS_JUNK;
- }
-
- if(proto->SubClass >= MaxItemSubclassValues[proto->Class])
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong Subclass value (%u) for class %u",i,proto->SubClass,proto->Class);
- const_cast<ItemPrototype*>(proto)->SubClass = 0;// exist for all item classes
- }
-
- if(proto->Quality >= MAX_ITEM_QUALITY)
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong Quality value (%u)",i,proto->Quality);
- const_cast<ItemPrototype*>(proto)->Quality = ITEM_QUALITY_NORMAL;
- }
-
- if(proto->BuyCount <= 0)
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong BuyCount value (%u), set to default(1).",i,proto->BuyCount);
- const_cast<ItemPrototype*>(proto)->BuyCount = 1;
- }
-
- if(proto->InventoryType >= MAX_INVTYPE)
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong InventoryType value (%u)",i,proto->InventoryType);
- const_cast<ItemPrototype*>(proto)->InventoryType = INVTYPE_NON_EQUIP;
- }
-
- if(proto->RequiredSkill >= MAX_SKILL_TYPE)
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong RequiredSkill value (%u)",i,proto->RequiredSkill);
- const_cast<ItemPrototype*>(proto)->RequiredSkill = 0;
- }
-
- if(!(proto->AllowableClass & CLASSMASK_ALL_PLAYABLE))
- {
- sLog.outErrorDb("Item (Entry: %u) not have in `AllowableClass` any playable classes (%u) and can't be equipped.",i,proto->AllowableClass);
- }
-
- if(!(proto->AllowableRace & RACEMASK_ALL_PLAYABLE))
- {
- sLog.outErrorDb("Item (Entry: %u) not have in `AllowableRace` any playable races (%u) and can't be equipped.",i,proto->AllowableRace);
- }
-
- if(proto->RequiredSpell && !sSpellStore.LookupEntry(proto->RequiredSpell))
- {
- sLog.outErrorDb("Item (Entry: %u) have wrong (non-existed) spell in RequiredSpell (%u)",i,proto->RequiredSpell);
- const_cast<ItemPrototype*>(proto)->RequiredSpell = 0;
- }
-
- if(proto->RequiredReputationRank >= MAX_REPUTATION_RANK)
- sLog.outErrorDb("Item (Entry: %u) has wrong reputation rank in RequiredReputationRank (%u), item can't be used.",i,proto->RequiredReputationRank);
-
- if(proto->RequiredReputationFaction)
- {
- if(!sFactionStore.LookupEntry(proto->RequiredReputationFaction))
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) faction in RequiredReputationFaction (%u)",i,proto->RequiredReputationFaction);
- const_cast<ItemPrototype*>(proto)->RequiredReputationFaction = 0;
- }
-
- if(proto->RequiredReputationRank == MIN_REPUTATION_RANK)
- sLog.outErrorDb("Item (Entry: %u) has min. reputation rank in RequiredReputationRank (0) but RequiredReputationFaction > 0, faction setting is useless.",i);
- }
- else if(proto->RequiredReputationRank > MIN_REPUTATION_RANK)
- sLog.outErrorDb("Item (Entry: %u) has RequiredReputationFaction ==0 but RequiredReputationRank > 0, rank setting is useless.",i);
-
- if(proto->Stackable==0)
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong value in stackable (%u), replace by default 1.",i,proto->Stackable);
- const_cast<ItemPrototype*>(proto)->Stackable = 1;
- }
- else if(proto->Stackable > 255)
- {
- sLog.outErrorDb("Item (Entry: %u) has too large value in stackable (%u), replace by hardcoded upper limit (255).",i,proto->Stackable);
- const_cast<ItemPrototype*>(proto)->Stackable = 255;
- }
-
- for (int j = 0; j < 10; j++)
- {
- // for ItemStatValue != 0
- if(proto->ItemStat[j].ItemStatValue && proto->ItemStat[j].ItemStatType >= MAX_ITEM_MOD)
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong stat_type%d (%u)",i,j+1,proto->ItemStat[j].ItemStatType);
- const_cast<ItemPrototype*>(proto)->ItemStat[j].ItemStatType = 0;
- }
- }
-
- for (int j = 0; j < 5; j++)
- {
- if(proto->Damage[j].DamageType >= MAX_SPELL_SCHOOL)
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong dmg_type%d (%u)",i,j+1,proto->Damage[j].DamageType);
- const_cast<ItemPrototype*>(proto)->Damage[j].DamageType = 0;
- }
- }
-
- // special format
- if(proto->Spells[0].SpellId == SPELL_ID_GENERIC_LEARN)
- {
- // spell_1
- if(proto->Spells[0].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE)
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u) for special learning format",i,0+1,proto->Spells[0].SpellTrigger);
- const_cast<ItemPrototype*>(proto)->Spells[0].SpellId = 0;
- const_cast<ItemPrototype*>(proto)->Spells[0].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
- const_cast<ItemPrototype*>(proto)->Spells[1].SpellId = 0;
- const_cast<ItemPrototype*>(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
- }
-
- // spell_2 have learning spell
- if(proto->Spells[1].SpellTrigger != ITEM_SPELLTRIGGER_LEARN_SPELL_ID)
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u) for special learning format.",i,1+1,proto->Spells[1].SpellTrigger);
- const_cast<ItemPrototype*>(proto)->Spells[0].SpellId = 0;
- const_cast<ItemPrototype*>(proto)->Spells[1].SpellId = 0;
- const_cast<ItemPrototype*>(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
- }
- else if(!proto->Spells[1].SpellId)
- {
- sLog.outErrorDb("Item (Entry: %u) not has expected spell in spellid_%d in special learning format.",i,1+1);
- const_cast<ItemPrototype*>(proto)->Spells[0].SpellId = 0;
- const_cast<ItemPrototype*>(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
- }
- else
- {
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(proto->Spells[1].SpellId);
- if(!spellInfo)
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) spell in spellid_%d (%u)",i,1+1,proto->Spells[1].SpellId);
- const_cast<ItemPrototype*>(proto)->Spells[0].SpellId = 0;
- const_cast<ItemPrototype*>(proto)->Spells[1].SpellId = 0;
- const_cast<ItemPrototype*>(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
- }
- // allowed only in special format
- else if(proto->Spells[1].SpellId==SPELL_ID_GENERIC_LEARN)
- {
- sLog.outErrorDb("Item (Entry: %u) has broken spell in spellid_%d (%u)",i,1+1,proto->Spells[1].SpellId);
- const_cast<ItemPrototype*>(proto)->Spells[0].SpellId = 0;
- const_cast<ItemPrototype*>(proto)->Spells[1].SpellId = 0;
- const_cast<ItemPrototype*>(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
- }
- }
-
- // spell_3*,spell_4*,spell_5* is empty
- for (int j = 2; j < 5; j++)
- {
- if(proto->Spells[j].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE)
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u)",i,j+1,proto->Spells[j].SpellTrigger);
- const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
- const_cast<ItemPrototype*>(proto)->Spells[j].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
- }
- else if(proto->Spells[j].SpellId != 0)
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong spell in spellid_%d (%u) for learning special format",i,j+1,proto->Spells[j].SpellId);
- const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
- }
- }
- }
- // normal spell list
- else
- {
- for (int j = 0; j < 5; j++)
- {
- if(proto->Spells[j].SpellTrigger >= MAX_ITEM_SPELLTRIGGER || proto->Spells[j].SpellTrigger == ITEM_SPELLTRIGGER_LEARN_SPELL_ID)
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u)",i,j+1,proto->Spells[j].SpellTrigger);
- const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
- const_cast<ItemPrototype*>(proto)->Spells[j].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
- }
-
- if(proto->Spells[j].SpellId)
- {
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(proto->Spells[j].SpellId);
- if(!spellInfo)
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) spell in spellid_%d (%u)",i,j+1,proto->Spells[j].SpellId);
- const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
- }
- // allowed only in special format
- else if(proto->Spells[j].SpellId==SPELL_ID_GENERIC_LEARN)
- {
- sLog.outErrorDb("Item (Entry: %u) has broken spell in spellid_%d (%u)",i,j+1,proto->Spells[j].SpellId);
- const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
- }
- }
- }
- }
-
- if(proto->Bonding >= MAX_BIND_TYPE)
- sLog.outErrorDb("Item (Entry: %u) has wrong Bonding value (%u)",i,proto->Bonding);
-
- if(proto->PageText && !sPageTextStore.LookupEntry<PageText>(proto->PageText))
- sLog.outErrorDb("Item (Entry: %u) has non existing first page (Id:%u)", i,proto->PageText);
-
- if(proto->LockID && !sLockStore.LookupEntry(proto->LockID))
- sLog.outErrorDb("Item (Entry: %u) has wrong LockID (%u)",i,proto->LockID);
-
- if(proto->Sheath >= MAX_SHEATHETYPE)
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong Sheath (%u)",i,proto->Sheath);
- const_cast<ItemPrototype*>(proto)->Sheath = SHEATHETYPE_NONE;
- }
-
- if(proto->RandomProperty && !sItemRandomPropertiesStore.LookupEntry(GetItemEnchantMod(proto->RandomProperty)))
- {
- sLog.outErrorDb("Item (Entry: %u) has unknown (wrong or not listed in `item_enchantment_template`) RandomProperty (%u)",i,proto->RandomProperty);
- const_cast<ItemPrototype*>(proto)->RandomProperty = 0;
- }
-
- if(proto->RandomSuffix && !sItemRandomSuffixStore.LookupEntry(GetItemEnchantMod(proto->RandomSuffix)))
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong RandomSuffix (%u)",i,proto->RandomSuffix);
- const_cast<ItemPrototype*>(proto)->RandomSuffix = 0;
- }
-
- if(proto->ItemSet && !sItemSetStore.LookupEntry(proto->ItemSet))
- {
- sLog.outErrorDb("Item (Entry: %u) have wrong ItemSet (%u)",i,proto->ItemSet);
- const_cast<ItemPrototype*>(proto)->ItemSet = 0;
- }
-
- if(proto->Area && !GetAreaEntryByAreaID(proto->Area))
- sLog.outErrorDb("Item (Entry: %u) has wrong Area (%u)",i,proto->Area);
-
- if(proto->Map && !sMapStore.LookupEntry(proto->Map))
- sLog.outErrorDb("Item (Entry: %u) has wrong Map (%u)",i,proto->Map);
-
- if(proto->TotemCategory && !sTotemCategoryStore.LookupEntry(proto->TotemCategory))
- sLog.outErrorDb("Item (Entry: %u) has wrong TotemCategory (%u)",i,proto->TotemCategory);
-
- for (int j = 0; j < 3; j++)
- {
- if(proto->Socket[j].Color && (proto->Socket[j].Color & SOCKET_COLOR_ALL) != proto->Socket[j].Color)
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong socketColor_%d (%u)",i,j+1,proto->Socket[j].Color);
- const_cast<ItemPrototype*>(proto)->Socket[j].Color = 0;
- }
- }
-
- if(proto->GemProperties && !sGemPropertiesStore.LookupEntry(proto->GemProperties))
- sLog.outErrorDb("Item (Entry: %u) has wrong GemProperties (%u)",i,proto->GemProperties);
-
- if(proto->FoodType >= MAX_PET_DIET)
- {
- sLog.outErrorDb("Item (Entry: %u) has wrong FoodType value (%u)",i,proto->FoodType);
- const_cast<ItemPrototype*>(proto)->FoodType = 0;
- }
- }
-
- // this DBC used currently only for check item templates in DB.
- sItemStore.Clear();
-}
-
-void ObjectMgr::LoadAuctionItems()
-{
- QueryResult *result = CharacterDatabase.Query( "SELECT itemguid,item_template FROM auctionhouse" );
-
- if( !result )
- return;
-
- barGoLink bar( result->GetRowCount() );
-
- uint32 count = 0;
-
- Field *fields;
- do
- {
- bar.step();
-
- fields = result->Fetch();
- uint32 item_guid = fields[0].GetUInt32();
- uint32 item_template = fields[1].GetUInt32();
-
- ItemPrototype const *proto = GetItemPrototype(item_template);
-
- if(!proto)
- {
- sLog.outError( "ObjectMgr::LoadAuctionItems: Unknown item (GUID: %u id: #%u) in auction, skipped.", item_guid,item_template);
- continue;
- }
-
- Item *item = NewItemOrBag(proto);
-
- if(!item->LoadFromDB(item_guid,0))
- {
- delete item;
- continue;
- }
- AddAItem(item);
-
- ++count;
- }
- while( result->NextRow() );
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u auction items", count );
-}
-
-void ObjectMgr::LoadPetLevelInfo()
-{
- // Loading levels data
- {
- // 0 1 2 3 4 5 6 7 8 9
- QueryResult *result = WorldDatabase.Query("SELECT creature_entry, level, hp, mana, str, agi, sta, inte, spi, armor FROM pet_levelstats");
-
- uint32 count = 0;
-
- if (!result)
- {
- barGoLink bar( 1 );
-
- sLog.outString();
- sLog.outString( ">> Loaded %u level pet stats definitions", count );
- sLog.outErrorDb( "Error loading `pet_levelstats` table or empty table.");
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- Field* fields = result->Fetch();
-
- uint32 creature_id = fields[0].GetUInt32();
- if(!sCreatureStorage.LookupEntry<CreatureInfo>(creature_id))
- {
- sLog.outErrorDb("Wrong creature id %u in `pet_levelstats` table, ignoring.",creature_id);
- continue;
- }
-
- uint32 current_level = fields[1].GetUInt32();
- if(current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
- {
- if(current_level > 255) // hardcoded level maximum
- sLog.outErrorDb("Wrong (> 255) level %u in `pet_levelstats` table, ignoring.",current_level);
- else
- sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `pet_levelstats` table, ignoring.",current_level);
- continue;
- }
- else if(current_level < 1)
- {
- sLog.outErrorDb("Wrong (<1) level %u in `pet_levelstats` table, ignoring.",current_level);
- continue;
- }
-
- PetLevelInfo*& pInfoMapEntry = petInfo[creature_id];
-
- if(pInfoMapEntry==NULL)
- pInfoMapEntry = new PetLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)];
-
- // data for level 1 stored in [0] array element, ...
- PetLevelInfo* pLevelInfo = &pInfoMapEntry[current_level-1];
-
- pLevelInfo->health = fields[2].GetUInt16();
- pLevelInfo->mana = fields[3].GetUInt16();
- pLevelInfo->armor = fields[9].GetUInt16();
-
- for (int i = 0; i < MAX_STATS; i++)
- {
- pLevelInfo->stats[i] = fields[i+4].GetUInt16();
- }
-
- bar.step();
- ++count;
- }
- while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u level pet stats definitions", count );
- }
-
- // Fill gaps and check integrity
- for (PetLevelInfoMap::iterator itr = petInfo.begin(); itr != petInfo.end(); ++itr)
- {
- PetLevelInfo* pInfo = itr->second;
-
- // fatal error if no level 1 data
- if(!pInfo || pInfo[0].health == 0 )
- {
- sLog.outErrorDb("Creature %u does not have pet stats data for Level 1!",itr->first);
- exit(1);
- }
-
- // fill level gaps
- for (uint32 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
- {
- if(pInfo[level].health == 0)
- {
- sLog.outErrorDb("Creature %u has no data for Level %i pet stats data, using data of Level %i.",itr->first,level+1, level);
- pInfo[level] = pInfo[level-1];
- }
- }
- }
-}
-
-PetLevelInfo const* ObjectMgr::GetPetLevelInfo(uint32 creature_id, uint32 level) const
-{
- if(level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
- level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL);
-
- PetLevelInfoMap::const_iterator itr = petInfo.find(creature_id);
- if(itr == petInfo.end())
- return NULL;
-
- return &itr->second[level-1]; // data for level 1 stored in [0] array element, ...
-}
-
-void ObjectMgr::LoadPlayerInfo()
-{
- // Load playercreate
- {
- // 0 1 2 3 4 5 6
- QueryResult *result = WorldDatabase.Query("SELECT race, class, map, zone, position_x, position_y, position_z FROM playercreateinfo");
-
- uint32 count = 0;
-
- if (!result)
- {
- barGoLink bar( 1 );
-
- sLog.outString();
- sLog.outString( ">> Loaded %u player create definitions", count );
- sLog.outErrorDb( "Error loading `playercreateinfo` table or empty table.");
- exit(1);
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- Field* fields = result->Fetch();
-
- uint32 current_race = fields[0].GetUInt32();
- uint32 current_class = fields[1].GetUInt32();
- uint32 mapId = fields[2].GetUInt32();
- uint32 zoneId = fields[3].GetUInt32();
- float positionX = fields[4].GetFloat();
- float positionY = fields[5].GetFloat();
- float positionZ = fields[6].GetFloat();
-
- if(current_race >= MAX_RACES)
- {
- sLog.outErrorDb("Wrong race %u in `playercreateinfo` table, ignoring.",current_race);
- continue;
- }
-
- ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(current_race);
- if(!rEntry)
- {
- sLog.outErrorDb("Wrong race %u in `playercreateinfo` table, ignoring.",current_race);
- continue;
- }
-
- if(current_class >= MAX_CLASSES)
- {
- sLog.outErrorDb("Wrong class %u in `playercreateinfo` table, ignoring.",current_class);
- continue;
- }
-
- if(!sChrClassesStore.LookupEntry(current_class))
- {
- sLog.outErrorDb("Wrong class %u in `playercreateinfo` table, ignoring.",current_class);
- continue;
- }
-
- // accept DB data only for valid position (and non instanceable)
- if( !MapManager::IsValidMapCoord(mapId,positionX,positionY,positionZ) )
- {
- sLog.outErrorDb("Wrong home position for class %u race %u pair in `playercreateinfo` table, ignoring.",current_class,current_race);
- continue;
- }
-
- if( sMapStore.LookupEntry(mapId)->Instanceable() )
- {
- sLog.outErrorDb("Home position in instanceable map for class %u race %u pair in `playercreateinfo` table, ignoring.",current_class,current_race);
- continue;
- }
-
- PlayerInfo* pInfo = &playerInfo[current_race][current_class];
-
- pInfo->mapId = mapId;
- pInfo->zoneId = zoneId;
- pInfo->positionX = positionX;
- pInfo->positionY = positionY;
- pInfo->positionZ = positionZ;
-
- pInfo->displayId_m = rEntry->model_m;
- pInfo->displayId_f = rEntry->model_f;
-
- bar.step();
- ++count;
- }
- while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u player create definitions", count );
- }
-
- // Load playercreate items
- {
- // 0 1 2 3
- QueryResult *result = WorldDatabase.Query("SELECT race, class, itemid, amount FROM playercreateinfo_item");
-
- uint32 count = 0;
-
- if (!result)
- {
- barGoLink bar( 1 );
-
- sLog.outString();
- sLog.outString( ">> Loaded %u player create items", count );
- sLog.outErrorDb( "Error loading `playercreateinfo_item` table or empty table.");
- }
- else
- {
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- Field* fields = result->Fetch();
-
- uint32 current_race = fields[0].GetUInt32();
- if(current_race >= MAX_RACES)
- {
- sLog.outErrorDb("Wrong race %u in `playercreateinfo_item` table, ignoring.",current_race);
- continue;
- }
-
- uint32 current_class = fields[1].GetUInt32();
- if(current_class >= MAX_CLASSES)
- {
- sLog.outErrorDb("Wrong class %u in `playercreateinfo_item` table, ignoring.",current_class);
- continue;
- }
-
- PlayerInfo* pInfo = &playerInfo[current_race][current_class];
-
- uint32 item_id = fields[2].GetUInt32();
-
- if(!GetItemPrototype(item_id))
- {
- sLog.outErrorDb("Item id %u (race %u class %u) in `playercreateinfo_item` table but not listed in `item_template`, ignoring.",item_id,current_race,current_class);
- continue;
- }
-
- uint32 amount = fields[3].GetUInt32();
-
- if(!amount)
- {
- sLog.outErrorDb("Item id %u (class %u race %u) have amount==0 in `playercreateinfo_item` table, ignoring.",item_id,current_race,current_class);
- continue;
- }
-
- pInfo->item.push_back(PlayerCreateInfoItem( item_id, amount));
-
- bar.step();
- ++count;
- }
- while(result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u player create items", count );
- }
- }
-
- // Load playercreate spells
- {
-
- QueryResult *result = NULL;
- if(sWorld.getConfig(CONFIG_START_ALL_SPELLS))
- result = WorldDatabase.Query("SELECT race, class, Spell, Active FROM playercreateinfo_spell_custom");
- else
- result = WorldDatabase.Query("SELECT race, class, Spell, Active FROM playercreateinfo_spell");
-
- uint32 count = 0;
-
- if (!result)
- {
- barGoLink bar( 1 );
-
- sLog.outString();
- sLog.outString( ">> Loaded %u player create spells", count );
- sLog.outErrorDb( "Error loading player starting spells or empty table.");
- }
- else
- {
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- Field* fields = result->Fetch();
-
- uint32 current_race = fields[0].GetUInt32();
- if(current_race >= MAX_RACES)
- {
- sLog.outErrorDb("Wrong race %u in `playercreateinfo_spell` table, ignoring.",current_race);
- continue;
- }
-
- uint32 current_class = fields[1].GetUInt32();
- if(current_class >= MAX_CLASSES)
- {
- sLog.outErrorDb("Wrong class %u in `playercreateinfo_spell` table, ignoring.",current_class);
- continue;
- }
-
- PlayerInfo* pInfo = &playerInfo[current_race][current_class];
- pInfo->spell.push_back(CreateSpellPair(fields[2].GetUInt16(), fields[3].GetUInt8()));
-
- bar.step();
- ++count;
- }
- while( result->NextRow() );
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u player create spells", count );
- }
- }
-
- // Load playercreate actions
- {
- // 0 1 2 3 4 5
- QueryResult *result = WorldDatabase.Query("SELECT race, class, button, action, type, misc FROM playercreateinfo_action");
-
- uint32 count = 0;
-
- if (!result)
- {
- barGoLink bar( 1 );
-
- sLog.outString();
- sLog.outString( ">> Loaded %u player create actions", count );
- sLog.outErrorDb( "Error loading `playercreateinfo_action` table or empty table.");
- }
- else
- {
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- Field* fields = result->Fetch();
-
- uint32 current_race = fields[0].GetUInt32();
- if(current_race >= MAX_RACES)
- {
- sLog.outErrorDb("Wrong race %u in `playercreateinfo_action` table, ignoring.",current_race);
- continue;
- }
-
- uint32 current_class = fields[1].GetUInt32();
- if(current_class >= MAX_CLASSES)
- {
- sLog.outErrorDb("Wrong class %u in `playercreateinfo_action` table, ignoring.",current_class);
- continue;
- }
-
- PlayerInfo* pInfo = &playerInfo[current_race][current_class];
- pInfo->action[0].push_back(fields[2].GetUInt16());
- pInfo->action[1].push_back(fields[3].GetUInt16());
- pInfo->action[2].push_back(fields[4].GetUInt16());
- pInfo->action[3].push_back(fields[5].GetUInt16());
-
- bar.step();
- ++count;
- }
- while( result->NextRow() );
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u player create actions", count );
- }
- }
-
- // Loading levels data (class only dependent)
- {
- // 0 1 2 3
- QueryResult *result = WorldDatabase.Query("SELECT class, level, basehp, basemana FROM player_classlevelstats");
-
- uint32 count = 0;
-
- if (!result)
- {
- barGoLink bar( 1 );
-
- sLog.outString();
- sLog.outString( ">> Loaded %u level health/mana definitions", count );
- sLog.outErrorDb( "Error loading `player_classlevelstats` table or empty table.");
- exit(1);
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- Field* fields = result->Fetch();
-
- uint32 current_class = fields[0].GetUInt32();
- if(current_class >= MAX_CLASSES)
- {
- sLog.outErrorDb("Wrong class %u in `player_classlevelstats` table, ignoring.",current_class);
- continue;
- }
-
- uint32 current_level = fields[1].GetUInt32();
- if(current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
- {
- if(current_level > 255) // hardcoded level maximum
- sLog.outErrorDb("Wrong (> 255) level %u in `player_classlevelstats` table, ignoring.",current_level);
- else
- sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `player_classlevelstats` table, ignoring.",current_level);
- continue;
- }
-
- PlayerClassInfo* pClassInfo = &playerClassInfo[current_class];
-
- if(!pClassInfo->levelInfo)
- pClassInfo->levelInfo = new PlayerClassLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)];
-
- PlayerClassLevelInfo* pClassLevelInfo = &pClassInfo->levelInfo[current_level-1];
-
- pClassLevelInfo->basehealth = fields[2].GetUInt16();
- pClassLevelInfo->basemana = fields[3].GetUInt16();
-
- bar.step();
- ++count;
- }
- while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u level health/mana definitions", count );
- }
-
- // Fill gaps and check integrity
- for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
- {
- // skip non existed classes
- if(!sChrClassesStore.LookupEntry(class_))
- continue;
-
- PlayerClassInfo* pClassInfo = &playerClassInfo[class_];
-
- // fatal error if no level 1 data
- if(!pClassInfo->levelInfo || pClassInfo->levelInfo[0].basehealth == 0 )
- {
- sLog.outErrorDb("Class %i Level 1 does not have health/mana data!",class_);
- exit(1);
- }
-
- // fill level gaps
- for (uint32 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
- {
- if(pClassInfo->levelInfo[level].basehealth == 0)
- {
- sLog.outErrorDb("Class %i Level %i does not have health/mana data. Using stats data of level %i.",class_,level+1, level);
- pClassInfo->levelInfo[level] = pClassInfo->levelInfo[level-1];
- }
- }
- }
-
- // Loading levels data (class/race dependent)
- {
- // 0 1 2 3 4 5 6 7
- QueryResult *result = WorldDatabase.Query("SELECT race, class, level, str, agi, sta, inte, spi FROM player_levelstats");
-
- uint32 count = 0;
-
- if (!result)
- {
- barGoLink bar( 1 );
-
- sLog.outString();
- sLog.outString( ">> Loaded %u level stats definitions", count );
- sLog.outErrorDb( "Error loading `player_levelstats` table or empty table.");
- exit(1);
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- Field* fields = result->Fetch();
-
- uint32 current_race = fields[0].GetUInt32();
- if(current_race >= MAX_RACES)
- {
- sLog.outErrorDb("Wrong race %u in `player_levelstats` table, ignoring.",current_race);
- continue;
- }
-
- uint32 current_class = fields[1].GetUInt32();
- if(current_class >= MAX_CLASSES)
- {
- sLog.outErrorDb("Wrong class %u in `player_levelstats` table, ignoring.",current_class);
- continue;
- }
-
- uint32 current_level = fields[2].GetUInt32();
- if(current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
- {
- if(current_level > 255) // hardcoded level maximum
- sLog.outErrorDb("Wrong (> 255) level %u in `player_levelstats` table, ignoring.",current_level);
- else
- sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `player_levelstats` table, ignoring.",current_level);
- continue;
- }
-
- PlayerInfo* pInfo = &playerInfo[current_race][current_class];
-
- if(!pInfo->levelInfo)
- pInfo->levelInfo = new PlayerLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)];
-
- PlayerLevelInfo* pLevelInfo = &pInfo->levelInfo[current_level-1];
-
- for (int i = 0; i < MAX_STATS; i++)
- {
- pLevelInfo->stats[i] = fields[i+3].GetUInt8();
- }
-
- bar.step();
- ++count;
- }
- while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u level stats definitions", count );
- }
-
- // Fill gaps and check integrity
- for (int race = 0; race < MAX_RACES; ++race)
- {
- // skip non existed races
- if(!sChrRacesStore.LookupEntry(race))
- continue;
-
- for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
- {
- // skip non existed classes
- if(!sChrClassesStore.LookupEntry(class_))
- continue;
-
- PlayerInfo* pInfo = &playerInfo[race][class_];
-
- // skip non loaded combinations
- if(!pInfo->displayId_m || !pInfo->displayId_f)
- continue;
-
- // skip expansion races if not playing with expansion
- if (sWorld.getConfig(CONFIG_EXPANSION) < 1 && (race == RACE_BLOODELF || race == RACE_DRAENEI))
- continue;
-
- // skip expansion classes if not playing with expansion
- if (sWorld.getConfig(CONFIG_EXPANSION) < 2 && class_ == CLASS_DEATH_KNIGHT)
- continue;
-
- // fatal error if no level 1 data
- if(!pInfo->levelInfo || pInfo->levelInfo[0].stats[0] == 0 )
- {
- sLog.outErrorDb("Race %i Class %i Level 1 does not have stats data!",race,class_);
- exit(1);
- }
-
- // fill level gaps
- for (uint32 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
- {
- if(pInfo->levelInfo[level].stats[0] == 0)
- {
- sLog.outErrorDb("Race %i Class %i Level %i does not have stats data. Using stats data of level %i.",race,class_,level+1, level);
- pInfo->levelInfo[level] = pInfo->levelInfo[level-1];
- }
- }
- }
- }
-}
-
-void ObjectMgr::GetPlayerClassLevelInfo(uint32 class_, uint32 level, PlayerClassLevelInfo* info) const
-{
- if(level < 1 || class_ >= MAX_CLASSES)
- return;
-
- PlayerClassInfo const* pInfo = &playerClassInfo[class_];
-
- if(level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
- level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL);
-
- *info = pInfo->levelInfo[level-1];
-}
-
-void ObjectMgr::GetPlayerLevelInfo(uint32 race, uint32 class_, uint32 level, PlayerLevelInfo* info) const
-{
- if(level < 1 || race >= MAX_RACES || class_ >= MAX_CLASSES)
- return;
-
- PlayerInfo const* pInfo = &playerInfo[race][class_];
- if(pInfo->displayId_m==0 || pInfo->displayId_f==0)
- return;
-
- if(level <= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
- *info = pInfo->levelInfo[level-1];
- else
- BuildPlayerLevelInfo(race,class_,level,info);
-}
-
-void ObjectMgr::BuildPlayerLevelInfo(uint8 race, uint8 _class, uint8 level, PlayerLevelInfo* info) const
-{
- // base data (last known level)
- *info = playerInfo[race][_class].levelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)-1];
-
- for(int lvl = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)-1; lvl < level; ++lvl)
- {
- switch(_class)
- {
- case CLASS_WARRIOR:
- info->stats[STAT_STRENGTH] += (lvl > 23 ? 2: (lvl > 1 ? 1: 0));
- info->stats[STAT_STAMINA] += (lvl > 23 ? 2: (lvl > 1 ? 1: 0));
- info->stats[STAT_AGILITY] += (lvl > 36 ? 1: (lvl > 6 && (lvl%2) ? 1: 0));
- info->stats[STAT_INTELLECT] += (lvl > 9 && !(lvl%2) ? 1: 0);
- info->stats[STAT_SPIRIT] += (lvl > 9 && !(lvl%2) ? 1: 0);
- break;
- case CLASS_PALADIN:
- info->stats[STAT_STRENGTH] += (lvl > 3 ? 1: 0);
- info->stats[STAT_STAMINA] += (lvl > 33 ? 2: (lvl > 1 ? 1: 0));
- info->stats[STAT_AGILITY] += (lvl > 38 ? 1: (lvl > 7 && !(lvl%2) ? 1: 0));
- info->stats[STAT_INTELLECT] += (lvl > 6 && (lvl%2) ? 1: 0);
- info->stats[STAT_SPIRIT] += (lvl > 7 ? 1: 0);
- break;
- case CLASS_HUNTER:
- info->stats[STAT_STRENGTH] += (lvl > 4 ? 1: 0);
- info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0);
- info->stats[STAT_AGILITY] += (lvl > 33 ? 2: (lvl > 1 ? 1: 0));
- info->stats[STAT_INTELLECT] += (lvl > 8 && (lvl%2) ? 1: 0);
- info->stats[STAT_SPIRIT] += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0));
- break;
- case CLASS_ROGUE:
- info->stats[STAT_STRENGTH] += (lvl > 5 ? 1: 0);
- info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0);
- info->stats[STAT_AGILITY] += (lvl > 16 ? 2: (lvl > 1 ? 1: 0));
- info->stats[STAT_INTELLECT] += (lvl > 8 && !(lvl%2) ? 1: 0);
- info->stats[STAT_SPIRIT] += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0));
- break;
- case CLASS_PRIEST:
- info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0);
- info->stats[STAT_STAMINA] += (lvl > 5 ? 1: 0);
- info->stats[STAT_AGILITY] += (lvl > 38 ? 1: (lvl > 8 && (lvl%2) ? 1: 0));
- info->stats[STAT_INTELLECT] += (lvl > 22 ? 2: (lvl > 1 ? 1: 0));
- info->stats[STAT_SPIRIT] += (lvl > 3 ? 1: 0);
- break;
- case CLASS_SHAMAN:
- info->stats[STAT_STRENGTH] += (lvl > 34 ? 1: (lvl > 6 && (lvl%2) ? 1: 0));
- info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0);
- info->stats[STAT_AGILITY] += (lvl > 7 && !(lvl%2) ? 1: 0);
- info->stats[STAT_INTELLECT] += (lvl > 5 ? 1: 0);
- info->stats[STAT_SPIRIT] += (lvl > 4 ? 1: 0);
- break;
- case CLASS_MAGE:
- info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0);
- info->stats[STAT_STAMINA] += (lvl > 5 ? 1: 0);
- info->stats[STAT_AGILITY] += (lvl > 9 && !(lvl%2) ? 1: 0);
- info->stats[STAT_INTELLECT] += (lvl > 24 ? 2: (lvl > 1 ? 1: 0));
- info->stats[STAT_SPIRIT] += (lvl > 33 ? 2: (lvl > 2 ? 1: 0));
- break;
- case CLASS_WARLOCK:
- info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0);
- info->stats[STAT_STAMINA] += (lvl > 38 ? 2: (lvl > 3 ? 1: 0));
- info->stats[STAT_AGILITY] += (lvl > 9 && !(lvl%2) ? 1: 0);
- info->stats[STAT_INTELLECT] += (lvl > 33 ? 2: (lvl > 2 ? 1: 0));
- info->stats[STAT_SPIRIT] += (lvl > 38 ? 2: (lvl > 3 ? 1: 0));
- break;
- case CLASS_DRUID:
- info->stats[STAT_STRENGTH] += (lvl > 38 ? 2: (lvl > 6 && (lvl%2) ? 1: 0));
- info->stats[STAT_STAMINA] += (lvl > 32 ? 2: (lvl > 4 ? 1: 0));
- info->stats[STAT_AGILITY] += (lvl > 38 ? 2: (lvl > 8 && (lvl%2) ? 1: 0));
- info->stats[STAT_INTELLECT] += (lvl > 38 ? 3: (lvl > 4 ? 1: 0));
- info->stats[STAT_SPIRIT] += (lvl > 38 ? 3: (lvl > 5 ? 1: 0));
- }
- }
-}
-
-void ObjectMgr::LoadGuilds()
-{
- Guild *newguild;
- uint32 count = 0;
-
- QueryResult *result = CharacterDatabase.Query( "SELECT guildid FROM guild" );
-
- if( !result )
- {
-
- barGoLink bar( 1 );
-
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded %u guild definitions", count );
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- Field *fields = result->Fetch();
-
- bar.step();
- ++count;
-
- newguild = new Guild;
- if(!newguild->LoadGuildFromDB(fields[0].GetUInt32()))
- {
- newguild->Disband();
- delete newguild;
- continue;
- }
- AddGuild(newguild);
-
- }while( result->NextRow() );
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u guild definitions", count );
-}
-
-void ObjectMgr::LoadArenaTeams()
-{
- uint32 count = 0;
-
- QueryResult *result = CharacterDatabase.Query( "SELECT arenateamid FROM arena_team" );
-
- if( !result )
- {
-
- barGoLink bar( 1 );
-
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded %u arenateam definitions", count );
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- Field *fields = result->Fetch();
-
- bar.step();
- ++count;
-
- ArenaTeam *newarenateam = new ArenaTeam;
- if(!newarenateam->LoadArenaTeamFromDB(fields[0].GetUInt32()))
- {
- delete newarenateam;
- continue;
- }
- AddArenaTeam(newarenateam);
- }while( result->NextRow() );
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u arenateam definitions", count );
-}
-
-void ObjectMgr::LoadGroups()
-{
- // -- loading groups --
- Group *group = NULL;
- uint64 leaderGuid = 0;
- uint32 count = 0;
- // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- QueryResult *result = CharacterDatabase.Query("SELECT mainTank, mainAssistant, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, isRaid, difficulty, leaderGuid FROM groups");
-
- if( !result )
- {
- barGoLink bar( 1 );
-
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded %u group definitions", count );
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- bar.step();
- Field *fields = result->Fetch();
- ++count;
- leaderGuid = MAKE_NEW_GUID(fields[15].GetUInt32(),0,HIGHGUID_PLAYER);
-
- group = new Group;
- if(!group->LoadGroupFromDB(leaderGuid, result, false))
- {
- group->Disband();
- delete group;
- continue;
- }
- AddGroup(group);
- }while( result->NextRow() );
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u group definitions", count );
-
- // -- loading members --
- count = 0;
- group = NULL;
- leaderGuid = 0;
- // 0 1 2 3
- result = CharacterDatabase.Query("SELECT memberGuid, assistant, subgroup, leaderGuid FROM group_member ORDER BY leaderGuid");
- if(!result)
- {
- barGoLink bar( 1 );
- bar.step();
- }
- else
- {
- barGoLink bar( result->GetRowCount() );
- do
- {
- bar.step();
- Field *fields = result->Fetch();
- count++;
- leaderGuid = MAKE_NEW_GUID(fields[3].GetUInt32(), 0, HIGHGUID_PLAYER);
- if(!group || group->GetLeaderGUID() != leaderGuid)
- {
- group = GetGroupByLeader(leaderGuid);
- if(!group)
- {
- sLog.outErrorDb("Incorrect entry in group_member table : no group with leader %d for member %d!", fields[3].GetUInt32(), fields[0].GetUInt32());
- CharacterDatabase.PExecute("DELETE FROM group_member WHERE memberGuid = '%d'", fields[0].GetUInt32());
- continue;
- }
- }
-
- if(!group->LoadMemberFromDB(fields[0].GetUInt32(), fields[2].GetUInt8(), fields[1].GetBool()))
- {
- sLog.outErrorDb("Incorrect entry in group_member table : member %d cannot be added to player %d's group!", fields[0].GetUInt32(), fields[3].GetUInt32());
- CharacterDatabase.PExecute("DELETE FROM group_member WHERE memberGuid = '%d'", fields[0].GetUInt32());
- }
- }while( result->NextRow() );
- delete result;
- }
-
- // clean groups
- // TODO: maybe delete from the DB before loading in this case
- for(GroupSet::iterator itr = mGroupSet.begin(); itr != mGroupSet.end();)
- {
- if((*itr)->GetMembersCount() < 2)
- {
- (*itr)->Disband();
- delete *itr;
- mGroupSet.erase(itr++);
- }
- else
- ++itr;
- }
-
- // -- loading instances --
- count = 0;
- group = NULL;
- leaderGuid = 0;
- result = CharacterDatabase.Query(
- // 0 1 2 3 4 5
- "SELECT leaderGuid, map, instance, permanent, difficulty, resettime, "
- // 6
- "(SELECT COUNT(*) FROM character_instance WHERE guid = leaderGuid AND instance = group_instance.instance AND permanent = 1 LIMIT 1) "
- "FROM group_instance LEFT JOIN instance ON instance = id ORDER BY leaderGuid"
- );
-
- if(!result)
- {
- barGoLink bar( 1 );
- bar.step();
- }
- else
- {
- barGoLink bar( result->GetRowCount() );
- do
- {
- bar.step();
- Field *fields = result->Fetch();
- count++;
- leaderGuid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
- if(!group || group->GetLeaderGUID() != leaderGuid)
- {
- group = GetGroupByLeader(leaderGuid);
- if(!group)
- {
- sLog.outErrorDb("Incorrect entry in group_instance table : no group with leader %d", fields[0].GetUInt32());
- continue;
- }
- }
-
- InstanceSave *save = sInstanceSaveManager.AddInstanceSave(fields[1].GetUInt32(), fields[2].GetUInt32(), fields[4].GetUInt8(), (time_t)fields[5].GetUInt64(), (fields[6].GetUInt32() == 0), true);
- group->BindToInstance(save, fields[3].GetBool(), true);
- }while( result->NextRow() );
- delete result;
- }
-
- sLog.outString();
- sLog.outString( ">> Loaded %u group-instance binds total", count );
-
- sLog.outString();
- sLog.outString( ">> Loaded %u group members total", count );
-}
-
-void ObjectMgr::LoadQuests()
-{
- // For reload case
- for(QuestMap::const_iterator itr=mQuestTemplates.begin(); itr != mQuestTemplates.end(); ++itr)
- delete itr->second;
- mQuestTemplates.clear();
-
- mExclusiveQuestGroups.clear();
-
- // 0 1 2 3 4 5 6 7 8
- QueryResult *result = WorldDatabase.Query("SELECT entry, Method, ZoneOrSort, SkillOrClass, MinLevel, QuestLevel, Type, RequiredRaces, RequiredSkillValue,"
- // 9 10 11 12 13 14 15 16
- "RepObjectiveFaction, RepObjectiveValue, RequiredMinRepFaction, RequiredMinRepValue, RequiredMaxRepFaction, RequiredMaxRepValue, SuggestedPlayers, LimitTime,"
- // 17 18 19 20 21 22 23 24 25 26
- "QuestFlags, SpecialFlags, CharTitleId, PrevQuestId, NextQuestId, ExclusiveGroup, NextQuestInChain, SrcItemId, SrcItemCount, SrcSpell,"
- // 27 28 29 30 31 32 33 34 35 36
- "Title, Details, Objectives, OfferRewardText, RequestItemsText, EndText, ObjectiveText1, ObjectiveText2, ObjectiveText3, ObjectiveText4,"
- // 37 38 39 40 41 42 43 44
- "ReqItemId1, ReqItemId2, ReqItemId3, ReqItemId4, ReqItemCount1, ReqItemCount2, ReqItemCount3, ReqItemCount4,"
- // 45 46 47 48 49 50 51 52 53 54 54 55
- "ReqSourceId1, ReqSourceId2, ReqSourceId3, ReqSourceId4, ReqSourceCount1, ReqSourceCount2, ReqSourceCount3, ReqSourceCount4, ReqSourceRef1, ReqSourceRef2, ReqSourceRef3, ReqSourceRef4,"
- // 57 58 59 60 61 62 63 64
- "ReqCreatureOrGOId1, ReqCreatureOrGOId2, ReqCreatureOrGOId3, ReqCreatureOrGOId4, ReqCreatureOrGOCount1, ReqCreatureOrGOCount2, ReqCreatureOrGOCount3, ReqCreatureOrGOCount4,"
- // 65 66 67 68
- "ReqSpellCast1, ReqSpellCast2, ReqSpellCast3, ReqSpellCast4,"
- // 69 70 71 72 73 74
- "RewChoiceItemId1, RewChoiceItemId2, RewChoiceItemId3, RewChoiceItemId4, RewChoiceItemId5, RewChoiceItemId6,"
- // 75 76 77 78 79 80
- "RewChoiceItemCount1, RewChoiceItemCount2, RewChoiceItemCount3, RewChoiceItemCount4, RewChoiceItemCount5, RewChoiceItemCount6,"
- // 81 82 83 84 85 86 87 88
- "RewItemId1, RewItemId2, RewItemId3, RewItemId4, RewItemCount1, RewItemCount2, RewItemCount3, RewItemCount4,"
- // 89 90 91 92 93 94 95 96 97 98
- "RewRepFaction1, RewRepFaction2, RewRepFaction3, RewRepFaction4, RewRepFaction5, RewRepValue1, RewRepValue2, RewRepValue3, RewRepValue4, RewRepValue5,"
- // 99 100 101 102 103 104 105 106 107 108 109
- "RewHonorableKills, RewOrReqMoney, RewMoneyMaxLevel, RewSpell, RewSpellCast, RewMailTemplateId, RewMailDelaySecs, PointMapId, PointX, PointY, PointOpt,"
- // 110 111 112 113 114 115 116 117 118 119
- "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4,IncompleteEmote, CompleteEmote, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4,"
- // 120 121
- "StartScript, CompleteScript"
- " FROM quest_template");
- if(result == NULL)
- {
- barGoLink bar( 1 );
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded 0 quests definitions" );
- sLog.outErrorDb("`quest_template` table is empty!");
- return;
- }
-
- // create multimap previous quest for each existed quest
- // some quests can have many previous maps set by NextQuestId in previous quest
- // for example set of race quests can lead to single not race specific quest
- barGoLink bar( result->GetRowCount() );
- do
- {
- bar.step();
- Field *fields = result->Fetch();
-
- Quest * newQuest = new Quest(fields);
- mQuestTemplates[newQuest->GetQuestId()] = newQuest;
- } while( result->NextRow() );
-
- delete result;
-
- // Post processing
- for (QuestMap::iterator iter = mQuestTemplates.begin(); iter != mQuestTemplates.end(); iter++)
- {
- Quest * qinfo = iter->second;
-
- // additional quest integrity checks (GO, creature_template and item_template must be loaded already)
-
- if( qinfo->GetQuestMethod() >= 3 )
- {
- sLog.outErrorDb("Quest %u has `Method` = %u, expected values are 0, 1 or 2.",qinfo->GetQuestId(),qinfo->GetQuestMethod());
- }
-
- if (qinfo->QuestFlags & ~QUEST_TRINITY_FLAGS_DB_ALLOWED)
- {
- sLog.outErrorDb("Quest %u has `SpecialFlags` = %u > max allowed value. Correct `SpecialFlags` to value <= %u",
- qinfo->GetQuestId(),qinfo->QuestFlags,QUEST_TRINITY_FLAGS_DB_ALLOWED >> 16);
- qinfo->QuestFlags &= QUEST_TRINITY_FLAGS_DB_ALLOWED;
- }
-
- if(qinfo->QuestFlags & QUEST_FLAGS_DAILY)
- {
- if(!(qinfo->QuestFlags & QUEST_TRINITY_FLAGS_REPEATABLE))
- {
- sLog.outErrorDb("Daily Quest %u not marked as repeatable in `SpecialFlags`, added.",qinfo->GetQuestId());
- qinfo->QuestFlags |= QUEST_TRINITY_FLAGS_REPEATABLE;
- }
- }
-
- if(qinfo->QuestFlags & QUEST_FLAGS_AUTO_REWARDED)
- {
- // at auto-reward can be rewarded only RewChoiceItemId[0]
- for(int j = 1; j < QUEST_REWARD_CHOICES_COUNT; ++j )
- {
- if(uint32 id = qinfo->RewChoiceItemId[j])
- {
- sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but item from `RewChoiceItemId%d` can't be rewarded with quest flag QUEST_FLAGS_AUTO_REWARDED.",
- qinfo->GetQuestId(),j+1,id,j+1);
- // no changes, quest ignore this data
- }
- }
- }
-
- // client quest log visual (area case)
- if( qinfo->ZoneOrSort > 0 )
- {
- if(!GetAreaEntryByAreaID(qinfo->ZoneOrSort))
- {
- sLog.outErrorDb("Quest %u has `ZoneOrSort` = %u (zone case) but zone with this id does not exist.",
- qinfo->GetQuestId(),qinfo->ZoneOrSort);
- // no changes, quest not dependent from this value but can have problems at client
- }
- }
- // client quest log visual (sort case)
- if( qinfo->ZoneOrSort < 0 )
- {
- QuestSortEntry const* qSort = sQuestSortStore.LookupEntry(-int32(qinfo->ZoneOrSort));
- if( !qSort )
- {
- sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (sort case) but quest sort with this id does not exist.",
- qinfo->GetQuestId(),qinfo->ZoneOrSort);
- // no changes, quest not dependent from this value but can have problems at client (note some may be 0, we must allow this so no check)
- }
- //check SkillOrClass value (class case).
- if( ClassByQuestSort(-int32(qinfo->ZoneOrSort)) )
- {
- // SkillOrClass should not have class case when class case already set in ZoneOrSort.
- if(qinfo->SkillOrClass < 0)
- {
- sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (class sort case) and `SkillOrClass` = %i (class case), redundant.",
- qinfo->GetQuestId(),qinfo->ZoneOrSort,qinfo->SkillOrClass);
- }
- }
- //check for proper SkillOrClass value (skill case)
- if(int32 skill_id = SkillByQuestSort(-int32(qinfo->ZoneOrSort)))
- {
- // skill is positive value in SkillOrClass
- if(qinfo->SkillOrClass != skill_id )
- {
- sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (skill sort case) but `SkillOrClass` does not have a corresponding value (%i).",
- qinfo->GetQuestId(),qinfo->ZoneOrSort,skill_id);
- //override, and force proper value here?
- }
- }
- }
-
- // SkillOrClass (class case)
- if( qinfo->SkillOrClass < 0 )
- {
- if( !sChrClassesStore.LookupEntry(-int32(qinfo->SkillOrClass)) )
- {
- sLog.outErrorDb("Quest %u has `SkillOrClass` = %i (class case) but class (%i) does not exist",
- qinfo->GetQuestId(),qinfo->SkillOrClass,-qinfo->SkillOrClass);
- }
- }
- // SkillOrClass (skill case)
- if( qinfo->SkillOrClass > 0 )
- {
- if( !sSkillLineStore.LookupEntry(qinfo->SkillOrClass) )
- {
- sLog.outErrorDb("Quest %u has `SkillOrClass` = %u (skill case) but skill (%i) does not exist",
- qinfo->GetQuestId(),qinfo->SkillOrClass,qinfo->SkillOrClass);
- }
- }
-
- if( qinfo->RequiredSkillValue )
- {
- if( qinfo->RequiredSkillValue > sWorld.GetConfigMaxSkillValue() )
- {
- sLog.outErrorDb("Quest %u has `RequiredSkillValue` = %u but max possible skill is %u, quest can't be done.",
- qinfo->GetQuestId(),qinfo->RequiredSkillValue,sWorld.GetConfigMaxSkillValue());
- // no changes, quest can't be done for this requirement
- }
-
- if( qinfo->SkillOrClass <= 0 )
- {
- sLog.outErrorDb("Quest %u has `RequiredSkillValue` = %u but `SkillOrClass` = %i (class case), value ignored.",
- qinfo->GetQuestId(),qinfo->RequiredSkillValue,qinfo->SkillOrClass);
- // no changes, quest can't be done for this requirement (fail at wrong skill id)
- }
- }
- // else Skill quests can have 0 skill level, this is ok
-
- if(qinfo->RepObjectiveFaction && !sFactionStore.LookupEntry(qinfo->RepObjectiveFaction))
- {
- sLog.outErrorDb("Quest %u has `RepObjectiveFaction` = %u but faction template %u does not exist, quest can't be done.",
- qinfo->GetQuestId(),qinfo->RepObjectiveFaction,qinfo->RepObjectiveFaction);
- // no changes, quest can't be done for this requirement
- }
-
- if(qinfo->RequiredMinRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMinRepFaction))
- {
- sLog.outErrorDb("Quest %u has `RequiredMinRepFaction` = %u but faction template %u does not exist, quest can't be done.",
- qinfo->GetQuestId(),qinfo->RequiredMinRepFaction,qinfo->RequiredMinRepFaction);
- // no changes, quest can't be done for this requirement
- }
-
- if(qinfo->RequiredMaxRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMaxRepFaction))
- {
- sLog.outErrorDb("Quest %u has `RequiredMaxRepFaction` = %u but faction template %u does not exist, quest can't be done.",
- qinfo->GetQuestId(),qinfo->RequiredMaxRepFaction,qinfo->RequiredMaxRepFaction);
- // no changes, quest can't be done for this requirement
- }
-
- if(qinfo->RequiredMinRepValue && qinfo->RequiredMinRepValue > Player::Reputation_Cap)
- {
- sLog.outErrorDb("Quest %u has `RequiredMinRepValue` = %d but max reputation is %u, quest can't be done.",
- qinfo->GetQuestId(),qinfo->RequiredMinRepValue,Player::Reputation_Cap);
- // no changes, quest can't be done for this requirement
- }
-
- if(qinfo->RequiredMinRepValue && qinfo->RequiredMaxRepValue && qinfo->RequiredMaxRepValue <= qinfo->RequiredMinRepValue)
- {
- sLog.outErrorDb("Quest %u has `RequiredMaxRepValue` = %d and `RequiredMinRepValue` = %d, quest can't be done.",
- qinfo->GetQuestId(),qinfo->RequiredMaxRepValue,qinfo->RequiredMinRepValue);
- // no changes, quest can't be done for this requirement
- }
-
- if(!qinfo->RepObjectiveFaction && qinfo->RepObjectiveValue > 0 )
- {
- sLog.outErrorDb("Quest %u has `RepObjectiveValue` = %d but `RepObjectiveFaction` is 0, value has no effect",
- qinfo->GetQuestId(),qinfo->RepObjectiveValue);
- // warning
- }
-
- if(!qinfo->RequiredMinRepFaction && qinfo->RequiredMinRepValue > 0 )
- {
- sLog.outErrorDb("Quest %u has `RequiredMinRepValue` = %d but `RequiredMinRepFaction` is 0, value has no effect",
- qinfo->GetQuestId(),qinfo->RequiredMinRepValue);
- // warning
- }
-
- if(!qinfo->RequiredMaxRepFaction && qinfo->RequiredMaxRepValue > 0 )
- {
- sLog.outErrorDb("Quest %u has `RequiredMaxRepValue` = %d but `RequiredMaxRepFaction` is 0, value has no effect",
- qinfo->GetQuestId(),qinfo->RequiredMaxRepValue);
- // warning
- }
-
- if(qinfo->CharTitleId && !sCharTitlesStore.LookupEntry(qinfo->CharTitleId))
- {
- sLog.outErrorDb("Quest %u has `CharTitleId` = %u but CharTitle Id %u does not exist, quest can't be rewarded with title.",
- qinfo->GetQuestId(),qinfo->GetCharTitleId(),qinfo->GetCharTitleId());
- qinfo->CharTitleId = 0;
- // quest can't reward this title
- }
-
- if(qinfo->SrcItemId)
- {
- if(!sItemStorage.LookupEntry<ItemPrototype>(qinfo->SrcItemId))
- {
- sLog.outErrorDb("Quest %u has `SrcItemId` = %u but item with entry %u does not exist, quest can't be done.",
- qinfo->GetQuestId(),qinfo->SrcItemId,qinfo->SrcItemId);
- qinfo->SrcItemId = 0; // quest can't be done for this requirement
- }
- else if(qinfo->SrcItemCount==0)
- {
- sLog.outErrorDb("Quest %u has `SrcItemId` = %u but `SrcItemCount` = 0, set to 1 but need fix in DB.",
- qinfo->GetQuestId(),qinfo->SrcItemId);
- qinfo->SrcItemCount = 1; // update to 1 for allow quest work for backward compatibility with DB
- }
- }
- else if(qinfo->SrcItemCount>0)
- {
- sLog.outErrorDb("Quest %u has `SrcItemId` = 0 but `SrcItemCount` = %u, useless value.",
- qinfo->GetQuestId(),qinfo->SrcItemCount);
- qinfo->SrcItemCount=0; // no quest work changes in fact
- }
-
- if(qinfo->SrcSpell)
- {
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->SrcSpell);
- if(!spellInfo)
- {
- sLog.outErrorDb("Quest %u has `SrcSpell` = %u but spell %u doesn't exist, quest can't be done.",
- qinfo->GetQuestId(),qinfo->SrcSpell,qinfo->SrcSpell);
- qinfo->SrcSpell = 0; // quest can't be done for this requirement
- }
- else if(!SpellMgr::IsSpellValid(spellInfo))
- {
- sLog.outErrorDb("Quest %u has `SrcSpell` = %u but spell %u is broken, quest can't be done.",
- qinfo->GetQuestId(),qinfo->SrcSpell,qinfo->SrcSpell);
- qinfo->SrcSpell = 0; // quest can't be done for this requirement
- }
- }
-
- for(int j = 0; j < QUEST_OBJECTIVES_COUNT; ++j )
- {
- uint32 id = qinfo->ReqItemId[j];
- if(id)
- {
- if(qinfo->ReqItemCount[j]==0)
- {
- sLog.outErrorDb("Quest %u has `ReqItemId%d` = %u but `ReqItemCount%d` = 0, quest can't be done.",
- qinfo->GetQuestId(),j+1,id,j+1);
- // no changes, quest can't be done for this requirement
- }
-
- qinfo->SetFlag(QUEST_TRINITY_FLAGS_DELIVER);
-
- if(!sItemStorage.LookupEntry<ItemPrototype>(id))
- {
- sLog.outErrorDb("Quest %u has `ReqItemId%d` = %u but item with entry %u does not exist, quest can't be done.",
- qinfo->GetQuestId(),j+1,id,id);
- qinfo->ReqItemCount[j] = 0; // prevent incorrect work of quest
- }
- }
- else if(qinfo->ReqItemCount[j]>0)
- {
- sLog.outErrorDb("Quest %u has `ReqItemId%d` = 0 but `ReqItemCount%d` = %u, quest can't be done.",
- qinfo->GetQuestId(),j+1,j+1,qinfo->ReqItemCount[j]);
- qinfo->ReqItemCount[j] = 0; // prevent incorrect work of quest
- }
- }
-
- for(int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j )
- {
- uint32 id = qinfo->ReqSourceId[j];
- if(id)
- {
- if(!sItemStorage.LookupEntry<ItemPrototype>(id))
- {
- sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but item with entry %u does not exist, quest can't be done.",
- qinfo->GetQuestId(),j+1,id,id);
- // no changes, quest can't be done for this requirement
- }
-
- if(!qinfo->ReqSourceCount[j])
- {
- sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but `ReqSourceCount%d` = 0, quest can't be done.",
- qinfo->GetQuestId(),j+1,id,j+1);
- qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest
- }
-
- if(!qinfo->ReqSourceRef[j])
- {
- sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but `ReqSourceRef%d` = 0, quest can't be done.",
- qinfo->GetQuestId(),j+1,id,j+1);
- qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest
- }
- }
- else
- {
- if(qinfo->ReqSourceCount[j]>0)
- {
- sLog.outErrorDb("Quest %u has `ReqSourceId%d` = 0 but `ReqSourceCount%d` = %u.",
- qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceCount[j]);
- // no changes, quest ignore this data
- }
-
- if(qinfo->ReqSourceRef[j]>0)
- {
- sLog.outErrorDb("Quest %u has `ReqSourceId%d` = 0 but `ReqSourceRef%d` = %u.",
- qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceRef[j]);
- // no changes, quest ignore this data
- }
- }
- }
-
- for(int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j )
- {
- uint32 ref = qinfo->ReqSourceRef[j];
- if(ref)
- {
- if(ref > QUEST_OBJECTIVES_COUNT)
- {
- sLog.outErrorDb("Quest %u has `ReqSourceRef%d` = %u but max value in `ReqSourceRef%d` is %u, quest can't be done.",
- qinfo->GetQuestId(),j+1,ref,j+1,QUEST_OBJECTIVES_COUNT);
- // no changes, quest can't be done for this requirement
- }
- else
- if(!qinfo->ReqItemId[ref-1] && !qinfo->ReqSpell[ref-1])
- {
- sLog.outErrorDb("Quest %u has `ReqSourceRef%d` = %u but `ReqItemId%u` = 0 and `ReqSpellCast%u` = 0, quest can't be done.",
- qinfo->GetQuestId(),j+1,ref,ref,ref);
- // no changes, quest can't be done for this requirement
- }
- else if(qinfo->ReqItemId[ref-1] && qinfo->ReqSpell[ref-1])
- {
- sLog.outErrorDb("Quest %u has `ReqItemId%u` = %u and `ReqSpellCast%u` = %u, quest can't have both fields <> 0, then can't be done.",
- qinfo->GetQuestId(),ref,qinfo->ReqItemId[ref-1],ref,qinfo->ReqSpell[ref-1]);
- // no changes, quest can't be done for this requirement
- qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest
- }
- }
- }
-
- for(int j = 0; j < QUEST_OBJECTIVES_COUNT; ++j )
- {
- uint32 id = qinfo->ReqSpell[j];
- if(id)
- {
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(id);
- if(!spellInfo)
- {
- sLog.outErrorDb("Quest %u has `ReqSpellCast%d` = %u but spell %u does not exist, quest can't be done.",
- qinfo->GetQuestId(),j+1,id,id);
- // no changes, quest can't be done for this requirement
- }
-
- if(!qinfo->ReqCreatureOrGOId[j])
- {
- bool found = false;
- for(int k = 0; k < 3; ++k)
- {
- if( spellInfo->Effect[k]==SPELL_EFFECT_QUEST_COMPLETE && uint32(spellInfo->EffectMiscValue[k])==qinfo->QuestId ||
- spellInfo->Effect[k]==SPELL_EFFECT_SEND_EVENT)
- {
- found = true;
- break;
- }
- }
-
- if(found)
- {
- if(!qinfo->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
- {
- sLog.outErrorDb("Spell (id: %u) have SPELL_EFFECT_QUEST_COMPLETE or SPELL_EFFECT_SEND_EVENT for quest %u and ReqCreatureOrGOId%d = 0, but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT. Quest flags or ReqCreatureOrGOId%d must be fixed, quest modified to enable objective.",spellInfo->Id,qinfo->QuestId,j+1,j+1);
-
- // this will prevent quest completing without objective
- const_cast<Quest*>(qinfo)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT);
- }
- }
- else
- {
- sLog.outErrorDb("Quest %u has `ReqSpellCast%d` = %u and ReqCreatureOrGOId%d = 0 but spell %u does not have SPELL_EFFECT_QUEST_COMPLETE or SPELL_EFFECT_SEND_EVENT effect for this quest, quest can't be done.",
- qinfo->GetQuestId(),j+1,id,j+1,id);
- // no changes, quest can't be done for this requirement
- }
- }
- }
- }
-
- for(int j = 0; j < QUEST_OBJECTIVES_COUNT; ++j )
- {
- int32 id = qinfo->ReqCreatureOrGOId[j];
- if(id < 0 && !sGOStorage.LookupEntry<GameObjectInfo>(-id))
- {
- sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %i but gameobject %u does not exist, quest can't be done.",
- qinfo->GetQuestId(),j+1,id,uint32(-id));
- qinfo->ReqCreatureOrGOId[j] = 0; // quest can't be done for this requirement
- }
-
- if(id > 0 && !sCreatureStorage.LookupEntry<CreatureInfo>(id))
- {
- sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %i but creature with entry %u does not exist, quest can't be done.",
- qinfo->GetQuestId(),j+1,id,uint32(id));
- qinfo->ReqCreatureOrGOId[j] = 0; // quest can't be done for this requirement
- }
-
- if(id)
- {
- // In fact SpeakTo and Kill are quite same: either you can speak to mob:SpeakTo or you can't:Kill/Cast
-
- qinfo->SetFlag(QUEST_TRINITY_FLAGS_KILL_OR_CAST | QUEST_TRINITY_FLAGS_SPEAKTO);
-
- if(!qinfo->ReqCreatureOrGOCount[j])
- {
- sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %u but `ReqCreatureOrGOCount%d` = 0, quest can't be done.",
- qinfo->GetQuestId(),j+1,id,j+1);
- // no changes, quest can be incorrectly done, but we already report this
- }
- }
- else if(qinfo->ReqCreatureOrGOCount[j]>0)
- {
- sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = 0 but `ReqCreatureOrGOCount%d` = %u.",
- qinfo->GetQuestId(),j+1,j+1,qinfo->ReqCreatureOrGOCount[j]);
- // no changes, quest ignore this data
- }
- }
-
- for(int j = 0; j < QUEST_REWARD_CHOICES_COUNT; ++j )
- {
- uint32 id = qinfo->RewChoiceItemId[j];
- if(id)
- {
- if(!sItemStorage.LookupEntry<ItemPrototype>(id))
- {
- sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but item with entry %u does not exist, quest will not reward this item.",
- qinfo->GetQuestId(),j+1,id,id);
- qinfo->RewChoiceItemId[j] = 0; // no changes, quest will not reward this
- }
-
- if(!qinfo->RewChoiceItemCount[j])
- {
- sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but `RewChoiceItemCount%d` = 0, quest can't be done.",
- qinfo->GetQuestId(),j+1,id,j+1);
- // no changes, quest can't be done
- }
- }
- else if(qinfo->RewChoiceItemCount[j]>0)
- {
- sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = 0 but `RewChoiceItemCount%d` = %u.",
- qinfo->GetQuestId(),j+1,j+1,qinfo->RewChoiceItemCount[j]);
- // no changes, quest ignore this data
- }
- }
-
- for(int j = 0; j < QUEST_REWARDS_COUNT; ++j )
- {
- uint32 id = qinfo->RewItemId[j];
- if(id)
- {
- if(!sItemStorage.LookupEntry<ItemPrototype>(id))
- {
- sLog.outErrorDb("Quest %u has `RewItemId%d` = %u but item with entry %u does not exist, quest will not reward this item.",
- qinfo->GetQuestId(),j+1,id,id);
- qinfo->RewItemId[j] = 0; // no changes, quest will not reward this item
- }
-
- if(!qinfo->RewItemCount[j])
- {
- sLog.outErrorDb("Quest %u has `RewItemId%d` = %u but `RewItemCount%d` = 0, quest will not reward this item.",
- qinfo->GetQuestId(),j+1,id,j+1);
- // no changes
- }
- }
- else if(qinfo->RewItemCount[j]>0)
- {
- sLog.outErrorDb("Quest %u has `RewItemId%d` = 0 but `RewItemCount%d` = %u.",
- qinfo->GetQuestId(),j+1,j+1,qinfo->RewItemCount[j]);
- // no changes, quest ignore this data
- }
- }
-
- for(int j = 0; j < QUEST_REPUTATIONS_COUNT; ++j)
- {
- if(qinfo->RewRepFaction[j])
- {
- if(!qinfo->RewRepValue[j])
- {
- sLog.outErrorDb("Quest %u has `RewRepFaction%d` = %u but `RewRepValue%d` = 0, quest will not reward this reputation.",
- qinfo->GetQuestId(),j+1,qinfo->RewRepValue[j],j+1);
- // no changes
- }
-
- if(!sFactionStore.LookupEntry(qinfo->RewRepFaction[j]))
- {
- sLog.outErrorDb("Quest %u has `RewRepFaction%d` = %u but raw faction (faction.dbc) %u does not exist, quest will not reward reputation for this faction.",
- qinfo->GetQuestId(),j+1,qinfo->RewRepFaction[j] ,qinfo->RewRepFaction[j] );
- qinfo->RewRepFaction[j] = 0; // quest will not reward this
- }
- }
- else if(qinfo->RewRepValue[j]!=0)
- {
- sLog.outErrorDb("Quest %u has `RewRepFaction%d` = 0 but `RewRepValue%d` = %u.",
- qinfo->GetQuestId(),j+1,j+1,qinfo->RewRepValue[j]);
- // no changes, quest ignore this data
- }
- }
-
- if(qinfo->RewSpell)
- {
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->RewSpell);
-
- if(!spellInfo)
- {
- sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u does not exist, spell removed as display reward.",
- qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell);
- qinfo->RewSpell = 0; // no spell reward will display for this quest
- }
-
- else if(!SpellMgr::IsSpellValid(spellInfo))
- {
- sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is broken, quest can't be done.",
- qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell);
- qinfo->RewSpell = 0; // no spell reward will display for this quest
- }
-
- }
-
- if(qinfo->RewSpellCast)
- {
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->RewSpellCast);
-
- if(!spellInfo)
- {
- sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u does not exist, quest will not have a spell reward.",
- qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast);
- qinfo->RewSpellCast = 0; // no spell will be casted on player
- }
-
- else if(!SpellMgr::IsSpellValid(spellInfo))
- {
- sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u is broken, quest can't be done.",
- qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast);
- qinfo->RewSpellCast = 0; // no spell will be casted on player
- }
-
- }
-
- if(qinfo->RewMailTemplateId)
- {
- if(!sMailTemplateStore.LookupEntry(qinfo->RewMailTemplateId))
- {
- sLog.outErrorDb("Quest %u has `RewMailTemplateId` = %u but mail template %u does not exist, quest will not have a mail reward.",
- qinfo->GetQuestId(),qinfo->RewMailTemplateId,qinfo->RewMailTemplateId);
- qinfo->RewMailTemplateId = 0; // no mail will send to player
- qinfo->RewMailDelaySecs = 0; // no mail will send to player
- }
- }
-
- if(qinfo->NextQuestInChain)
- {
- if(mQuestTemplates.find(qinfo->NextQuestInChain) == mQuestTemplates.end())
- {
- sLog.outErrorDb("Quest %u has `NextQuestInChain` = %u but quest %u does not exist, quest chain will not work.",
- qinfo->GetQuestId(),qinfo->NextQuestInChain ,qinfo->NextQuestInChain );
- qinfo->NextQuestInChain = 0;
- }
- else
- mQuestTemplates[qinfo->NextQuestInChain]->prevChainQuests.push_back(qinfo->GetQuestId());
- }
-
- // fill additional data stores
- if(qinfo->PrevQuestId)
- {
- if (mQuestTemplates.find(abs(qinfo->GetPrevQuestId())) == mQuestTemplates.end())
- {
- sLog.outErrorDb("Quest %d has PrevQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetPrevQuestId());
- }
- else
- {
- qinfo->prevQuests.push_back(qinfo->PrevQuestId);
- }
- }
-
- if(qinfo->NextQuestId)
- {
- if (mQuestTemplates.find(abs(qinfo->GetNextQuestId())) == mQuestTemplates.end())
- {
- sLog.outErrorDb("Quest %d has NextQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetNextQuestId());
- }
- else
- {
- int32 signedQuestId = qinfo->NextQuestId < 0 ? -int32(qinfo->GetQuestId()) : int32(qinfo->GetQuestId());
- mQuestTemplates[abs(qinfo->GetNextQuestId())]->prevQuests.push_back(signedQuestId);
- }
- }
-
- if(qinfo->ExclusiveGroup)
- mExclusiveQuestGroups.insert(std::pair<int32, uint32>(qinfo->ExclusiveGroup, qinfo->GetQuestId()));
- if(qinfo->LimitTime)
- qinfo->SetFlag(QUEST_TRINITY_FLAGS_TIMED);
- }
-
- // check QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE
- for (uint32 i = 0; i < sSpellStore.GetNumRows(); ++i)
- {
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(i);
- if(!spellInfo)
- continue;
-
- for(int j = 0; j < 3; ++j)
- {
- if(spellInfo->Effect[j] != SPELL_EFFECT_QUEST_COMPLETE)
- continue;
-
- uint32 quest_id = spellInfo->EffectMiscValue[j];
-
- Quest const* quest = GetQuestTemplate(quest_id);
-
- // some quest referenced in spells not exist (outdated spells)
- if(!quest)
- continue;
-
- if(!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
- {
- sLog.outErrorDb("Spell (id: %u) have SPELL_EFFECT_QUEST_COMPLETE for quest %u , but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT. Quest flags must be fixed, quest modified to enable objective.",spellInfo->Id,quest_id);
-
- // this will prevent quest completing without objective
- const_cast<Quest*>(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT);
- }
- }
- }
-
- sLog.outString();
- sLog.outString( ">> Loaded %u quests definitions", mQuestTemplates.size() );
-}
-
-void ObjectMgr::LoadQuestLocales()
-{
- mQuestLocaleMap.clear(); // need for reload case
-
- QueryResult *result = WorldDatabase.Query("SELECT entry,"
- "Title_loc1,Details_loc1,Objectives_loc1,OfferRewardText_loc1,RequestItemsText_loc1,EndText_loc1,ObjectiveText1_loc1,ObjectiveText2_loc1,ObjectiveText3_loc1,ObjectiveText4_loc1,"
- "Title_loc2,Details_loc2,Objectives_loc2,OfferRewardText_loc2,RequestItemsText_loc2,EndText_loc2,ObjectiveText1_loc2,ObjectiveText2_loc2,ObjectiveText3_loc2,ObjectiveText4_loc2,"
- "Title_loc3,Details_loc3,Objectives_loc3,OfferRewardText_loc3,RequestItemsText_loc3,EndText_loc3,ObjectiveText1_loc3,ObjectiveText2_loc3,ObjectiveText3_loc3,ObjectiveText4_loc3,"
- "Title_loc4,Details_loc4,Objectives_loc4,OfferRewardText_loc4,RequestItemsText_loc4,EndText_loc4,ObjectiveText1_loc4,ObjectiveText2_loc4,ObjectiveText3_loc4,ObjectiveText4_loc4,"
- "Title_loc5,Details_loc5,Objectives_loc5,OfferRewardText_loc5,RequestItemsText_loc5,EndText_loc5,ObjectiveText1_loc5,ObjectiveText2_loc5,ObjectiveText3_loc5,ObjectiveText4_loc5,"
- "Title_loc6,Details_loc6,Objectives_loc6,OfferRewardText_loc6,RequestItemsText_loc6,EndText_loc6,ObjectiveText1_loc6,ObjectiveText2_loc6,ObjectiveText3_loc6,ObjectiveText4_loc6,"
- "Title_loc7,Details_loc7,Objectives_loc7,OfferRewardText_loc7,RequestItemsText_loc7,EndText_loc7,ObjectiveText1_loc7,ObjectiveText2_loc7,ObjectiveText3_loc7,ObjectiveText4_loc7,"
- "Title_loc8,Details_loc8,Objectives_loc8,OfferRewardText_loc8,RequestItemsText_loc8,EndText_loc8,ObjectiveText1_loc8,ObjectiveText2_loc8,ObjectiveText3_loc8,ObjectiveText4_loc8"
- " FROM locales_quest"
- );
-
- if(!result)
- {
- barGoLink bar(1);
-
- bar.step();
-
- sLog.outString("");
- sLog.outString(">> Loaded 0 Quest locale strings. DB table `locales_quest` is empty.");
- return;
- }
-
- barGoLink bar(result->GetRowCount());
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- uint32 entry = fields[0].GetUInt32();
-
- QuestLocale& data = mQuestLocaleMap[entry];
-
- for(int i = 1; i < MAX_LOCALE; ++i)
- {
- std::string str = fields[1+10*(i-1)].GetCppString();
- if(!str.empty())
- {
- int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
- {
- if(data.Title.size() <= idx)
- data.Title.resize(idx+1);
-
- data.Title[idx] = str;
- }
- }
- str = fields[1+10*(i-1)+1].GetCppString();
- if(!str.empty())
- {
- int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
- {
- if(data.Details.size() <= idx)
- data.Details.resize(idx+1);
-
- data.Details[idx] = str;
- }
- }
- str = fields[1+10*(i-1)+2].GetCppString();
- if(!str.empty())
- {
- int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
- {
- if(data.Objectives.size() <= idx)
- data.Objectives.resize(idx+1);
-
- data.Objectives[idx] = str;
- }
- }
- str = fields[1+10*(i-1)+3].GetCppString();
- if(!str.empty())
- {
- int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
- {
- if(data.OfferRewardText.size() <= idx)
- data.OfferRewardText.resize(idx+1);
-
- data.OfferRewardText[idx] = str;
- }
- }
- str = fields[1+10*(i-1)+4].GetCppString();
- if(!str.empty())
- {
- int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
- {
- if(data.RequestItemsText.size() <= idx)
- data.RequestItemsText.resize(idx+1);
-
- data.RequestItemsText[idx] = str;
- }
- }
- str = fields[1+10*(i-1)+5].GetCppString();
- if(!str.empty())
- {
- int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
- {
- if(data.EndText.size() <= idx)
- data.EndText.resize(idx+1);
-
- data.EndText[idx] = str;
- }
- }
- for(int k = 0; k < 4; ++k)
- {
- str = fields[1+10*(i-1)+6+k].GetCppString();
- if(!str.empty())
- {
- int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
- {
- if(data.ObjectiveText[k].size() <= idx)
- data.ObjectiveText[k].resize(idx+1);
-
- data.ObjectiveText[k][idx] = str;
- }
- }
- }
- }
- } while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u Quest locale strings", mQuestLocaleMap.size() );
-}
-
-void ObjectMgr::LoadPetCreateSpells()
-{
- QueryResult *result = WorldDatabase.Query("SELECT entry, Spell1, Spell2, Spell3, Spell4 FROM petcreateinfo_spell");
- if(!result)
- {
- barGoLink bar( 1 );
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded 0 pet create spells" );
- sLog.outErrorDb("`petcreateinfo_spell` table is empty!");
- return;
- }
-
- uint32 count = 0;
-
- barGoLink bar( result->GetRowCount() );
-
- mPetCreateSpell.clear();
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- uint32 creature_id = fields[0].GetUInt32();
-
- if(!creature_id || !sCreatureStorage.LookupEntry<CreatureInfo>(creature_id))
- continue;
-
- PetCreateSpellEntry PetCreateSpell;
- for(int i = 0; i < 4; i++)
- {
- PetCreateSpell.spellid[i] = fields[i + 1].GetUInt32();
-
- if(PetCreateSpell.spellid[i] && !sSpellStore.LookupEntry(PetCreateSpell.spellid[i]))
- sLog.outErrorDb("Spell %u listed in `petcreateinfo_spell` does not exist",PetCreateSpell.spellid[i]);
- }
-
- mPetCreateSpell[creature_id] = PetCreateSpell;
-
- ++count;
- }
- while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u pet create spells", count );
-}
-
-void ObjectMgr::LoadScripts(ScriptMapMap& scripts, char const* tablename)
-{
- if(sWorld.IsScriptScheduled()) // function don't must be called in time scripts use.
- return;
-
- sLog.outString( "%s :", tablename);
-
- scripts.clear(); // need for reload support
-
- QueryResult *result = WorldDatabase.PQuery( "SELECT id,delay,command,datalong,datalong2,dataint, x, y, z, o FROM %s", tablename );
-
- uint32 count = 0;
-
- if( !result )
- {
- barGoLink bar( 1 );
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded %u script definitions", count );
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- bar.step();
-
- Field *fields = result->Fetch();
- ScriptInfo tmp;
- tmp.id = fields[0].GetUInt32();
- tmp.delay = fields[1].GetUInt32();
- tmp.command = fields[2].GetUInt32();
- tmp.datalong = fields[3].GetUInt32();
- tmp.datalong2 = fields[4].GetUInt32();
- tmp.dataint = fields[5].GetInt32();
- tmp.x = fields[6].GetFloat();
- tmp.y = fields[7].GetFloat();
- tmp.z = fields[8].GetFloat();
- tmp.o = fields[9].GetFloat();
-
- // generic command args check
- switch(tmp.command)
- {
- case SCRIPT_COMMAND_TALK:
- {
- if(tmp.datalong > 3)
- {
- sLog.outErrorDb("Table `%s` has invalid talk type (datalong = %u) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.datalong,tmp.id);
- continue;
- }
- if(tmp.dataint==0)
- {
- sLog.outErrorDb("Table `%s` has invalid talk text id (dataint = %i) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.dataint,tmp.id);
- continue;
- }
- if(tmp.dataint < MIN_DB_SCRIPT_STRING_ID || tmp.dataint >= MAX_DB_SCRIPT_STRING_ID)
- {
- sLog.outErrorDb("Table `%s` has out of range text id (dataint = %i expected %u-%u) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.dataint,MIN_DB_SCRIPT_STRING_ID,MAX_DB_SCRIPT_STRING_ID,tmp.id);
- continue;
- }
-
- // if(!objmgr.GetMangosStringLocale(tmp.dataint)) will checked after db_script_string loading
- break;
- }
-
- case SCRIPT_COMMAND_TELEPORT_TO:
- {
- if(!sMapStore.LookupEntry(tmp.datalong))
- {
- sLog.outErrorDb("Table `%s` has invalid map (Id: %u) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",tablename,tmp.datalong,tmp.id);
- continue;
- }
-
- if(!Trinity::IsValidMapCoord(tmp.x,tmp.y,tmp.z,tmp.o))
- {
- sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",tablename,tmp.x,tmp.y,tmp.id);
- continue;
- }
- break;
- }
-
- case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE:
- {
- if(!Trinity::IsValidMapCoord(tmp.x,tmp.y,tmp.z,tmp.o))
- {
- sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",tablename,tmp.x,tmp.y,tmp.id);
- continue;
- }
-
- if(!GetCreatureTemplate(tmp.datalong))
- {
- sLog.outErrorDb("Table `%s` has invalid creature (Entry: %u) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",tablename,tmp.datalong,tmp.id);
- continue;
- }
- break;
- }
-
- case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT:
- {
- GameObjectData const* data = GetGOData(tmp.datalong);
- if(!data)
- {
- sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,tmp.datalong,tmp.id);
- continue;
- }
-
- GameObjectInfo const* info = GetGameObjectInfo(data->id);
- if(!info)
- {
- sLog.outErrorDb("Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,tmp.datalong,data->id,tmp.id);
- continue;
- }
-
- if( info->type==GAMEOBJECT_TYPE_FISHINGNODE ||
- info->type==GAMEOBJECT_TYPE_FISHINGHOLE ||
- info->type==GAMEOBJECT_TYPE_DOOR ||
- info->type==GAMEOBJECT_TYPE_BUTTON ||
- info->type==GAMEOBJECT_TYPE_TRAP )
- {
- sLog.outErrorDb("Table `%s` have gameobject type (%u) unsupported by command SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,info->id,tmp.id);
- continue;
- }
- break;
- }
- case SCRIPT_COMMAND_OPEN_DOOR:
- case SCRIPT_COMMAND_CLOSE_DOOR:
- {
- GameObjectData const* data = GetGOData(tmp.datalong);
- if(!data)
- {
- sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in %s for script id %u",tablename,tmp.datalong,(tmp.command==SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id);
- continue;
- }
-
- GameObjectInfo const* info = GetGameObjectInfo(data->id);
- if(!info)
- {
- sLog.outErrorDb("Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in %s for script id %u",tablename,tmp.datalong,data->id,(tmp.command==SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id);
- continue;
- }
-
- if( info->type!=GAMEOBJECT_TYPE_DOOR)
- {
- sLog.outErrorDb("Table `%s` has gameobject type (%u) non supported by command %s for script id %u",tablename,info->id,(tmp.command==SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id);
- continue;
- }
-
- break;
- }
- case SCRIPT_COMMAND_QUEST_EXPLORED:
- {
- Quest const* quest = GetQuestTemplate(tmp.datalong);
- if(!quest)
- {
- sLog.outErrorDb("Table `%s` has invalid quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u",tablename,tmp.datalong,tmp.id);
- continue;
- }
-
- if(!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
- {
- sLog.outErrorDb("Table `%s` has quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT in quest flags. Script command or quest flags wrong. Quest modified to require objective.",tablename,tmp.datalong,tmp.id);
-
- // this will prevent quest completing without objective
- const_cast<Quest*>(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT);
-
- // continue; - quest objective requirement set and command can be allowed
- }
-
- if(float(tmp.datalong2) > DEFAULT_VISIBILITY_DISTANCE)
- {
- sLog.outErrorDb("Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u",
- tablename,tmp.datalong2,tmp.id);
- continue;
- }
-
- if(tmp.datalong2 && float(tmp.datalong2) > DEFAULT_VISIBILITY_DISTANCE)
- {
- sLog.outErrorDb("Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, max distance is %f or 0 for disable distance check",
- tablename,tmp.datalong2,tmp.id,DEFAULT_VISIBILITY_DISTANCE);
- continue;
- }
-
- if(tmp.datalong2 && float(tmp.datalong2) < INTERACTION_DISTANCE)
- {
- sLog.outErrorDb("Table `%s` has too small distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, min distance is %f or 0 for disable distance check",
- tablename,tmp.datalong2,tmp.id,INTERACTION_DISTANCE);
- continue;
- }
-
- break;
- }
-
- case SCRIPT_COMMAND_REMOVE_AURA:
- case SCRIPT_COMMAND_CAST_SPELL:
- {
- if(!sSpellStore.LookupEntry(tmp.datalong))
- {
- sLog.outErrorDb("Table `%s` using non-existent spell (id: %u) in SCRIPT_COMMAND_REMOVE_AURA or SCRIPT_COMMAND_CAST_SPELL for script id %u",
- tablename,tmp.datalong,tmp.id);
- continue;
- }
- break;
- }
- }
-
- if (scripts.find(tmp.id) == scripts.end())
- {
- ScriptMap emptyMap;
- scripts[tmp.id] = emptyMap;
- }
- scripts[tmp.id].insert(std::pair<uint32, ScriptInfo>(tmp.delay, tmp));
-
- ++count;
- } while( result->NextRow() );
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u script definitions", count );
-}
-
-void ObjectMgr::LoadGameObjectScripts()
-{
- LoadScripts(sGameObjectScripts, "gameobject_scripts");
-
- // check ids
- for(ScriptMapMap::const_iterator itr = sGameObjectScripts.begin(); itr != sGameObjectScripts.end(); ++itr)
- {
- if(!GetGOData(itr->first))
- sLog.outErrorDb("Table `gameobject_scripts` has not existing gameobject (GUID: %u) as script id",itr->first);
- }
-}
-
-void ObjectMgr::LoadQuestEndScripts()
-{
- LoadScripts(sQuestEndScripts, "quest_end_scripts");
-
- // check ids
- for(ScriptMapMap::const_iterator itr = sQuestEndScripts.begin(); itr != sQuestEndScripts.end(); ++itr)
- {
- if(!GetQuestTemplate(itr->first))
- sLog.outErrorDb("Table `quest_end_scripts` has not existing quest (Id: %u) as script id",itr->first);
- }
-}
-
-void ObjectMgr::LoadQuestStartScripts()
-{
- LoadScripts(sQuestStartScripts,"quest_start_scripts");
-
- // check ids
- for(ScriptMapMap::const_iterator itr = sQuestStartScripts.begin(); itr != sQuestStartScripts.end(); ++itr)
- {
- if(!GetQuestTemplate(itr->first))
- sLog.outErrorDb("Table `quest_start_scripts` has not existing quest (Id: %u) as script id",itr->first);
- }
-}
-
-void ObjectMgr::LoadSpellScripts()
-{
- LoadScripts(sSpellScripts, "spell_scripts");
-
- // check ids
- for(ScriptMapMap::const_iterator itr = sSpellScripts.begin(); itr != sSpellScripts.end(); ++itr)
- {
- SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first);
-
- if(!spellInfo)
- {
- sLog.outErrorDb("Table `spell_scripts` has not existing spell (Id: %u) as script id",itr->first);
- continue;
- }
-
- //check for correct spellEffect
- bool found = false;
- for(int i=0; i<3; ++i)
- {
- // skip empty effects
- if( !spellInfo->Effect[i] )
- continue;
-
- if( spellInfo->Effect[i] == SPELL_EFFECT_SCRIPT_EFFECT )
- {
- found = true;
- break;
- }
- }
-
- if(!found)
- sLog.outErrorDb("Table `spell_scripts` has unsupported spell (Id: %u) without SPELL_EFFECT_SCRIPT_EFFECT (%u) spell effect",itr->first,SPELL_EFFECT_SCRIPT_EFFECT);
- }
-}
-
-void ObjectMgr::LoadEventScripts()
-{
- LoadScripts(sEventScripts, "event_scripts");
-
- std::set<uint32> evt_scripts;
- // Load all possible script entries from gameobjects
- for(uint32 i = 1; i < sGOStorage.MaxEntry; ++i)
- {
- GameObjectInfo const * goInfo = sGOStorage.LookupEntry<GameObjectInfo>(i);
- if (goInfo)
- {
- switch(goInfo->type)
- {
- case GAMEOBJECT_TYPE_GOOBER:
- if(goInfo->goober.eventId)
- evt_scripts.insert(goInfo->goober.eventId);
- break;
- case GAMEOBJECT_TYPE_CHEST:
- if(goInfo->chest.eventId)
- evt_scripts.insert(goInfo->chest.eventId);
- break;
- default:
- break;
- }
- }
- }
- // Load all possible script entries from spells
- for(uint32 i = 1; i < sSpellStore.GetNumRows(); ++i)
- {
- SpellEntry const * spell = sSpellStore.LookupEntry(i);
- if (spell)
- {
- for(int j=0; j<3; ++j)
- {
- if( spell->Effect[j] == SPELL_EFFECT_SEND_EVENT )
- {
- if (spell->EffectMiscValue[j])
- evt_scripts.insert(spell->EffectMiscValue[j]);
- }
- }
- }
- }
- // Then check if all scripts are in above list of possible script entries
- for(ScriptMapMap::const_iterator itr = sEventScripts.begin(); itr != sEventScripts.end(); ++itr)
- {
- std::set<uint32>::const_iterator itr2 = evt_scripts.find(itr->first);
- if (itr2 == evt_scripts.end())
- sLog.outErrorDb("Table `event_scripts` has script (Id: %u) not referring to any gameobject_template type 10 data2 field or type 3 data6 field or any spell effect %u", itr->first, SPELL_EFFECT_SEND_EVENT);
- }
-}
-
-void ObjectMgr::LoadItemTexts()
-{
- QueryResult *result = CharacterDatabase.Query("SELECT id, text FROM item_text");
-
- uint32 count = 0;
-
- if( !result )
- {
- barGoLink bar( 1 );
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded %u item pages", count );
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- Field* fields;
- do
- {
- bar.step();
-
- fields = result->Fetch();
-
- mItemTexts[ fields[0].GetUInt32() ] = fields[1].GetCppString();
-
- ++count;
-
- } while ( result->NextRow() );
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u item texts", count );
-}
-
-void ObjectMgr::LoadPageTexts()
-{
- sPageTextStore.Free(); // for reload case
-
- sPageTextStore.Load();
- sLog.outString( ">> Loaded %u page texts", sPageTextStore.RecordCount );
- sLog.outString();
-
- for(uint32 i = 1; i < sPageTextStore.MaxEntry; ++i)
- {
- // check data correctness
- PageText const* page = sPageTextStore.LookupEntry<PageText>(i);
- if(!page)
- continue;
-
- if(page->Next_Page && !sPageTextStore.LookupEntry<PageText>(page->Next_Page))
- {
- sLog.outErrorDb("Page text (Id: %u) has not existing next page (Id:%u)", i,page->Next_Page);
- continue;
- }
-
- // detect circular reference
- std::set<uint32> checkedPages;
- for(PageText const* pageItr = page; pageItr; pageItr = sPageTextStore.LookupEntry<PageText>(pageItr->Next_Page))
- {
- if(!pageItr->Next_Page)
- break;
- checkedPages.insert(pageItr->Page_ID);
- if(checkedPages.find(pageItr->Next_Page)!=checkedPages.end())
- {
- std::ostringstream ss;
- ss<< "The text page(s) ";
- for (std::set<uint32>::iterator itr= checkedPages.begin();itr!=checkedPages.end(); itr++)
- ss << *itr << " ";
- ss << "create(s) a circular reference, which can cause the server to freeze. Changing Next_Page of page "
- << pageItr->Page_ID <<" to 0";
- sLog.outErrorDb(ss.str().c_str());
- const_cast<PageText*>(pageItr)->Next_Page = 0;
- break;
- }
- }
- }
-}
-
-void ObjectMgr::LoadPageTextLocales()
-{
- mPageTextLocaleMap.clear(); // need for reload case
-
- QueryResult *result = WorldDatabase.Query("SELECT entry,text_loc1,text_loc2,text_loc3,text_loc4,text_loc5,text_loc6,text_loc7,text_loc8 FROM locales_page_text");
-
- if(!result)
- {
- barGoLink bar(1);
-
- bar.step();
-
- sLog.outString("");
- sLog.outString(">> Loaded 0 PageText locale strings. DB table `locales_page_text` is empty.");
- return;
- }
-
- barGoLink bar(result->GetRowCount());
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- uint32 entry = fields[0].GetUInt32();
-
- PageTextLocale& data = mPageTextLocaleMap[entry];
-
- for(int i = 1; i < MAX_LOCALE; ++i)
- {
- std::string str = fields[i].GetCppString();
- if(str.empty())
- continue;
-
- int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
- {
- if(data.Text.size() <= idx)
- data.Text.resize(idx+1);
-
- data.Text[idx] = str;
- }
- }
-
- } while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u PageText locale strings", mPageTextLocaleMap.size() );
-}
-
-struct SQLInstanceLoader : public SQLStorageLoaderBase<SQLInstanceLoader>
-{
- template<class D>
- void convert_from_str(uint32 field_pos, char *src, D &dst)
- {
- dst = D(objmgr.GetScriptId(src));
- }
-};
-
-void ObjectMgr::LoadInstanceTemplate()
-{
- SQLInstanceLoader loader;
- loader.Load(sInstanceTemplate);
-
- for(uint32 i = 0; i < sInstanceTemplate.MaxEntry; i++)
- {
- InstanceTemplate* temp = (InstanceTemplate*)GetInstanceTemplate(i);
- if(!temp) continue;
- const MapEntry* entry = sMapStore.LookupEntry(temp->map);
- if(!entry)
- {
- sLog.outErrorDb("ObjectMgr::LoadInstanceTemplate: bad mapid %d for template!", temp->map);
- continue;
- }
- else if(!entry->HasResetTime())
- continue;
-
- if(temp->reset_delay == 0)
- {
- // use defaults from the DBC
- if(entry->SupportsHeroicMode())
- {
- temp->reset_delay = entry->resetTimeHeroic / DAY;
- }
- else if (entry->resetTimeRaid && entry->map_type == MAP_RAID)
- {
- temp->reset_delay = entry->resetTimeRaid / DAY;
- }
- }
-
- // the reset_delay must be at least one day
- temp->reset_delay = std::max((uint32)1, (uint32)(temp->reset_delay * sWorld.getRate(RATE_INSTANCE_RESET_TIME)));
- }
-
- sLog.outString( ">> Loaded %u Instance Template definitions", sInstanceTemplate.RecordCount );
- sLog.outString();
-}
-
-void ObjectMgr::AddGossipText(GossipText *pGText)
-{
- ASSERT( pGText->Text_ID );
- ASSERT( mGossipText.find(pGText->Text_ID) == mGossipText.end() );
- mGossipText[pGText->Text_ID] = pGText;
-}
-
-GossipText *ObjectMgr::GetGossipText(uint32 Text_ID)
-{
- GossipTextMap::const_iterator itr;
- for (itr = mGossipText.begin(); itr != mGossipText.end(); itr++)
- {
- if(itr->second->Text_ID == Text_ID)
- return itr->second;
- }
- return NULL;
-}
-
-void ObjectMgr::LoadGossipText()
-{
- GossipText *pGText;
- QueryResult *result = WorldDatabase.Query( "SELECT * FROM npc_text" );
-
- int count = 0;
- if( !result )
- {
- barGoLink bar( 1 );
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded %u npc texts", count );
- return;
- }
-
- int cic;
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- ++count;
- cic = 0;
-
- Field *fields = result->Fetch();
-
- bar.step();
-
- pGText = new GossipText;
- pGText->Text_ID = fields[cic++].GetUInt32();
-
- for (int i=0; i< 8; i++)
- {
- pGText->Options[i].Text_0 = fields[cic++].GetCppString();
- pGText->Options[i].Text_1 = fields[cic++].GetCppString();
-
- pGText->Options[i].Language = fields[cic++].GetUInt32();
- pGText->Options[i].Probability = fields[cic++].GetFloat();
-
- pGText->Options[i].Emotes[0]._Delay = fields[cic++].GetUInt32();
- pGText->Options[i].Emotes[0]._Emote = fields[cic++].GetUInt32();
-
- pGText->Options[i].Emotes[1]._Delay = fields[cic++].GetUInt32();
- pGText->Options[i].Emotes[1]._Emote = fields[cic++].GetUInt32();
-
- pGText->Options[i].Emotes[2]._Delay = fields[cic++].GetUInt32();
- pGText->Options[i].Emotes[2]._Emote = fields[cic++].GetUInt32();
- }
-
- if ( !pGText->Text_ID ) continue;
- AddGossipText( pGText );
-
- } while( result->NextRow() );
-
- sLog.outString();
- sLog.outString( ">> Loaded %u npc texts", count );
- delete result;
-}
-
-void ObjectMgr::LoadNpcTextLocales()
-{
- mNpcTextLocaleMap.clear(); // need for reload case
-
- QueryResult *result = WorldDatabase.Query("SELECT entry,"
- "Text0_0_loc1,Text0_1_loc1,Text1_0_loc1,Text1_1_loc1,Text2_0_loc1,Text2_1_loc1,Text3_0_loc1,Text3_1_loc1,Text4_0_loc1,Text4_1_loc1,Text5_0_loc1,Text5_1_loc1,Text6_0_loc1,Text6_1_loc1,Text7_0_loc1,Text7_1_loc1,"
- "Text0_0_loc2,Text0_1_loc2,Text1_0_loc2,Text1_1_loc2,Text2_0_loc2,Text2_1_loc2,Text3_0_loc2,Text3_1_loc1,Text4_0_loc2,Text4_1_loc2,Text5_0_loc2,Text5_1_loc2,Text6_0_loc2,Text6_1_loc2,Text7_0_loc2,Text7_1_loc2,"
- "Text0_0_loc3,Text0_1_loc3,Text1_0_loc3,Text1_1_loc3,Text2_0_loc3,Text2_1_loc3,Text3_0_loc3,Text3_1_loc1,Text4_0_loc3,Text4_1_loc3,Text5_0_loc3,Text5_1_loc3,Text6_0_loc3,Text6_1_loc3,Text7_0_loc3,Text7_1_loc3,"
- "Text0_0_loc4,Text0_1_loc4,Text1_0_loc4,Text1_1_loc4,Text2_0_loc4,Text2_1_loc4,Text3_0_loc4,Text3_1_loc1,Text4_0_loc4,Text4_1_loc4,Text5_0_loc4,Text5_1_loc4,Text6_0_loc4,Text6_1_loc4,Text7_0_loc4,Text7_1_loc4,"
- "Text0_0_loc5,Text0_1_loc5,Text1_0_loc5,Text1_1_loc5,Text2_0_loc5,Text2_1_loc5,Text3_0_loc5,Text3_1_loc1,Text4_0_loc5,Text4_1_loc5,Text5_0_loc5,Text5_1_loc5,Text6_0_loc5,Text6_1_loc5,Text7_0_loc5,Text7_1_loc5,"
- "Text0_0_loc6,Text0_1_loc6,Text1_0_loc6,Text1_1_loc6,Text2_0_loc6,Text2_1_loc6,Text3_0_loc6,Text3_1_loc1,Text4_0_loc6,Text4_1_loc6,Text5_0_loc6,Text5_1_loc6,Text6_0_loc6,Text6_1_loc6,Text7_0_loc6,Text7_1_loc6,"
- "Text0_0_loc7,Text0_1_loc7,Text1_0_loc7,Text1_1_loc7,Text2_0_loc7,Text2_1_loc7,Text3_0_loc7,Text3_1_loc1,Text4_0_loc7,Text4_1_loc7,Text5_0_loc7,Text5_1_loc7,Text6_0_loc7,Text6_1_loc7,Text7_0_loc7,Text7_1_loc7, "
- "Text0_0_loc8,Text0_1_loc8,Text1_0_loc8,Text1_1_loc8,Text2_0_loc8,Text2_1_loc8,Text3_0_loc8,Text3_1_loc1,Text4_0_loc8,Text4_1_loc8,Text5_0_loc8,Text5_1_loc8,Text6_0_loc8,Text6_1_loc8,Text7_0_loc8,Text7_1_loc8 "
- " FROM locales_npc_text");
-
- if(!result)
- {
- barGoLink bar(1);
-
- bar.step();
-
- sLog.outString("");
- sLog.outString(">> Loaded 0 Quest locale strings. DB table `locales_npc_text` is empty.");
- return;
- }
-
- barGoLink bar(result->GetRowCount());
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- uint32 entry = fields[0].GetUInt32();
-
- NpcTextLocale& data = mNpcTextLocaleMap[entry];
-
- for(int i=1; i<MAX_LOCALE; ++i)
- {
- for(int j=0; j<8; ++j)
- {
- std::string str0 = fields[1+8*2*(i-1)+2*j].GetCppString();
- if(!str0.empty())
- {
- int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
- {
- if(data.Text_0[j].size() <= idx)
- data.Text_0[j].resize(idx+1);
-
- data.Text_0[j][idx] = str0;
- }
- }
- std::string str1 = fields[1+8*2*(i-1)+2*j+1].GetCppString();
- if(!str1.empty())
- {
- int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
- {
- if(data.Text_1[j].size() <= idx)
- data.Text_1[j].resize(idx+1);
-
- data.Text_1[j][idx] = str1;
- }
- }
- }
- }
- } while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u NpcText locale strings", mNpcTextLocaleMap.size() );
-}
-
-//not very fast function but it is called only once a day, or on starting-up
-void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp)
-{
- time_t basetime = time(NULL);
- sLog.outDebug("Returning mails current time: hour: %d, minute: %d, second: %d ", localtime(&basetime)->tm_hour, localtime(&basetime)->tm_min, localtime(&basetime)->tm_sec);
- //delete all old mails without item and without body immediately, if starting server
- if (!serverUp)
- CharacterDatabase.PExecute("DELETE FROM mail WHERE expire_time < '" I64FMTD "' AND has_items = '0' AND itemTextId = 0", (uint64)basetime);
- // 0 1 2 3 4 5 6 7 8 9
- QueryResult* result = CharacterDatabase.PQuery("SELECT id,messageType,sender,receiver,itemTextId,has_items,expire_time,cod,checked,mailTemplateId FROM mail WHERE expire_time < '" I64FMTD "'", (uint64)basetime);
- if ( !result )
- return; // any mails need to be returned or deleted
- Field *fields;
- //std::ostringstream delitems, delmails; //will be here for optimization
- //bool deletemail = false, deleteitem = false;
- //delitems << "DELETE FROM item_instance WHERE guid IN ( ";
- //delmails << "DELETE FROM mail WHERE id IN ( "
- do
- {
- fields = result->Fetch();
- Mail *m = new Mail;
- m->messageID = fields[0].GetUInt32();
- m->messageType = fields[1].GetUInt8();
- m->sender = fields[2].GetUInt32();
- m->receiver = fields[3].GetUInt32();
- m->itemTextId = fields[4].GetUInt32();
- bool has_items = fields[5].GetBool();
- m->expire_time = (time_t)fields[6].GetUInt64();
- m->deliver_time = 0;
- m->COD = fields[7].GetUInt32();
- m->checked = fields[8].GetUInt32();
- m->mailTemplateId = fields[9].GetInt16();
-
- Player *pl = 0;
- if (serverUp)
- pl = GetPlayer((uint64)m->receiver);
- if (pl && pl->m_mailsLoaded)
- { //this code will run very improbably (the time is between 4 and 5 am, in game is online a player, who has old mail
- //his in mailbox and he has already listed his mails )
- delete m;
- continue;
- }
- //delete or return mail:
- if (has_items)
- {
- QueryResult *resultItems = CharacterDatabase.PQuery("SELECT item_guid,item_template FROM mail_items WHERE mail_id='%u'", m->messageID);
- if(resultItems)
- {
- do
- {
- Field *fields2 = resultItems->Fetch();
-
- uint32 item_guid_low = fields2[0].GetUInt32();
- uint32 item_template = fields2[1].GetUInt32();
-
- m->AddItem(item_guid_low, item_template);
- }
- while (resultItems->NextRow());
-
- delete resultItems;
- }
- //if it is mail from AH, it shouldn't be returned, but deleted
- if (m->messageType != MAIL_NORMAL || (m->checked & (MAIL_CHECK_MASK_AUCTION | MAIL_CHECK_MASK_COD_PAYMENT | MAIL_CHECK_MASK_RETURNED)))
- {
- // mail open and then not returned
- for(std::vector<MailItemInfo>::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2)
- CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", itr2->item_guid);
- }
- else
- {
- //mail will be returned:
- CharacterDatabase.PExecute("UPDATE mail SET sender = '%u', receiver = '%u', expire_time = '" I64FMTD "', deliver_time = '" I64FMTD "',cod = '0', checked = '%u' WHERE id = '%u'", m->receiver, m->sender, (uint64)(basetime + 30*DAY), (uint64)basetime, MAIL_CHECK_MASK_RETURNED, m->messageID);
- delete m;
- continue;
- }
- }
-
- if (m->itemTextId)
- CharacterDatabase.PExecute("DELETE FROM item_text WHERE id = '%u'", m->itemTextId);
-
- //deletemail = true;
- //delmails << m->messageID << ", ";
- CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", m->messageID);
- delete m;
- } while (result->NextRow());
- delete result;
-}
-
-void ObjectMgr::LoadQuestAreaTriggers()
-{
- mQuestAreaTriggerMap.clear(); // need for reload case
-
- QueryResult *result = WorldDatabase.Query( "SELECT id,quest FROM areatrigger_involvedrelation" );
-
- uint32 count = 0;
-
- if( !result )
- {
- barGoLink bar( 1 );
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded %u quest trigger points", count );
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- ++count;
- bar.step();
-
- Field *fields = result->Fetch();
-
- uint32 trigger_ID = fields[0].GetUInt32();
- uint32 quest_ID = fields[1].GetUInt32();
-
- AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(trigger_ID);
- if(!atEntry)
- {
- sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",trigger_ID);
- continue;
- }
-
- Quest const* quest = GetQuestTemplate(quest_ID);
-
- if(!quest)
- {
- sLog.outErrorDb("Table `areatrigger_involvedrelation` has record (id: %u) for not existing quest %u",trigger_ID,quest_ID);
- continue;
- }
-
- if(!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
- {
- sLog.outErrorDb("Table `areatrigger_involvedrelation` has record (id: %u) for not quest %u, but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT. Trigger or quest flags must be fixed, quest modified to require objective.",trigger_ID,quest_ID);
-
- // this will prevent quest completing without objective
- const_cast<Quest*>(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT);
-
- // continue; - quest modified to required objective and trigger can be allowed.
- }
-
- mQuestAreaTriggerMap[trigger_ID] = quest_ID;
-
- } while( result->NextRow() );
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u quest trigger points", count );
-}
-
-void ObjectMgr::LoadTavernAreaTriggers()
-{
- mTavernAreaTriggerSet.clear(); // need for reload case
-
- QueryResult *result = WorldDatabase.Query("SELECT id FROM areatrigger_tavern");
-
- uint32 count = 0;
-
- if( !result )
- {
- barGoLink bar( 1 );
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded %u tavern triggers", count );
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- ++count;
- bar.step();
-
- Field *fields = result->Fetch();
-
- uint32 Trigger_ID = fields[0].GetUInt32();
-
- AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
- if(!atEntry)
- {
- sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID);
- continue;
- }
-
- mTavernAreaTriggerSet.insert(Trigger_ID);
- } while( result->NextRow() );
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u tavern triggers", count );
-}
-
-void ObjectMgr::LoadAreaTriggerScripts()
-{
- mAreaTriggerScripts.clear(); // need for reload case
- QueryResult *result = WorldDatabase.Query("SELECT entry, ScriptName FROM areatrigger_scripts");
-
- uint32 count = 0;
-
- if( !result )
- {
- barGoLink bar( 1 );
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded %u areatrigger scripts", count );
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- ++count;
- bar.step();
-
- Field *fields = result->Fetch();
-
- uint32 Trigger_ID = fields[0].GetUInt32();
- const char *scriptName = fields[1].GetString();
-
- AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
- if(!atEntry)
- {
- sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID);
- continue;
- }
- mAreaTriggerScripts[Trigger_ID] = GetScriptId(scriptName);
- } while( result->NextRow() );
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u areatrigger scripts", count );
-}
-
-uint32 ObjectMgr::GetNearestTaxiNode( float x, float y, float z, uint32 mapid )
-{
- bool found = false;
- float dist;
- uint32 id = 0;
-
- for(uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i)
- {
- TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i);
- if(node && node->map_id == mapid)
- {
- float dist2 = (node->x - x)*(node->x - x)+(node->y - y)*(node->y - y)+(node->z - z)*(node->z - z);
- if(found)
- {
- if(dist2 < dist)
- {
- dist = dist2;
- id = i;
- }
- }
- else
- {
- found = true;
- dist = dist2;
- id = i;
- }
- }
- }
-
- return id;
-}
-
-void ObjectMgr::GetTaxiPath( uint32 source, uint32 destination, uint32 &path, uint32 &cost)
-{
- TaxiPathSetBySource::iterator src_i = sTaxiPathSetBySource.find(source);
- if(src_i==sTaxiPathSetBySource.end())
- {
- path = 0;
- cost = 0;
- return;
- }
-
- TaxiPathSetForSource& pathSet = src_i->second;
-
- TaxiPathSetForSource::iterator dest_i = pathSet.find(destination);
- if(dest_i==pathSet.end())
- {
- path = 0;
- cost = 0;
- return;
- }
-
- cost = dest_i->second.price;
- path = dest_i->second.ID;
-}
-
-uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team )
-{
- uint16 mount_entry = 0;
- uint16 mount_id = 0;
-
- TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(id);
- if(node)
- {
- if (team == ALLIANCE) mount_entry = node->alliance_mount_type;
- else mount_entry = node->horde_mount_type;
-
- CreatureInfo const *cinfo = GetCreatureTemplate(mount_entry);
- if (cinfo)
- {
- if(! (mount_id = cinfo->GetRandomValidModelId()))
- {
- sLog.outErrorDb("No displayid found for the taxi mount with the entry %u! Can't load it!", mount_entry);
- return false;
- }
- }
- }
-
- CreatureModelInfo const *minfo = GetCreatureModelInfo(mount_id);
- if(!minfo)
- {
- sLog.outErrorDb("Taxi mount (Entry: %u) for taxi node (Id: %u) for team %u has model %u not found in table `creature_model_info`, can't load. ",
- mount_entry,id,team,mount_id);
-
- return false;
- }
- if(minfo->modelid_other_gender!=0)
- mount_id = urand(0,1) ? mount_id : minfo->modelid_other_gender;
-
- return mount_id;
-}
-
-void ObjectMgr::GetTaxiPathNodes( uint32 path, Path &pathnodes, std::vector<uint32>& mapIds)
-{
- if(path >= sTaxiPathNodesByPath.size())
- return;
-
- TaxiPathNodeList& nodeList = sTaxiPathNodesByPath[path];
-
- pathnodes.Resize(nodeList.size());
- mapIds.resize(nodeList.size());
-
- for(size_t i = 0; i < nodeList.size(); ++i)
- {
- pathnodes[ i ].x = nodeList[i].x;
- pathnodes[ i ].y = nodeList[i].y;
- pathnodes[ i ].z = nodeList[i].z;
-
- mapIds[i] = nodeList[i].mapid;
- }
-}
-
-void ObjectMgr::GetTransportPathNodes( uint32 path, TransportPath &pathnodes )
-{
- if(path >= sTaxiPathNodesByPath.size())
- return;
-
- TaxiPathNodeList& nodeList = sTaxiPathNodesByPath[path];
-
- pathnodes.Resize(nodeList.size());
-
- for(size_t i = 0; i < nodeList.size(); ++i)
- {
- pathnodes[ i ].mapid = nodeList[i].mapid;
- pathnodes[ i ].x = nodeList[i].x;
- pathnodes[ i ].y = nodeList[i].y;
- pathnodes[ i ].z = nodeList[i].z;
- pathnodes[ i ].actionFlag = nodeList[i].actionFlag;
- pathnodes[ i ].delay = nodeList[i].delay;
- }
-}
-
-void ObjectMgr::LoadGraveyardZones()
-{
- mGraveYardMap.clear(); // need for reload case
-
- QueryResult *result = WorldDatabase.Query("SELECT id,ghost_zone,faction FROM game_graveyard_zone");
-
- uint32 count = 0;
-
- if( !result )
- {
- barGoLink bar( 1 );
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded %u graveyard-zone links", count );
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- ++count;
- bar.step();
-
- Field *fields = result->Fetch();
-
- uint32 safeLocId = fields[0].GetUInt32();
- uint32 zoneId = fields[1].GetUInt32();
- uint32 team = fields[2].GetUInt32();
-
- WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(safeLocId);
- if(!entry)
- {
- sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing graveyard (WorldSafeLocs.dbc id) %u, skipped.",safeLocId);
- continue;
- }
-
- AreaTableEntry const *areaEntry = GetAreaEntryByAreaID(zoneId);
- if(!areaEntry)
- {
- sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing zone id (%u), skipped.",zoneId);
- continue;
- }
-
- if(areaEntry->zone != 0)
- {
- sLog.outErrorDb("Table `game_graveyard_zone` has record subzone id (%u) instead of zone, skipped.",zoneId);
- continue;
- }
-
- if(team!=0 && team!=HORDE && team!=ALLIANCE)
- {
- sLog.outErrorDb("Table `game_graveyard_zone` has record for non player faction (%u), skipped.",team);
- continue;
- }
-
- if(!AddGraveYardLink(safeLocId,zoneId,team,false))
- sLog.outErrorDb("Table `game_graveyard_zone` has a duplicate record for Graveyard (ID: %u) and Zone (ID: %u), skipped.",safeLocId,zoneId);
- } while( result->NextRow() );
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u graveyard-zone links", count );
-}
-
-WorldSafeLocsEntry const *ObjectMgr::GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team)
-{
- // search for zone associated closest graveyard
- uint32 zoneId = MapManager::Instance().GetZoneId(MapId,x,y);
-
- // Simulate std. algorithm:
- // found some graveyard associated to (ghost_zone,ghost_map)
- //
- // if mapId == graveyard.mapId (ghost in plain zone or city or battleground) and search graveyard at same map
- // then check faction
- // if mapId != graveyard.mapId (ghost in instance) and search any graveyard associated
- // then check faction
- GraveYardMap::const_iterator graveLow = mGraveYardMap.lower_bound(zoneId);
- GraveYardMap::const_iterator graveUp = mGraveYardMap.upper_bound(zoneId);
- if(graveLow==graveUp)
- {
- sLog.outErrorDb("Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.",zoneId,team);
- return NULL;
- }
-
- // at corpse map
- bool foundNear = false;
- float distNear;
- WorldSafeLocsEntry const* entryNear = NULL;
-
- // at entrance map for corpse map
- bool foundEntr = false;
- float distEntr;
- WorldSafeLocsEntry const* entryEntr = NULL;
-
- // some where other
- WorldSafeLocsEntry const* entryFar = NULL;
-
- MapEntry const* mapEntry = sMapStore.LookupEntry(MapId);
-
- for(GraveYardMap::const_iterator itr = graveLow; itr != graveUp; ++itr)
- {
- GraveYardData const& data = itr->second;
-
- WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(data.safeLocId);
- if(!entry)
- {
- sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing graveyard (WorldSafeLocs.dbc id) %u, skipped.",data.safeLocId);
- continue;
- }
-
- // skip enemy faction graveyard
- // team == 0 case can be at call from .neargrave
- if(data.team != 0 && team != 0 && data.team != team)
- continue;
-
- // find now nearest graveyard at other map
- if(MapId != entry->map_id)
- {
- // if find graveyard at different map from where entrance placed (or no entrance data), use any first
- if (!mapEntry || mapEntry->entrance_map < 0 || mapEntry->entrance_map != entry->map_id ||
- mapEntry->entrance_x == 0 && mapEntry->entrance_y == 0)
- {
- // not have any corrdinates for check distance anyway
- entryFar = entry;
- continue;
- }
-
- // at entrance map calculate distance (2D);
- float dist2 = (entry->x - mapEntry->entrance_x)*(entry->x - mapEntry->entrance_x)
- +(entry->y - mapEntry->entrance_y)*(entry->y - mapEntry->entrance_y);
- if(foundEntr)
- {
- if(dist2 < distEntr)
- {
- distEntr = dist2;
- entryEntr = entry;
- }
- }
- else
- {
- foundEntr = true;
- distEntr = dist2;
- entryEntr = entry;
- }
- }
- // find now nearest graveyard at same map
- else
- {
- float dist2 = (entry->x - x)*(entry->x - x)+(entry->y - y)*(entry->y - y)+(entry->z - z)*(entry->z - z);
- if(foundNear)
- {
- if(dist2 < distNear)
- {
- distNear = dist2;
- entryNear = entry;
- }
- }
- else
- {
- foundNear = true;
- distNear = dist2;
- entryNear = entry;
- }
- }
- }
-
- if(entryNear)
- return entryNear;
-
- if(entryEntr)
- return entryEntr;
-
- return entryFar;
-}
-
-GraveYardData const* ObjectMgr::FindGraveYardData(uint32 id, uint32 zoneId)
-{
- GraveYardMap::const_iterator graveLow = mGraveYardMap.lower_bound(zoneId);
- GraveYardMap::const_iterator graveUp = mGraveYardMap.upper_bound(zoneId);
-
- for(GraveYardMap::const_iterator itr = graveLow; itr != graveUp; ++itr)
- {
- if(itr->second.safeLocId==id)
- return &itr->second;
- }
-
- return NULL;
-}
-
-bool ObjectMgr::AddGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool inDB)
-{
- if(FindGraveYardData(id,zoneId))
- return false;
-
- // add link to loaded data
- GraveYardData data;
- data.safeLocId = id;
- data.team = team;
-
- mGraveYardMap.insert(GraveYardMap::value_type(zoneId,data));
-
- // add link to DB
- if(inDB)
- {
- WorldDatabase.PExecuteLog("INSERT INTO game_graveyard_zone ( id,ghost_zone,faction) "
- "VALUES ('%u', '%u','%u')",id,zoneId,team);
- }
-
- return true;
-}
-
-void ObjectMgr::RemoveGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool inDB)
-{
- GraveYardMap::iterator graveLow = mGraveYardMap.lower_bound(zoneId);
- GraveYardMap::iterator graveUp = mGraveYardMap.upper_bound(zoneId);
- if(graveLow==graveUp)
- {
- //sLog.outErrorDb("Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.",zoneId,team);
- return;
- }
-
- bool found = false;
-
- GraveYardMap::iterator itr;
-
- for(itr = graveLow; itr != graveUp; ++itr)
- {
- GraveYardData & data = itr->second;
-
- // skip not matching safezone id
- if(data.safeLocId != id)
- continue;
-
- // skip enemy faction graveyard at same map (normal area, city, or battleground)
- // team == 0 case can be at call from .neargrave
- if(data.team != 0 && team != 0 && data.team != team)
- continue;
-
- found = true;
- break;
- }
-
- // no match, return
- if(!found)
- return;
-
- // remove from links
- mGraveYardMap.erase(itr);
-
- // remove link from DB
- if(inDB)
- {
- WorldDatabase.PExecute("DELETE FROM game_graveyard_zone WHERE id = '%u' AND ghost_zone = '%u' AND faction = '%u'",id,zoneId,team);
- }
-
- return;
-}
-
-
-void ObjectMgr::LoadAreaTriggerTeleports()
-{
- mAreaTriggers.clear(); // need for reload case
-
- uint32 count = 0;
-
- // 0 1 2 3 4 5 6 7 8 9 10 11 12
- QueryResult *result = WorldDatabase.Query("SELECT id, required_level, required_item, required_item2, heroic_key, heroic_key2, required_quest_done, required_failed_text, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM areatrigger_teleport");
- if( !result )
- {
-
- barGoLink bar( 1 );
-
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded %u area trigger teleport definitions", count );
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- Field *fields = result->Fetch();
-
- bar.step();
-
- ++count;
-
- uint32 Trigger_ID = fields[0].GetUInt32();
-
- AreaTrigger at;
-
- at.requiredLevel = fields[1].GetUInt8();
- at.requiredItem = fields[2].GetUInt32();
- at.requiredItem2 = fields[3].GetUInt32();
- at.heroicKey = fields[4].GetUInt32();
- at.heroicKey2 = fields[5].GetUInt32();
- at.requiredQuest = fields[6].GetUInt32();
- at.requiredFailedText = fields[7].GetCppString();
- at.target_mapId = fields[8].GetUInt32();
- at.target_X = fields[9].GetFloat();
- at.target_Y = fields[10].GetFloat();
- at.target_Z = fields[11].GetFloat();
- at.target_Orientation = fields[12].GetFloat();
-
- AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
- if(!atEntry)
- {
- sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID);
- continue;
- }
-
- if(at.requiredItem)
- {
- ItemPrototype const *pProto = GetItemPrototype(at.requiredItem);
- if(!pProto)
- {
- sLog.outError("Key item %u does not exist for trigger %u, removing key requirement.", at.requiredItem, Trigger_ID);
- at.requiredItem = 0;
- }
- }
- if(at.requiredItem2)
- {
- ItemPrototype const *pProto = GetItemPrototype(at.requiredItem2);
- if(!pProto)
- {
- sLog.outError("Second item %u not exist for trigger %u, remove key requirement.", at.requiredItem2, Trigger_ID);
- at.requiredItem2 = 0;
- }
- }
-
- if(at.heroicKey)
- {
- ItemPrototype const *pProto = GetItemPrototype(at.heroicKey);
- if(!pProto)
- {
- sLog.outError("Heroic key item %u not exist for trigger %u, remove key requirement.", at.heroicKey, Trigger_ID);
- at.heroicKey = 0;
- }
- }
-
- if(at.heroicKey2)
- {
- ItemPrototype const *pProto = GetItemPrototype(at.heroicKey2);
- if(!pProto)
- {
- sLog.outError("Heroic second key item %u not exist for trigger %u, remove key requirement.", at.heroicKey2, Trigger_ID);
- at.heroicKey2 = 0;
- }
- }
-
- if(at.requiredQuest)
- {
- if(!mQuestTemplates[at.requiredQuest])
- {
- sLog.outErrorDb("Required Quest %u not exist for trigger %u, remove quest done requirement.",at.requiredQuest,Trigger_ID);
- at.requiredQuest = 0;
- }
- }
-
- MapEntry const* mapEntry = sMapStore.LookupEntry(at.target_mapId);
- if(!mapEntry)
- {
- sLog.outErrorDb("Area trigger (ID:%u) target map (ID: %u) does not exist in `Map.dbc`.",Trigger_ID,at.target_mapId);
- continue;
- }
-
- if(at.target_X==0 && at.target_Y==0 && at.target_Z==0)
- {
- sLog.outErrorDb("Area trigger (ID:%u) target coordinates not provided.",Trigger_ID);
- continue;
- }
-
- mAreaTriggers[Trigger_ID] = at;
-
- } while( result->NextRow() );
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u area trigger teleport definitions", count );
-}
-
-AreaTrigger const* ObjectMgr::GetGoBackTrigger(uint32 Map) const
-{
- const MapEntry *mapEntry = sMapStore.LookupEntry(Map);
- if(!mapEntry) return NULL;
- for (AreaTriggerMap::const_iterator itr = mAreaTriggers.begin(); itr != mAreaTriggers.end(); itr++)
- {
- if(itr->second.target_mapId == mapEntry->entrance_map)
- {
- AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(itr->first);
- if(atEntry && atEntry->mapid == Map)
- return &itr->second;
- }
- }
- return NULL;
-}
-
-void ObjectMgr::SetHighestGuids()
-{
- QueryResult *result = CharacterDatabase.Query( "SELECT MAX(guid) FROM characters" );
- if( result )
- {
- m_hiCharGuid = (*result)[0].GetUInt32()+1;
- delete result;
- }
-
- result = WorldDatabase.Query( "SELECT MAX(guid) FROM creature" );
- if( result )
- {
- m_hiCreatureGuid = (*result)[0].GetUInt32()+1;
- delete result;
- }
-
- // pet guids are not saved to DB, set to 0 (pet guid != pet id)
- m_hiPetGuid = 0;
-
- result = CharacterDatabase.Query( "SELECT MAX(guid) FROM item_instance" );
- if( result )
- {
- m_hiItemGuid = (*result)[0].GetUInt32()+1;
- delete result;
- }
-
- // Cleanup other tables from not existed guids (>=m_hiItemGuid)
- CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item >= '%u'", m_hiItemGuid);
- CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid >= '%u'", m_hiItemGuid);
- CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE itemguid >= '%u'", m_hiItemGuid);
- CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE item_guid >= '%u'", m_hiItemGuid);
-
- result = WorldDatabase.Query("SELECT MAX(guid) FROM gameobject" );
- if( result )
- {
- m_hiGoGuid = (*result)[0].GetUInt32()+1;
- delete result;
- }
-
- result = CharacterDatabase.Query("SELECT MAX(id) FROM auctionhouse" );
- if( result )
- {
- m_auctionid = (*result)[0].GetUInt32()+1;
- delete result;
- }
-
- result = CharacterDatabase.Query( "SELECT MAX(id) FROM mail" );
- if( result )
- {
- m_mailid = (*result)[0].GetUInt32()+1;
- delete result;
- }
-
- result = CharacterDatabase.Query( "SELECT MAX(id) FROM item_text" );
- if( result )
- {
- m_ItemTextId = (*result)[0].GetUInt32()+1;
- delete result;
- }
-
- result = CharacterDatabase.Query( "SELECT MAX(guid) FROM corpse" );
- if( result )
- {
- m_hiCorpseGuid = (*result)[0].GetUInt32()+1;
- delete result;
- }
-
- result = CharacterDatabase.Query("SELECT MAX(arenateamid) FROM arena_team");
- if (result)
- {
- m_arenaTeamId = (*result)[0].GetUInt32()+1;
- delete result;
- }
-
- result = CharacterDatabase.Query( "SELECT MAX(guildid) FROM guild" );
- if (result)
- {
- m_guildId = (*result)[0].GetUInt32()+1;
- delete result;
- }
-}
-
-uint32 ObjectMgr::GenerateArenaTeamId()
-{
- if(m_arenaTeamId>=0xFFFFFFFE)
- {
- sLog.outError("Arena team ids overflow!! Can't continue, shutting down server. ");
- World::StopNow(ERROR_EXIT_CODE);
- }
- return m_arenaTeamId++;
-}
-
-uint32 ObjectMgr::GenerateGuildId()
-{
- if(m_guildId>=0xFFFFFFFE)
- {
- sLog.outError("Guild ids overflow!! Can't continue, shutting down server. ");
- World::StopNow(ERROR_EXIT_CODE);
- }
- return m_guildId++;
-}
-
-uint32 ObjectMgr::GenerateAuctionID()
-{
- if(m_auctionid>=0xFFFFFFFE)
- {
- sLog.outError("Auctions ids overflow!! Can't continue, shutting down server. ");
- World::StopNow(ERROR_EXIT_CODE);
- }
- return m_auctionid++;
-}
-
-uint32 ObjectMgr::GenerateMailID()
-{
- if(m_mailid>=0xFFFFFFFE)
- {
- sLog.outError("Mail ids overflow!! Can't continue, shutting down server. ");
- World::StopNow(ERROR_EXIT_CODE);
- }
- return m_mailid++;
-}
-
-uint32 ObjectMgr::GenerateItemTextID()
-{
- if(m_ItemTextId>=0xFFFFFFFE)
- {
- sLog.outError("Item text ids overflow!! Can't continue, shutting down server. ");
- World::StopNow(ERROR_EXIT_CODE);
- }
- return m_ItemTextId++;
-}
-
-uint32 ObjectMgr::CreateItemText(std::string text)
-{
- uint32 newItemTextId = GenerateItemTextID();
- //insert new itempage to container
- mItemTexts[ newItemTextId ] = text;
- //save new itempage
- CharacterDatabase.escape_string(text);
- //any Delete query needed, itemTextId is maximum of all ids
- std::ostringstream query;
- query << "INSERT INTO item_text (id,text) VALUES ( '" << newItemTextId << "', '" << text << "')";
- CharacterDatabase.Execute(query.str().c_str()); //needs to be run this way, because mail body may be more than 1024 characters
- return newItemTextId;
-}
-
-uint32 ObjectMgr::GenerateLowGuid(HighGuid guidhigh)
-{
- switch(guidhigh)
- {
- case HIGHGUID_ITEM:
- if(m_hiItemGuid>=0xFFFFFFFE)
- {
- sLog.outError("Item guid overflow!! Can't continue, shutting down server. ");
- World::StopNow(ERROR_EXIT_CODE);
- }
- return m_hiItemGuid++;
- case HIGHGUID_UNIT:
- if(m_hiCreatureGuid>=0x00FFFFFE)
- {
- sLog.outError("Creature guid overflow!! Can't continue, shutting down server. ");
- World::StopNow(ERROR_EXIT_CODE);
- }
- return m_hiCreatureGuid++;
- case HIGHGUID_PET:
- if(m_hiPetGuid>=0x00FFFFFE)
- {
- sLog.outError("Pet guid overflow!! Can't continue, shutting down server. ");
- World::StopNow(ERROR_EXIT_CODE);
- }
- return m_hiPetGuid++;
- case HIGHGUID_PLAYER:
- if(m_hiCharGuid>=0xFFFFFFFE)
- {
- sLog.outError("Players guid overflow!! Can't continue, shutting down server. ");
- World::StopNow(ERROR_EXIT_CODE);
- }
- return m_hiCharGuid++;
- case HIGHGUID_GAMEOBJECT:
- if(m_hiGoGuid>=0x00FFFFFE)
- {
- sLog.outError("Gameobject guid overflow!! Can't continue, shutting down server. ");
- World::StopNow(ERROR_EXIT_CODE);
- }
- return m_hiGoGuid++;
- case HIGHGUID_CORPSE:
- if(m_hiCorpseGuid>=0xFFFFFFFE)
- {
- sLog.outError("Corpse guid overflow!! Can't continue, shutting down server. ");
- World::StopNow(ERROR_EXIT_CODE);
- }
- return m_hiCorpseGuid++;
- case HIGHGUID_DYNAMICOBJECT:
- if(m_hiDoGuid>=0xFFFFFFFE)
- {
- sLog.outError("DynamicObject guid overflow!! Can't continue, shutting down server. ");
- World::StopNow(ERROR_EXIT_CODE);
- }
- return m_hiDoGuid++;
- default:
- ASSERT(0);
- }
-
- ASSERT(0);
- return 0;
-}
-
-void ObjectMgr::LoadGameObjectLocales()
-{
- mGameObjectLocaleMap.clear(); // need for reload case
-
- QueryResult *result = WorldDatabase.Query("SELECT entry,"
- "name_loc1,name_loc2,name_loc3,name_loc4,name_loc5,name_loc6,name_loc7,name_loc8,"
- "castbarcaption_loc1,castbarcaption_loc2,castbarcaption_loc3,castbarcaption_loc4,"
- "castbarcaption_loc5,castbarcaption_loc6,castbarcaption_loc7,castbarcaption_loc8 FROM locales_gameobject");
-
- if(!result)
- {
- barGoLink bar(1);
-
- bar.step();
-
- sLog.outString("");
- sLog.outString(">> Loaded 0 gameobject locale strings. DB table `locales_gameobject` is empty.");
- return;
- }
-
- barGoLink bar(result->GetRowCount());
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- uint32 entry = fields[0].GetUInt32();
-
- GameObjectLocale& data = mGameObjectLocaleMap[entry];
-
- for(int i = 1; i < MAX_LOCALE; ++i)
- {
- std::string str = fields[i].GetCppString();
- if(!str.empty())
- {
- int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
- {
- if(data.Name.size() <= idx)
- data.Name.resize(idx+1);
-
- data.Name[idx] = str;
- }
- }
- }
-
- for(int i = MAX_LOCALE; i < MAX_LOCALE*2-1; ++i)
- {
- std::string str = fields[i].GetCppString();
- if(!str.empty())
- {
- int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
- {
- if(data.CastBarCaption.size() <= idx)
- data.CastBarCaption.resize(idx+1);
-
- data.CastBarCaption[idx] = str;
- }
- }
- }
-
- } while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u gameobject locale strings", mGameObjectLocaleMap.size() );
-}
-
-struct SQLGameObjectLoader : public SQLStorageLoaderBase<SQLGameObjectLoader>
-{
- template<class D>
- void convert_from_str(uint32 field_pos, char *src, D &dst)
- {
- dst = D(objmgr.GetScriptId(src));
- }
-};
-
-void ObjectMgr::LoadGameobjectInfo()
-{
- SQLGameObjectLoader loader;
- loader.Load(sGOStorage);
-
- // some checks
- for(uint32 id = 1; id < sGOStorage.MaxEntry; id++)
- {
- GameObjectInfo const* goInfo = sGOStorage.LookupEntry<GameObjectInfo>(id);
- if(!goInfo)
- continue;
-
- switch(goInfo->type)
- {
- case GAMEOBJECT_TYPE_DOOR: //0
- {
- if(goInfo->door.lockId)
- {
- if(!sLockStore.LookupEntry(goInfo->door.lockId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but lock (Id: %u) not found.",
- id,goInfo->type,goInfo->door.lockId,goInfo->door.lockId);
- }
- break;
- }
- case GAMEOBJECT_TYPE_BUTTON: //1
- {
- if(goInfo->button.lockId)
- {
- if(!sLockStore.LookupEntry(goInfo->button.lockId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but lock (Id: %u) not found.",
- id,goInfo->type,goInfo->button.lockId,goInfo->button.lockId);
- }
- break;
- }
- case GAMEOBJECT_TYPE_CHEST: //3
- {
- if(goInfo->chest.lockId)
- {
- if(!sLockStore.LookupEntry(goInfo->chest.lockId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but lock (Id: %u) not found.",
- id,goInfo->type,goInfo->chest.lockId,goInfo->chest.lockId);
- }
- if(goInfo->chest.linkedTrapId) // linked trap
- {
- if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->chest.linkedTrapId))
- {
- if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
- id,goInfo->type,goInfo->chest.linkedTrapId,goInfo->chest.linkedTrapId,GAMEOBJECT_TYPE_TRAP);
- }
- /* disable check for while
- else
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
- id,goInfo->type,goInfo->chest.linkedTrapId,goInfo->chest.linkedTrapId);
- */
- }
- break;
- }
- case GAMEOBJECT_TYPE_TRAP: //6
- {
- /* disable check for while
- if(goInfo->trap.spellId) // spell
- {
- if(!sSpellStore.LookupEntry(goInfo->trap.spellId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data3=%u but Spell (Entry %u) not exist.",
- id,goInfo->type,goInfo->trap.spellId,goInfo->trap.spellId);
- }
- */
- break;
- }
- case GAMEOBJECT_TYPE_CHAIR: //7
- if(goInfo->chair.height > 2)
- {
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but correct chair height in range 0..2.",
- id,goInfo->type,goInfo->chair.height);
-
- // prevent client and server unexpected work
- const_cast<GameObjectInfo*>(goInfo)->chair.height = 0;
- }
- break;
- case GAMEOBJECT_TYPE_SPELL_FOCUS: //8
- {
- if(goInfo->spellFocus.focusId)
- {
- if(!sSpellFocusObjectStore.LookupEntry(goInfo->spellFocus.focusId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but SpellFocus (Id: %u) not exist.",
- id,goInfo->type,goInfo->spellFocus.focusId,goInfo->spellFocus.focusId);
- }
-
- if(goInfo->spellFocus.linkedTrapId) // linked trap
- {
- if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->spellFocus.linkedTrapId))
- {
- if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
- id,goInfo->type,goInfo->spellFocus.linkedTrapId,goInfo->spellFocus.linkedTrapId,GAMEOBJECT_TYPE_TRAP);
- }
- /* disable check for while
- else
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
- id,goInfo->type,goInfo->spellFocus.linkedTrapId,goInfo->spellFocus.linkedTrapId);
- */
- }
- break;
- }
- case GAMEOBJECT_TYPE_GOOBER: //10
- {
- if(goInfo->goober.pageId) // pageId
- {
- if(!sPageTextStore.LookupEntry<PageText>(goInfo->goober.pageId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but PageText (Entry %u) not exist.",
- id,goInfo->type,goInfo->goober.pageId,goInfo->goober.pageId);
- }
- /* disable check for while
- if(goInfo->goober.spellId) // spell
- {
- if(!sSpellStore.LookupEntry(goInfo->goober.spellId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but Spell (Entry %u) not exist.",
- id,goInfo->type,goInfo->goober.spellId,goInfo->goober.spellId);
- }
- */
- if(goInfo->goober.linkedTrapId) // linked trap
- {
- if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->goober.linkedTrapId))
- {
- if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data12=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
- id,goInfo->type,goInfo->goober.linkedTrapId,goInfo->goober.linkedTrapId,GAMEOBJECT_TYPE_TRAP);
- }
- /* disable check for while
- else
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data12=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
- id,goInfo->type,goInfo->goober.linkedTrapId,goInfo->goober.linkedTrapId);
- */
- }
- break;
- }
- case GAMEOBJECT_TYPE_MO_TRANSPORT: //15
- {
- if(goInfo->moTransport.taxiPathId)
- {
- if(goInfo->moTransport.taxiPathId >= sTaxiPathNodesByPath.size() || sTaxiPathNodesByPath[goInfo->moTransport.taxiPathId].empty())
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but TaxiPath (Id: %u) not exist.",
- id,goInfo->type,goInfo->moTransport.taxiPathId,goInfo->moTransport.taxiPathId);
- }
- break;
- }
- case GAMEOBJECT_TYPE_SUMMONING_RITUAL: //18
- {
- /* disabled
- if(goInfo->summoningRitual.spellId)
- {
- if(!sSpellStore.LookupEntry(goInfo->summoningRitual.spellId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but Spell (Entry %u) not exist.",
- id,goInfo->type,goInfo->summoningRitual.spellId,goInfo->summoningRitual.spellId);
- }
- */
- break;
- }
- case GAMEOBJECT_TYPE_SPELLCASTER: //22
- {
- if(goInfo->spellcaster.spellId) // spell
- {
- if(!sSpellStore.LookupEntry(goInfo->spellcaster.spellId))
- sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data3=%u but Spell (Entry %u) not exist.",
- id,goInfo->type,goInfo->spellcaster.spellId,goInfo->spellcaster.spellId);
- }
- break;
- }
- }
- }
-
- sLog.outString( ">> Loaded %u game object templates", sGOStorage.RecordCount );
- sLog.outString();
-}
-
-void ObjectMgr::LoadExplorationBaseXP()
-{
- uint32 count = 0;
- QueryResult *result = WorldDatabase.Query("SELECT level,basexp FROM exploration_basexp");
-
- if( !result )
- {
- barGoLink bar( 1 );
-
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded %u BaseXP definitions", count );
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- bar.step();
-
- Field *fields = result->Fetch();
- uint32 level = fields[0].GetUInt32();
- uint32 basexp = fields[1].GetUInt32();
- mBaseXPTable[level] = basexp;
- ++count;
- }
- while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u BaseXP definitions", count );
-}
-
-uint32 ObjectMgr::GetBaseXP(uint32 level)
-{
- return mBaseXPTable[level] ? mBaseXPTable[level] : 0;
-}
-
-void ObjectMgr::LoadPetNames()
-{
- uint32 count = 0;
- QueryResult *result = WorldDatabase.Query("SELECT word,entry,half FROM pet_name_generation");
-
- if( !result )
- {
- barGoLink bar( 1 );
-
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded %u pet name parts", count );
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- bar.step();
-
- Field *fields = result->Fetch();
- std::string word = fields[0].GetString();
- uint32 entry = fields[1].GetUInt32();
- bool half = fields[2].GetBool();
- if(half)
- PetHalfName1[entry].push_back(word);
- else
- PetHalfName0[entry].push_back(word);
- ++count;
- }
- while (result->NextRow());
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u pet name parts", count );
-}
-
-void ObjectMgr::LoadPetNumber()
-{
- QueryResult* result = CharacterDatabase.Query("SELECT MAX(id) FROM character_pet");
- if(result)
- {
- Field *fields = result->Fetch();
- m_hiPetNumber = fields[0].GetUInt32()+1;
- delete result;
- }
-
- barGoLink bar( 1 );
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded the max pet number: %d", m_hiPetNumber-1);
-}
-
-std::string ObjectMgr::GeneratePetName(uint32 entry)
-{
- std::vector<std::string> & list0 = PetHalfName0[entry];
- std::vector<std::string> & list1 = PetHalfName1[entry];
-
- if(list0.empty() || list1.empty())
- {
- CreatureInfo const *cinfo = GetCreatureTemplate(entry);
- char* petname = GetPetName(cinfo->family, sWorld.GetDefaultDbcLocale());
- if(!petname)
- petname = cinfo->Name;
- return std::string(petname);
- }
-
- return *(list0.begin()+urand(0, list0.size()-1)) + *(list1.begin()+urand(0, list1.size()-1));
-}
-
-uint32 ObjectMgr::GeneratePetNumber()
-{
- return ++m_hiPetNumber;
-}
-
-void ObjectMgr::LoadCorpses()
-{
- uint32 count = 0;
- // 0 1 2 3 4 5 6 7 8 10
- QueryResult *result = CharacterDatabase.Query("SELECT position_x, position_y, position_z, orientation, map, data, time, corpse_type, instance, guid FROM corpse WHERE corpse_type <> 0");
-
- if( !result )
- {
- barGoLink bar( 1 );
-
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded %u corpses", count );
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- bar.step();
-
- Field *fields = result->Fetch();
-
- uint32 guid = fields[result->GetFieldCount()-1].GetUInt32();
-
- Corpse *corpse = new Corpse;
- if(!corpse->LoadFromDB(guid,fields))
- {
- delete corpse;
- continue;
- }
-
- ObjectAccessor::Instance().AddCorpse(corpse);
-
- ++count;
- }
- while (result->NextRow());
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u corpses", count );
-}
-
-void ObjectMgr::LoadReputationOnKill()
-{
- uint32 count = 0;
-
- // 0 1 2
- QueryResult *result = WorldDatabase.Query("SELECT creature_id, RewOnKillRepFaction1, RewOnKillRepFaction2,"
- // 3 4 5 6 7 8 9
- "IsTeamAward1, MaxStanding1, RewOnKillRepValue1, IsTeamAward2, MaxStanding2, RewOnKillRepValue2, TeamDependent "
- "FROM creature_onkill_reputation");
-
- if(!result)
- {
- barGoLink bar(1);
-
- bar.step();
-
- sLog.outString();
- sLog.outErrorDb(">> Loaded 0 creature award reputation definitions. DB table `creature_onkill_reputation` is empty.");
- return;
- }
-
- barGoLink bar(result->GetRowCount());
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- uint32 creature_id = fields[0].GetUInt32();
-
- ReputationOnKillEntry repOnKill;
- repOnKill.repfaction1 = fields[1].GetUInt32();
- repOnKill.repfaction2 = fields[2].GetUInt32();
- repOnKill.is_teamaward1 = fields[3].GetBool();
- repOnKill.reputation_max_cap1 = fields[4].GetUInt32();
- repOnKill.repvalue1 = fields[5].GetInt32();
- repOnKill.is_teamaward2 = fields[6].GetBool();
- repOnKill.reputation_max_cap2 = fields[7].GetUInt32();
- repOnKill.repvalue2 = fields[8].GetInt32();
- repOnKill.team_dependent = fields[9].GetUInt8();
-
- if(!GetCreatureTemplate(creature_id))
- {
- sLog.outErrorDb("Table `creature_onkill_reputation` have data for not existed creature entry (%u), skipped",creature_id);
- continue;
- }
-
- if(repOnKill.repfaction1)
- {
- FactionEntry const *factionEntry1 = sFactionStore.LookupEntry(repOnKill.repfaction1);
- if(!factionEntry1)
- {
- sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `creature_onkill_reputation`",repOnKill.repfaction1);
- continue;
- }
- }
-
- if(repOnKill.repfaction2)
- {
- FactionEntry const *factionEntry2 = sFactionStore.LookupEntry(repOnKill.repfaction2);
- if(!factionEntry2)
- {
- sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `creature_onkill_reputation`",repOnKill.repfaction2);
- continue;
- }
- }
-
- mRepOnKill[creature_id] = repOnKill;
-
- ++count;
- } while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString(">> Loaded %u creature award reputation definitions", count);
-}
-
-void ObjectMgr::LoadWeatherZoneChances()
-{
- uint32 count = 0;
-
- // 0 1 2 3 4 5 6 7 8 9 10 11 12
- QueryResult *result = WorldDatabase.Query("SELECT zone, spring_rain_chance, spring_snow_chance, spring_storm_chance, summer_rain_chance, summer_snow_chance, summer_storm_chance, fall_rain_chance, fall_snow_chance, fall_storm_chance, winter_rain_chance, winter_snow_chance, winter_storm_chance FROM game_weather");
-
- if(!result)
- {
- barGoLink bar(1);
-
- bar.step();
-
- sLog.outString();
- sLog.outErrorDb(">> Loaded 0 weather definitions. DB table `game_weather` is empty.");
- return;
- }
-
- barGoLink bar(result->GetRowCount());
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- uint32 zone_id = fields[0].GetUInt32();
-
- WeatherZoneChances& wzc = mWeatherZoneMap[zone_id];
-
- for(int season = 0; season < WEATHER_SEASONS; ++season)
- {
- wzc.data[season].rainChance = fields[season * (MAX_WEATHER_TYPE-1) + 1].GetUInt32();
- wzc.data[season].snowChance = fields[season * (MAX_WEATHER_TYPE-1) + 2].GetUInt32();
- wzc.data[season].stormChance = fields[season * (MAX_WEATHER_TYPE-1) + 3].GetUInt32();
-
- if(wzc.data[season].rainChance > 100)
- {
- wzc.data[season].rainChance = 25;
- sLog.outErrorDb("Weather for zone %u season %u has wrong rain chance > 100%",zone_id,season);
- }
-
- if(wzc.data[season].snowChance > 100)
- {
- wzc.data[season].snowChance = 25;
- sLog.outErrorDb("Weather for zone %u season %u has wrong snow chance > 100%",zone_id,season);
- }
-
- if(wzc.data[season].stormChance > 100)
- {
- wzc.data[season].stormChance = 25;
- sLog.outErrorDb("Weather for zone %u season %u has wrong storm chance > 100%",zone_id,season);
- }
- }
-
- ++count;
- } while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString(">> Loaded %u weather definitions", count);
-}
-
-void ObjectMgr::SaveCreatureRespawnTime(uint32 loguid, uint32 instance, time_t t)
-{
- mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)] = t;
- WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE guid = '%u' AND instance = '%u'", loguid, instance);
- if(t)
- WorldDatabase.PExecute("INSERT INTO creature_respawn VALUES ( '%u', '" I64FMTD "', '%u' )", loguid, uint64(t), instance);
-}
-
-void ObjectMgr::DeleteCreatureData(uint32 guid)
-{
- // remove mapid*cellid -> guid_set map
- CreatureData const* data = GetCreatureData(guid);
- if(data)
- RemoveCreatureFromGrid(guid, data);
-
- mCreatureDataMap.erase(guid);
-}
-
-void ObjectMgr::SaveGORespawnTime(uint32 loguid, uint32 instance, time_t t)
-{
- mGORespawnTimes[MAKE_PAIR64(loguid,instance)] = t;
- WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE guid = '%u' AND instance = '%u'", loguid, instance);
- if(t)
- WorldDatabase.PExecute("INSERT INTO gameobject_respawn VALUES ( '%u', '" I64FMTD "', '%u' )", loguid, uint64(t), instance);
-}
-
-void ObjectMgr::DeleteRespawnTimeForInstance(uint32 instance)
-{
- RespawnTimes::iterator next;
-
- for(RespawnTimes::iterator itr = mGORespawnTimes.begin(); itr != mGORespawnTimes.end(); itr = next)
- {
- next = itr;
- ++next;
-
- if(GUID_HIPART(itr->first)==instance)
- mGORespawnTimes.erase(itr);
- }
-
- for(RespawnTimes::iterator itr = mCreatureRespawnTimes.begin(); itr != mCreatureRespawnTimes.end(); itr = next)
- {
- next = itr;
- ++next;
-
- if(GUID_HIPART(itr->first)==instance)
- mCreatureRespawnTimes.erase(itr);
- }
-
- WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'", instance);
- WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'", instance);
-}
-
-void ObjectMgr::DeleteGOData(uint32 guid)
-{
- // remove mapid*cellid -> guid_set map
- GameObjectData const* data = GetGOData(guid);
- if(data)
- RemoveGameobjectFromGrid(guid, data);
-
- mGameObjectDataMap.erase(guid);
-}
-
-void ObjectMgr::AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance)
-{
- // corpses are always added to spawn mode 0 and they are spawned by their instance id
- CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(mapid,0)][cellid];
- cell_guids.corpses[player_guid] = instance;
-}
-
-void ObjectMgr::DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid)
-{
- // corpses are always added to spawn mode 0 and they are spawned by their instance id
- CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(mapid,0)][cellid];
- cell_guids.corpses.erase(player_guid);
-}
-
-void ObjectMgr::LoadQuestRelationsHelper(QuestRelations& map,char const* table)
-{
- map.clear(); // need for reload case
-
- uint32 count = 0;
-
- QueryResult *result = WorldDatabase.PQuery("SELECT id,quest FROM %s",table);
-
- if(!result)
- {
- barGoLink bar(1);
-
- bar.step();
-
- sLog.outString();
- sLog.outErrorDb(">> Loaded 0 quest relations from %s. DB table `%s` is empty.",table,table);
- return;
- }
-
- barGoLink bar(result->GetRowCount());
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- uint32 id = fields[0].GetUInt32();
- uint32 quest = fields[1].GetUInt32();
-
- if(mQuestTemplates.find(quest) == mQuestTemplates.end())
- {
- sLog.outErrorDb("Table `%s: Quest %u listed for entry %u does not exist.",table,quest,id);
- continue;
- }
-
- map.insert(QuestRelations::value_type(id,quest));
-
- ++count;
- } while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString(">> Loaded %u quest relations from %s", count,table);
-}
-
-void ObjectMgr::LoadGameobjectQuestRelations()
-{
- LoadQuestRelationsHelper(mGOQuestRelations,"gameobject_questrelation");
-
- for(QuestRelations::iterator itr = mGOQuestRelations.begin(); itr != mGOQuestRelations.end(); ++itr)
- {
- GameObjectInfo const* goInfo = GetGameObjectInfo(itr->first);
- if(!goInfo)
- sLog.outErrorDb("Table `gameobject_questrelation` have data for not existed gameobject entry (%u) and existed quest %u",itr->first,itr->second);
- else if(goInfo->type != GAMEOBJECT_TYPE_QUESTGIVER)
- sLog.outErrorDb("Table `gameobject_questrelation` have data gameobject entry (%u) for quest %u, but GO is not GAMEOBJECT_TYPE_QUESTGIVER",itr->first,itr->second);
- }
-}
-
-void ObjectMgr::LoadGameobjectInvolvedRelations()
-{
- LoadQuestRelationsHelper(mGOQuestInvolvedRelations,"gameobject_involvedrelation");
-
- for(QuestRelations::iterator itr = mGOQuestInvolvedRelations.begin(); itr != mGOQuestInvolvedRelations.end(); ++itr)
- {
- GameObjectInfo const* goInfo = GetGameObjectInfo(itr->first);
- if(!goInfo)
- sLog.outErrorDb("Table `gameobject_involvedrelation` have data for not existed gameobject entry (%u) and existed quest %u",itr->first,itr->second);
- else if(goInfo->type != GAMEOBJECT_TYPE_QUESTGIVER)
- sLog.outErrorDb("Table `gameobject_involvedrelation` have data gameobject entry (%u) for quest %u, but GO is not GAMEOBJECT_TYPE_QUESTGIVER",itr->first,itr->second);
- }
-}
-
-void ObjectMgr::LoadCreatureQuestRelations()
-{
- LoadQuestRelationsHelper(mCreatureQuestRelations,"creature_questrelation");
-
- for(QuestRelations::iterator itr = mCreatureQuestRelations.begin(); itr != mCreatureQuestRelations.end(); ++itr)
- {
- CreatureInfo const* cInfo = GetCreatureTemplate(itr->first);
- if(!cInfo)
- sLog.outErrorDb("Table `creature_questrelation` have data for not existed creature entry (%u) and existed quest %u",itr->first,itr->second);
- else if(!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER))
- sLog.outErrorDb("Table `creature_questrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER",itr->first,itr->second);
- }
-}
-
-void ObjectMgr::LoadCreatureInvolvedRelations()
-{
- LoadQuestRelationsHelper(mCreatureQuestInvolvedRelations,"creature_involvedrelation");
-
- for(QuestRelations::iterator itr = mCreatureQuestInvolvedRelations.begin(); itr != mCreatureQuestInvolvedRelations.end(); ++itr)
- {
- CreatureInfo const* cInfo = GetCreatureTemplate(itr->first);
- if(!cInfo)
- sLog.outErrorDb("Table `creature_involvedrelation` have data for not existed creature entry (%u) and existed quest %u",itr->first,itr->second);
- else if(!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER))
- sLog.outErrorDb("Table `creature_involvedrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER",itr->first,itr->second);
- }
-}
-
-void ObjectMgr::LoadReservedPlayersNames()
-{
- m_ReservedNames.clear(); // need for reload case
-
- QueryResult *result = WorldDatabase.Query("SELECT name FROM reserved_name");
-
- uint32 count = 0;
-
- if( !result )
- {
- barGoLink bar( 1 );
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded %u reserved player names", count );
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- Field* fields;
- do
- {
- bar.step();
- fields = result->Fetch();
- std::string name= fields[0].GetCppString();
- if(normalizePlayerName(name))
- {
- m_ReservedNames.insert(name);
- ++count;
- }
- } while ( result->NextRow() );
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u reserved player names", count );
-}
-
-enum LanguageType
-{
- LT_BASIC_LATIN = 0x0000,
- LT_EXTENDEN_LATIN = 0x0001,
- LT_CYRILLIC = 0x0002,
- LT_EAST_ASIA = 0x0004,
- LT_ANY = 0xFFFF
-};
-
-static LanguageType GetRealmLanguageType(bool create)
-{
- switch(sWorld.getConfig(CONFIG_REALM_ZONE))
- {
- case REALM_ZONE_UNKNOWN: // any language
- case REALM_ZONE_DEVELOPMENT:
- case REALM_ZONE_TEST_SERVER:
- case REALM_ZONE_QA_SERVER:
- return LT_ANY;
- case REALM_ZONE_UNITED_STATES: // extended-Latin
- case REALM_ZONE_OCEANIC:
- case REALM_ZONE_LATIN_AMERICA:
- case REALM_ZONE_ENGLISH:
- case REALM_ZONE_GERMAN:
- case REALM_ZONE_FRENCH:
- case REALM_ZONE_SPANISH:
- return LT_EXTENDEN_LATIN;
- case REALM_ZONE_KOREA: // East-Asian
- case REALM_ZONE_TAIWAN:
- case REALM_ZONE_CHINA:
- return LT_EAST_ASIA;
- case REALM_ZONE_RUSSIAN: // Cyrillic
- return LT_CYRILLIC;
- default:
- return create ? LT_BASIC_LATIN : LT_ANY; // basic-Latin at create, any at login
- }
-}
-
-bool isValidString(std::wstring wstr, uint32 strictMask, bool numericOrSpace, bool create = false)
-{
- if(strictMask==0) // any language, ignore realm
- {
- if(isExtendedLatinString(wstr,numericOrSpace))
- return true;
- if(isCyrillicString(wstr,numericOrSpace))
- return true;
- if(isEastAsianString(wstr,numericOrSpace))
- return true;
- return false;
- }
-
- if(strictMask & 0x2) // realm zone specific
- {
- LanguageType lt = GetRealmLanguageType(create);
- if(lt & LT_EXTENDEN_LATIN)
- if(isExtendedLatinString(wstr,numericOrSpace))
- return true;
- if(lt & LT_CYRILLIC)
- if(isCyrillicString(wstr,numericOrSpace))
- return true;
- if(lt & LT_EAST_ASIA)
- if(isEastAsianString(wstr,numericOrSpace))
- return true;
- }
-
- if(strictMask & 0x1) // basic Latin
- {
- if(isBasicLatinString(wstr,numericOrSpace))
- return true;
- }
-
- return false;
-}
-
-bool ObjectMgr::IsValidName( std::string name, bool create )
-{
- std::wstring wname;
- if(!Utf8toWStr(name,wname))
- return false;
-
- if(wname.size() < 1 || wname.size() > MAX_PLAYER_NAME)
- return false;
-
- uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PLAYER_NAMES);
-
- return isValidString(wname,strictMask,false,create);
-}
-
-bool ObjectMgr::IsValidCharterName( std::string name )
-{
- std::wstring wname;
- if(!Utf8toWStr(name,wname))
- return false;
-
- if(wname.size() < 1)
- return false;
-
- uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_CHARTER_NAMES);
-
- return isValidString(wname,strictMask,true);
-}
-
-bool ObjectMgr::IsValidPetName( std::string name )
-{
- std::wstring wname;
- if(!Utf8toWStr(name,wname))
- return false;
-
- if(wname.size() < 1)
- return false;
-
- uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PET_NAMES);
-
- return isValidString(wname,strictMask,false);
-}
-
-int ObjectMgr::GetIndexForLocale( LocaleConstant loc )
-{
- if(loc==LOCALE_enUS)
- return -1;
-
- for(size_t i=0;i < m_LocalForIndex.size(); ++i)
- if(m_LocalForIndex[i]==loc)
- return i;
-
- return -1;
-}
-
-LocaleConstant ObjectMgr::GetLocaleForIndex(int i)
-{
- if (i<0 || i>=m_LocalForIndex.size())
- return LOCALE_enUS;
-
- return m_LocalForIndex[i];
-}
-
-int ObjectMgr::GetOrNewIndexForLocale( LocaleConstant loc )
-{
- if(loc==LOCALE_enUS)
- return -1;
-
- for(size_t i=0;i < m_LocalForIndex.size(); ++i)
- if(m_LocalForIndex[i]==loc)
- return i;
-
- m_LocalForIndex.push_back(loc);
- return m_LocalForIndex.size()-1;
-}
-
-void ObjectMgr::LoadBattleMastersEntry()
-{
- mBattleMastersMap.clear(); // need for reload case
-
- QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" );
-
- uint32 count = 0;
-
- if( !result )
- {
- barGoLink bar( 1 );
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- ++count;
- bar.step();
-
- Field *fields = result->Fetch();
-
- uint32 entry = fields[0].GetUInt32();
- uint32 bgTypeId = fields[1].GetUInt32();
-
- mBattleMastersMap[entry] = bgTypeId;
-
- } while( result->NextRow() );
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u battlemaster entries", count );
-}
-
-void ObjectMgr::LoadGameObjectForQuests()
-{
- mGameObjectForQuestSet.clear(); // need for reload case
-
- uint32 count = 0;
-
- // collect GO entries for GO that must activated
- for(uint32 go_entry = 1; go_entry < sGOStorage.MaxEntry; ++go_entry)
- {
- GameObjectInfo const* goInfo = sGOStorage.LookupEntry<GameObjectInfo>(go_entry);
- if(!goInfo)
- continue;
-
- switch(goInfo->type)
- {
- // scan GO chest with loot including quest items
- case GAMEOBJECT_TYPE_CHEST:
- {
- uint32 loot_id = GameObject::GetLootId(goInfo);
-
- // find quest loot for GO
- if(LootTemplates_Gameobject.HaveQuestLootFor(loot_id))
- {
- mGameObjectForQuestSet.insert(go_entry);
- ++count;
- }
- break;
- }
- case GAMEOBJECT_TYPE_GOOBER:
- {
- if(goInfo->goober.questId) //quests objects
- {
- mGameObjectForQuestSet.insert(go_entry);
- count++;
- }
- break;
- }
- default:
- break;
- }
- }
-
- sLog.outString();
- sLog.outString( ">> Loaded %u GameObject for quests", count );
-}
-
-bool ObjectMgr::LoadTrinityStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value)
-{
- // cleanup affected map part for reloading case
- for(TrinityStringLocaleMap::iterator itr = mTrinityStringLocaleMap.begin(); itr != mTrinityStringLocaleMap.end();)
- {
- if(itr->first >= min_value && itr->first <= max_value)
- {
- TrinityStringLocaleMap::iterator itr2 = itr;
- ++itr;
- mTrinityStringLocaleMap.erase(itr2);
- }
- else
- ++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);
-
- if(!result)
- {
- barGoLink bar(1);
-
- bar.step();
-
- sLog.outString("");
- if(min_value > 0) // error only in case internal strings
- sLog.outErrorDb(">> Loaded 0 trinity strings. DB table `%s` is empty. Cannot continue.",table);
- else
- sLog.outString(">> Loaded 0 string templates. DB table `%s` is empty.",table);
- return false;
- }
-
- uint32 count = 0;
-
- barGoLink bar(result->GetRowCount());
-
- do
- {
- Field *fields = result->Fetch();
- bar.step();
-
- int32 entry = fields[0].GetInt32();
-
- if(entry==0)
- {
- sLog.outErrorDb("Table `%s` contain reserved entry 0, ignored.",table);
- continue;
- }
- else if(entry < min_value || entry > max_value)
- {
- int32 start = min_value > 0 ? min_value : max_value;
- int32 end = min_value > 0 ? max_value : min_value;
- sLog.outErrorDb("Table `%s` contain entry %i out of allowed range (%d - %d), ignored.",table,entry,start,end);
- continue;
- }
-
- TrinityStringLocale& data = mTrinityStringLocaleMap[entry];
-
- if(data.Content.size() > 0)
- {
- sLog.outErrorDb("Table `%s` contain data for already loaded entry %i (from another table?), ignored.",table,entry);
- continue;
- }
-
- data.Content.resize(1);
- ++count;
-
- // 0 -> default, idx in to idx+1
- data.Content[0] = fields[1].GetCppString();
-
- for(int i = 1; i < MAX_LOCALE; ++i)
- {
- std::string str = fields[i+1].GetCppString();
- if(!str.empty())
- {
- int idx = GetOrNewIndexForLocale(LocaleConstant(i));
- if(idx >= 0)
- {
- // 0 -> default, idx in to idx+1
- if(data.Content.size() <= idx+1)
- data.Content.resize(idx+2);
-
- data.Content[idx+1] = str;
- }
- }
- }
- } while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- if(min_value > 0) // internal Trinity strings
- sLog.outString( ">> Loaded %u Trinity strings from table %s", count,table);
- else
- sLog.outString( ">> Loaded %u string templates from %s", count,table);
-
- return true;
-}
-
-const char *ObjectMgr::GetTrinityString(int32 entry, int locale_idx) const
-{
- // locale_idx==-1 -> default, locale_idx >= 0 in to idx+1
- // Content[0] always exist if exist TrinityStringLocale
- if(TrinityStringLocale const *msl = GetTrinityStringLocale(entry))
- {
- if(msl->Content.size() > locale_idx+1 && !msl->Content[locale_idx+1].empty())
- return msl->Content[locale_idx+1].c_str();
- else
- return msl->Content[0].c_str();
- }
-
- if(entry > 0)
- sLog.outErrorDb("Entry %i not found in `trinity_string` table.",entry);
- else
- sLog.outErrorDb("Trinity string entry %i not found in DB.",entry);
- return "<error>";
-}
-
-void ObjectMgr::LoadSpellDisabledEntrys()
-{
- m_DisabledPlayerSpells.clear(); // need for reload case
- m_DisabledCreatureSpells.clear();
- QueryResult *result = WorldDatabase.Query("SELECT entry, disable_mask FROM spell_disabled");
-
- uint32 total_count = 0;
-
- if( !result )
- {
- barGoLink bar( 1 );
- bar.step();
-
- sLog.outString();
- sLog.outString( ">> Loaded %u disabled spells", total_count );
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- Field* fields;
- do
- {
- bar.step();
- fields = result->Fetch();
- uint32 spellid = fields[0].GetUInt32();
- if(!sSpellStore.LookupEntry(spellid))
- {
- sLog.outErrorDb("Spell entry %u from `spell_disabled` doesn't exist in dbc, ignoring.",spellid);
- continue;
- }
- uint32 disable_mask = fields[1].GetUInt32();
- if(disable_mask & SPELL_DISABLE_PLAYER)
- m_DisabledPlayerSpells.insert(spellid);
- if(disable_mask & SPELL_DISABLE_CREATURE)
- m_DisabledCreatureSpells.insert(spellid);
- ++total_count;
- } while ( result->NextRow() );
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u disabled spells from `spell_disabled`", total_count);
-}
-
-void ObjectMgr::LoadFishingBaseSkillLevel()
-{
- mFishingBaseForArea.clear(); // for reload case
-
- uint32 count = 0;
- QueryResult *result = WorldDatabase.Query("SELECT entry,skill FROM skill_fishing_base_level");
-
- if( !result )
- {
- barGoLink bar( 1 );
-
- bar.step();
-
- sLog.outString();
- sLog.outErrorDb(">> Loaded `skill_fishing_base_level`, table is empty!");
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- bar.step();
-
- Field *fields = result->Fetch();
- uint32 entry = fields[0].GetUInt32();
- int32 skill = fields[1].GetInt32();
-
- AreaTableEntry const* fArea = GetAreaEntryByAreaID(entry);
- if(!fArea)
- {
- sLog.outErrorDb("AreaId %u defined in `skill_fishing_base_level` does not exist",entry);
- continue;
- }
-
- mFishingBaseForArea[entry] = skill;
- ++count;
- }
- while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u areas for fishing base skill level", count );
-}
-
-// Searches for the same condition already in Conditions store
-// Returns Id if found, else adds it to Conditions and returns Id
-uint16 ObjectMgr::GetConditionId( ConditionType condition, uint32 value1, uint32 value2 )
-{
- PlayerCondition lc = PlayerCondition(condition, value1, value2);
- for (uint16 i=0; i < mConditions.size(); ++i)
- {
- if (lc == mConditions[i])
- return i;
- }
-
- mConditions.push_back(lc);
-
- if(mConditions.size() > 0xFFFF)
- {
- sLog.outError("Conditions store overflow! Current and later loaded conditions will ignored!");
- return 0;
- }
-
- return mConditions.size() - 1;
-}
-
-bool ObjectMgr::CheckDeclinedNames( std::wstring mainpart, DeclinedName const& names )
-{
- for(int i =0; i < MAX_DECLINED_NAME_CASES; ++i)
- {
- std::wstring wname;
- if(!Utf8toWStr(names.name[i],wname))
- return false;
-
- if(mainpart!=GetMainPartOfName(wname,i+1))
- return false;
- }
- return true;
-}
-
-uint32 ObjectMgr::GetAreaTriggerScriptId(uint32 trigger_id)
-{
- AreaTriggerScriptMap::const_iterator i = mAreaTriggerScripts.find(trigger_id);
- if(i!= mAreaTriggerScripts.end())
- return i->second;
- return 0;
-}
-
-// Checks if player meets the condition
-bool PlayerCondition::Meets(Player const * player) const
-{
- if( !player )
- return false; // player not present, return false
-
- switch (condition)
- {
- case CONDITION_NONE:
- return true; // empty condition, always met
- case CONDITION_AURA:
- return player->HasAura(value1, value2);
- case CONDITION_ITEM:
- return player->HasItemCount(value1, value2);
- case CONDITION_ITEM_EQUIPPED:
- return player->GetItemOrItemWithGemEquipped(value1) != NULL;
- case CONDITION_ZONEID:
- return player->GetZoneId() == value1;
- case CONDITION_REPUTATION_RANK:
- {
- FactionEntry const* faction = sFactionStore.LookupEntry(value1);
- return faction && player->GetReputationRank(faction) >= value2;
- }
- case CONDITION_TEAM:
- return player->GetTeam() == value1;
- case CONDITION_SKILL:
- return player->HasSkill(value1) && player->GetBaseSkillValue(value1) >= value2;
- case CONDITION_QUESTREWARDED:
- return player->GetQuestRewardStatus(value1);
- case CONDITION_QUESTTAKEN:
- {
- QuestStatus status = player->GetQuestStatus(value1);
- return (status == QUEST_STATUS_INCOMPLETE);
- }
- case CONDITION_AD_COMMISSION_AURA:
- {
- Unit::AuraMap const& auras = player->GetAuras();
- for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
- if((itr->second->GetSpellProto()->Attributes & 0x1000010) && itr->second->GetSpellProto()->SpellVisual==3580)
- return true;
- return false;
- }
- case CONDITION_NO_AURA:
- return !player->HasAura(value1, value2);
- case CONDITION_ACTIVE_EVENT:
- return gameeventmgr.IsActiveEvent(value1);
- default:
- return false;
- }
-}
-
-// Verification of condition values validity
-bool PlayerCondition::IsValid(ConditionType condition, uint32 value1, uint32 value2)
-{
- if( condition >= MAX_CONDITION) // Wrong condition type
- {
- sLog.outErrorDb("Condition has bad type of %u, skipped ", condition );
- return false;
- }
-
- switch (condition)
- {
- case CONDITION_AURA:
- {
- if(!sSpellStore.LookupEntry(value1))
- {
- sLog.outErrorDb("Aura condition requires to have non existing spell (Id: %d), skipped", value1);
- return false;
- }
- if(value2 > 2)
- {
- sLog.outErrorDb("Aura condition requires to have non existing effect index (%u) (must be 0..2), skipped", value2);
- return false;
- }
- break;
- }
- case CONDITION_ITEM:
- {
- ItemPrototype const *proto = objmgr.GetItemPrototype(value1);
- if(!proto)
- {
- sLog.outErrorDb("Item condition requires to have non existing item (%u), skipped", value1);
- return false;
- }
- break;
- }
- case CONDITION_ITEM_EQUIPPED:
- {
- ItemPrototype const *proto = objmgr.GetItemPrototype(value1);
- if(!proto)
- {
- sLog.outErrorDb("ItemEquipped condition requires to have non existing item (%u) equipped, skipped", value1);
- return false;
- }
- break;
- }
- case CONDITION_ZONEID:
- {
- AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(value1);
- if(!areaEntry)
- {
- sLog.outErrorDb("Zone condition requires to be in non existing area (%u), skipped", value1);
- return false;
- }
- if(areaEntry->zone != 0)
- {
- sLog.outErrorDb("Zone condition requires to be in area (%u) which is a subzone but zone expected, skipped", value1);
- return false;
- }
- break;
- }
- case CONDITION_REPUTATION_RANK:
- {
- FactionEntry const* factionEntry = sFactionStore.LookupEntry(value1);
- if(!factionEntry)
- {
- sLog.outErrorDb("Reputation condition requires to have reputation non existing faction (%u), skipped", value1);
- return false;
- }
- break;
- }
- case CONDITION_TEAM:
- {
- if (value1 != ALLIANCE && value1 != HORDE)
- {
- sLog.outErrorDb("Team condition specifies unknown team (%u), skipped", value1);
- return false;
- }
- break;
- }
- case CONDITION_SKILL:
- {
- SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(value1);
- if (!pSkill)
- {
- sLog.outErrorDb("Skill condition specifies non-existing skill (%u), skipped", value1);
- return false;
- }
- if (value2 < 1 || value2 > sWorld.GetConfigMaxSkillValue() )
- {
- sLog.outErrorDb("Skill condition specifies invalid skill value (%u), skipped", value2);
- return false;
- }
- break;
- }
- case CONDITION_QUESTREWARDED:
- case CONDITION_QUESTTAKEN:
- {
- Quest const *Quest = objmgr.GetQuestTemplate(value1);
- if (!Quest)
- {
- sLog.outErrorDb("Quest condition specifies non-existing quest (%u), skipped", value1);
- return false;
- }
- if(value2)
- sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", value2);
- break;
- }
- case CONDITION_AD_COMMISSION_AURA:
- {
- if(value1)
- sLog.outErrorDb("Quest condition has useless data in value1 (%u)!", value1);
- if(value2)
- sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", value2);
- break;
- }
- case CONDITION_NO_AURA:
- {
- if(!sSpellStore.LookupEntry(value1))
- {
- sLog.outErrorDb("Aura condition requires to have non existing spell (Id: %d), skipped", value1);
- return false;
- }
- if(value2 > 2)
- {
- sLog.outErrorDb("Aura condition requires to have non existing effect index (%u) (must be 0..2), skipped", value2);
- return false;
- }
- break;
- }
- case CONDITION_ACTIVE_EVENT:
- {
- GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap();
- if(value1 >=events.size() || !events[value1].isValid())
- {
- sLog.outErrorDb("Active event condition requires existed event id (%u), skipped", value1);
- return false;
- }
- break;
- }
- }
- return true;
-}
-
-SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial)
-{
- switch(pSkill->categoryId)
- {
- case SKILL_CATEGORY_LANGUAGES: return SKILL_RANGE_LANGUAGE;
- case SKILL_CATEGORY_WEAPON:
- if(pSkill->id!=SKILL_FIST_WEAPONS)
- return SKILL_RANGE_LEVEL;
- else
- return SKILL_RANGE_MONO;
- case SKILL_CATEGORY_ARMOR:
- case SKILL_CATEGORY_CLASS:
- if(pSkill->id != SKILL_POISONS && pSkill->id != SKILL_LOCKPICKING)
- return SKILL_RANGE_MONO;
- else
- return SKILL_RANGE_LEVEL;
- case SKILL_CATEGORY_SECONDARY:
- case SKILL_CATEGORY_PROFESSION:
- // not set skills for professions and racial abilities
- if(IsProfessionSkill(pSkill->id))
- return SKILL_RANGE_RANK;
- else if(racial)
- return SKILL_RANGE_NONE;
- else
- return SKILL_RANGE_MONO;
- default:
- case SKILL_CATEGORY_ATTRIBUTES: //not found in dbc
- case SKILL_CATEGORY_NOT_DISPLAYED: //only GENEREC(DND)
- return SKILL_RANGE_NONE;
- }
-}
-
-void ObjectMgr::LoadGameTele()
-{
- m_GameTeleMap.clear(); // for reload case
-
- uint32 count = 0;
- QueryResult *result = WorldDatabase.Query("SELECT id, position_x, position_y, position_z, orientation, map, name FROM game_tele");
-
- if( !result )
- {
- barGoLink bar( 1 );
-
- bar.step();
-
- sLog.outString();
- sLog.outErrorDb(">> Loaded `game_tele`, table is empty!");
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- do
- {
- bar.step();
-
- Field *fields = result->Fetch();
-
- uint32 id = fields[0].GetUInt32();
-
- GameTele gt;
-
- gt.position_x = fields[1].GetFloat();
- gt.position_y = fields[2].GetFloat();
- gt.position_z = fields[3].GetFloat();
- gt.orientation = fields[4].GetFloat();
- gt.mapId = fields[5].GetUInt32();
- gt.name = fields[6].GetCppString();
-
- if(!MapManager::IsValidMapCoord(gt.mapId,gt.position_x,gt.position_y,gt.position_z,gt.orientation))
- {
- sLog.outErrorDb("Wrong position for id %u (name: %s) in `game_tele` table, ignoring.",id,gt.name.c_str());
- continue;
- }
-
- if(!Utf8toWStr(gt.name,gt.wnameLow))
- {
- sLog.outErrorDb("Wrong UTF8 name for id %u in `game_tele` table, ignoring.",id);
- continue;
- }
-
- wstrToLower( gt.wnameLow );
-
- m_GameTeleMap[id] = gt;
-
- ++count;
- }
- while (result->NextRow());
-
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %u game tele's", count );
-}
-
-GameTele const* ObjectMgr::GetGameTele(std::string name) const
-{
- // explicit name case
- std::wstring wname;
- if(!Utf8toWStr(name,wname))
- return false;
-
- // converting string that we try to find to lower case
- wstrToLower( wname );
-
- // Alternative first GameTele what contains wnameLow as substring in case no GameTele location found
- const GameTele* alt = NULL;
- for(GameTeleMap::const_iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr)
- {
- if(itr->second.wnameLow == wname)
- return &itr->second;
- else if (alt == NULL && itr->second.wnameLow.find(wname) != std::wstring::npos)
- alt = &itr->second;
- }
-
- return alt;
-}
-
-bool ObjectMgr::AddGameTele(GameTele& tele)
-{
- // find max id
- uint32 new_id = 0;
- for(GameTeleMap::const_iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr)
- if(itr->first > new_id)
- new_id = itr->first;
-
- // use next
- ++new_id;
-
- if(!Utf8toWStr(tele.name,tele.wnameLow))
- return false;
-
- wstrToLower( tele.wnameLow );
-
- m_GameTeleMap[new_id] = tele;
-
- return WorldDatabase.PExecuteLog("INSERT INTO game_tele (id,position_x,position_y,position_z,orientation,map,name) VALUES (%u,%f,%f,%f,%f,%d,'%s')",
- new_id,tele.position_x,tele.position_y,tele.position_z,tele.orientation,tele.mapId,tele.name.c_str());
-}
-
-bool ObjectMgr::DeleteGameTele(std::string name)
-{
- // explicit name case
- std::wstring wname;
- if(!Utf8toWStr(name,wname))
- return false;
-
- // converting string that we try to find to lower case
- wstrToLower( wname );
-
- for(GameTeleMap::iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr)
- {
- if(itr->second.wnameLow == wname)
- {
- WorldDatabase.PExecuteLog("DELETE FROM game_tele WHERE name = '%s'",itr->second.name.c_str());
- m_GameTeleMap.erase(itr);
- return true;
- }
- }
-
- return false;
-}
-
-void ObjectMgr::LoadTrainerSpell()
-{
- // For reload case
- for (CacheTrainerSpellMap::iterator itr = m_mCacheTrainerSpellMap.begin(); itr != m_mCacheTrainerSpellMap.end(); ++itr)
- itr->second.Clear();
- m_mCacheTrainerSpellMap.clear();
-
- std::set<uint32> skip_trainers;
-
- QueryResult *result = WorldDatabase.Query("SELECT entry, spell,spellcost,reqskill,reqskillvalue,reqlevel FROM npc_trainer");
-
- if( !result )
- {
- barGoLink bar( 1 );
-
- bar.step();
-
- sLog.outString();
- sLog.outErrorDb(">> Loaded `npc_trainer`, table is empty!");
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- uint32 count = 0;
- do
- {
- bar.step();
-
- Field* fields = result->Fetch();
-
- uint32 entry = fields[0].GetUInt32();
- uint32 spell = fields[1].GetUInt32();
-
- CreatureInfo const* cInfo = GetCreatureTemplate(entry);
-
- if(!cInfo)
- {
- sLog.outErrorDb("Table `npc_trainer` have entry for not existed creature template (Entry: %u), ignore", entry);
- continue;
- }
-
- if(!(cInfo->npcflag & UNIT_NPC_FLAG_TRAINER))
- {
- if(skip_trainers.count(entry) == 0)
- {
- sLog.outErrorDb("Table `npc_trainer` have data for not creature template (Entry: %u) without trainer flag, ignore", entry);
- skip_trainers.insert(entry);
- }
- continue;
- }
-
- SpellEntry const *spellinfo = sSpellStore.LookupEntry(spell);
- if(!spellinfo)
- {
- sLog.outErrorDb("Table `npc_trainer` for Trainer (Entry: %u ) has non existing spell %u, ignore", entry,spell);
- continue;
- }
-
- if(!SpellMgr::IsSpellValid(spellinfo))
- {
- sLog.outErrorDb("Table `npc_trainer` for Trainer (Entry: %u) has broken learning spell %u, ignore", entry, spell);
- continue;
- }
-
- TrainerSpell* pTrainerSpell = new TrainerSpell();
- pTrainerSpell->spell = spell;
- pTrainerSpell->spellcost = fields[2].GetUInt32();
- pTrainerSpell->reqskill = fields[3].GetUInt32();
- pTrainerSpell->reqskillvalue = fields[4].GetUInt32();
- pTrainerSpell->reqlevel = fields[5].GetUInt32();
-
- if(!pTrainerSpell->reqlevel)
- pTrainerSpell->reqlevel = spellinfo->spellLevel;
-
-
- TrainerSpellData& data = m_mCacheTrainerSpellMap[entry];
-
- if(SpellMgr::IsProfessionSpell(spell))
- data.trainerType = 2;
-
- data.spellList.push_back(pTrainerSpell);
- ++count;
-
- } while (result->NextRow());
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded Trainers %d", count );
-}
-
-void ObjectMgr::LoadVendors()
-{
- // For reload case
- for (CacheVendorItemMap::iterator itr = m_mCacheVendorItemMap.begin(); itr != m_mCacheVendorItemMap.end(); ++itr)
- itr->second.Clear();
- m_mCacheVendorItemMap.clear();
-
- std::set<uint32> skip_vendors;
-
- QueryResult *result = WorldDatabase.Query("SELECT entry, item, maxcount, incrtime, ExtendedCost FROM npc_vendor");
- if( !result )
- {
- barGoLink bar( 1 );
-
- bar.step();
-
- sLog.outString();
- sLog.outErrorDb(">> Loaded `npc_vendor`, table is empty!");
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- uint32 count = 0;
- do
- {
- bar.step();
- Field* fields = result->Fetch();
-
- uint32 entry = fields[0].GetUInt32();
- uint32 item_id = fields[1].GetUInt32();
- uint32 maxcount = fields[2].GetUInt32();
- uint32 incrtime = fields[3].GetUInt32();
- uint32 ExtendedCost = fields[4].GetUInt32();
-
- if(!IsVendorItemValid(entry,item_id,maxcount,incrtime,ExtendedCost,NULL,&skip_vendors))
- continue;
-
- VendorItemData& vList = m_mCacheVendorItemMap[entry];
-
- vList.AddItem(item_id,maxcount,incrtime,ExtendedCost);
- ++count;
-
- } while (result->NextRow());
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %d Vendors ", count );
-}
-
-void ObjectMgr::LoadNpcTextId()
-{
-
- m_mCacheNpcTextIdMap.clear();
-
- QueryResult* result = WorldDatabase.Query("SELECT npc_guid, textid FROM npc_gossip");
- if( !result )
- {
- barGoLink bar( 1 );
-
- bar.step();
-
- sLog.outString();
- sLog.outErrorDb(">> Loaded `npc_gossip`, table is empty!");
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- uint32 count = 0;
- uint32 guid,textid;
- do
- {
- bar.step();
-
- Field* fields = result->Fetch();
-
- guid = fields[0].GetUInt32();
- textid = fields[1].GetUInt32();
-
- if (!GetCreatureData(guid))
- {
- sLog.outErrorDb("Table `npc_gossip` have not existed creature (GUID: %u) entry, ignore. ",guid);
- continue;
- }
- if (!GetGossipText(textid))
- {
- sLog.outErrorDb("Table `npc_gossip` for creature (GUID: %u) have wrong Textid (%u), ignore. ", guid, textid);
- continue;
- }
-
- m_mCacheNpcTextIdMap[guid] = textid ;
- ++count;
-
- } while (result->NextRow());
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %d NpcTextId ", count );
-}
-
-void ObjectMgr::LoadNpcOptions()
-{
- m_mCacheNpcOptionList.clear(); // For reload case
-
- QueryResult *result = WorldDatabase.Query(
- // 0 1 2 3 4 5 6 7 8
- "SELECT id,gossip_id,npcflag,icon,action,box_money,coded,option_text,box_text "
- "FROM npc_option");
-
- if( !result )
- {
- barGoLink bar( 1 );
-
- bar.step();
-
- sLog.outString();
- sLog.outErrorDb(">> Loaded `npc_option`, table is empty!");
- return;
- }
-
- barGoLink bar( result->GetRowCount() );
-
- uint32 count = 0;
-
- do
- {
- bar.step();
-
- Field* fields = result->Fetch();
-
- GossipOption go;
- go.Id = fields[0].GetUInt32();
- go.GossipId = fields[1].GetUInt32();
- go.NpcFlag = fields[2].GetUInt32();
- go.Icon = fields[3].GetUInt32();
- go.Action = fields[4].GetUInt32();
- go.BoxMoney = fields[5].GetUInt32();
- go.Coded = fields[6].GetUInt8()!=0;
- go.OptionText = fields[7].GetCppString();
- go.BoxText = fields[8].GetCppString();
-
- m_mCacheNpcOptionList.push_back(go);
-
- ++count;
-
- } while (result->NextRow());
- delete result;
-
- sLog.outString();
- sLog.outString( ">> Loaded %d npc_option entries", count );
-}
-
-void ObjectMgr::AddVendorItem( uint32 entry,uint32 item, uint32 maxcount, uint32 incrtime, uint32 extendedcost, bool savetodb)
-{
- VendorItemData& vList = m_mCacheVendorItemMap[entry];
- vList.AddItem(item,maxcount,incrtime,extendedcost);
-
- if(savetodb) WorldDatabase.PExecuteLog("INSERT INTO npc_vendor (entry,item,maxcount,incrtime,extendedcost) VALUES('%u','%u','%u','%u','%u')",entry, item, maxcount,incrtime,extendedcost);
-}
-
-bool ObjectMgr::RemoveVendorItem( uint32 entry,uint32 item, bool savetodb)
-{
- CacheVendorItemMap::iterator iter = m_mCacheVendorItemMap.find(entry);
- if(iter == m_mCacheVendorItemMap.end())
- return false;
-
- if(!iter->second.FindItem(item))
- return false;
-
- iter->second.RemoveItem(item);
- if(savetodb) WorldDatabase.PExecuteLog("DELETE FROM npc_vendor WHERE entry='%u' AND item='%u'",entry, item);
- return true;
-}
-
-bool ObjectMgr::IsVendorItemValid( uint32 vendor_entry, uint32 item_id, uint32 maxcount, uint32 incrtime, uint32 ExtendedCost, Player* pl, std::set<uint32>* skip_vendors, uint32 ORnpcflag ) const
-{
- CreatureInfo const* cInfo = GetCreatureTemplate(vendor_entry);
- if(!cInfo)
- {
- if(pl)
- ChatHandler(pl).SendSysMessage(LANG_COMMAND_VENDORSELECTION);
- else
- sLog.outErrorDb("Table `(game_event_)npc_vendor` have data for not existed creature template (Entry: %u), ignore", vendor_entry);
- return false;
- }
-
- if(!((cInfo->npcflag | ORnpcflag) & UNIT_NPC_FLAG_VENDOR))
- {
- if(!skip_vendors || skip_vendors->count(vendor_entry)==0)
- {
- if(pl)
- ChatHandler(pl).SendSysMessage(LANG_COMMAND_VENDORSELECTION);
- else
- sLog.outErrorDb("Table `(game_event_)npc_vendor` have data for not creature template (Entry: %u) without vendor flag, ignore", vendor_entry);
-
- if(skip_vendors)
- skip_vendors->insert(vendor_entry);
- }
- return false;
- }
-
- if(!GetItemPrototype(item_id))
- {
- if(pl)
- ChatHandler(pl).PSendSysMessage(LANG_ITEM_NOT_FOUND, item_id);
- else
- sLog.outErrorDb("Table `(game_event_)npc_vendor` for Vendor (Entry: %u) have in item list non-existed item (%u), ignore",vendor_entry,item_id);
- return false;
- }
-
- if(ExtendedCost && !sItemExtendedCostStore.LookupEntry(ExtendedCost))
- {
- if(pl)
- ChatHandler(pl).PSendSysMessage(LANG_EXTENDED_COST_NOT_EXIST,ExtendedCost);
- else
- sLog.outErrorDb("Table `(game_event_)npc_vendor` have Item (Entry: %u) with wrong ExtendedCost (%u) for vendor (%u), ignore",item_id,ExtendedCost,vendor_entry);
- return false;
- }
-
- if(maxcount > 0 && incrtime == 0)
- {
- if(pl)
- ChatHandler(pl).PSendSysMessage("MaxCount!=0 (%u) but IncrTime==0", maxcount);
- else
- sLog.outErrorDb( "Table `(game_event_)npc_vendor` has `maxcount` (%u) for item %u of vendor (Entry: %u) but `incrtime`=0, ignore", maxcount, item_id, vendor_entry);
- return false;
- }
- else if(maxcount==0 && incrtime > 0)
- {
- if(pl)
- ChatHandler(pl).PSendSysMessage("MaxCount==0 but IncrTime<>=0");
- else
- sLog.outErrorDb( "Table `(game_event_)npc_vendor` has `maxcount`=0 for item %u of vendor (Entry: %u) but `incrtime`<>0, ignore", item_id, vendor_entry);
- return false;
- }
-
- VendorItemData const* vItems = GetNpcVendorItemList(vendor_entry);
- if(!vItems)
- return true; // later checks for non-empty lists
-
- if(vItems->FindItem(item_id))
- {
- if(pl)
- ChatHandler(pl).PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST,item_id);
- else
- sLog.outErrorDb( "Table `(game_event_)npc_vendor` has duplicate items %u for vendor (Entry: %u), ignore", item_id, vendor_entry);
- return false;
- }
-
- if(vItems->GetItemCount() >= MAX_VENDOR_ITEMS)
- {
- if(pl)
- ChatHandler(pl).SendSysMessage(LANG_COMMAND_ADDVENDORITEMITEMS);
- else
- sLog.outErrorDb( "Table `npc_vendor` has too many items (%u >= %i) for vendor (Entry: %u), ignore", vItems->GetItemCount(), MAX_VENDOR_ITEMS, vendor_entry);
- return false;
- }
-
- return true;
-}
-
-void ObjectMgr::LoadScriptNames()
-{
- m_scriptNames.push_back("");
- QueryResult *result = WorldDatabase.Query(
- "SELECT DISTINCT(ScriptName) FROM creature_template WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(ScriptName) FROM gameobject_template WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(ScriptName) FROM item_template WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(ScriptName) FROM areatrigger_scripts WHERE ScriptName <> '' "
- "UNION "
- "SELECT DISTINCT(script) FROM instance_template WHERE script <> ''");
- if(result)
- {
- do
- {
- m_scriptNames.push_back((*result)[0].GetString());
- } while (result->NextRow());
- delete result;
- }
-
- std::sort(m_scriptNames.begin(), m_scriptNames.end());
-}
-
-uint32 ObjectMgr::GetScriptId(const char *name)
-{
- // use binary search to find the script name in the sorted vector
- // assume "" is the first element
- if(!name) return 0;
- ScriptNameMap::const_iterator itr =
- std::lower_bound(m_scriptNames.begin(), m_scriptNames.end(), name);
- if(itr == m_scriptNames.end()) return 0;
- return itr - m_scriptNames.begin();
-}
-
-void ObjectMgr::CheckScripts(ScriptMapMap const& scripts,std::set<int32>& ids)
-{
- for(ScriptMapMap::const_iterator itrMM = scripts.begin(); itrMM != scripts.end(); ++itrMM)
- {
- for(ScriptMap::const_iterator itrM = itrMM->second.begin(); itrM != itrMM->second.end(); ++itrM)
- {
- if(itrM->second.dataint)
- {
- if(!GetTrinityStringLocale (itrM->second.dataint))
- sLog.outErrorDb( "Table `db_script_string` has not existed string id %u", *itrM);
-
- if(ids.count(itrM->second.dataint))
- ids.erase(itrM->second.dataint);
- }
- }
- }
-}
-
-void ObjectMgr::LoadDbScriptStrings()
-{
- LoadTrinityStrings(WorldDatabase,"db_script_string",MIN_DB_SCRIPT_STRING_ID,MAX_DB_SCRIPT_STRING_ID);
-
- std::set<int32> ids;
-
- for(int32 i = MIN_DB_SCRIPT_STRING_ID; i < MAX_DB_SCRIPT_STRING_ID; ++i)
- if(GetTrinityStringLocale(i))
- ids.insert(i);
-
- CheckScripts(sQuestEndScripts,ids);
- CheckScripts(sQuestStartScripts,ids);
- CheckScripts(sSpellScripts,ids);
- CheckScripts(sGameObjectScripts,ids);
- CheckScripts(sEventScripts,ids);
-
- for(std::set<int32>::const_iterator itr = ids.begin(); itr != ids.end(); ++itr)
- sLog.outErrorDb( "Table `db_script_string` has unused string id %u", *itr);
-}
-
-// Functions for scripting access
-uint32 GetAreaTriggerScriptId(uint32 trigger_id)
-{
- return objmgr.GetAreaTriggerScriptId(trigger_id);
-}
-
-bool LoadTrinityStrings(DatabaseType& db, char const* table,int32 start_value, int32 end_value)
-{
- if(start_value >= 0 || start_value <= end_value) // start/end reversed for negative values
- {
- sLog.outErrorDb("Table '%s' attempt loaded with invalid range (%d - %d), use (%d - %d) instead.",table,start_value,end_value,-1,std::numeric_limits<int32>::min());
- start_value = -1;
- end_value = std::numeric_limits<int32>::min();
- }
-
- // for scripting localized strings allowed use _only_ negative entries
- return objmgr.LoadTrinityStrings(db,table,end_value,start_value);
-}
-
-uint32 TRINITY_DLL_SPEC GetScriptId(const char *name)
-{
- return objmgr.GetScriptId(name);
-}
-
-ObjectMgr::ScriptNameMap & GetScriptNames()
-{
- return objmgr.GetScriptNames();
-}
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ *
+ * 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
+ */
+
+#include "Common.h"
+#include "Database/DatabaseEnv.h"
+#include "Database/SQLStorage.h"
+#include "Database/SQLStorageImpl.h"
+
+#include "Log.h"
+#include "MapManager.h"
+#include "ObjectMgr.h"
+#include "SpellMgr.h"
+#include "UpdateMask.h"
+#include "World.h"
+#include "WorldSession.h"
+#include "Group.h"
+#include "Guild.h"
+#include "ArenaTeam.h"
+#include "Transports.h"
+#include "ProgressBar.h"
+#include "Policies/SingletonImp.h"
+#include "Language.h"
+#include "GameEvent.h"
+#include "Spell.h"
+#include "Chat.h"
+#include "AccountMgr.h"
+#include "InstanceSaveMgr.h"
+#include "SpellAuras.h"
+#include "Util.h"
+#include "WaypointManager.h"
+#include "InstanceData.h" //for condition_instance_data
+
+INSTANTIATE_SINGLETON_1(ObjectMgr);
+
+ScriptMapMap sQuestEndScripts;
+ScriptMapMap sQuestStartScripts;
+ScriptMapMap sSpellScripts;
+ScriptMapMap sGameObjectScripts;
+ScriptMapMap sEventScripts;
+
+bool normalizePlayerName(std::string& name)
+{
+ if(name.empty())
+ return false;
+
+ wchar_t wstr_buf[MAX_INTERNAL_PLAYER_NAME+1];
+ size_t wstr_len = MAX_INTERNAL_PLAYER_NAME;
+
+ if(!Utf8toWStr(name,&wstr_buf[0],wstr_len))
+ return false;
+
+ wstr_buf[0] = wcharToUpper(wstr_buf[0]);
+ for(size_t i = 1; i < wstr_len; ++i)
+ wstr_buf[i] = wcharToLower(wstr_buf[i]);
+
+ if(!WStrToUtf8(wstr_buf,wstr_len,name))
+ return false;
+
+ return true;
+}
+
+LanguageDesc lang_description[LANGUAGES_COUNT] =
+{
+ { LANG_ADDON, 0, 0 },
+ { LANG_UNIVERSAL, 0, 0 },
+ { LANG_ORCISH, 669, SKILL_LANG_ORCISH },
+ { LANG_DARNASSIAN, 671, SKILL_LANG_DARNASSIAN },
+ { LANG_TAURAHE, 670, SKILL_LANG_TAURAHE },
+ { LANG_DWARVISH, 672, SKILL_LANG_DWARVEN },
+ { LANG_COMMON, 668, SKILL_LANG_COMMON },
+ { LANG_DEMONIC, 815, SKILL_LANG_DEMON_TONGUE },
+ { LANG_TITAN, 816, SKILL_LANG_TITAN },
+ { LANG_THALASSIAN, 813, SKILL_LANG_THALASSIAN },
+ { LANG_DRACONIC, 814, SKILL_LANG_DRACONIC },
+ { LANG_KALIMAG, 817, SKILL_LANG_OLD_TONGUE },
+ { LANG_GNOMISH, 7340, SKILL_LANG_GNOMISH },
+ { LANG_TROLL, 7341, SKILL_LANG_TROLL },
+ { LANG_GUTTERSPEAK, 17737, SKILL_LANG_GUTTERSPEAK },
+ { LANG_DRAENEI, 29932, SKILL_LANG_DRAENEI },
+ { LANG_ZOMBIE, 0, 0 },
+ { LANG_GNOMISH_BINARY, 0, 0 },
+ { LANG_GOBLIN_BINARY, 0, 0 }
+};
+
+LanguageDesc const* GetLanguageDescByID(uint32 lang)
+{
+ for(int i = 0; i < LANGUAGES_COUNT; ++i)
+ {
+ if(uint32(lang_description[i].lang_id) == lang)
+ return &lang_description[i];
+ }
+
+ return NULL;
+}
+
+ObjectMgr::ObjectMgr()
+{
+ m_hiCharGuid = 1;
+ m_hiCreatureGuid = 1;
+ m_hiPetGuid = 1;
+ m_hiItemGuid = 1;
+ m_hiGoGuid = 1;
+ m_hiDoGuid = 1;
+ m_hiCorpseGuid = 1;
+ m_hiPetNumber = 1;
+ m_ItemTextId = 1;
+ m_mailid = 1;
+ m_auctionid = 1;
+ m_guildId = 1;
+ m_arenaTeamId = 1;
+
+ mGuildBankTabPrice.resize(GUILD_BANK_MAX_TABS);
+ mGuildBankTabPrice[0] = 100;
+ mGuildBankTabPrice[1] = 250;
+ mGuildBankTabPrice[2] = 500;
+ mGuildBankTabPrice[3] = 1000;
+ mGuildBankTabPrice[4] = 2500;
+ mGuildBankTabPrice[5] = 5000;
+
+ // Only zero condition left, others will be added while loading DB tables
+ mConditions.resize(1);
+}
+
+ObjectMgr::~ObjectMgr()
+{
+ for( QuestMap::iterator i = mQuestTemplates.begin( ); i != mQuestTemplates.end( ); ++ i )
+ {
+ delete i->second;
+ }
+ mQuestTemplates.clear( );
+
+ for( GossipTextMap::iterator i = mGossipText.begin( ); i != mGossipText.end( ); ++ i )
+ {
+ delete i->second;
+ }
+ mGossipText.clear( );
+
+ mAreaTriggers.clear();
+
+ for(PetLevelInfoMap::iterator i = petInfo.begin( ); i != petInfo.end( ); ++ i )
+ {
+ delete[] i->second;
+ }
+ petInfo.clear();
+
+ // free only if loaded
+ for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
+ delete[] playerClassInfo[class_].levelInfo;
+
+ for (int race = 0; race < MAX_RACES; ++race)
+ for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
+ delete[] playerInfo[race][class_].levelInfo;
+
+ // free group and guild objects
+ for (GroupSet::iterator itr = mGroupSet.begin(); itr != mGroupSet.end(); ++itr)
+ delete (*itr);
+ for (GuildSet::iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); ++itr)
+ delete (*itr);
+
+ for (CachePlayerInfoMap::iterator itr = m_mPlayerInfoMap.begin(); itr != m_mPlayerInfoMap.end(); ++itr)
+ delete itr->second;
+
+ for(ItemMap::iterator itr = mAitems.begin(); itr != mAitems.end(); ++itr)
+ delete itr->second;
+
+ for (CacheVendorItemMap::iterator itr = m_mCacheVendorItemMap.begin(); itr != m_mCacheVendorItemMap.end(); ++itr)
+ itr->second.Clear();
+
+ for (CacheTrainerSpellMap::iterator itr = m_mCacheTrainerSpellMap.begin(); itr != m_mCacheTrainerSpellMap.end(); ++itr)
+ itr->second.Clear();
+}
+
+void ObjectMgr::LoadPlayerInfoInCache()
+{
+ QueryResult *result = CharacterDatabase.PQuery("SELECT guid, name, data, class FROM characters");
+ if(!result)
+ {
+ sLog.outError( "Loading Player Cache failed.");
+ return;
+ }
+
+ PCachePlayerInfo pPPlayerInfo = NULL;
+ Field *fields = NULL;
+ Tokens tdata;
+ barGoLink bar( result->GetRowCount() );
+ do
+ {
+ bar.step();
+ fields = result->Fetch();
+ pPPlayerInfo = new CachePlayerInfo();
+
+ pPPlayerInfo->sPlayerName = fields[1].GetString();
+
+ tdata.clear();
+ tdata = StrSplit(fields[2].GetCppString(), " ");
+
+ pPPlayerInfo->unLevel = Player::GetUInt32ValueFromArray(tdata,UNIT_FIELD_LEVEL);
+ pPPlayerInfo->unfield = Player::GetUInt32ValueFromArray(tdata,UNIT_FIELD_BYTES_0);
+
+ pPPlayerInfo->unArenaInfoId0 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 0 * 6);
+ pPPlayerInfo->unArenaInfoId1 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 * 6);
+ pPPlayerInfo->unArenaInfoId2 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 2 * 6);
+
+ pPPlayerInfo->unArenaInfoSlot0 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 0 * 6 + 5);
+ pPPlayerInfo->unArenaInfoSlot1 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 * 6 + 5);
+ pPPlayerInfo->unArenaInfoSlot2 = Player::GetUInt32ValueFromArray(tdata,PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 2 * 6 + 5);
+
+ pPPlayerInfo->unClass = (uint32)fields[3].GetUInt32();
+ m_mPlayerInfoMap[fields[0].GetUInt32()] = pPPlayerInfo;
+ }
+ while (result->NextRow());
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded info about %d players", m_mPlayerInfoMap.size());
+}
+
+PCachePlayerInfo ObjectMgr::GetPlayerInfoFromCache(uint32 unPlayerGuid) const
+{
+ //Now m_mPlayerInfoMap is using only for search, but when dinamic inserting/removing
+ //will be implemented we should lock it to prevent simultaneous access.
+ //Inserting - when new created player is saving
+ //Removing - when player has been deleted
+ CachePlayerInfoMap::const_iterator ipos = m_mPlayerInfoMap.find(unPlayerGuid);
+ return ipos == m_mPlayerInfoMap.end() ? NULL : ipos->second;
+}
+
+Group * ObjectMgr::GetGroupByLeader(const uint64 &guid) const
+{
+ for(GroupSet::const_iterator itr = mGroupSet.begin(); itr != mGroupSet.end(); ++itr)
+ if ((*itr)->GetLeaderGUID() == guid)
+ return *itr;
+
+ return NULL;
+}
+
+Guild * ObjectMgr::GetGuildById(const uint32 GuildId) const
+{
+ for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); itr++)
+ if ((*itr)->GetId() == GuildId)
+ return *itr;
+
+ return NULL;
+}
+
+Guild * ObjectMgr::GetGuildByName(std::string guildname) const
+{
+ for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); itr++)
+ if ((*itr)->GetName() == guildname)
+ return *itr;
+
+ return NULL;
+}
+
+std::string ObjectMgr::GetGuildNameById(const uint32 GuildId) const
+{
+ for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); itr++)
+ if ((*itr)->GetId() == GuildId)
+ return (*itr)->GetName();
+
+ return "";
+}
+
+Guild* ObjectMgr::GetGuildByLeader(const uint64 &guid) const
+{
+ for(GuildSet::const_iterator itr = mGuildSet.begin(); itr != mGuildSet.end(); ++itr)
+ if( (*itr)->GetLeader() == guid)
+ return *itr;
+
+ return NULL;
+}
+
+ArenaTeam* ObjectMgr::GetArenaTeamById(const uint32 ArenaTeamId) const
+{
+ for(ArenaTeamSet::const_iterator itr = mArenaTeamSet.begin(); itr != mArenaTeamSet.end(); itr++)
+ if ((*itr)->GetId() == ArenaTeamId)
+ return *itr;
+
+ return NULL;
+}
+
+ArenaTeam* ObjectMgr::GetArenaTeamByName(std::string arenateamname) const
+{
+ for(ArenaTeamSet::const_iterator itr = mArenaTeamSet.begin(); itr != mArenaTeamSet.end(); itr++)
+ if ((*itr)->GetName() == arenateamname)
+ return *itr;
+
+ return NULL;
+}
+
+ArenaTeam* ObjectMgr::GetArenaTeamByCapitan(uint64 const& guid) const
+{
+ for(ArenaTeamSet::const_iterator itr = mArenaTeamSet.begin(); itr != mArenaTeamSet.end(); itr++)
+ if ((*itr)->GetCaptain() == guid)
+ return *itr;
+
+ return NULL;
+}
+
+AuctionHouseObject * ObjectMgr::GetAuctionsMap( uint32 location )
+{
+ switch ( location )
+ {
+ case 6: //horde
+ return & mHordeAuctions;
+ break;
+ case 2: //alliance
+ return & mAllianceAuctions;
+ break;
+ default: //neutral
+ return & mNeutralAuctions;
+ }
+}
+
+uint32 ObjectMgr::GetAuctionCut(uint32 location, uint32 highBid)
+{
+ if (location == 7 && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
+ return (uint32) (0.15f * highBid * sWorld.getRate(RATE_AUCTION_CUT));
+ else
+ return (uint32) (0.05f * highBid * sWorld.getRate(RATE_AUCTION_CUT));
+}
+
+uint32 ObjectMgr::GetAuctionDeposit(uint32 location, uint32 time, Item *pItem)
+{
+ float percentance; // in 0..1
+ if ( location == 7 && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
+ percentance = 0.75f;
+ else
+ percentance = 0.15f;
+
+ percentance *= sWorld.getRate(RATE_AUCTION_DEPOSIT);
+
+ return uint32( percentance * pItem->GetProto()->SellPrice * pItem->GetCount() * (time / MIN_AUCTION_TIME ) );
+}
+
+/// the sum of outbid is (1% from current bid)*5, if bid is very small, it is 1c
+uint32 ObjectMgr::GetAuctionOutBid(uint32 currentBid)
+{
+ uint32 outbid = (currentBid / 100) * 5;
+ if (!outbid)
+ outbid = 1;
+ return outbid;
+}
+
+//does not clear ram
+void ObjectMgr::SendAuctionWonMail( AuctionEntry *auction )
+{
+ Item *pItem = GetAItem(auction->item_guidlow);
+ if(!pItem)
+ return;
+
+ uint64 bidder_guid = MAKE_NEW_GUID(auction->bidder, 0, HIGHGUID_PLAYER);
+ Player *bidder = GetPlayer(bidder_guid);
+
+ uint32 bidder_accId = 0;
+
+ // data for gm.log
+ if( sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
+ {
+ uint32 bidder_security = 0;
+ std::string bidder_name;
+ if (bidder)
+ {
+ bidder_accId = bidder->GetSession()->GetAccountId();
+ bidder_security = bidder->GetSession()->GetSecurity();
+ bidder_name = bidder->GetName();
+ }
+ else
+ {
+ bidder_accId = GetPlayerAccountIdByGUID(bidder_guid);
+ bidder_security = accmgr.GetSecurity(bidder_accId);
+
+ if(bidder_security > SEC_PLAYER ) // not do redundant DB requests
+ {
+ if(!GetPlayerNameByGUID(bidder_guid,bidder_name))
+ bidder_name = GetTrinityStringForDBCLocale(LANG_UNKNOWN);
+ }
+ }
+
+ if( bidder_security > SEC_PLAYER )
+ {
+ std::string owner_name;
+ if(!GetPlayerNameByGUID(auction->owner,owner_name))
+ owner_name = GetTrinityStringForDBCLocale(LANG_UNKNOWN);
+
+ uint32 owner_accid = GetPlayerAccountIdByGUID(auction->owner);
+
+ sLog.outCommand(bidder_accId,"GM %s (Account: %u) won item in auction: %s (Entry: %u Count: %u) and pay money: %u. Original owner %s (Account: %u)",
+ bidder_name.c_str(),bidder_accId,pItem->GetProto()->Name1,pItem->GetEntry(),pItem->GetCount(),auction->bid,owner_name.c_str(),owner_accid);
+ }
+ }
+ else if(!bidder)
+ bidder_accId = GetPlayerAccountIdByGUID(bidder_guid);
+
+ // receiver exist
+ if(bidder || bidder_accId)
+ {
+ std::ostringstream msgAuctionWonSubject;
+ msgAuctionWonSubject << auction->item_template << ":0:" << AUCTION_WON;
+
+ std::ostringstream msgAuctionWonBody;
+ msgAuctionWonBody.width(16);
+ msgAuctionWonBody << std::right << std::hex << auction->owner;
+ msgAuctionWonBody << std::dec << ":" << auction->bid << ":" << auction->buyout;
+ sLog.outDebug( "AuctionWon body string : %s", msgAuctionWonBody.str().c_str() );
+
+ //prepare mail data... :
+ uint32 itemTextId = CreateItemText( msgAuctionWonBody.str() );
+
+ // set owner to bidder (to prevent delete item with sender char deleting)
+ // owner in `data` will set at mail receive and item extracting
+ CharacterDatabase.PExecute("UPDATE item_instance SET owner_guid = '%u' WHERE guid='%u'",auction->bidder,pItem->GetGUIDLow());
+ CharacterDatabase.CommitTransaction();
+
+ MailItemsInfo mi;
+ mi.AddItem(auction->item_guidlow, auction->item_template, pItem);
+
+ if (bidder)
+ bidder->GetSession()->SendAuctionBidderNotification( auction->location, auction->Id, bidder_guid, 0, 0, auction->item_template);
+ else
+ RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !!
+
+ // will delete item or place to receiver mail list
+ WorldSession::SendMailTo(bidder, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, auction->bidder, msgAuctionWonSubject.str(), itemTextId, &mi, 0, 0, MAIL_CHECK_MASK_AUCTION);
+ }
+ // receiver not exist
+ else
+ {
+ CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid='%u'", pItem->GetGUIDLow());
+ RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !!
+ delete pItem;
+ }
+}
+
+void ObjectMgr::SendAuctionSalePendingMail( AuctionEntry * auction )
+{
+ uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER);
+ Player *owner = GetPlayer(owner_guid);
+
+ // owner exist (online or offline)
+ if(owner || GetPlayerAccountIdByGUID(owner_guid))
+ {
+ std::ostringstream msgAuctionSalePendingSubject;
+ msgAuctionSalePendingSubject << auction->item_template << ":0:" << AUCTION_SALE_PENDING;
+
+ std::ostringstream msgAuctionSalePendingBody;
+ uint32 auctionCut = GetAuctionCut(auction->location, auction->bid);
+
+ time_t distrTime = time(NULL) + HOUR;
+
+ msgAuctionSalePendingBody.width(16);
+ msgAuctionSalePendingBody << std::right << std::hex << auction->bidder;
+ msgAuctionSalePendingBody << std::dec << ":" << auction->bid << ":" << auction->buyout;
+ msgAuctionSalePendingBody << ":" << auction->deposit << ":" << auctionCut << ":0:";
+ msgAuctionSalePendingBody << secsToTimeBitFields(distrTime);
+
+ sLog.outDebug("AuctionSalePending body string : %s", msgAuctionSalePendingBody.str().c_str());
+
+ uint32 itemTextId = CreateItemText( msgAuctionSalePendingBody.str() );
+
+ WorldSession::SendMailTo(owner, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, auction->owner, msgAuctionSalePendingSubject.str(), itemTextId, NULL, 0, 0, MAIL_CHECK_MASK_AUCTION);
+ }
+}
+
+//call this method to send mail to auction owner, when auction is successful, it does not clear ram
+void ObjectMgr::SendAuctionSuccessfulMail( AuctionEntry * auction )
+{
+ uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER);
+ Player *owner = GetPlayer(owner_guid);
+
+ uint32 owner_accId = 0;
+ if(!owner)
+ owner_accId = GetPlayerAccountIdByGUID(owner_guid);
+
+ // owner exist
+ if(owner || owner_accId)
+ {
+ std::ostringstream msgAuctionSuccessfulSubject;
+ msgAuctionSuccessfulSubject << auction->item_template << ":0:" << AUCTION_SUCCESSFUL;
+
+ std::ostringstream auctionSuccessfulBody;
+ uint32 auctionCut = GetAuctionCut(auction->location, auction->bid);
+
+ auctionSuccessfulBody.width(16);
+ auctionSuccessfulBody << std::right << std::hex << auction->bidder;
+ auctionSuccessfulBody << std::dec << ":" << auction->bid << ":" << auction->buyout;
+ auctionSuccessfulBody << ":" << auction->deposit << ":" << auctionCut;
+
+ sLog.outDebug("AuctionSuccessful body string : %s", auctionSuccessfulBody.str().c_str());
+
+ uint32 itemTextId = CreateItemText( auctionSuccessfulBody.str() );
+
+ uint32 profit = auction->bid + auction->deposit - auctionCut;
+
+ if (owner)
+ {
+ //send auction owner notification, bidder must be current!
+ owner->GetSession()->SendAuctionOwnerNotification( auction );
+ }
+
+ WorldSession::SendMailTo(owner, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, auction->owner, msgAuctionSuccessfulSubject.str(), itemTextId, NULL, profit, 0, MAIL_CHECK_MASK_AUCTION, HOUR);
+ }
+}
+
+//does not clear ram
+void ObjectMgr::SendAuctionExpiredMail( AuctionEntry * auction )
+{ //return an item in auction to its owner by mail
+ Item *pItem = GetAItem(auction->item_guidlow);
+ if(!pItem)
+ {
+ sLog.outError("Auction item (GUID: %u) not found, and lost.",auction->item_guidlow);
+ return;
+ }
+
+ uint64 owner_guid = MAKE_NEW_GUID(auction->owner, 0, HIGHGUID_PLAYER);
+ Player *owner = GetPlayer(owner_guid);
+
+ uint32 owner_accId = 0;
+ if(!owner)
+ owner_accId = GetPlayerAccountIdByGUID(owner_guid);
+
+ // owner exist
+ if(owner || owner_accId)
+ {
+ std::ostringstream subject;
+ subject << auction->item_template << ":0:" << AUCTION_EXPIRED;
+
+ if ( owner )
+ owner->GetSession()->SendAuctionOwnerNotification( auction );
+ else
+ RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !!
+
+ MailItemsInfo mi;
+ mi.AddItem(auction->item_guidlow, auction->item_template, pItem);
+
+ // will delete item or place to receiver mail list
+ WorldSession::SendMailTo(owner, MAIL_AUCTION, MAIL_STATIONERY_AUCTION, auction->location, GUID_LOPART(owner_guid), subject.str(), 0, &mi, 0, 0, MAIL_CHECK_MASK_NONE);
+ }
+ // owner not found
+ else
+ {
+ CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid='%u'",pItem->GetGUIDLow());
+ RemoveAItem(pItem->GetGUIDLow()); // we have to remove the item, before we delete it !!
+ delete pItem;
+ }
+}
+
+CreatureInfo const* ObjectMgr::GetCreatureTemplate(uint32 id)
+{
+ return sCreatureStorage.LookupEntry<CreatureInfo>(id);
+}
+
+void ObjectMgr::LoadCreatureLocales()
+{
+ mCreatureLocaleMap.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query("SELECT entry,name_loc1,subname_loc1,name_loc2,subname_loc2,name_loc3,subname_loc3,name_loc4,subname_loc4,name_loc5,subname_loc5,name_loc6,subname_loc6,name_loc7,subname_loc7,name_loc8,subname_loc8 FROM locales_creature");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString("");
+ sLog.outString(">> Loaded 0 creature locale strings. DB table `locales_creature` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 entry = fields[0].GetUInt32();
+
+ CreatureLocale& data = mCreatureLocaleMap[entry];
+
+ for(int i = 1; i < MAX_LOCALE; ++i)
+ {
+ std::string str = fields[1+2*(i-1)].GetCppString();
+ if(!str.empty())
+ {
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.Name.size() <= idx)
+ data.Name.resize(idx+1);
+
+ data.Name[idx] = str;
+ }
+ }
+ str = fields[1+2*(i-1)+1].GetCppString();
+ if(!str.empty())
+ {
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.SubName.size() <= idx)
+ data.SubName.resize(idx+1);
+
+ data.SubName[idx] = str;
+ }
+ }
+ }
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u creature locale strings", mCreatureLocaleMap.size() );
+}
+
+void ObjectMgr::LoadNpcOptionLocales()
+{
+ mNpcOptionLocaleMap.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query("SELECT entry,"
+ "option_text_loc1,box_text_loc1,option_text_loc2,box_text_loc2,"
+ "option_text_loc3,box_text_loc3,option_text_loc4,box_text_loc4,"
+ "option_text_loc5,box_text_loc5,option_text_loc6,box_text_loc6,"
+ "option_text_loc7,box_text_loc7,option_text_loc8,box_text_loc8 "
+ "FROM locales_npc_option");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString("");
+ sLog.outString(">> Loaded 0 npc_option locale strings. DB table `locales_npc_option` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 entry = fields[0].GetUInt32();
+
+ NpcOptionLocale& data = mNpcOptionLocaleMap[entry];
+
+ for(int i = 1; i < MAX_LOCALE; ++i)
+ {
+ std::string str = fields[1+2*(i-1)].GetCppString();
+ if(!str.empty())
+ {
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.OptionText.size() <= idx)
+ data.OptionText.resize(idx+1);
+
+ data.OptionText[idx] = str;
+ }
+ }
+ str = fields[1+2*(i-1)+1].GetCppString();
+ if(!str.empty())
+ {
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.BoxText.size() <= idx)
+ data.BoxText.resize(idx+1);
+
+ data.BoxText[idx] = str;
+ }
+ }
+ }
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u npc_option locale strings", mNpcOptionLocaleMap.size() );
+}
+
+struct SQLCreatureLoader : public SQLStorageLoaderBase<SQLCreatureLoader>
+{
+ template<class D>
+ void convert_from_str(uint32 field_pos, char *src, D &dst)
+ {
+ dst = D(objmgr.GetScriptId(src));
+ }
+};
+
+void ObjectMgr::LoadCreatureTemplates()
+{
+ SQLCreatureLoader loader;
+ loader.Load(sCreatureStorage);
+
+ sLog.outString( ">> Loaded %u creature definitions", sCreatureStorage.RecordCount );
+ sLog.outString();
+
+ std::set<uint32> heroicEntries; // already loaded heroic value in creatures
+ std::set<uint32> hasHeroicEntries; // already loaded creatures with heroic entry values
+
+ // check data correctness
+ for(uint32 i = 1; i < sCreatureStorage.MaxEntry; ++i)
+ {
+ CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i);
+ if(!cInfo)
+ continue;
+
+ if(cInfo->HeroicEntry)
+ {
+ CreatureInfo const* heroicInfo = GetCreatureTemplate(cInfo->HeroicEntry);
+ if(!heroicInfo)
+ {
+ sLog.outErrorDb("Creature (Entry: %u) have `heroic_entry`=%u but creature entry %u not exist.",cInfo->HeroicEntry,cInfo->HeroicEntry);
+ continue;
+ }
+
+ if(heroicEntries.find(i)!=heroicEntries.end())
+ {
+ sLog.outErrorDb("Creature (Entry: %u) listed as heroic but have value in `heroic_entry`.",i);
+ continue;
+ }
+
+ if(heroicEntries.find(cInfo->HeroicEntry)!=heroicEntries.end())
+ {
+ sLog.outErrorDb("Creature (Entry: %u) already listed as heroic for another entry.",cInfo->HeroicEntry);
+ continue;
+ }
+
+ if(hasHeroicEntries.find(cInfo->HeroicEntry)!=hasHeroicEntries.end())
+ {
+ sLog.outErrorDb("Creature (Entry: %u) have `heroic_entry`=%u but creature entry %u have heroic entry also.",i,cInfo->HeroicEntry,cInfo->HeroicEntry);
+ continue;
+ }
+
+ if(cInfo->npcflag != heroicInfo->npcflag)
+ {
+ sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `npcflag` in heroic mode.",i);
+ continue;
+ }
+
+ if(cInfo->classNum != heroicInfo->classNum)
+ {
+ sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `classNum` in heroic mode.",i);
+ continue;
+ }
+
+ if(cInfo->race != heroicInfo->race)
+ {
+ sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `race` in heroic mode.",i);
+ continue;
+ }
+
+ if(cInfo->trainer_type != heroicInfo->trainer_type)
+ {
+ sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `trainer_type` in heroic mode.",i);
+ continue;
+ }
+
+ if(cInfo->trainer_spell != heroicInfo->trainer_spell)
+ {
+ sLog.outErrorDb("Creature (Entry: %u) listed in `creature_template_substitution` has different `trainer_spell` in heroic mode.",i);
+ continue;
+ }
+
+ hasHeroicEntries.insert(i);
+ heroicEntries.insert(cInfo->HeroicEntry);
+ }
+
+ FactionTemplateEntry const* factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_A);
+ if(!factionTemplate)
+ sLog.outErrorDb("Creature (Entry: %u) has non-existing faction_A template (%u)", cInfo->Entry, cInfo->faction_A);
+
+ factionTemplate = sFactionTemplateStore.LookupEntry(cInfo->faction_H);
+ if(!factionTemplate)
+ sLog.outErrorDb("Creature (Entry: %u) has non-existing faction_H template (%u)", cInfo->Entry, cInfo->faction_H);
+
+ // check model ids, supplying and sending non-existent ids to the client might crash them
+ if(cInfo->Modelid1 && !sCreatureModelStorage.LookupEntry<CreatureModelInfo>(cInfo->Modelid1))
+ {
+ sLog.outErrorDb("Creature (Entry: %u) has non-existing modelId_A (%u), setting it to 0", cInfo->Entry, cInfo->Modelid1);
+ const_cast<CreatureInfo*>(cInfo)->Modelid1 = 0;
+ }
+ if(cInfo->Modelid2 && !sCreatureModelStorage.LookupEntry<CreatureModelInfo>(cInfo->Modelid2))
+ {
+ sLog.outErrorDb("Creature (Entry: %u) has non-existing modelId_A2 (%u), setting it to 0", cInfo->Entry, cInfo->Modelid2);
+ const_cast<CreatureInfo*>(cInfo)->Modelid2 = 0;
+ }
+ if(cInfo->Modelid3 && !sCreatureModelStorage.LookupEntry<CreatureModelInfo>(cInfo->Modelid3))
+ {
+ sLog.outErrorDb("Creature (Entry: %u) has non-existing modelId_H (%u), setting it to 0", cInfo->Entry, cInfo->Modelid3);
+ const_cast<CreatureInfo*>(cInfo)->Modelid3 = 0;
+ }
+ if(cInfo->Modelid4 && !sCreatureModelStorage.LookupEntry<CreatureModelInfo>(cInfo->Modelid4))
+ {
+ sLog.outErrorDb("Creature (Entry: %u) has non-existing modelId_H2 (%u), setting it to 0", cInfo->Entry, cInfo->Modelid4);
+ const_cast<CreatureInfo*>(cInfo)->Modelid4 = 0;
+ }
+
+ if(cInfo->dmgschool >= MAX_SPELL_SCHOOL)
+ {
+ sLog.outErrorDb("Creature (Entry: %u) has invalid spell school value (%u) in `dmgschool`",cInfo->Entry,cInfo->dmgschool);
+ const_cast<CreatureInfo*>(cInfo)->dmgschool = SPELL_SCHOOL_NORMAL;
+ }
+
+ if(cInfo->baseattacktime == 0)
+ const_cast<CreatureInfo*>(cInfo)->baseattacktime = BASE_ATTACK_TIME;
+
+ if(cInfo->rangeattacktime == 0)
+ const_cast<CreatureInfo*>(cInfo)->rangeattacktime = BASE_ATTACK_TIME;
+
+ if((cInfo->npcflag & UNIT_NPC_FLAG_TRAINER) && cInfo->trainer_type >= MAX_TRAINER_TYPE)
+ sLog.outErrorDb("Creature (Entry: %u) has wrong trainer type %u",cInfo->Entry,cInfo->trainer_type);
+
+ if(cInfo->InhabitType <= 0 || cInfo->InhabitType > INHABIT_ANYWHERE)
+ {
+ sLog.outErrorDb("Creature (Entry: %u) has wrong value (%u) in `InhabitType`, creature will not correctly walk/swim/fly",cInfo->Entry,cInfo->InhabitType);
+ const_cast<CreatureInfo*>(cInfo)->InhabitType = INHABIT_ANYWHERE;
+ }
+
+ if(cInfo->PetSpellDataId)
+ {
+ CreatureSpellDataEntry const* spellDataId = sCreatureSpellDataStore.LookupEntry(cInfo->PetSpellDataId);
+ if(!spellDataId)
+ sLog.outErrorDb("Creature (Entry: %u) has non-existing PetSpellDataId (%u)", cInfo->Entry, cInfo->PetSpellDataId);
+ }
+
+ if(cInfo->MovementType >= MAX_DB_MOTION_TYPE)
+ {
+ sLog.outErrorDb("Creature (Entry: %u) has wrong movement generator type (%u), ignore and set to IDLE.",cInfo->Entry,cInfo->MovementType);
+ const_cast<CreatureInfo*>(cInfo)->MovementType = IDLE_MOTION_TYPE;
+ }
+
+ if(cInfo->equipmentId > 0) // 0 no equipment
+ {
+ if(!GetEquipmentInfo(cInfo->equipmentId))
+ {
+ sLog.outErrorDb("Table `creature_template` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", cInfo->Entry, cInfo->equipmentId);
+ const_cast<CreatureInfo*>(cInfo)->equipmentId = 0;
+ }
+ }
+
+ /// if not set custom creature scale then load scale from CreatureDisplayInfo.dbc
+ if(cInfo->scale <= 0.0f)
+ {
+ uint32 modelid = cInfo->GetFirstValidModelId();
+ CreatureDisplayInfoEntry const* ScaleEntry = sCreatureDisplayInfoStore.LookupEntry(modelid);
+ const_cast<CreatureInfo*>(cInfo)->scale = ScaleEntry ? ScaleEntry->scale : 1.0f;
+ }
+ }
+}
+
+void ObjectMgr::ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr)
+{
+ // Now add the auras, format "spellid effectindex spellid effectindex..."
+ char *p,*s;
+ std::vector<int> val;
+ s=p=(char*)reinterpret_cast<char const*>(addon->auras);
+ if(p)
+ {
+ while (p[0]!=0)
+ {
+ ++p;
+ if (p[0]==' ')
+ {
+ val.push_back(atoi(s));
+ s=++p;
+ }
+ }
+ if (p!=s)
+ val.push_back(atoi(s));
+
+ // free char* loaded memory
+ delete[] (char*)reinterpret_cast<char const*>(addon->auras);
+
+ // wrong list
+ if (val.size()%2)
+ {
+ addon->auras = NULL;
+ sLog.outErrorDb("Creature (%s: %u) has wrong `auras` data in `%s`.",guidEntryStr,addon->guidOrEntry,table);
+ return;
+ }
+ }
+
+ // empty list
+ if(val.empty())
+ {
+ addon->auras = NULL;
+ return;
+ }
+
+ // replace by new structures array
+ const_cast<CreatureDataAddonAura*&>(addon->auras) = new CreatureDataAddonAura[val.size()/2+1];
+
+ int i=0;
+ for(int j=0;j<val.size()/2;++j)
+ {
+ CreatureDataAddonAura& cAura = const_cast<CreatureDataAddonAura&>(addon->auras[i]);
+ cAura.spell_id = (uint32)val[2*j+0];
+ cAura.effect_idx = (uint32)val[2*j+1];
+ if ( cAura.effect_idx > 2 )
+ {
+ sLog.outErrorDb("Creature (%s: %u) has wrong effect %u for spell %u in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,cAura.effect_idx,cAura.spell_id,table);
+ continue;
+ }
+ SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(cAura.spell_id);
+ if (!AdditionalSpellInfo)
+ {
+ sLog.outErrorDb("Creature (%s: %u) has wrong spell %u defined in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,cAura.spell_id,table);
+ continue;
+ }
+
+ if (!AdditionalSpellInfo->Effect[cAura.effect_idx] || !AdditionalSpellInfo->EffectApplyAuraName[cAura.effect_idx])
+ {
+ sLog.outErrorDb("Creature (%s: %u) has not aura effect %u of spell %u defined in `auras` field in `%s`.",guidEntryStr,addon->guidOrEntry,cAura.effect_idx,cAura.spell_id,table);
+ continue;
+ }
+
+ ++i;
+ }
+
+ // fill terminator element (after last added)
+ CreatureDataAddonAura& endAura = const_cast<CreatureDataAddonAura&>(addon->auras[i]);
+ endAura.spell_id = 0;
+ endAura.effect_idx = 0;
+}
+
+void ObjectMgr::LoadCreatureAddons()
+{
+ sCreatureInfoAddonStorage.Load();
+
+ sLog.outString( ">> Loaded %u creature template addons", sCreatureInfoAddonStorage.RecordCount );
+ sLog.outString();
+
+ // check data correctness and convert 'auras'
+ for(uint32 i = 1; i < sCreatureInfoAddonStorage.MaxEntry; ++i)
+ {
+ CreatureDataAddon const* addon = sCreatureInfoAddonStorage.LookupEntry<CreatureDataAddon>(i);
+ if(!addon)
+ continue;
+
+ ConvertCreatureAddonAuras(const_cast<CreatureDataAddon*>(addon), "creature_template_addon", "Entry");
+
+ if(!sCreatureStorage.LookupEntry<CreatureInfo>(addon->guidOrEntry))
+ sLog.outErrorDb("Creature (Entry: %u) does not exist but has a record in `creature_template_addon`",addon->guidOrEntry);
+ }
+
+ sCreatureDataAddonStorage.Load();
+
+ sLog.outString( ">> Loaded %u creature addons", sCreatureDataAddonStorage.RecordCount );
+ sLog.outString();
+
+ // check data correctness and convert 'auras'
+ for(uint32 i = 1; i < sCreatureDataAddonStorage.MaxEntry; ++i)
+ {
+ CreatureDataAddon const* addon = sCreatureDataAddonStorage.LookupEntry<CreatureDataAddon>(i);
+ if(!addon)
+ continue;
+
+ ConvertCreatureAddonAuras(const_cast<CreatureDataAddon*>(addon), "creature_addon", "GUIDLow");
+
+ if(mCreatureDataMap.find(addon->guidOrEntry)==mCreatureDataMap.end())
+ sLog.outErrorDb("Creature (GUID: %u) does not exist but has a record in `creature_addon`",addon->guidOrEntry);
+ }
+}
+
+EquipmentInfo const* ObjectMgr::GetEquipmentInfo(uint32 entry)
+{
+ return sEquipmentStorage.LookupEntry<EquipmentInfo>(entry);
+}
+
+void ObjectMgr::LoadEquipmentTemplates()
+{
+ sEquipmentStorage.Load();
+
+ sLog.outString( ">> Loaded %u equipment template", sEquipmentStorage.RecordCount );
+ sLog.outString();
+}
+
+CreatureModelInfo const* ObjectMgr::GetCreatureModelInfo(uint32 modelid)
+{
+ return sCreatureModelStorage.LookupEntry<CreatureModelInfo>(modelid);
+}
+
+uint32 ObjectMgr::ChooseDisplayId(uint32 team, const CreatureInfo *cinfo, const CreatureData *data)
+{
+ // Load creature model (display id)
+ uint32 display_id = 0;
+
+ if (!data || data->displayid == 0) // use defaults from the template
+ {
+ display_id = cinfo->GetRandomValidModelId();
+ } else display_id = data->displayid; // overwritten from creature data
+
+ return display_id;
+}
+
+CreatureModelInfo const* ObjectMgr::GetCreatureModelRandomGender(uint32 display_id)
+{
+ CreatureModelInfo const *minfo = GetCreatureModelInfo(display_id);
+ if(!minfo)
+ return NULL;
+
+ // If a model for another gender exists, 50% chance to use it
+ if(minfo->modelid_other_gender != 0 && urand(0,1) == 0)
+ {
+ CreatureModelInfo const *minfo_tmp = GetCreatureModelInfo(minfo->modelid_other_gender);
+ if(!minfo_tmp)
+ {
+ sLog.outErrorDb("Model (Entry: %u) has modelid_other_gender %u not found in table `creature_model_info`. ", minfo->modelid, minfo->modelid_other_gender);
+ return minfo; // not fatal, just use the previous one
+ }
+ else
+ return minfo_tmp;
+ }
+ else
+ return minfo;
+}
+
+void ObjectMgr::LoadCreatureModelInfo()
+{
+ sCreatureModelStorage.Load();
+
+ sLog.outString( ">> Loaded %u creature model based info", sCreatureModelStorage.RecordCount );
+ sLog.outString();
+
+ // check if combat_reach is valid
+ for(uint32 i = 1; i < sCreatureModelStorage.MaxEntry; ++i)
+ {
+ CreatureModelInfo const* mInfo = sCreatureModelStorage.LookupEntry<CreatureModelInfo>(i);
+ if(!mInfo)
+ continue;
+
+ if(mInfo->combat_reach < 0.5f)
+ {
+ //sLog.outErrorDb("Creature model (Entry: %u) has invalid combat reach (%f), setting it to 0.5", mInfo->modelid, mInfo->combat_reach);
+ const_cast<CreatureModelInfo*>(mInfo)->combat_reach = 0.5f;
+ }
+ }
+}
+
+void ObjectMgr::LoadCreatures()
+{
+ uint32 count = 0;
+ // 0 1 2 3
+ QueryResult *result = WorldDatabase.Query("SELECT creature.guid, id, map, modelid,"
+ // 4 5 6 7 8 9 10 11
+ "equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, currentwaypoint,"
+ // 12 13 14 15 16 17
+ "curhealth, curmana, DeathState, MovementType, spawnMask, event "
+ "FROM creature LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString("");
+ sLog.outErrorDb(">> Loaded 0 creature. DB table `creature` is empty.");
+ return;
+ }
+
+ // build single time for check creature data
+ std::set<uint32> heroicCreatures;
+ for(uint32 i = 0; i < sCreatureStorage.MaxEntry; ++i)
+ if(CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(i))
+ if(cInfo->HeroicEntry)
+ heroicCreatures.insert(cInfo->HeroicEntry);
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 guid = fields[0].GetUInt32();
+
+ CreatureData& data = mCreatureDataMap[guid];
+
+ data.id = fields[ 1].GetUInt32();
+ data.mapid = fields[ 2].GetUInt32();
+ data.displayid = fields[ 3].GetUInt32();
+ data.equipmentId = fields[ 4].GetUInt32();
+ data.posX = fields[ 5].GetFloat();
+ data.posY = fields[ 6].GetFloat();
+ data.posZ = fields[ 7].GetFloat();
+ data.orientation = fields[ 8].GetFloat();
+ data.spawntimesecs = fields[ 9].GetUInt32();
+ data.spawndist = fields[10].GetFloat();
+ data.currentwaypoint= fields[11].GetUInt32();
+ data.curhealth = fields[12].GetUInt32();
+ data.curmana = fields[13].GetUInt32();
+ data.is_dead = fields[14].GetBool();
+ data.movementType = fields[15].GetUInt8();
+ data.spawnMask = fields[16].GetUInt8();
+ int16 gameEvent = fields[17].GetInt16();
+
+ CreatureInfo const* cInfo = GetCreatureTemplate(data.id);
+ if(!cInfo)
+ {
+ sLog.outErrorDb("Table `creature` have creature (GUID: %u) with not existed creature entry %u, skipped.",guid,data.id );
+ continue;
+ }
+
+ if(heroicCreatures.find(data.id)!=heroicCreatures.end())
+ {
+ sLog.outErrorDb("Table `creature` have creature (GUID: %u) that listed as heroic template in `creature_template_substitution`, skipped.",guid,data.id );
+ continue;
+ }
+
+ if(data.equipmentId > 0) // -1 no equipment, 0 use default
+ {
+ if(!GetEquipmentInfo(data.equipmentId))
+ {
+ sLog.outErrorDb("Table `creature` have creature (Entry: %u) with equipment_id %u not found in table `creature_equip_template`, set to no equipment.", data.id, data.equipmentId);
+ data.equipmentId = -1;
+ }
+ }
+
+ if(cInfo->RegenHealth && data.curhealth < cInfo->minhealth)
+ {
+ sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `creature_template`.`RegenHealth`=1 and low current health (%u), `creature_template`.`minhealth`=%u.",guid,data.id,data.curhealth, cInfo->minhealth );
+ data.curhealth = cInfo->minhealth;
+ }
+
+ if(data.curmana < cInfo->minmana)
+ {
+ sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with low current mana (%u), `creature_template`.`minmana`=%u.",guid,data.id,data.curmana, cInfo->minmana );
+ data.curmana = cInfo->minmana;
+ }
+
+ if(data.spawndist < 0.0f)
+ {
+ sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `spawndist`< 0, set to 0.",guid,data.id );
+ data.spawndist = 0.0f;
+ }
+ else if(data.movementType == RANDOM_MOTION_TYPE)
+ {
+ if(data.spawndist == 0.0f)
+ {
+ sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `MovementType`=1 (random movement) but with `spawndist`=0, replace by idle movement type (0).",guid,data.id );
+ data.movementType = IDLE_MOTION_TYPE;
+ }
+ }
+ else if(data.movementType == IDLE_MOTION_TYPE)
+ {
+ if(data.spawndist != 0.0f)
+ {
+ sLog.outErrorDb("Table `creature` have creature (GUID: %u Entry: %u) with `MovementType`=0 (idle) have `spawndist`<>0, set to 0.",guid,data.id );
+ data.spawndist = 0.0f;
+ }
+ }
+
+ if (gameEvent==0) // if not this is to be managed by GameEvent System
+ AddCreatureToGrid(guid, &data);
+ ++count;
+
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u creatures", mCreatureDataMap.size() );
+}
+
+void ObjectMgr::AddCreatureToGrid(uint32 guid, CreatureData const* data)
+{
+ uint8 mask = data->spawnMask;
+ for(uint8 i = 0; mask != 0; i++, mask >>= 1)
+ {
+ if(mask & 1)
+ {
+ CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY);
+ uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
+
+ CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id];
+ cell_guids.creatures.insert(guid);
+ }
+ }
+}
+
+void ObjectMgr::RemoveCreatureFromGrid(uint32 guid, CreatureData const* data)
+{
+ uint8 mask = data->spawnMask;
+ for(uint8 i = 0; mask != 0; i++, mask >>= 1)
+ {
+ if(mask & 1)
+ {
+ CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY);
+ uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
+
+ CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id];
+ cell_guids.creatures.erase(guid);
+ }
+ }
+}
+
+void ObjectMgr::LoadGameobjects()
+{
+ uint32 count = 0;
+
+ // 0 1 2 3 4 5 6
+ QueryResult *result = WorldDatabase.Query("SELECT gameobject.guid, id, map, position_x, position_y, position_z, orientation,"
+ // 7 8 9 10 11 12 13 14 15
+ "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, event "
+ "FROM gameobject LEFT OUTER JOIN game_event_gameobject ON gameobject.guid = game_event_gameobject.guid");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded 0 gameobjects. DB table `gameobject` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 guid = fields[0].GetUInt32();
+
+ GameObjectData& data = mGameObjectDataMap[guid];
+
+ data.id = fields[ 1].GetUInt32();
+ data.mapid = fields[ 2].GetUInt32();
+ data.posX = fields[ 3].GetFloat();
+ data.posY = fields[ 4].GetFloat();
+ data.posZ = fields[ 5].GetFloat();
+ data.orientation = fields[ 6].GetFloat();
+ data.rotation0 = fields[ 7].GetFloat();
+ data.rotation1 = fields[ 8].GetFloat();
+ data.rotation2 = fields[ 9].GetFloat();
+ data.rotation3 = fields[10].GetFloat();
+ data.spawntimesecs = fields[11].GetInt32();
+ data.animprogress = fields[12].GetUInt32();
+ data.go_state = fields[13].GetUInt32();
+ data.ArtKit = 0;
+ data.spawnMask = fields[14].GetUInt8();
+ int16 gameEvent = fields[15].GetInt16();
+
+ GameObjectInfo const* gInfo = GetGameObjectInfo(data.id);
+ if(!gInfo)
+ {
+ sLog.outErrorDb("Table `gameobject` have gameobject (GUID: %u) with not existed gameobject entry %u, skipped.",guid,data.id );
+ continue;
+ }
+
+ if (gameEvent==0) // if not this is to be managed by GameEvent System
+ AddGameobjectToGrid(guid, &data);
+ ++count;
+
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u gameobjects", mGameObjectDataMap.size());
+}
+
+void ObjectMgr::AddGameobjectToGrid(uint32 guid, GameObjectData const* data)
+{
+ uint8 mask = data->spawnMask;
+ for(uint8 i = 0; mask != 0; i++, mask >>= 1)
+ {
+ if(mask & 1)
+ {
+ CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY);
+ uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
+
+ CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id];
+ cell_guids.gameobjects.insert(guid);
+ }
+ }
+}
+
+void ObjectMgr::RemoveGameobjectFromGrid(uint32 guid, GameObjectData const* data)
+{
+ uint8 mask = data->spawnMask;
+ for(uint8 i = 0; mask != 0; i++, mask >>= 1)
+ {
+ if(mask & 1)
+ {
+ CellPair cell_pair = Trinity::ComputeCellPair(data->posX, data->posY);
+ uint32 cell_id = (cell_pair.y_coord*TOTAL_NUMBER_OF_CELLS_PER_MAP) + cell_pair.x_coord;
+
+ CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(data->mapid,i)][cell_id];
+ cell_guids.gameobjects.erase(guid);
+ }
+ }
+}
+
+void ObjectMgr::LoadCreatureRespawnTimes()
+{
+ // remove outdated data
+ WorldDatabase.DirectExecute("DELETE FROM creature_respawn WHERE respawntime <= UNIX_TIMESTAMP(NOW())");
+
+ uint32 count = 0;
+
+ QueryResult *result = WorldDatabase.Query("SELECT guid,respawntime,instance FROM creature_respawn");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outString(">> Loaded 0 creature respawn time.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 loguid = fields[0].GetUInt32();
+ uint64 respawn_time = fields[1].GetUInt64();
+ uint32 instance = fields[2].GetUInt32();
+
+ mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)] = time_t(respawn_time);
+
+ ++count;
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString( ">> Loaded %u creature respawn times", mCreatureRespawnTimes.size() );
+ sLog.outString();
+}
+
+void ObjectMgr::LoadGameobjectRespawnTimes()
+{
+ // remove outdated data
+ WorldDatabase.DirectExecute("DELETE FROM gameobject_respawn WHERE respawntime <= UNIX_TIMESTAMP(NOW())");
+
+ uint32 count = 0;
+
+ QueryResult *result = WorldDatabase.Query("SELECT guid,respawntime,instance FROM gameobject_respawn");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outString(">> Loaded 0 gameobject respawn time.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 loguid = fields[0].GetUInt32();
+ uint64 respawn_time = fields[1].GetUInt64();
+ uint32 instance = fields[2].GetUInt32();
+
+ mGORespawnTimes[MAKE_PAIR64(loguid,instance)] = time_t(respawn_time);
+
+ ++count;
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString( ">> Loaded %u gameobject respawn times", mGORespawnTimes.size() );
+ sLog.outString();
+}
+
+// name must be checked to correctness (if received) before call this function
+uint64 ObjectMgr::GetPlayerGUIDByName(std::string name) const
+{
+ uint64 guid = 0;
+
+ CharacterDatabase.escape_string(name);
+
+ // Player name safe to sending to DB (checked at login) and this function using
+ QueryResult *result = CharacterDatabase.PQuery("SELECT guid FROM characters WHERE name = '%s'", name.c_str());
+ if(result)
+ {
+ guid = MAKE_NEW_GUID((*result)[0].GetUInt32(), 0, HIGHGUID_PLAYER);
+
+ delete result;
+ }
+
+ return guid;
+}
+
+bool ObjectMgr::GetPlayerNameByGUID(const uint64 &guid, std::string &name) const
+{
+ // prevent DB access for online player
+ if(Player* player = GetPlayer(guid))
+ {
+ name = player->GetName();
+ return true;
+ }
+
+ PCachePlayerInfo pInfo = GetPlayerInfoFromCache(GUID_LOPART(guid));
+ if(pInfo)
+ {
+ name = pInfo->sPlayerName.c_str();
+ return true;
+ }
+
+ QueryResult *result = CharacterDatabase.PQuery("SELECT name FROM characters WHERE guid = '%u'", GUID_LOPART(guid));
+
+ if(result)
+ {
+ name = (*result)[0].GetCppString();
+ delete result;
+ return true;
+ }
+
+ return false;
+}
+
+uint32 ObjectMgr::GetPlayerTeamByGUID(const uint64 &guid) const
+{
+ QueryResult *result = CharacterDatabase.PQuery("SELECT race FROM characters WHERE guid = '%u'", GUID_LOPART(guid));
+
+ if(result)
+ {
+ uint8 race = (*result)[0].GetUInt8();
+ delete result;
+ return Player::TeamForRace(race);
+ }
+
+ return 0;
+}
+
+uint32 ObjectMgr::GetPlayerAccountIdByGUID(const uint64 &guid) const
+{
+ QueryResult *result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE guid = '%u'", GUID_LOPART(guid));
+ if(result)
+ {
+ uint32 acc = (*result)[0].GetUInt32();
+ delete result;
+ return acc;
+ }
+
+ return 0;
+}
+
+uint32 ObjectMgr::GetPlayerAccountIdByPlayerName(std::string name) const
+{
+ QueryResult *result = CharacterDatabase.PQuery("SELECT account FROM characters WHERE name = '%s'", name.c_str());
+ if(result)
+ {
+ uint32 acc = (*result)[0].GetUInt32();
+ delete result;
+ return acc;
+ }
+
+ return 0;
+}
+
+void ObjectMgr::LoadAuctions()
+{
+ QueryResult *result = CharacterDatabase.Query("SELECT COUNT(*) FROM auctionhouse");
+ if( !result )
+ return;
+
+ Field *fields = result->Fetch();
+ uint32 AuctionCount=fields[0].GetUInt32();
+ delete result;
+
+ if(!AuctionCount)
+ return;
+
+ result = CharacterDatabase.Query( "SELECT id,auctioneerguid,itemguid,item_template,itemowner,buyoutprice,time,buyguid,lastbid,startbid,deposit,location FROM auctionhouse" );
+ if( !result )
+ return;
+
+ barGoLink bar( AuctionCount );
+
+ AuctionEntry *aItem;
+
+ do
+ {
+ fields = result->Fetch();
+
+ bar.step();
+
+ aItem = new AuctionEntry;
+ aItem->Id = fields[0].GetUInt32();
+ aItem->auctioneer = fields[1].GetUInt32();
+ aItem->item_guidlow = fields[2].GetUInt32();
+ aItem->item_template = fields[3].GetUInt32();
+ aItem->owner = fields[4].GetUInt32();
+ aItem->buyout = fields[5].GetUInt32();
+ aItem->time = fields[6].GetUInt32();
+ aItem->bidder = fields[7].GetUInt32();
+ aItem->bid = fields[8].GetUInt32();
+ aItem->startbid = fields[9].GetUInt32();
+ aItem->deposit = fields[10].GetUInt32();
+ aItem->location = fields[11].GetUInt8();
+ //check if sold item exists
+ if ( GetAItem( aItem->item_guidlow ) )
+ {
+ GetAuctionsMap( aItem->location )->AddAuction(aItem);
+ }
+ else
+ {
+ CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE id = '%u'",aItem->Id);
+ sLog.outError("Auction %u has not a existing item : %u", aItem->Id, aItem->item_guidlow);
+ delete aItem;
+ }
+ } while (result->NextRow());
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u auctions", AuctionCount );
+ sLog.outString();
+}
+
+void ObjectMgr::LoadItemLocales()
+{
+ mItemLocaleMap.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query("SELECT entry,name_loc1,description_loc1,name_loc2,description_loc2,name_loc3,description_loc3,name_loc4,description_loc4,name_loc5,description_loc5,name_loc6,description_loc6,name_loc7,description_loc7,name_loc8,description_loc8 FROM locales_item");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString("");
+ sLog.outString(">> Loaded 0 Item locale strings. DB table `locales_item` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 entry = fields[0].GetUInt32();
+
+ ItemLocale& data = mItemLocaleMap[entry];
+
+ for(int i = 1; i < MAX_LOCALE; ++i)
+ {
+ std::string str = fields[1+2*(i-1)].GetCppString();
+ if(!str.empty())
+ {
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.Name.size() <= idx)
+ data.Name.resize(idx+1);
+
+ data.Name[idx] = str;
+ }
+ }
+
+ str = fields[1+2*(i-1)+1].GetCppString();
+ if(!str.empty())
+ {
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.Description.size() <= idx)
+ data.Description.resize(idx+1);
+
+ data.Description[idx] = str;
+ }
+ }
+ }
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u Item locale strings", mItemLocaleMap.size() );
+}
+
+struct SQLItemLoader : public SQLStorageLoaderBase<SQLItemLoader>
+{
+ template<class D>
+ void convert_from_str(uint32 field_pos, char *src, D &dst)
+ {
+ dst = D(objmgr.GetScriptId(src));
+ }
+};
+
+void ObjectMgr::LoadItemPrototypes()
+{
+ SQLItemLoader loader;
+ loader.Load(sItemStorage);
+ sLog.outString( ">> Loaded %u item prototypes", sItemStorage.RecordCount );
+ sLog.outString();
+
+ // check data correctness
+ for(uint32 i = 1; i < sItemStorage.MaxEntry; ++i)
+ {
+ ItemPrototype const* proto = sItemStorage.LookupEntry<ItemPrototype >(i);
+ ItemEntry const *dbcitem = sItemStore.LookupEntry(i);
+ if(!proto)
+ {
+ /* to many errors, and possible not all items really used in game
+ if (dbcitem)
+ sLog.outErrorDb("Item (Entry: %u) doesn't exists in DB, but must exist.",i);
+ */
+ continue;
+ }
+
+ if(dbcitem)
+ {
+ if(proto->InventoryType != dbcitem->InventoryType)
+ {
+ sLog.outErrorDb("Item (Entry: %u) not correct %u inventory type, must be %u (still using DB value).",i,proto->InventoryType,dbcitem->InventoryType);
+ // It safe let use InventoryType from DB
+ }
+
+ if(proto->DisplayInfoID != dbcitem->DisplayId)
+ {
+ sLog.outErrorDb("Item (Entry: %u) not correct %u display id, must be %u (using it).",i,proto->DisplayInfoID,dbcitem->DisplayId);
+ const_cast<ItemPrototype*>(proto)->DisplayInfoID = dbcitem->DisplayId;
+ }
+ if(proto->Sheath != dbcitem->Sheath)
+ {
+ sLog.outErrorDb("Item (Entry: %u) not correct %u sheath, must be %u (using it).",i,proto->Sheath,dbcitem->Sheath);
+ const_cast<ItemPrototype*>(proto)->Sheath = dbcitem->Sheath;
+ }
+ }
+ else
+ {
+ sLog.outErrorDb("Item (Entry: %u) not correct (not listed in list of existed items).",i);
+ }
+
+ if(proto->Class >= MAX_ITEM_CLASS)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong Class value (%u)",i,proto->Class);
+ const_cast<ItemPrototype*>(proto)->Class = ITEM_CLASS_JUNK;
+ }
+
+ if(proto->SubClass >= MaxItemSubclassValues[proto->Class])
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong Subclass value (%u) for class %u",i,proto->SubClass,proto->Class);
+ const_cast<ItemPrototype*>(proto)->SubClass = 0;// exist for all item classes
+ }
+
+ if(proto->Quality >= MAX_ITEM_QUALITY)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong Quality value (%u)",i,proto->Quality);
+ const_cast<ItemPrototype*>(proto)->Quality = ITEM_QUALITY_NORMAL;
+ }
+
+ if(proto->BuyCount <= 0)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong BuyCount value (%u), set to default(1).",i,proto->BuyCount);
+ const_cast<ItemPrototype*>(proto)->BuyCount = 1;
+ }
+
+ if(proto->InventoryType >= MAX_INVTYPE)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong InventoryType value (%u)",i,proto->InventoryType);
+ const_cast<ItemPrototype*>(proto)->InventoryType = INVTYPE_NON_EQUIP;
+ }
+
+ if(proto->RequiredSkill >= MAX_SKILL_TYPE)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong RequiredSkill value (%u)",i,proto->RequiredSkill);
+ const_cast<ItemPrototype*>(proto)->RequiredSkill = 0;
+ }
+
+ if(!(proto->AllowableClass & CLASSMASK_ALL_PLAYABLE))
+ {
+ sLog.outErrorDb("Item (Entry: %u) not have in `AllowableClass` any playable classes (%u) and can't be equipped.",i,proto->AllowableClass);
+ }
+
+ if(!(proto->AllowableRace & RACEMASK_ALL_PLAYABLE))
+ {
+ sLog.outErrorDb("Item (Entry: %u) not have in `AllowableRace` any playable races (%u) and can't be equipped.",i,proto->AllowableRace);
+ }
+
+ if(proto->RequiredSpell && !sSpellStore.LookupEntry(proto->RequiredSpell))
+ {
+ sLog.outErrorDb("Item (Entry: %u) have wrong (non-existed) spell in RequiredSpell (%u)",i,proto->RequiredSpell);
+ const_cast<ItemPrototype*>(proto)->RequiredSpell = 0;
+ }
+
+ if(proto->RequiredReputationRank >= MAX_REPUTATION_RANK)
+ sLog.outErrorDb("Item (Entry: %u) has wrong reputation rank in RequiredReputationRank (%u), item can't be used.",i,proto->RequiredReputationRank);
+
+ if(proto->RequiredReputationFaction)
+ {
+ if(!sFactionStore.LookupEntry(proto->RequiredReputationFaction))
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) faction in RequiredReputationFaction (%u)",i,proto->RequiredReputationFaction);
+ const_cast<ItemPrototype*>(proto)->RequiredReputationFaction = 0;
+ }
+
+ if(proto->RequiredReputationRank == MIN_REPUTATION_RANK)
+ sLog.outErrorDb("Item (Entry: %u) has min. reputation rank in RequiredReputationRank (0) but RequiredReputationFaction > 0, faction setting is useless.",i);
+ }
+ else if(proto->RequiredReputationRank > MIN_REPUTATION_RANK)
+ sLog.outErrorDb("Item (Entry: %u) has RequiredReputationFaction ==0 but RequiredReputationRank > 0, rank setting is useless.",i);
+
+ if(proto->Stackable==0)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong value in stackable (%u), replace by default 1.",i,proto->Stackable);
+ const_cast<ItemPrototype*>(proto)->Stackable = 1;
+ }
+ else if(proto->Stackable > 255)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has too large value in stackable (%u), replace by hardcoded upper limit (255).",i,proto->Stackable);
+ const_cast<ItemPrototype*>(proto)->Stackable = 255;
+ }
+
+ for (int j = 0; j < 10; j++)
+ {
+ // for ItemStatValue != 0
+ if(proto->ItemStat[j].ItemStatValue && proto->ItemStat[j].ItemStatType >= MAX_ITEM_MOD)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong stat_type%d (%u)",i,j+1,proto->ItemStat[j].ItemStatType);
+ const_cast<ItemPrototype*>(proto)->ItemStat[j].ItemStatType = 0;
+ }
+ }
+
+ for (int j = 0; j < 5; j++)
+ {
+ if(proto->Damage[j].DamageType >= MAX_SPELL_SCHOOL)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong dmg_type%d (%u)",i,j+1,proto->Damage[j].DamageType);
+ const_cast<ItemPrototype*>(proto)->Damage[j].DamageType = 0;
+ }
+ }
+
+ // special format
+ if(proto->Spells[0].SpellId == SPELL_ID_GENERIC_LEARN)
+ {
+ // spell_1
+ if(proto->Spells[0].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u) for special learning format",i,0+1,proto->Spells[0].SpellTrigger);
+ const_cast<ItemPrototype*>(proto)->Spells[0].SpellId = 0;
+ const_cast<ItemPrototype*>(proto)->Spells[0].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
+ const_cast<ItemPrototype*>(proto)->Spells[1].SpellId = 0;
+ const_cast<ItemPrototype*>(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
+ }
+
+ // spell_2 have learning spell
+ if(proto->Spells[1].SpellTrigger != ITEM_SPELLTRIGGER_LEARN_SPELL_ID)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u) for special learning format.",i,1+1,proto->Spells[1].SpellTrigger);
+ const_cast<ItemPrototype*>(proto)->Spells[0].SpellId = 0;
+ const_cast<ItemPrototype*>(proto)->Spells[1].SpellId = 0;
+ const_cast<ItemPrototype*>(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
+ }
+ else if(!proto->Spells[1].SpellId)
+ {
+ sLog.outErrorDb("Item (Entry: %u) not has expected spell in spellid_%d in special learning format.",i,1+1);
+ const_cast<ItemPrototype*>(proto)->Spells[0].SpellId = 0;
+ const_cast<ItemPrototype*>(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
+ }
+ else
+ {
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(proto->Spells[1].SpellId);
+ if(!spellInfo)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) spell in spellid_%d (%u)",i,1+1,proto->Spells[1].SpellId);
+ const_cast<ItemPrototype*>(proto)->Spells[0].SpellId = 0;
+ const_cast<ItemPrototype*>(proto)->Spells[1].SpellId = 0;
+ const_cast<ItemPrototype*>(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
+ }
+ // allowed only in special format
+ else if(proto->Spells[1].SpellId==SPELL_ID_GENERIC_LEARN)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has broken spell in spellid_%d (%u)",i,1+1,proto->Spells[1].SpellId);
+ const_cast<ItemPrototype*>(proto)->Spells[0].SpellId = 0;
+ const_cast<ItemPrototype*>(proto)->Spells[1].SpellId = 0;
+ const_cast<ItemPrototype*>(proto)->Spells[1].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
+ }
+ }
+
+ // spell_3*,spell_4*,spell_5* is empty
+ for (int j = 2; j < 5; j++)
+ {
+ if(proto->Spells[j].SpellTrigger != ITEM_SPELLTRIGGER_ON_USE)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u)",i,j+1,proto->Spells[j].SpellTrigger);
+ const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
+ const_cast<ItemPrototype*>(proto)->Spells[j].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
+ }
+ else if(proto->Spells[j].SpellId != 0)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong spell in spellid_%d (%u) for learning special format",i,j+1,proto->Spells[j].SpellId);
+ const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
+ }
+ }
+ }
+ // normal spell list
+ else
+ {
+ for (int j = 0; j < 5; j++)
+ {
+ if(proto->Spells[j].SpellTrigger >= MAX_ITEM_SPELLTRIGGER || proto->Spells[j].SpellTrigger == ITEM_SPELLTRIGGER_LEARN_SPELL_ID)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong item spell trigger value in spelltrigger_%d (%u)",i,j+1,proto->Spells[j].SpellTrigger);
+ const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
+ const_cast<ItemPrototype*>(proto)->Spells[j].SpellTrigger = ITEM_SPELLTRIGGER_ON_USE;
+ }
+
+ if(proto->Spells[j].SpellId)
+ {
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(proto->Spells[j].SpellId);
+ if(!spellInfo)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong (not existing) spell in spellid_%d (%u)",i,j+1,proto->Spells[j].SpellId);
+ const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
+ }
+ // allowed only in special format
+ else if(proto->Spells[j].SpellId==SPELL_ID_GENERIC_LEARN)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has broken spell in spellid_%d (%u)",i,j+1,proto->Spells[j].SpellId);
+ const_cast<ItemPrototype*>(proto)->Spells[j].SpellId = 0;
+ }
+ }
+ }
+ }
+
+ if(proto->Bonding >= MAX_BIND_TYPE)
+ sLog.outErrorDb("Item (Entry: %u) has wrong Bonding value (%u)",i,proto->Bonding);
+
+ if(proto->PageText && !sPageTextStore.LookupEntry<PageText>(proto->PageText))
+ sLog.outErrorDb("Item (Entry: %u) has non existing first page (Id:%u)", i,proto->PageText);
+
+ if(proto->LockID && !sLockStore.LookupEntry(proto->LockID))
+ sLog.outErrorDb("Item (Entry: %u) has wrong LockID (%u)",i,proto->LockID);
+
+ if(proto->Sheath >= MAX_SHEATHETYPE)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong Sheath (%u)",i,proto->Sheath);
+ const_cast<ItemPrototype*>(proto)->Sheath = SHEATHETYPE_NONE;
+ }
+
+ if(proto->RandomProperty && !sItemRandomPropertiesStore.LookupEntry(GetItemEnchantMod(proto->RandomProperty)))
+ {
+ sLog.outErrorDb("Item (Entry: %u) has unknown (wrong or not listed in `item_enchantment_template`) RandomProperty (%u)",i,proto->RandomProperty);
+ const_cast<ItemPrototype*>(proto)->RandomProperty = 0;
+ }
+
+ if(proto->RandomSuffix && !sItemRandomSuffixStore.LookupEntry(GetItemEnchantMod(proto->RandomSuffix)))
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong RandomSuffix (%u)",i,proto->RandomSuffix);
+ const_cast<ItemPrototype*>(proto)->RandomSuffix = 0;
+ }
+
+ if(proto->ItemSet && !sItemSetStore.LookupEntry(proto->ItemSet))
+ {
+ sLog.outErrorDb("Item (Entry: %u) have wrong ItemSet (%u)",i,proto->ItemSet);
+ const_cast<ItemPrototype*>(proto)->ItemSet = 0;
+ }
+
+ if(proto->Area && !GetAreaEntryByAreaID(proto->Area))
+ sLog.outErrorDb("Item (Entry: %u) has wrong Area (%u)",i,proto->Area);
+
+ if(proto->Map && !sMapStore.LookupEntry(proto->Map))
+ sLog.outErrorDb("Item (Entry: %u) has wrong Map (%u)",i,proto->Map);
+
+ if(proto->TotemCategory && !sTotemCategoryStore.LookupEntry(proto->TotemCategory))
+ sLog.outErrorDb("Item (Entry: %u) has wrong TotemCategory (%u)",i,proto->TotemCategory);
+
+ for (int j = 0; j < 3; j++)
+ {
+ if(proto->Socket[j].Color && (proto->Socket[j].Color & SOCKET_COLOR_ALL) != proto->Socket[j].Color)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong socketColor_%d (%u)",i,j+1,proto->Socket[j].Color);
+ const_cast<ItemPrototype*>(proto)->Socket[j].Color = 0;
+ }
+ }
+
+ if(proto->GemProperties && !sGemPropertiesStore.LookupEntry(proto->GemProperties))
+ sLog.outErrorDb("Item (Entry: %u) has wrong GemProperties (%u)",i,proto->GemProperties);
+
+ if(proto->FoodType >= MAX_PET_DIET)
+ {
+ sLog.outErrorDb("Item (Entry: %u) has wrong FoodType value (%u)",i,proto->FoodType);
+ const_cast<ItemPrototype*>(proto)->FoodType = 0;
+ }
+ }
+
+ // this DBC used currently only for check item templates in DB.
+ sItemStore.Clear();
+}
+
+void ObjectMgr::LoadAuctionItems()
+{
+ QueryResult *result = CharacterDatabase.Query( "SELECT itemguid,item_template FROM auctionhouse" );
+
+ if( !result )
+ return;
+
+ barGoLink bar( result->GetRowCount() );
+
+ uint32 count = 0;
+
+ Field *fields;
+ do
+ {
+ bar.step();
+
+ fields = result->Fetch();
+ uint32 item_guid = fields[0].GetUInt32();
+ uint32 item_template = fields[1].GetUInt32();
+
+ ItemPrototype const *proto = GetItemPrototype(item_template);
+
+ if(!proto)
+ {
+ sLog.outError( "ObjectMgr::LoadAuctionItems: Unknown item (GUID: %u id: #%u) in auction, skipped.", item_guid,item_template);
+ continue;
+ }
+
+ Item *item = NewItemOrBag(proto);
+
+ if(!item->LoadFromDB(item_guid,0))
+ {
+ delete item;
+ continue;
+ }
+ AddAItem(item);
+
+ ++count;
+ }
+ while( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u auction items", count );
+}
+
+void ObjectMgr::LoadPetLevelInfo()
+{
+ // Loading levels data
+ {
+ // 0 1 2 3 4 5 6 7 8 9
+ QueryResult *result = WorldDatabase.Query("SELECT creature_entry, level, hp, mana, str, agi, sta, inte, spi, armor FROM pet_levelstats");
+
+ uint32 count = 0;
+
+ if (!result)
+ {
+ barGoLink bar( 1 );
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u level pet stats definitions", count );
+ sLog.outErrorDb( "Error loading `pet_levelstats` table or empty table.");
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ Field* fields = result->Fetch();
+
+ uint32 creature_id = fields[0].GetUInt32();
+ if(!sCreatureStorage.LookupEntry<CreatureInfo>(creature_id))
+ {
+ sLog.outErrorDb("Wrong creature id %u in `pet_levelstats` table, ignoring.",creature_id);
+ continue;
+ }
+
+ uint32 current_level = fields[1].GetUInt32();
+ if(current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
+ {
+ if(current_level > 255) // hardcoded level maximum
+ sLog.outErrorDb("Wrong (> 255) level %u in `pet_levelstats` table, ignoring.",current_level);
+ else
+ sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `pet_levelstats` table, ignoring.",current_level);
+ continue;
+ }
+ else if(current_level < 1)
+ {
+ sLog.outErrorDb("Wrong (<1) level %u in `pet_levelstats` table, ignoring.",current_level);
+ continue;
+ }
+
+ PetLevelInfo*& pInfoMapEntry = petInfo[creature_id];
+
+ if(pInfoMapEntry==NULL)
+ pInfoMapEntry = new PetLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)];
+
+ // data for level 1 stored in [0] array element, ...
+ PetLevelInfo* pLevelInfo = &pInfoMapEntry[current_level-1];
+
+ pLevelInfo->health = fields[2].GetUInt16();
+ pLevelInfo->mana = fields[3].GetUInt16();
+ pLevelInfo->armor = fields[9].GetUInt16();
+
+ for (int i = 0; i < MAX_STATS; i++)
+ {
+ pLevelInfo->stats[i] = fields[i+4].GetUInt16();
+ }
+
+ bar.step();
+ ++count;
+ }
+ while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u level pet stats definitions", count );
+ }
+
+ // Fill gaps and check integrity
+ for (PetLevelInfoMap::iterator itr = petInfo.begin(); itr != petInfo.end(); ++itr)
+ {
+ PetLevelInfo* pInfo = itr->second;
+
+ // fatal error if no level 1 data
+ if(!pInfo || pInfo[0].health == 0 )
+ {
+ sLog.outErrorDb("Creature %u does not have pet stats data for Level 1!",itr->first);
+ exit(1);
+ }
+
+ // fill level gaps
+ for (uint32 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
+ {
+ if(pInfo[level].health == 0)
+ {
+ sLog.outErrorDb("Creature %u has no data for Level %i pet stats data, using data of Level %i.",itr->first,level+1, level);
+ pInfo[level] = pInfo[level-1];
+ }
+ }
+ }
+}
+
+PetLevelInfo const* ObjectMgr::GetPetLevelInfo(uint32 creature_id, uint32 level) const
+{
+ if(level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
+ level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL);
+
+ PetLevelInfoMap::const_iterator itr = petInfo.find(creature_id);
+ if(itr == petInfo.end())
+ return NULL;
+
+ return &itr->second[level-1]; // data for level 1 stored in [0] array element, ...
+}
+
+void ObjectMgr::LoadPlayerInfo()
+{
+ // Load playercreate
+ {
+ // 0 1 2 3 4 5 6
+ QueryResult *result = WorldDatabase.Query("SELECT race, class, map, zone, position_x, position_y, position_z FROM playercreateinfo");
+
+ uint32 count = 0;
+
+ if (!result)
+ {
+ barGoLink bar( 1 );
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u player create definitions", count );
+ sLog.outErrorDb( "Error loading `playercreateinfo` table or empty table.");
+ exit(1);
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ Field* fields = result->Fetch();
+
+ uint32 current_race = fields[0].GetUInt32();
+ uint32 current_class = fields[1].GetUInt32();
+ uint32 mapId = fields[2].GetUInt32();
+ uint32 zoneId = fields[3].GetUInt32();
+ float positionX = fields[4].GetFloat();
+ float positionY = fields[5].GetFloat();
+ float positionZ = fields[6].GetFloat();
+
+ if(current_race >= MAX_RACES)
+ {
+ sLog.outErrorDb("Wrong race %u in `playercreateinfo` table, ignoring.",current_race);
+ continue;
+ }
+
+ ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(current_race);
+ if(!rEntry)
+ {
+ sLog.outErrorDb("Wrong race %u in `playercreateinfo` table, ignoring.",current_race);
+ continue;
+ }
+
+ if(current_class >= MAX_CLASSES)
+ {
+ sLog.outErrorDb("Wrong class %u in `playercreateinfo` table, ignoring.",current_class);
+ continue;
+ }
+
+ if(!sChrClassesStore.LookupEntry(current_class))
+ {
+ sLog.outErrorDb("Wrong class %u in `playercreateinfo` table, ignoring.",current_class);
+ continue;
+ }
+
+ // accept DB data only for valid position (and non instanceable)
+ if( !MapManager::IsValidMapCoord(mapId,positionX,positionY,positionZ) )
+ {
+ sLog.outErrorDb("Wrong home position for class %u race %u pair in `playercreateinfo` table, ignoring.",current_class,current_race);
+ continue;
+ }
+
+ if( sMapStore.LookupEntry(mapId)->Instanceable() )
+ {
+ sLog.outErrorDb("Home position in instanceable map for class %u race %u pair in `playercreateinfo` table, ignoring.",current_class,current_race);
+ continue;
+ }
+
+ PlayerInfo* pInfo = &playerInfo[current_race][current_class];
+
+ pInfo->mapId = mapId;
+ pInfo->zoneId = zoneId;
+ pInfo->positionX = positionX;
+ pInfo->positionY = positionY;
+ pInfo->positionZ = positionZ;
+
+ pInfo->displayId_m = rEntry->model_m;
+ pInfo->displayId_f = rEntry->model_f;
+
+ bar.step();
+ ++count;
+ }
+ while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u player create definitions", count );
+ }
+
+ // Load playercreate items
+ {
+ // 0 1 2 3
+ QueryResult *result = WorldDatabase.Query("SELECT race, class, itemid, amount FROM playercreateinfo_item");
+
+ uint32 count = 0;
+
+ if (!result)
+ {
+ barGoLink bar( 1 );
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u custom player create items", count );
+ }
+ else
+ {
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ Field* fields = result->Fetch();
+
+ uint32 current_race = fields[0].GetUInt32();
+ if(current_race >= MAX_RACES)
+ {
+ sLog.outErrorDb("Wrong race %u in `playercreateinfo_item` table, ignoring.",current_race);
+ continue;
+ }
+
+ uint32 current_class = fields[1].GetUInt32();
+ if(current_class >= MAX_CLASSES)
+ {
+ sLog.outErrorDb("Wrong class %u in `playercreateinfo_item` table, ignoring.",current_class);
+ continue;
+ }
+
+ PlayerInfo* pInfo = &playerInfo[current_race][current_class];
+
+ uint32 item_id = fields[2].GetUInt32();
+
+ if(!GetItemPrototype(item_id))
+ {
+ sLog.outErrorDb("Item id %u (race %u class %u) in `playercreateinfo_item` table but not listed in `item_template`, ignoring.",item_id,current_race,current_class);
+ continue;
+ }
+
+ uint32 amount = fields[3].GetUInt32();
+
+ if(!amount)
+ {
+ sLog.outErrorDb("Item id %u (class %u race %u) have amount==0 in `playercreateinfo_item` table, ignoring.",item_id,current_race,current_class);
+ continue;
+ }
+
+ pInfo->item.push_back(PlayerCreateInfoItem( item_id, amount));
+
+ bar.step();
+ ++count;
+ }
+ while(result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u custom player create items", count );
+ }
+ }
+
+ // Load playercreate spells
+ {
+
+ QueryResult *result = NULL;
+ if(sWorld.getConfig(CONFIG_START_ALL_SPELLS))
+ result = WorldDatabase.Query("SELECT race, class, Spell, Active FROM playercreateinfo_spell_custom");
+ else
+ result = WorldDatabase.Query("SELECT race, class, Spell, Active FROM playercreateinfo_spell");
+
+ uint32 count = 0;
+
+ if (!result)
+ {
+ barGoLink bar( 1 );
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u player create spells", count );
+ sLog.outErrorDb( "Error loading player starting spells or empty table.");
+ }
+ else
+ {
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ Field* fields = result->Fetch();
+
+ uint32 current_race = fields[0].GetUInt32();
+ if(current_race >= MAX_RACES)
+ {
+ sLog.outErrorDb("Wrong race %u in `playercreateinfo_spell` table, ignoring.",current_race);
+ continue;
+ }
+
+ uint32 current_class = fields[1].GetUInt32();
+ if(current_class >= MAX_CLASSES)
+ {
+ sLog.outErrorDb("Wrong class %u in `playercreateinfo_spell` table, ignoring.",current_class);
+ continue;
+ }
+
+ PlayerInfo* pInfo = &playerInfo[current_race][current_class];
+ pInfo->spell.push_back(CreateSpellPair(fields[2].GetUInt16(), fields[3].GetUInt8()));
+
+ bar.step();
+ ++count;
+ }
+ while( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u player create spells", count );
+ }
+ }
+
+ // Load playercreate actions
+ {
+ // 0 1 2 3 4 5
+ QueryResult *result = WorldDatabase.Query("SELECT race, class, button, action, type, misc FROM playercreateinfo_action");
+
+ uint32 count = 0;
+
+ if (!result)
+ {
+ barGoLink bar( 1 );
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u player create actions", count );
+ sLog.outErrorDb( "Error loading `playercreateinfo_action` table or empty table.");
+ }
+ else
+ {
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ Field* fields = result->Fetch();
+
+ uint32 current_race = fields[0].GetUInt32();
+ if(current_race >= MAX_RACES)
+ {
+ sLog.outErrorDb("Wrong race %u in `playercreateinfo_action` table, ignoring.",current_race);
+ continue;
+ }
+
+ uint32 current_class = fields[1].GetUInt32();
+ if(current_class >= MAX_CLASSES)
+ {
+ sLog.outErrorDb("Wrong class %u in `playercreateinfo_action` table, ignoring.",current_class);
+ continue;
+ }
+
+ PlayerInfo* pInfo = &playerInfo[current_race][current_class];
+ pInfo->action[0].push_back(fields[2].GetUInt16());
+ pInfo->action[1].push_back(fields[3].GetUInt16());
+ pInfo->action[2].push_back(fields[4].GetUInt16());
+ pInfo->action[3].push_back(fields[5].GetUInt16());
+
+ bar.step();
+ ++count;
+ }
+ while( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u player create actions", count );
+ }
+ }
+
+ // Loading levels data (class only dependent)
+ {
+ // 0 1 2 3
+ QueryResult *result = WorldDatabase.Query("SELECT class, level, basehp, basemana FROM player_classlevelstats");
+
+ uint32 count = 0;
+
+ if (!result)
+ {
+ barGoLink bar( 1 );
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u level health/mana definitions", count );
+ sLog.outErrorDb( "Error loading `player_classlevelstats` table or empty table.");
+ exit(1);
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ Field* fields = result->Fetch();
+
+ uint32 current_class = fields[0].GetUInt32();
+ if(current_class >= MAX_CLASSES)
+ {
+ sLog.outErrorDb("Wrong class %u in `player_classlevelstats` table, ignoring.",current_class);
+ continue;
+ }
+
+ uint32 current_level = fields[1].GetUInt32();
+ if(current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
+ {
+ if(current_level > 255) // hardcoded level maximum
+ sLog.outErrorDb("Wrong (> 255) level %u in `player_classlevelstats` table, ignoring.",current_level);
+ else
+ sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `player_classlevelstats` table, ignoring.",current_level);
+ continue;
+ }
+
+ PlayerClassInfo* pClassInfo = &playerClassInfo[current_class];
+
+ if(!pClassInfo->levelInfo)
+ pClassInfo->levelInfo = new PlayerClassLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)];
+
+ PlayerClassLevelInfo* pClassLevelInfo = &pClassInfo->levelInfo[current_level-1];
+
+ pClassLevelInfo->basehealth = fields[2].GetUInt16();
+ pClassLevelInfo->basemana = fields[3].GetUInt16();
+
+ bar.step();
+ ++count;
+ }
+ while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u level health/mana definitions", count );
+ }
+
+ // Fill gaps and check integrity
+ for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
+ {
+ // skip non existed classes
+ if(!sChrClassesStore.LookupEntry(class_))
+ continue;
+
+ PlayerClassInfo* pClassInfo = &playerClassInfo[class_];
+
+ // fatal error if no level 1 data
+ if(!pClassInfo->levelInfo || pClassInfo->levelInfo[0].basehealth == 0 )
+ {
+ sLog.outErrorDb("Class %i Level 1 does not have health/mana data!",class_);
+ exit(1);
+ }
+
+ // fill level gaps
+ for (uint32 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
+ {
+ if(pClassInfo->levelInfo[level].basehealth == 0)
+ {
+ sLog.outErrorDb("Class %i Level %i does not have health/mana data. Using stats data of level %i.",class_,level+1, level);
+ pClassInfo->levelInfo[level] = pClassInfo->levelInfo[level-1];
+ }
+ }
+ }
+
+ // Loading levels data (class/race dependent)
+ {
+ // 0 1 2 3 4 5 6 7
+ QueryResult *result = WorldDatabase.Query("SELECT race, class, level, str, agi, sta, inte, spi FROM player_levelstats");
+
+ uint32 count = 0;
+
+ if (!result)
+ {
+ barGoLink bar( 1 );
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u level stats definitions", count );
+ sLog.outErrorDb( "Error loading `player_levelstats` table or empty table.");
+ exit(1);
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ Field* fields = result->Fetch();
+
+ uint32 current_race = fields[0].GetUInt32();
+ if(current_race >= MAX_RACES)
+ {
+ sLog.outErrorDb("Wrong race %u in `player_levelstats` table, ignoring.",current_race);
+ continue;
+ }
+
+ uint32 current_class = fields[1].GetUInt32();
+ if(current_class >= MAX_CLASSES)
+ {
+ sLog.outErrorDb("Wrong class %u in `player_levelstats` table, ignoring.",current_class);
+ continue;
+ }
+
+ uint32 current_level = fields[2].GetUInt32();
+ if(current_level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
+ {
+ if(current_level > 255) // hardcoded level maximum
+ sLog.outErrorDb("Wrong (> 255) level %u in `player_levelstats` table, ignoring.",current_level);
+ else
+ sLog.outDetail("Unused (> MaxPlayerLevel in Trinityd.conf) level %u in `player_levelstats` table, ignoring.",current_level);
+ continue;
+ }
+
+ PlayerInfo* pInfo = &playerInfo[current_race][current_class];
+
+ if(!pInfo->levelInfo)
+ pInfo->levelInfo = new PlayerLevelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)];
+
+ PlayerLevelInfo* pLevelInfo = &pInfo->levelInfo[current_level-1];
+
+ for (int i = 0; i < MAX_STATS; i++)
+ {
+ pLevelInfo->stats[i] = fields[i+3].GetUInt8();
+ }
+
+ bar.step();
+ ++count;
+ }
+ while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u level stats definitions", count );
+ }
+
+ // Fill gaps and check integrity
+ for (int race = 0; race < MAX_RACES; ++race)
+ {
+ // skip non existed races
+ if(!sChrRacesStore.LookupEntry(race))
+ continue;
+
+ for (int class_ = 0; class_ < MAX_CLASSES; ++class_)
+ {
+ // skip non existed classes
+ if(!sChrClassesStore.LookupEntry(class_))
+ continue;
+
+ PlayerInfo* pInfo = &playerInfo[race][class_];
+
+ // skip non loaded combinations
+ if(!pInfo->displayId_m || !pInfo->displayId_f)
+ continue;
+
+ // skip expansion races if not playing with expansion
+ if (sWorld.getConfig(CONFIG_EXPANSION) < 1 && (race == RACE_BLOODELF || race == RACE_DRAENEI))
+ continue;
+
+ // skip expansion classes if not playing with expansion
+ if (sWorld.getConfig(CONFIG_EXPANSION) < 2 && class_ == CLASS_DEATH_KNIGHT)
+ continue;
+
+ // fatal error if no level 1 data
+ if(!pInfo->levelInfo || pInfo->levelInfo[0].stats[0] == 0 )
+ {
+ sLog.outErrorDb("Race %i Class %i Level 1 does not have stats data!",race,class_);
+ exit(1);
+ }
+
+ // fill level gaps
+ for (uint32 level = 1; level < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL); ++level)
+ {
+ if(pInfo->levelInfo[level].stats[0] == 0)
+ {
+ sLog.outErrorDb("Race %i Class %i Level %i does not have stats data. Using stats data of level %i.",race,class_,level+1, level);
+ pInfo->levelInfo[level] = pInfo->levelInfo[level-1];
+ }
+ }
+ }
+ }
+}
+
+void ObjectMgr::GetPlayerClassLevelInfo(uint32 class_, uint32 level, PlayerClassLevelInfo* info) const
+{
+ if(level < 1 || class_ >= MAX_CLASSES)
+ return;
+
+ PlayerClassInfo const* pInfo = &playerClassInfo[class_];
+
+ if(level > sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
+ level = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL);
+
+ *info = pInfo->levelInfo[level-1];
+}
+
+void ObjectMgr::GetPlayerLevelInfo(uint32 race, uint32 class_, uint32 level, PlayerLevelInfo* info) const
+{
+ if(level < 1 || race >= MAX_RACES || class_ >= MAX_CLASSES)
+ return;
+
+ PlayerInfo const* pInfo = &playerInfo[race][class_];
+ if(pInfo->displayId_m==0 || pInfo->displayId_f==0)
+ return;
+
+ if(level <= sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
+ *info = pInfo->levelInfo[level-1];
+ else
+ BuildPlayerLevelInfo(race,class_,level,info);
+}
+
+void ObjectMgr::BuildPlayerLevelInfo(uint8 race, uint8 _class, uint8 level, PlayerLevelInfo* info) const
+{
+ // base data (last known level)
+ *info = playerInfo[race][_class].levelInfo[sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)-1];
+
+ for(int lvl = sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL)-1; lvl < level; ++lvl)
+ {
+ switch(_class)
+ {
+ case CLASS_WARRIOR:
+ info->stats[STAT_STRENGTH] += (lvl > 23 ? 2: (lvl > 1 ? 1: 0));
+ info->stats[STAT_STAMINA] += (lvl > 23 ? 2: (lvl > 1 ? 1: 0));
+ info->stats[STAT_AGILITY] += (lvl > 36 ? 1: (lvl > 6 && (lvl%2) ? 1: 0));
+ info->stats[STAT_INTELLECT] += (lvl > 9 && !(lvl%2) ? 1: 0);
+ info->stats[STAT_SPIRIT] += (lvl > 9 && !(lvl%2) ? 1: 0);
+ break;
+ case CLASS_PALADIN:
+ info->stats[STAT_STRENGTH] += (lvl > 3 ? 1: 0);
+ info->stats[STAT_STAMINA] += (lvl > 33 ? 2: (lvl > 1 ? 1: 0));
+ info->stats[STAT_AGILITY] += (lvl > 38 ? 1: (lvl > 7 && !(lvl%2) ? 1: 0));
+ info->stats[STAT_INTELLECT] += (lvl > 6 && (lvl%2) ? 1: 0);
+ info->stats[STAT_SPIRIT] += (lvl > 7 ? 1: 0);
+ break;
+ case CLASS_HUNTER:
+ info->stats[STAT_STRENGTH] += (lvl > 4 ? 1: 0);
+ info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0);
+ info->stats[STAT_AGILITY] += (lvl > 33 ? 2: (lvl > 1 ? 1: 0));
+ info->stats[STAT_INTELLECT] += (lvl > 8 && (lvl%2) ? 1: 0);
+ info->stats[STAT_SPIRIT] += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0));
+ break;
+ case CLASS_ROGUE:
+ info->stats[STAT_STRENGTH] += (lvl > 5 ? 1: 0);
+ info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0);
+ info->stats[STAT_AGILITY] += (lvl > 16 ? 2: (lvl > 1 ? 1: 0));
+ info->stats[STAT_INTELLECT] += (lvl > 8 && !(lvl%2) ? 1: 0);
+ info->stats[STAT_SPIRIT] += (lvl > 38 ? 1: (lvl > 9 && !(lvl%2) ? 1: 0));
+ break;
+ case CLASS_PRIEST:
+ info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0);
+ info->stats[STAT_STAMINA] += (lvl > 5 ? 1: 0);
+ info->stats[STAT_AGILITY] += (lvl > 38 ? 1: (lvl > 8 && (lvl%2) ? 1: 0));
+ info->stats[STAT_INTELLECT] += (lvl > 22 ? 2: (lvl > 1 ? 1: 0));
+ info->stats[STAT_SPIRIT] += (lvl > 3 ? 1: 0);
+ break;
+ case CLASS_SHAMAN:
+ info->stats[STAT_STRENGTH] += (lvl > 34 ? 1: (lvl > 6 && (lvl%2) ? 1: 0));
+ info->stats[STAT_STAMINA] += (lvl > 4 ? 1: 0);
+ info->stats[STAT_AGILITY] += (lvl > 7 && !(lvl%2) ? 1: 0);
+ info->stats[STAT_INTELLECT] += (lvl > 5 ? 1: 0);
+ info->stats[STAT_SPIRIT] += (lvl > 4 ? 1: 0);
+ break;
+ case CLASS_MAGE:
+ info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0);
+ info->stats[STAT_STAMINA] += (lvl > 5 ? 1: 0);
+ info->stats[STAT_AGILITY] += (lvl > 9 && !(lvl%2) ? 1: 0);
+ info->stats[STAT_INTELLECT] += (lvl > 24 ? 2: (lvl > 1 ? 1: 0));
+ info->stats[STAT_SPIRIT] += (lvl > 33 ? 2: (lvl > 2 ? 1: 0));
+ break;
+ case CLASS_WARLOCK:
+ info->stats[STAT_STRENGTH] += (lvl > 9 && !(lvl%2) ? 1: 0);
+ info->stats[STAT_STAMINA] += (lvl > 38 ? 2: (lvl > 3 ? 1: 0));
+ info->stats[STAT_AGILITY] += (lvl > 9 && !(lvl%2) ? 1: 0);
+ info->stats[STAT_INTELLECT] += (lvl > 33 ? 2: (lvl > 2 ? 1: 0));
+ info->stats[STAT_SPIRIT] += (lvl > 38 ? 2: (lvl > 3 ? 1: 0));
+ break;
+ case CLASS_DRUID:
+ info->stats[STAT_STRENGTH] += (lvl > 38 ? 2: (lvl > 6 && (lvl%2) ? 1: 0));
+ info->stats[STAT_STAMINA] += (lvl > 32 ? 2: (lvl > 4 ? 1: 0));
+ info->stats[STAT_AGILITY] += (lvl > 38 ? 2: (lvl > 8 && (lvl%2) ? 1: 0));
+ info->stats[STAT_INTELLECT] += (lvl > 38 ? 3: (lvl > 4 ? 1: 0));
+ info->stats[STAT_SPIRIT] += (lvl > 38 ? 3: (lvl > 5 ? 1: 0));
+ }
+ }
+}
+
+void ObjectMgr::LoadGuilds()
+{
+ Guild *newguild;
+ uint32 count = 0;
+
+ QueryResult *result = CharacterDatabase.Query( "SELECT guildid FROM guild" );
+
+ if( !result )
+ {
+
+ barGoLink bar( 1 );
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u guild definitions", count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ Field *fields = result->Fetch();
+
+ bar.step();
+ ++count;
+
+ newguild = new Guild;
+ if(!newguild->LoadGuildFromDB(fields[0].GetUInt32()))
+ {
+ newguild->Disband();
+ delete newguild;
+ continue;
+ }
+ AddGuild(newguild);
+
+ }while( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u guild definitions", count );
+}
+
+void ObjectMgr::LoadArenaTeams()
+{
+ uint32 count = 0;
+
+ QueryResult *result = CharacterDatabase.Query( "SELECT arenateamid FROM arena_team" );
+
+ if( !result )
+ {
+
+ barGoLink bar( 1 );
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u arenateam definitions", count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ Field *fields = result->Fetch();
+
+ bar.step();
+ ++count;
+
+ ArenaTeam *newarenateam = new ArenaTeam;
+ if(!newarenateam->LoadArenaTeamFromDB(fields[0].GetUInt32()))
+ {
+ delete newarenateam;
+ continue;
+ }
+ AddArenaTeam(newarenateam);
+ }while( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u arenateam definitions", count );
+}
+
+void ObjectMgr::LoadGroups()
+{
+ // -- loading groups --
+ Group *group = NULL;
+ uint64 leaderGuid = 0;
+ uint32 count = 0;
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ QueryResult *result = CharacterDatabase.Query("SELECT mainTank, mainAssistant, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, isRaid, difficulty, leaderGuid FROM groups");
+
+ if( !result )
+ {
+ barGoLink bar( 1 );
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u group definitions", count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ bar.step();
+ Field *fields = result->Fetch();
+ ++count;
+ leaderGuid = MAKE_NEW_GUID(fields[15].GetUInt32(),0,HIGHGUID_PLAYER);
+
+ group = new Group;
+ if(!group->LoadGroupFromDB(leaderGuid, result, false))
+ {
+ group->Disband();
+ delete group;
+ continue;
+ }
+ AddGroup(group);
+ }while( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u group definitions", count );
+
+ // -- loading members --
+ count = 0;
+ group = NULL;
+ leaderGuid = 0;
+ // 0 1 2 3
+ result = CharacterDatabase.Query("SELECT memberGuid, assistant, subgroup, leaderGuid FROM group_member ORDER BY leaderGuid");
+ if(!result)
+ {
+ barGoLink bar( 1 );
+ bar.step();
+ }
+ else
+ {
+ barGoLink bar( result->GetRowCount() );
+ do
+ {
+ bar.step();
+ Field *fields = result->Fetch();
+ count++;
+ leaderGuid = MAKE_NEW_GUID(fields[3].GetUInt32(), 0, HIGHGUID_PLAYER);
+ if(!group || group->GetLeaderGUID() != leaderGuid)
+ {
+ group = GetGroupByLeader(leaderGuid);
+ if(!group)
+ {
+ sLog.outErrorDb("Incorrect entry in group_member table : no group with leader %d for member %d!", fields[3].GetUInt32(), fields[0].GetUInt32());
+ CharacterDatabase.PExecute("DELETE FROM group_member WHERE memberGuid = '%d'", fields[0].GetUInt32());
+ continue;
+ }
+ }
+
+ if(!group->LoadMemberFromDB(fields[0].GetUInt32(), fields[2].GetUInt8(), fields[1].GetBool()))
+ {
+ sLog.outErrorDb("Incorrect entry in group_member table : member %d cannot be added to player %d's group!", fields[0].GetUInt32(), fields[3].GetUInt32());
+ CharacterDatabase.PExecute("DELETE FROM group_member WHERE memberGuid = '%d'", fields[0].GetUInt32());
+ }
+ }while( result->NextRow() );
+ delete result;
+ }
+
+ // clean groups
+ // TODO: maybe delete from the DB before loading in this case
+ for(GroupSet::iterator itr = mGroupSet.begin(); itr != mGroupSet.end();)
+ {
+ if((*itr)->GetMembersCount() < 2)
+ {
+ (*itr)->Disband();
+ delete *itr;
+ mGroupSet.erase(itr++);
+ }
+ else
+ ++itr;
+ }
+
+ // -- loading instances --
+ count = 0;
+ group = NULL;
+ leaderGuid = 0;
+ result = CharacterDatabase.Query(
+ // 0 1 2 3 4 5
+ "SELECT leaderGuid, map, instance, permanent, difficulty, resettime, "
+ // 6
+ "(SELECT COUNT(*) FROM character_instance WHERE guid = leaderGuid AND instance = group_instance.instance AND permanent = 1 LIMIT 1) "
+ "FROM group_instance LEFT JOIN instance ON instance = id ORDER BY leaderGuid"
+ );
+
+ if(!result)
+ {
+ barGoLink bar( 1 );
+ bar.step();
+ }
+ else
+ {
+ barGoLink bar( result->GetRowCount() );
+ do
+ {
+ bar.step();
+ Field *fields = result->Fetch();
+ count++;
+ leaderGuid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
+ if(!group || group->GetLeaderGUID() != leaderGuid)
+ {
+ group = GetGroupByLeader(leaderGuid);
+ if(!group)
+ {
+ sLog.outErrorDb("Incorrect entry in group_instance table : no group with leader %d", fields[0].GetUInt32());
+ continue;
+ }
+ }
+
+ InstanceSave *save = sInstanceSaveManager.AddInstanceSave(fields[1].GetUInt32(), fields[2].GetUInt32(), fields[4].GetUInt8(), (time_t)fields[5].GetUInt64(), (fields[6].GetUInt32() == 0), true);
+ group->BindToInstance(save, fields[3].GetBool(), true);
+ }while( result->NextRow() );
+ delete result;
+ }
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u group-instance binds total", count );
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u group members total", count );
+}
+
+void ObjectMgr::LoadQuests()
+{
+ // For reload case
+ for(QuestMap::const_iterator itr=mQuestTemplates.begin(); itr != mQuestTemplates.end(); ++itr)
+ delete itr->second;
+ mQuestTemplates.clear();
+
+ mExclusiveQuestGroups.clear();
+
+ // 0 1 2 3 4 5 6 7 8
+ QueryResult *result = WorldDatabase.Query("SELECT entry, Method, ZoneOrSort, SkillOrClass, MinLevel, QuestLevel, Type, RequiredRaces, RequiredSkillValue,"
+ // 9 10 11 12 13 14 15 16
+ "RepObjectiveFaction, RepObjectiveValue, RequiredMinRepFaction, RequiredMinRepValue, RequiredMaxRepFaction, RequiredMaxRepValue, SuggestedPlayers, LimitTime,"
+ // 17 18 19 20 21 22 23 24 25 26
+ "QuestFlags, SpecialFlags, CharTitleId, PrevQuestId, NextQuestId, ExclusiveGroup, NextQuestInChain, SrcItemId, SrcItemCount, SrcSpell,"
+ // 27 28 29 30 31 32 33 34 35 36
+ "Title, Details, Objectives, OfferRewardText, RequestItemsText, EndText, ObjectiveText1, ObjectiveText2, ObjectiveText3, ObjectiveText4,"
+ // 37 38 39 40 41 42 43 44
+ "ReqItemId1, ReqItemId2, ReqItemId3, ReqItemId4, ReqItemCount1, ReqItemCount2, ReqItemCount3, ReqItemCount4,"
+ // 45 46 47 48 49 50 51 52 53 54 54 55
+ "ReqSourceId1, ReqSourceId2, ReqSourceId3, ReqSourceId4, ReqSourceCount1, ReqSourceCount2, ReqSourceCount3, ReqSourceCount4, ReqSourceRef1, ReqSourceRef2, ReqSourceRef3, ReqSourceRef4,"
+ // 57 58 59 60 61 62 63 64
+ "ReqCreatureOrGOId1, ReqCreatureOrGOId2, ReqCreatureOrGOId3, ReqCreatureOrGOId4, ReqCreatureOrGOCount1, ReqCreatureOrGOCount2, ReqCreatureOrGOCount3, ReqCreatureOrGOCount4,"
+ // 65 66 67 68
+ "ReqSpellCast1, ReqSpellCast2, ReqSpellCast3, ReqSpellCast4,"
+ // 69 70 71 72 73 74
+ "RewChoiceItemId1, RewChoiceItemId2, RewChoiceItemId3, RewChoiceItemId4, RewChoiceItemId5, RewChoiceItemId6,"
+ // 75 76 77 78 79 80
+ "RewChoiceItemCount1, RewChoiceItemCount2, RewChoiceItemCount3, RewChoiceItemCount4, RewChoiceItemCount5, RewChoiceItemCount6,"
+ // 81 82 83 84 85 86 87 88
+ "RewItemId1, RewItemId2, RewItemId3, RewItemId4, RewItemCount1, RewItemCount2, RewItemCount3, RewItemCount4,"
+ // 89 90 91 92 93 94 95 96 97 98
+ "RewRepFaction1, RewRepFaction2, RewRepFaction3, RewRepFaction4, RewRepFaction5, RewRepValue1, RewRepValue2, RewRepValue3, RewRepValue4, RewRepValue5,"
+ // 99 100 101 102 103 104 105 106 107 108 109
+ "RewHonorableKills, RewOrReqMoney, RewMoneyMaxLevel, RewSpell, RewSpellCast, RewMailTemplateId, RewMailDelaySecs, PointMapId, PointX, PointY, PointOpt,"
+ // 110 111 112 113 114 115 116 117 118 119
+ "DetailsEmote1, DetailsEmote2, DetailsEmote3, DetailsEmote4,IncompleteEmote, CompleteEmote, OfferRewardEmote1, OfferRewardEmote2, OfferRewardEmote3, OfferRewardEmote4,"
+ // 120 121
+ "StartScript, CompleteScript"
+ " FROM quest_template");
+ if(result == NULL)
+ {
+ barGoLink bar( 1 );
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded 0 quests definitions" );
+ sLog.outErrorDb("`quest_template` table is empty!");
+ return;
+ }
+
+ // create multimap previous quest for each existed quest
+ // some quests can have many previous maps set by NextQuestId in previous quest
+ // for example set of race quests can lead to single not race specific quest
+ barGoLink bar( result->GetRowCount() );
+ do
+ {
+ bar.step();
+ Field *fields = result->Fetch();
+
+ Quest * newQuest = new Quest(fields);
+ mQuestTemplates[newQuest->GetQuestId()] = newQuest;
+ } while( result->NextRow() );
+
+ delete result;
+
+ // Post processing
+ for (QuestMap::iterator iter = mQuestTemplates.begin(); iter != mQuestTemplates.end(); iter++)
+ {
+ Quest * qinfo = iter->second;
+
+ // additional quest integrity checks (GO, creature_template and item_template must be loaded already)
+
+ if( qinfo->GetQuestMethod() >= 3 )
+ {
+ sLog.outErrorDb("Quest %u has `Method` = %u, expected values are 0, 1 or 2.",qinfo->GetQuestId(),qinfo->GetQuestMethod());
+ }
+
+ if (qinfo->QuestFlags & ~QUEST_TRINITY_FLAGS_DB_ALLOWED)
+ {
+ sLog.outErrorDb("Quest %u has `SpecialFlags` = %u > max allowed value. Correct `SpecialFlags` to value <= %u",
+ qinfo->GetQuestId(),qinfo->QuestFlags,QUEST_TRINITY_FLAGS_DB_ALLOWED >> 16);
+ qinfo->QuestFlags &= QUEST_TRINITY_FLAGS_DB_ALLOWED;
+ }
+
+ if(qinfo->QuestFlags & QUEST_FLAGS_DAILY)
+ {
+ if(!(qinfo->QuestFlags & QUEST_TRINITY_FLAGS_REPEATABLE))
+ {
+ sLog.outErrorDb("Daily Quest %u not marked as repeatable in `SpecialFlags`, added.",qinfo->GetQuestId());
+ qinfo->QuestFlags |= QUEST_TRINITY_FLAGS_REPEATABLE;
+ }
+ }
+
+ if(qinfo->QuestFlags & QUEST_FLAGS_AUTO_REWARDED)
+ {
+ // at auto-reward can be rewarded only RewChoiceItemId[0]
+ for(int j = 1; j < QUEST_REWARD_CHOICES_COUNT; ++j )
+ {
+ if(uint32 id = qinfo->RewChoiceItemId[j])
+ {
+ sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but item from `RewChoiceItemId%d` can't be rewarded with quest flag QUEST_FLAGS_AUTO_REWARDED.",
+ qinfo->GetQuestId(),j+1,id,j+1);
+ // no changes, quest ignore this data
+ }
+ }
+ }
+
+ // client quest log visual (area case)
+ if( qinfo->ZoneOrSort > 0 )
+ {
+ if(!GetAreaEntryByAreaID(qinfo->ZoneOrSort))
+ {
+ sLog.outErrorDb("Quest %u has `ZoneOrSort` = %u (zone case) but zone with this id does not exist.",
+ qinfo->GetQuestId(),qinfo->ZoneOrSort);
+ // no changes, quest not dependent from this value but can have problems at client
+ }
+ }
+ // client quest log visual (sort case)
+ if( qinfo->ZoneOrSort < 0 )
+ {
+ QuestSortEntry const* qSort = sQuestSortStore.LookupEntry(-int32(qinfo->ZoneOrSort));
+ if( !qSort )
+ {
+ sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (sort case) but quest sort with this id does not exist.",
+ qinfo->GetQuestId(),qinfo->ZoneOrSort);
+ // no changes, quest not dependent from this value but can have problems at client (note some may be 0, we must allow this so no check)
+ }
+ //check SkillOrClass value (class case).
+ if( ClassByQuestSort(-int32(qinfo->ZoneOrSort)) )
+ {
+ // SkillOrClass should not have class case when class case already set in ZoneOrSort.
+ if(qinfo->SkillOrClass < 0)
+ {
+ sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (class sort case) and `SkillOrClass` = %i (class case), redundant.",
+ qinfo->GetQuestId(),qinfo->ZoneOrSort,qinfo->SkillOrClass);
+ }
+ }
+ //check for proper SkillOrClass value (skill case)
+ if(int32 skill_id = SkillByQuestSort(-int32(qinfo->ZoneOrSort)))
+ {
+ // skill is positive value in SkillOrClass
+ if(qinfo->SkillOrClass != skill_id )
+ {
+ sLog.outErrorDb("Quest %u has `ZoneOrSort` = %i (skill sort case) but `SkillOrClass` does not have a corresponding value (%i).",
+ qinfo->GetQuestId(),qinfo->ZoneOrSort,skill_id);
+ //override, and force proper value here?
+ }
+ }
+ }
+
+ // SkillOrClass (class case)
+ if( qinfo->SkillOrClass < 0 )
+ {
+ if( !sChrClassesStore.LookupEntry(-int32(qinfo->SkillOrClass)) )
+ {
+ sLog.outErrorDb("Quest %u has `SkillOrClass` = %i (class case) but class (%i) does not exist",
+ qinfo->GetQuestId(),qinfo->SkillOrClass,-qinfo->SkillOrClass);
+ }
+ }
+ // SkillOrClass (skill case)
+ if( qinfo->SkillOrClass > 0 )
+ {
+ if( !sSkillLineStore.LookupEntry(qinfo->SkillOrClass) )
+ {
+ sLog.outErrorDb("Quest %u has `SkillOrClass` = %u (skill case) but skill (%i) does not exist",
+ qinfo->GetQuestId(),qinfo->SkillOrClass,qinfo->SkillOrClass);
+ }
+ }
+
+ if( qinfo->RequiredSkillValue )
+ {
+ if( qinfo->RequiredSkillValue > sWorld.GetConfigMaxSkillValue() )
+ {
+ sLog.outErrorDb("Quest %u has `RequiredSkillValue` = %u but max possible skill is %u, quest can't be done.",
+ qinfo->GetQuestId(),qinfo->RequiredSkillValue,sWorld.GetConfigMaxSkillValue());
+ // no changes, quest can't be done for this requirement
+ }
+
+ if( qinfo->SkillOrClass <= 0 )
+ {
+ sLog.outErrorDb("Quest %u has `RequiredSkillValue` = %u but `SkillOrClass` = %i (class case), value ignored.",
+ qinfo->GetQuestId(),qinfo->RequiredSkillValue,qinfo->SkillOrClass);
+ // no changes, quest can't be done for this requirement (fail at wrong skill id)
+ }
+ }
+ // else Skill quests can have 0 skill level, this is ok
+
+ if(qinfo->RepObjectiveFaction && !sFactionStore.LookupEntry(qinfo->RepObjectiveFaction))
+ {
+ sLog.outErrorDb("Quest %u has `RepObjectiveFaction` = %u but faction template %u does not exist, quest can't be done.",
+ qinfo->GetQuestId(),qinfo->RepObjectiveFaction,qinfo->RepObjectiveFaction);
+ // no changes, quest can't be done for this requirement
+ }
+
+ if(qinfo->RequiredMinRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMinRepFaction))
+ {
+ sLog.outErrorDb("Quest %u has `RequiredMinRepFaction` = %u but faction template %u does not exist, quest can't be done.",
+ qinfo->GetQuestId(),qinfo->RequiredMinRepFaction,qinfo->RequiredMinRepFaction);
+ // no changes, quest can't be done for this requirement
+ }
+
+ if(qinfo->RequiredMaxRepFaction && !sFactionStore.LookupEntry(qinfo->RequiredMaxRepFaction))
+ {
+ sLog.outErrorDb("Quest %u has `RequiredMaxRepFaction` = %u but faction template %u does not exist, quest can't be done.",
+ qinfo->GetQuestId(),qinfo->RequiredMaxRepFaction,qinfo->RequiredMaxRepFaction);
+ // no changes, quest can't be done for this requirement
+ }
+
+ if(qinfo->RequiredMinRepValue && qinfo->RequiredMinRepValue > Player::Reputation_Cap)
+ {
+ sLog.outErrorDb("Quest %u has `RequiredMinRepValue` = %d but max reputation is %u, quest can't be done.",
+ qinfo->GetQuestId(),qinfo->RequiredMinRepValue,Player::Reputation_Cap);
+ // no changes, quest can't be done for this requirement
+ }
+
+ if(qinfo->RequiredMinRepValue && qinfo->RequiredMaxRepValue && qinfo->RequiredMaxRepValue <= qinfo->RequiredMinRepValue)
+ {
+ sLog.outErrorDb("Quest %u has `RequiredMaxRepValue` = %d and `RequiredMinRepValue` = %d, quest can't be done.",
+ qinfo->GetQuestId(),qinfo->RequiredMaxRepValue,qinfo->RequiredMinRepValue);
+ // no changes, quest can't be done for this requirement
+ }
+
+ if(!qinfo->RepObjectiveFaction && qinfo->RepObjectiveValue > 0 )
+ {
+ sLog.outErrorDb("Quest %u has `RepObjectiveValue` = %d but `RepObjectiveFaction` is 0, value has no effect",
+ qinfo->GetQuestId(),qinfo->RepObjectiveValue);
+ // warning
+ }
+
+ if(!qinfo->RequiredMinRepFaction && qinfo->RequiredMinRepValue > 0 )
+ {
+ sLog.outErrorDb("Quest %u has `RequiredMinRepValue` = %d but `RequiredMinRepFaction` is 0, value has no effect",
+ qinfo->GetQuestId(),qinfo->RequiredMinRepValue);
+ // warning
+ }
+
+ if(!qinfo->RequiredMaxRepFaction && qinfo->RequiredMaxRepValue > 0 )
+ {
+ sLog.outErrorDb("Quest %u has `RequiredMaxRepValue` = %d but `RequiredMaxRepFaction` is 0, value has no effect",
+ qinfo->GetQuestId(),qinfo->RequiredMaxRepValue);
+ // warning
+ }
+
+ if(qinfo->CharTitleId && !sCharTitlesStore.LookupEntry(qinfo->CharTitleId))
+ {
+ sLog.outErrorDb("Quest %u has `CharTitleId` = %u but CharTitle Id %u does not exist, quest can't be rewarded with title.",
+ qinfo->GetQuestId(),qinfo->GetCharTitleId(),qinfo->GetCharTitleId());
+ qinfo->CharTitleId = 0;
+ // quest can't reward this title
+ }
+
+ if(qinfo->SrcItemId)
+ {
+ if(!sItemStorage.LookupEntry<ItemPrototype>(qinfo->SrcItemId))
+ {
+ sLog.outErrorDb("Quest %u has `SrcItemId` = %u but item with entry %u does not exist, quest can't be done.",
+ qinfo->GetQuestId(),qinfo->SrcItemId,qinfo->SrcItemId);
+ qinfo->SrcItemId = 0; // quest can't be done for this requirement
+ }
+ else if(qinfo->SrcItemCount==0)
+ {
+ sLog.outErrorDb("Quest %u has `SrcItemId` = %u but `SrcItemCount` = 0, set to 1 but need fix in DB.",
+ qinfo->GetQuestId(),qinfo->SrcItemId);
+ qinfo->SrcItemCount = 1; // update to 1 for allow quest work for backward compatibility with DB
+ }
+ }
+ else if(qinfo->SrcItemCount>0)
+ {
+ sLog.outErrorDb("Quest %u has `SrcItemId` = 0 but `SrcItemCount` = %u, useless value.",
+ qinfo->GetQuestId(),qinfo->SrcItemCount);
+ qinfo->SrcItemCount=0; // no quest work changes in fact
+ }
+
+ if(qinfo->SrcSpell)
+ {
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->SrcSpell);
+ if(!spellInfo)
+ {
+ sLog.outErrorDb("Quest %u has `SrcSpell` = %u but spell %u doesn't exist, quest can't be done.",
+ qinfo->GetQuestId(),qinfo->SrcSpell,qinfo->SrcSpell);
+ qinfo->SrcSpell = 0; // quest can't be done for this requirement
+ }
+ else if(!SpellMgr::IsSpellValid(spellInfo))
+ {
+ sLog.outErrorDb("Quest %u has `SrcSpell` = %u but spell %u is broken, quest can't be done.",
+ qinfo->GetQuestId(),qinfo->SrcSpell,qinfo->SrcSpell);
+ qinfo->SrcSpell = 0; // quest can't be done for this requirement
+ }
+ }
+
+ for(int j = 0; j < QUEST_OBJECTIVES_COUNT; ++j )
+ {
+ uint32 id = qinfo->ReqItemId[j];
+ if(id)
+ {
+ if(qinfo->ReqItemCount[j]==0)
+ {
+ sLog.outErrorDb("Quest %u has `ReqItemId%d` = %u but `ReqItemCount%d` = 0, quest can't be done.",
+ qinfo->GetQuestId(),j+1,id,j+1);
+ // no changes, quest can't be done for this requirement
+ }
+
+ qinfo->SetFlag(QUEST_TRINITY_FLAGS_DELIVER);
+
+ if(!sItemStorage.LookupEntry<ItemPrototype>(id))
+ {
+ sLog.outErrorDb("Quest %u has `ReqItemId%d` = %u but item with entry %u does not exist, quest can't be done.",
+ qinfo->GetQuestId(),j+1,id,id);
+ qinfo->ReqItemCount[j] = 0; // prevent incorrect work of quest
+ }
+ }
+ else if(qinfo->ReqItemCount[j]>0)
+ {
+ sLog.outErrorDb("Quest %u has `ReqItemId%d` = 0 but `ReqItemCount%d` = %u, quest can't be done.",
+ qinfo->GetQuestId(),j+1,j+1,qinfo->ReqItemCount[j]);
+ qinfo->ReqItemCount[j] = 0; // prevent incorrect work of quest
+ }
+ }
+
+ for(int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j )
+ {
+ uint32 id = qinfo->ReqSourceId[j];
+ if(id)
+ {
+ if(!sItemStorage.LookupEntry<ItemPrototype>(id))
+ {
+ sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but item with entry %u does not exist, quest can't be done.",
+ qinfo->GetQuestId(),j+1,id,id);
+ // no changes, quest can't be done for this requirement
+ }
+
+ if(!qinfo->ReqSourceCount[j])
+ {
+ sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but `ReqSourceCount%d` = 0, quest can't be done.",
+ qinfo->GetQuestId(),j+1,id,j+1);
+ qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest
+ }
+
+ if(!qinfo->ReqSourceRef[j])
+ {
+ sLog.outErrorDb("Quest %u has `ReqSourceId%d` = %u but `ReqSourceRef%d` = 0, quest can't be done.",
+ qinfo->GetQuestId(),j+1,id,j+1);
+ qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest
+ }
+ }
+ else
+ {
+ if(qinfo->ReqSourceCount[j]>0)
+ {
+ sLog.outErrorDb("Quest %u has `ReqSourceId%d` = 0 but `ReqSourceCount%d` = %u.",
+ qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceCount[j]);
+ // no changes, quest ignore this data
+ }
+
+ if(qinfo->ReqSourceRef[j]>0)
+ {
+ sLog.outErrorDb("Quest %u has `ReqSourceId%d` = 0 but `ReqSourceRef%d` = %u.",
+ qinfo->GetQuestId(),j+1,j+1,qinfo->ReqSourceRef[j]);
+ // no changes, quest ignore this data
+ }
+ }
+ }
+
+ for(int j = 0; j < QUEST_SOURCE_ITEM_IDS_COUNT; ++j )
+ {
+ uint32 ref = qinfo->ReqSourceRef[j];
+ if(ref)
+ {
+ if(ref > QUEST_OBJECTIVES_COUNT)
+ {
+ sLog.outErrorDb("Quest %u has `ReqSourceRef%d` = %u but max value in `ReqSourceRef%d` is %u, quest can't be done.",
+ qinfo->GetQuestId(),j+1,ref,j+1,QUEST_OBJECTIVES_COUNT);
+ // no changes, quest can't be done for this requirement
+ }
+ else
+ if(!qinfo->ReqItemId[ref-1] && !qinfo->ReqSpell[ref-1])
+ {
+ sLog.outErrorDb("Quest %u has `ReqSourceRef%d` = %u but `ReqItemId%u` = 0 and `ReqSpellCast%u` = 0, quest can't be done.",
+ qinfo->GetQuestId(),j+1,ref,ref,ref);
+ // no changes, quest can't be done for this requirement
+ }
+ else if(qinfo->ReqItemId[ref-1] && qinfo->ReqSpell[ref-1])
+ {
+ sLog.outErrorDb("Quest %u has `ReqItemId%u` = %u and `ReqSpellCast%u` = %u, quest can't have both fields <> 0, then can't be done.",
+ qinfo->GetQuestId(),ref,qinfo->ReqItemId[ref-1],ref,qinfo->ReqSpell[ref-1]);
+ // no changes, quest can't be done for this requirement
+ qinfo->ReqSourceId[j] = 0; // prevent incorrect work of quest
+ }
+ }
+ }
+
+ for(int j = 0; j < QUEST_OBJECTIVES_COUNT; ++j )
+ {
+ uint32 id = qinfo->ReqSpell[j];
+ if(id)
+ {
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(id);
+ if(!spellInfo)
+ {
+ sLog.outErrorDb("Quest %u has `ReqSpellCast%d` = %u but spell %u does not exist, quest can't be done.",
+ qinfo->GetQuestId(),j+1,id,id);
+ // no changes, quest can't be done for this requirement
+ }
+
+ if(!qinfo->ReqCreatureOrGOId[j])
+ {
+ bool found = false;
+ for(int k = 0; k < 3; ++k)
+ {
+ if( spellInfo->Effect[k]==SPELL_EFFECT_QUEST_COMPLETE && uint32(spellInfo->EffectMiscValue[k])==qinfo->QuestId ||
+ spellInfo->Effect[k]==SPELL_EFFECT_SEND_EVENT)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if(found)
+ {
+ if(!qinfo->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
+ {
+ sLog.outErrorDb("Spell (id: %u) have SPELL_EFFECT_QUEST_COMPLETE or SPELL_EFFECT_SEND_EVENT for quest %u and ReqCreatureOrGOId%d = 0, but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT. Quest flags or ReqCreatureOrGOId%d must be fixed, quest modified to enable objective.",spellInfo->Id,qinfo->QuestId,j+1,j+1);
+
+ // this will prevent quest completing without objective
+ const_cast<Quest*>(qinfo)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT);
+ }
+ }
+ else
+ {
+ sLog.outErrorDb("Quest %u has `ReqSpellCast%d` = %u and ReqCreatureOrGOId%d = 0 but spell %u does not have SPELL_EFFECT_QUEST_COMPLETE or SPELL_EFFECT_SEND_EVENT effect for this quest, quest can't be done.",
+ qinfo->GetQuestId(),j+1,id,j+1,id);
+ // no changes, quest can't be done for this requirement
+ }
+ }
+ }
+ }
+
+ for(int j = 0; j < QUEST_OBJECTIVES_COUNT; ++j )
+ {
+ int32 id = qinfo->ReqCreatureOrGOId[j];
+ if(id < 0 && !sGOStorage.LookupEntry<GameObjectInfo>(-id))
+ {
+ sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %i but gameobject %u does not exist, quest can't be done.",
+ qinfo->GetQuestId(),j+1,id,uint32(-id));
+ qinfo->ReqCreatureOrGOId[j] = 0; // quest can't be done for this requirement
+ }
+
+ if(id > 0 && !sCreatureStorage.LookupEntry<CreatureInfo>(id))
+ {
+ sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %i but creature with entry %u does not exist, quest can't be done.",
+ qinfo->GetQuestId(),j+1,id,uint32(id));
+ qinfo->ReqCreatureOrGOId[j] = 0; // quest can't be done for this requirement
+ }
+
+ if(id)
+ {
+ // In fact SpeakTo and Kill are quite same: either you can speak to mob:SpeakTo or you can't:Kill/Cast
+
+ qinfo->SetFlag(QUEST_TRINITY_FLAGS_KILL_OR_CAST | QUEST_TRINITY_FLAGS_SPEAKTO);
+
+ if(!qinfo->ReqCreatureOrGOCount[j])
+ {
+ sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = %u but `ReqCreatureOrGOCount%d` = 0, quest can't be done.",
+ qinfo->GetQuestId(),j+1,id,j+1);
+ // no changes, quest can be incorrectly done, but we already report this
+ }
+ }
+ else if(qinfo->ReqCreatureOrGOCount[j]>0)
+ {
+ sLog.outErrorDb("Quest %u has `ReqCreatureOrGOId%d` = 0 but `ReqCreatureOrGOCount%d` = %u.",
+ qinfo->GetQuestId(),j+1,j+1,qinfo->ReqCreatureOrGOCount[j]);
+ // no changes, quest ignore this data
+ }
+ }
+
+ for(int j = 0; j < QUEST_REWARD_CHOICES_COUNT; ++j )
+ {
+ uint32 id = qinfo->RewChoiceItemId[j];
+ if(id)
+ {
+ if(!sItemStorage.LookupEntry<ItemPrototype>(id))
+ {
+ sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but item with entry %u does not exist, quest will not reward this item.",
+ qinfo->GetQuestId(),j+1,id,id);
+ qinfo->RewChoiceItemId[j] = 0; // no changes, quest will not reward this
+ }
+
+ if(!qinfo->RewChoiceItemCount[j])
+ {
+ sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = %u but `RewChoiceItemCount%d` = 0, quest can't be done.",
+ qinfo->GetQuestId(),j+1,id,j+1);
+ // no changes, quest can't be done
+ }
+ }
+ else if(qinfo->RewChoiceItemCount[j]>0)
+ {
+ sLog.outErrorDb("Quest %u has `RewChoiceItemId%d` = 0 but `RewChoiceItemCount%d` = %u.",
+ qinfo->GetQuestId(),j+1,j+1,qinfo->RewChoiceItemCount[j]);
+ // no changes, quest ignore this data
+ }
+ }
+
+ for(int j = 0; j < QUEST_REWARDS_COUNT; ++j )
+ {
+ uint32 id = qinfo->RewItemId[j];
+ if(id)
+ {
+ if(!sItemStorage.LookupEntry<ItemPrototype>(id))
+ {
+ sLog.outErrorDb("Quest %u has `RewItemId%d` = %u but item with entry %u does not exist, quest will not reward this item.",
+ qinfo->GetQuestId(),j+1,id,id);
+ qinfo->RewItemId[j] = 0; // no changes, quest will not reward this item
+ }
+
+ if(!qinfo->RewItemCount[j])
+ {
+ sLog.outErrorDb("Quest %u has `RewItemId%d` = %u but `RewItemCount%d` = 0, quest will not reward this item.",
+ qinfo->GetQuestId(),j+1,id,j+1);
+ // no changes
+ }
+ }
+ else if(qinfo->RewItemCount[j]>0)
+ {
+ sLog.outErrorDb("Quest %u has `RewItemId%d` = 0 but `RewItemCount%d` = %u.",
+ qinfo->GetQuestId(),j+1,j+1,qinfo->RewItemCount[j]);
+ // no changes, quest ignore this data
+ }
+ }
+
+ for(int j = 0; j < QUEST_REPUTATIONS_COUNT; ++j)
+ {
+ if(qinfo->RewRepFaction[j])
+ {
+ if(!qinfo->RewRepValue[j])
+ {
+ sLog.outErrorDb("Quest %u has `RewRepFaction%d` = %u but `RewRepValue%d` = 0, quest will not reward this reputation.",
+ qinfo->GetQuestId(),j+1,qinfo->RewRepValue[j],j+1);
+ // no changes
+ }
+
+ if(!sFactionStore.LookupEntry(qinfo->RewRepFaction[j]))
+ {
+ sLog.outErrorDb("Quest %u has `RewRepFaction%d` = %u but raw faction (faction.dbc) %u does not exist, quest will not reward reputation for this faction.",
+ qinfo->GetQuestId(),j+1,qinfo->RewRepFaction[j] ,qinfo->RewRepFaction[j] );
+ qinfo->RewRepFaction[j] = 0; // quest will not reward this
+ }
+ }
+ else if(qinfo->RewRepValue[j]!=0)
+ {
+ sLog.outErrorDb("Quest %u has `RewRepFaction%d` = 0 but `RewRepValue%d` = %u.",
+ qinfo->GetQuestId(),j+1,j+1,qinfo->RewRepValue[j]);
+ // no changes, quest ignore this data
+ }
+ }
+
+ if(qinfo->RewSpell)
+ {
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->RewSpell);
+
+ if(!spellInfo)
+ {
+ sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u does not exist, spell removed as display reward.",
+ qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell);
+ qinfo->RewSpell = 0; // no spell reward will display for this quest
+ }
+
+ else if(!SpellMgr::IsSpellValid(spellInfo))
+ {
+ sLog.outErrorDb("Quest %u has `RewSpell` = %u but spell %u is broken, quest can't be done.",
+ qinfo->GetQuestId(),qinfo->RewSpell,qinfo->RewSpell);
+ qinfo->RewSpell = 0; // no spell reward will display for this quest
+ }
+
+ }
+
+ if(qinfo->RewSpellCast)
+ {
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(qinfo->RewSpellCast);
+
+ if(!spellInfo)
+ {
+ sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u does not exist, quest will not have a spell reward.",
+ qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast);
+ qinfo->RewSpellCast = 0; // no spell will be casted on player
+ }
+
+ else if(!SpellMgr::IsSpellValid(spellInfo))
+ {
+ sLog.outErrorDb("Quest %u has `RewSpellCast` = %u but spell %u is broken, quest can't be done.",
+ qinfo->GetQuestId(),qinfo->RewSpellCast,qinfo->RewSpellCast);
+ qinfo->RewSpellCast = 0; // no spell will be casted on player
+ }
+
+ }
+
+ if(qinfo->RewMailTemplateId)
+ {
+ if(!sMailTemplateStore.LookupEntry(qinfo->RewMailTemplateId))
+ {
+ sLog.outErrorDb("Quest %u has `RewMailTemplateId` = %u but mail template %u does not exist, quest will not have a mail reward.",
+ qinfo->GetQuestId(),qinfo->RewMailTemplateId,qinfo->RewMailTemplateId);
+ qinfo->RewMailTemplateId = 0; // no mail will send to player
+ qinfo->RewMailDelaySecs = 0; // no mail will send to player
+ }
+ }
+
+ if(qinfo->NextQuestInChain)
+ {
+ if(mQuestTemplates.find(qinfo->NextQuestInChain) == mQuestTemplates.end())
+ {
+ sLog.outErrorDb("Quest %u has `NextQuestInChain` = %u but quest %u does not exist, quest chain will not work.",
+ qinfo->GetQuestId(),qinfo->NextQuestInChain ,qinfo->NextQuestInChain );
+ qinfo->NextQuestInChain = 0;
+ }
+ else
+ mQuestTemplates[qinfo->NextQuestInChain]->prevChainQuests.push_back(qinfo->GetQuestId());
+ }
+
+ // fill additional data stores
+ if(qinfo->PrevQuestId)
+ {
+ if (mQuestTemplates.find(abs(qinfo->GetPrevQuestId())) == mQuestTemplates.end())
+ {
+ sLog.outErrorDb("Quest %d has PrevQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetPrevQuestId());
+ }
+ else
+ {
+ qinfo->prevQuests.push_back(qinfo->PrevQuestId);
+ }
+ }
+
+ if(qinfo->NextQuestId)
+ {
+ if (mQuestTemplates.find(abs(qinfo->GetNextQuestId())) == mQuestTemplates.end())
+ {
+ sLog.outErrorDb("Quest %d has NextQuestId %i, but no such quest", qinfo->GetQuestId(), qinfo->GetNextQuestId());
+ }
+ else
+ {
+ int32 signedQuestId = qinfo->NextQuestId < 0 ? -int32(qinfo->GetQuestId()) : int32(qinfo->GetQuestId());
+ mQuestTemplates[abs(qinfo->GetNextQuestId())]->prevQuests.push_back(signedQuestId);
+ }
+ }
+
+ if(qinfo->ExclusiveGroup)
+ mExclusiveQuestGroups.insert(std::pair<int32, uint32>(qinfo->ExclusiveGroup, qinfo->GetQuestId()));
+ if(qinfo->LimitTime)
+ qinfo->SetFlag(QUEST_TRINITY_FLAGS_TIMED);
+ }
+
+ // check QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT for spell with SPELL_EFFECT_QUEST_COMPLETE
+ for (uint32 i = 0; i < sSpellStore.GetNumRows(); ++i)
+ {
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(i);
+ if(!spellInfo)
+ continue;
+
+ for(int j = 0; j < 3; ++j)
+ {
+ if(spellInfo->Effect[j] != SPELL_EFFECT_QUEST_COMPLETE)
+ continue;
+
+ uint32 quest_id = spellInfo->EffectMiscValue[j];
+
+ Quest const* quest = GetQuestTemplate(quest_id);
+
+ // some quest referenced in spells not exist (outdated spells)
+ if(!quest)
+ continue;
+
+ if(!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
+ {
+ sLog.outErrorDb("Spell (id: %u) have SPELL_EFFECT_QUEST_COMPLETE for quest %u , but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT. Quest flags must be fixed, quest modified to enable objective.",spellInfo->Id,quest_id);
+
+ // this will prevent quest completing without objective
+ const_cast<Quest*>(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT);
+ }
+ }
+ }
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u quests definitions", mQuestTemplates.size() );
+}
+
+void ObjectMgr::LoadQuestLocales()
+{
+ mQuestLocaleMap.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query("SELECT entry,"
+ "Title_loc1,Details_loc1,Objectives_loc1,OfferRewardText_loc1,RequestItemsText_loc1,EndText_loc1,ObjectiveText1_loc1,ObjectiveText2_loc1,ObjectiveText3_loc1,ObjectiveText4_loc1,"
+ "Title_loc2,Details_loc2,Objectives_loc2,OfferRewardText_loc2,RequestItemsText_loc2,EndText_loc2,ObjectiveText1_loc2,ObjectiveText2_loc2,ObjectiveText3_loc2,ObjectiveText4_loc2,"
+ "Title_loc3,Details_loc3,Objectives_loc3,OfferRewardText_loc3,RequestItemsText_loc3,EndText_loc3,ObjectiveText1_loc3,ObjectiveText2_loc3,ObjectiveText3_loc3,ObjectiveText4_loc3,"
+ "Title_loc4,Details_loc4,Objectives_loc4,OfferRewardText_loc4,RequestItemsText_loc4,EndText_loc4,ObjectiveText1_loc4,ObjectiveText2_loc4,ObjectiveText3_loc4,ObjectiveText4_loc4,"
+ "Title_loc5,Details_loc5,Objectives_loc5,OfferRewardText_loc5,RequestItemsText_loc5,EndText_loc5,ObjectiveText1_loc5,ObjectiveText2_loc5,ObjectiveText3_loc5,ObjectiveText4_loc5,"
+ "Title_loc6,Details_loc6,Objectives_loc6,OfferRewardText_loc6,RequestItemsText_loc6,EndText_loc6,ObjectiveText1_loc6,ObjectiveText2_loc6,ObjectiveText3_loc6,ObjectiveText4_loc6,"
+ "Title_loc7,Details_loc7,Objectives_loc7,OfferRewardText_loc7,RequestItemsText_loc7,EndText_loc7,ObjectiveText1_loc7,ObjectiveText2_loc7,ObjectiveText3_loc7,ObjectiveText4_loc7,"
+ "Title_loc8,Details_loc8,Objectives_loc8,OfferRewardText_loc8,RequestItemsText_loc8,EndText_loc8,ObjectiveText1_loc8,ObjectiveText2_loc8,ObjectiveText3_loc8,ObjectiveText4_loc8"
+ " FROM locales_quest"
+ );
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString("");
+ sLog.outString(">> Loaded 0 Quest locale strings. DB table `locales_quest` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 entry = fields[0].GetUInt32();
+
+ QuestLocale& data = mQuestLocaleMap[entry];
+
+ for(int i = 1; i < MAX_LOCALE; ++i)
+ {
+ std::string str = fields[1+10*(i-1)].GetCppString();
+ if(!str.empty())
+ {
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.Title.size() <= idx)
+ data.Title.resize(idx+1);
+
+ data.Title[idx] = str;
+ }
+ }
+ str = fields[1+10*(i-1)+1].GetCppString();
+ if(!str.empty())
+ {
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.Details.size() <= idx)
+ data.Details.resize(idx+1);
+
+ data.Details[idx] = str;
+ }
+ }
+ str = fields[1+10*(i-1)+2].GetCppString();
+ if(!str.empty())
+ {
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.Objectives.size() <= idx)
+ data.Objectives.resize(idx+1);
+
+ data.Objectives[idx] = str;
+ }
+ }
+ str = fields[1+10*(i-1)+3].GetCppString();
+ if(!str.empty())
+ {
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.OfferRewardText.size() <= idx)
+ data.OfferRewardText.resize(idx+1);
+
+ data.OfferRewardText[idx] = str;
+ }
+ }
+ str = fields[1+10*(i-1)+4].GetCppString();
+ if(!str.empty())
+ {
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.RequestItemsText.size() <= idx)
+ data.RequestItemsText.resize(idx+1);
+
+ data.RequestItemsText[idx] = str;
+ }
+ }
+ str = fields[1+10*(i-1)+5].GetCppString();
+ if(!str.empty())
+ {
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.EndText.size() <= idx)
+ data.EndText.resize(idx+1);
+
+ data.EndText[idx] = str;
+ }
+ }
+ for(int k = 0; k < 4; ++k)
+ {
+ str = fields[1+10*(i-1)+6+k].GetCppString();
+ if(!str.empty())
+ {
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.ObjectiveText[k].size() <= idx)
+ data.ObjectiveText[k].resize(idx+1);
+
+ data.ObjectiveText[k][idx] = str;
+ }
+ }
+ }
+ }
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u Quest locale strings", mQuestLocaleMap.size() );
+}
+
+void ObjectMgr::LoadPetCreateSpells()
+{
+ QueryResult *result = WorldDatabase.Query("SELECT entry, Spell1, Spell2, Spell3, Spell4 FROM petcreateinfo_spell");
+ if(!result)
+ {
+ barGoLink bar( 1 );
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded 0 pet create spells" );
+ sLog.outErrorDb("`petcreateinfo_spell` table is empty!");
+ return;
+ }
+
+ uint32 count = 0;
+
+ barGoLink bar( result->GetRowCount() );
+
+ mPetCreateSpell.clear();
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 creature_id = fields[0].GetUInt32();
+
+ if(!creature_id || !sCreatureStorage.LookupEntry<CreatureInfo>(creature_id))
+ continue;
+
+ PetCreateSpellEntry PetCreateSpell;
+ for(int i = 0; i < 4; i++)
+ {
+ PetCreateSpell.spellid[i] = fields[i + 1].GetUInt32();
+
+ if(PetCreateSpell.spellid[i] && !sSpellStore.LookupEntry(PetCreateSpell.spellid[i]))
+ sLog.outErrorDb("Spell %u listed in `petcreateinfo_spell` does not exist",PetCreateSpell.spellid[i]);
+ }
+
+ mPetCreateSpell[creature_id] = PetCreateSpell;
+
+ ++count;
+ }
+ while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u pet create spells", count );
+}
+
+void ObjectMgr::LoadScripts(ScriptMapMap& scripts, char const* tablename)
+{
+ if(sWorld.IsScriptScheduled()) // function don't must be called in time scripts use.
+ return;
+
+ sLog.outString( "%s :", tablename);
+
+ scripts.clear(); // need for reload support
+
+ QueryResult *result = WorldDatabase.PQuery( "SELECT id,delay,command,datalong,datalong2,dataint, x, y, z, o FROM %s", tablename );
+
+ uint32 count = 0;
+
+ if( !result )
+ {
+ barGoLink bar( 1 );
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u script definitions", count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ bar.step();
+
+ Field *fields = result->Fetch();
+ ScriptInfo tmp;
+ tmp.id = fields[0].GetUInt32();
+ tmp.delay = fields[1].GetUInt32();
+ tmp.command = fields[2].GetUInt32();
+ tmp.datalong = fields[3].GetUInt32();
+ tmp.datalong2 = fields[4].GetUInt32();
+ tmp.dataint = fields[5].GetInt32();
+ tmp.x = fields[6].GetFloat();
+ tmp.y = fields[7].GetFloat();
+ tmp.z = fields[8].GetFloat();
+ tmp.o = fields[9].GetFloat();
+
+ // generic command args check
+ switch(tmp.command)
+ {
+ case SCRIPT_COMMAND_TALK:
+ {
+ if(tmp.datalong > 3)
+ {
+ sLog.outErrorDb("Table `%s` has invalid talk type (datalong = %u) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.datalong,tmp.id);
+ continue;
+ }
+ if(tmp.dataint==0)
+ {
+ sLog.outErrorDb("Table `%s` has invalid talk text id (dataint = %i) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.dataint,tmp.id);
+ continue;
+ }
+ if(tmp.dataint < MIN_DB_SCRIPT_STRING_ID || tmp.dataint >= MAX_DB_SCRIPT_STRING_ID)
+ {
+ sLog.outErrorDb("Table `%s` has out of range text id (dataint = %i expected %u-%u) in SCRIPT_COMMAND_TALK for script id %u",tablename,tmp.dataint,MIN_DB_SCRIPT_STRING_ID,MAX_DB_SCRIPT_STRING_ID,tmp.id);
+ continue;
+ }
+
+ // if(!objmgr.GetMangosStringLocale(tmp.dataint)) will checked after db_script_string loading
+ break;
+ }
+
+ case SCRIPT_COMMAND_TELEPORT_TO:
+ {
+ if(!sMapStore.LookupEntry(tmp.datalong))
+ {
+ sLog.outErrorDb("Table `%s` has invalid map (Id: %u) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",tablename,tmp.datalong,tmp.id);
+ continue;
+ }
+
+ if(!Trinity::IsValidMapCoord(tmp.x,tmp.y,tmp.z,tmp.o))
+ {
+ sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f) in SCRIPT_COMMAND_TELEPORT_TO for script id %u",tablename,tmp.x,tmp.y,tmp.id);
+ continue;
+ }
+ break;
+ }
+
+ case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE:
+ {
+ if(!Trinity::IsValidMapCoord(tmp.x,tmp.y,tmp.z,tmp.o))
+ {
+ sLog.outErrorDb("Table `%s` has invalid coordinates (X: %f Y: %f) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",tablename,tmp.x,tmp.y,tmp.id);
+ continue;
+ }
+
+ if(!GetCreatureTemplate(tmp.datalong))
+ {
+ sLog.outErrorDb("Table `%s` has invalid creature (Entry: %u) in SCRIPT_COMMAND_TEMP_SUMMON_CREATURE for script id %u",tablename,tmp.datalong,tmp.id);
+ continue;
+ }
+ break;
+ }
+
+ case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT:
+ {
+ GameObjectData const* data = GetGOData(tmp.datalong);
+ if(!data)
+ {
+ sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,tmp.datalong,tmp.id);
+ continue;
+ }
+
+ GameObjectInfo const* info = GetGameObjectInfo(data->id);
+ if(!info)
+ {
+ sLog.outErrorDb("Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,tmp.datalong,data->id,tmp.id);
+ continue;
+ }
+
+ if( info->type==GAMEOBJECT_TYPE_FISHINGNODE ||
+ info->type==GAMEOBJECT_TYPE_FISHINGHOLE ||
+ info->type==GAMEOBJECT_TYPE_DOOR ||
+ info->type==GAMEOBJECT_TYPE_BUTTON ||
+ info->type==GAMEOBJECT_TYPE_TRAP )
+ {
+ sLog.outErrorDb("Table `%s` have gameobject type (%u) unsupported by command SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u",tablename,info->id,tmp.id);
+ continue;
+ }
+ break;
+ }
+ case SCRIPT_COMMAND_OPEN_DOOR:
+ case SCRIPT_COMMAND_CLOSE_DOOR:
+ {
+ GameObjectData const* data = GetGOData(tmp.datalong);
+ if(!data)
+ {
+ sLog.outErrorDb("Table `%s` has invalid gameobject (GUID: %u) in %s for script id %u",tablename,tmp.datalong,(tmp.command==SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id);
+ continue;
+ }
+
+ GameObjectInfo const* info = GetGameObjectInfo(data->id);
+ if(!info)
+ {
+ sLog.outErrorDb("Table `%s` has gameobject with invalid entry (GUID: %u Entry: %u) in %s for script id %u",tablename,tmp.datalong,data->id,(tmp.command==SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id);
+ continue;
+ }
+
+ if( info->type!=GAMEOBJECT_TYPE_DOOR)
+ {
+ sLog.outErrorDb("Table `%s` has gameobject type (%u) non supported by command %s for script id %u",tablename,info->id,(tmp.command==SCRIPT_COMMAND_OPEN_DOOR ? "SCRIPT_COMMAND_OPEN_DOOR" : "SCRIPT_COMMAND_CLOSE_DOOR"),tmp.id);
+ continue;
+ }
+
+ break;
+ }
+ case SCRIPT_COMMAND_QUEST_EXPLORED:
+ {
+ Quest const* quest = GetQuestTemplate(tmp.datalong);
+ if(!quest)
+ {
+ sLog.outErrorDb("Table `%s` has invalid quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u",tablename,tmp.datalong,tmp.id);
+ continue;
+ }
+
+ if(!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
+ {
+ sLog.outErrorDb("Table `%s` has quest (ID: %u) in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT in quest flags. Script command or quest flags wrong. Quest modified to require objective.",tablename,tmp.datalong,tmp.id);
+
+ // this will prevent quest completing without objective
+ const_cast<Quest*>(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT);
+
+ // continue; - quest objective requirement set and command can be allowed
+ }
+
+ if(float(tmp.datalong2) > DEFAULT_VISIBILITY_DISTANCE)
+ {
+ sLog.outErrorDb("Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u",
+ tablename,tmp.datalong2,tmp.id);
+ continue;
+ }
+
+ if(tmp.datalong2 && float(tmp.datalong2) > DEFAULT_VISIBILITY_DISTANCE)
+ {
+ sLog.outErrorDb("Table `%s` has too large distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, max distance is %f or 0 for disable distance check",
+ tablename,tmp.datalong2,tmp.id,DEFAULT_VISIBILITY_DISTANCE);
+ continue;
+ }
+
+ if(tmp.datalong2 && float(tmp.datalong2) < INTERACTION_DISTANCE)
+ {
+ sLog.outErrorDb("Table `%s` has too small distance (%u) for exploring objective complete in `datalong2` in SCRIPT_COMMAND_QUEST_EXPLORED in `datalong` for script id %u, min distance is %f or 0 for disable distance check",
+ tablename,tmp.datalong2,tmp.id,INTERACTION_DISTANCE);
+ continue;
+ }
+
+ break;
+ }
+
+ case SCRIPT_COMMAND_REMOVE_AURA:
+ case SCRIPT_COMMAND_CAST_SPELL:
+ {
+ if(!sSpellStore.LookupEntry(tmp.datalong))
+ {
+ sLog.outErrorDb("Table `%s` using non-existent spell (id: %u) in SCRIPT_COMMAND_REMOVE_AURA or SCRIPT_COMMAND_CAST_SPELL for script id %u",
+ tablename,tmp.datalong,tmp.id);
+ continue;
+ }
+ break;
+ }
+ }
+
+ if (scripts.find(tmp.id) == scripts.end())
+ {
+ ScriptMap emptyMap;
+ scripts[tmp.id] = emptyMap;
+ }
+ scripts[tmp.id].insert(std::pair<uint32, ScriptInfo>(tmp.delay, tmp));
+
+ ++count;
+ } while( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u script definitions", count );
+}
+
+void ObjectMgr::LoadGameObjectScripts()
+{
+ LoadScripts(sGameObjectScripts, "gameobject_scripts");
+
+ // check ids
+ for(ScriptMapMap::const_iterator itr = sGameObjectScripts.begin(); itr != sGameObjectScripts.end(); ++itr)
+ {
+ if(!GetGOData(itr->first))
+ sLog.outErrorDb("Table `gameobject_scripts` has not existing gameobject (GUID: %u) as script id",itr->first);
+ }
+}
+
+void ObjectMgr::LoadQuestEndScripts()
+{
+ LoadScripts(sQuestEndScripts, "quest_end_scripts");
+
+ // check ids
+ for(ScriptMapMap::const_iterator itr = sQuestEndScripts.begin(); itr != sQuestEndScripts.end(); ++itr)
+ {
+ if(!GetQuestTemplate(itr->first))
+ sLog.outErrorDb("Table `quest_end_scripts` has not existing quest (Id: %u) as script id",itr->first);
+ }
+}
+
+void ObjectMgr::LoadQuestStartScripts()
+{
+ LoadScripts(sQuestStartScripts,"quest_start_scripts");
+
+ // check ids
+ for(ScriptMapMap::const_iterator itr = sQuestStartScripts.begin(); itr != sQuestStartScripts.end(); ++itr)
+ {
+ if(!GetQuestTemplate(itr->first))
+ sLog.outErrorDb("Table `quest_start_scripts` has not existing quest (Id: %u) as script id",itr->first);
+ }
+}
+
+void ObjectMgr::LoadSpellScripts()
+{
+ LoadScripts(sSpellScripts, "spell_scripts");
+
+ // check ids
+ for(ScriptMapMap::const_iterator itr = sSpellScripts.begin(); itr != sSpellScripts.end(); ++itr)
+ {
+ SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first);
+
+ if(!spellInfo)
+ {
+ sLog.outErrorDb("Table `spell_scripts` has not existing spell (Id: %u) as script id",itr->first);
+ continue;
+ }
+
+ //check for correct spellEffect
+ bool found = false;
+ for(int i=0; i<3; ++i)
+ {
+ // skip empty effects
+ if( !spellInfo->Effect[i] )
+ continue;
+
+ if( spellInfo->Effect[i] == SPELL_EFFECT_SCRIPT_EFFECT )
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if(!found)
+ sLog.outErrorDb("Table `spell_scripts` has unsupported spell (Id: %u) without SPELL_EFFECT_SCRIPT_EFFECT (%u) spell effect",itr->first,SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+}
+
+void ObjectMgr::LoadEventScripts()
+{
+ LoadScripts(sEventScripts, "event_scripts");
+
+ std::set<uint32> evt_scripts;
+ // Load all possible script entries from gameobjects
+ for(uint32 i = 1; i < sGOStorage.MaxEntry; ++i)
+ {
+ GameObjectInfo const * goInfo = sGOStorage.LookupEntry<GameObjectInfo>(i);
+ if (goInfo)
+ {
+ switch(goInfo->type)
+ {
+ case GAMEOBJECT_TYPE_GOOBER:
+ if(goInfo->goober.eventId)
+ evt_scripts.insert(goInfo->goober.eventId);
+ break;
+ case GAMEOBJECT_TYPE_CHEST:
+ if(goInfo->chest.eventId)
+ evt_scripts.insert(goInfo->chest.eventId);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ // Load all possible script entries from spells
+ for(uint32 i = 1; i < sSpellStore.GetNumRows(); ++i)
+ {
+ SpellEntry const * spell = sSpellStore.LookupEntry(i);
+ if (spell)
+ {
+ for(int j=0; j<3; ++j)
+ {
+ if( spell->Effect[j] == SPELL_EFFECT_SEND_EVENT )
+ {
+ if (spell->EffectMiscValue[j])
+ evt_scripts.insert(spell->EffectMiscValue[j]);
+ }
+ }
+ }
+ }
+ // Then check if all scripts are in above list of possible script entries
+ for(ScriptMapMap::const_iterator itr = sEventScripts.begin(); itr != sEventScripts.end(); ++itr)
+ {
+ std::set<uint32>::const_iterator itr2 = evt_scripts.find(itr->first);
+ if (itr2 == evt_scripts.end())
+ sLog.outErrorDb("Table `event_scripts` has script (Id: %u) not referring to any gameobject_template type 10 data2 field or type 3 data6 field or any spell effect %u", itr->first, SPELL_EFFECT_SEND_EVENT);
+ }
+}
+
+void ObjectMgr::LoadItemTexts()
+{
+ QueryResult *result = CharacterDatabase.Query("SELECT id, text FROM item_text");
+
+ uint32 count = 0;
+
+ if( !result )
+ {
+ barGoLink bar( 1 );
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u item pages", count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ Field* fields;
+ do
+ {
+ bar.step();
+
+ fields = result->Fetch();
+
+ mItemTexts[ fields[0].GetUInt32() ] = fields[1].GetCppString();
+
+ ++count;
+
+ } while ( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u item texts", count );
+}
+
+void ObjectMgr::LoadPageTexts()
+{
+ sPageTextStore.Free(); // for reload case
+
+ sPageTextStore.Load();
+ sLog.outString( ">> Loaded %u page texts", sPageTextStore.RecordCount );
+ sLog.outString();
+
+ for(uint32 i = 1; i < sPageTextStore.MaxEntry; ++i)
+ {
+ // check data correctness
+ PageText const* page = sPageTextStore.LookupEntry<PageText>(i);
+ if(!page)
+ continue;
+
+ if(page->Next_Page && !sPageTextStore.LookupEntry<PageText>(page->Next_Page))
+ {
+ sLog.outErrorDb("Page text (Id: %u) has not existing next page (Id:%u)", i,page->Next_Page);
+ continue;
+ }
+
+ // detect circular reference
+ std::set<uint32> checkedPages;
+ for(PageText const* pageItr = page; pageItr; pageItr = sPageTextStore.LookupEntry<PageText>(pageItr->Next_Page))
+ {
+ if(!pageItr->Next_Page)
+ break;
+ checkedPages.insert(pageItr->Page_ID);
+ if(checkedPages.find(pageItr->Next_Page)!=checkedPages.end())
+ {
+ std::ostringstream ss;
+ ss<< "The text page(s) ";
+ for (std::set<uint32>::iterator itr= checkedPages.begin();itr!=checkedPages.end(); itr++)
+ ss << *itr << " ";
+ ss << "create(s) a circular reference, which can cause the server to freeze. Changing Next_Page of page "
+ << pageItr->Page_ID <<" to 0";
+ sLog.outErrorDb(ss.str().c_str());
+ const_cast<PageText*>(pageItr)->Next_Page = 0;
+ break;
+ }
+ }
+ }
+}
+
+void ObjectMgr::LoadPageTextLocales()
+{
+ mPageTextLocaleMap.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query("SELECT entry,text_loc1,text_loc2,text_loc3,text_loc4,text_loc5,text_loc6,text_loc7,text_loc8 FROM locales_page_text");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString("");
+ sLog.outString(">> Loaded 0 PageText locale strings. DB table `locales_page_text` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 entry = fields[0].GetUInt32();
+
+ PageTextLocale& data = mPageTextLocaleMap[entry];
+
+ for(int i = 1; i < MAX_LOCALE; ++i)
+ {
+ std::string str = fields[i].GetCppString();
+ if(str.empty())
+ continue;
+
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.Text.size() <= idx)
+ data.Text.resize(idx+1);
+
+ data.Text[idx] = str;
+ }
+ }
+
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u PageText locale strings", mPageTextLocaleMap.size() );
+}
+
+struct SQLInstanceLoader : public SQLStorageLoaderBase<SQLInstanceLoader>
+{
+ template<class D>
+ void convert_from_str(uint32 field_pos, char *src, D &dst)
+ {
+ dst = D(objmgr.GetScriptId(src));
+ }
+};
+
+void ObjectMgr::LoadInstanceTemplate()
+{
+ SQLInstanceLoader loader;
+ loader.Load(sInstanceTemplate);
+
+ for(uint32 i = 0; i < sInstanceTemplate.MaxEntry; i++)
+ {
+ InstanceTemplate* temp = (InstanceTemplate*)GetInstanceTemplate(i);
+ if(!temp) continue;
+ const MapEntry* entry = sMapStore.LookupEntry(temp->map);
+ if(!entry)
+ {
+ sLog.outErrorDb("ObjectMgr::LoadInstanceTemplate: bad mapid %d for template!", temp->map);
+ continue;
+ }
+ else if(!entry->HasResetTime())
+ continue;
+
+ if(temp->reset_delay == 0)
+ {
+ // use defaults from the DBC
+ if(entry->SupportsHeroicMode())
+ {
+ temp->reset_delay = entry->resetTimeHeroic / DAY;
+ }
+ else if (entry->resetTimeRaid && entry->map_type == MAP_RAID)
+ {
+ temp->reset_delay = entry->resetTimeRaid / DAY;
+ }
+ }
+
+ // the reset_delay must be at least one day
+ temp->reset_delay = std::max((uint32)1, (uint32)(temp->reset_delay * sWorld.getRate(RATE_INSTANCE_RESET_TIME)));
+ }
+
+ sLog.outString( ">> Loaded %u Instance Template definitions", sInstanceTemplate.RecordCount );
+ sLog.outString();
+}
+
+void ObjectMgr::AddGossipText(GossipText *pGText)
+{
+ ASSERT( pGText->Text_ID );
+ ASSERT( mGossipText.find(pGText->Text_ID) == mGossipText.end() );
+ mGossipText[pGText->Text_ID] = pGText;
+}
+
+GossipText *ObjectMgr::GetGossipText(uint32 Text_ID)
+{
+ GossipTextMap::const_iterator itr;
+ for (itr = mGossipText.begin(); itr != mGossipText.end(); itr++)
+ {
+ if(itr->second->Text_ID == Text_ID)
+ return itr->second;
+ }
+ return NULL;
+}
+
+void ObjectMgr::LoadGossipText()
+{
+ GossipText *pGText;
+ QueryResult *result = WorldDatabase.Query( "SELECT * FROM npc_text" );
+
+ int count = 0;
+ if( !result )
+ {
+ barGoLink bar( 1 );
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u npc texts", count );
+ return;
+ }
+
+ int cic;
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ ++count;
+ cic = 0;
+
+ Field *fields = result->Fetch();
+
+ bar.step();
+
+ pGText = new GossipText;
+ pGText->Text_ID = fields[cic++].GetUInt32();
+
+ for (int i=0; i< 8; i++)
+ {
+ pGText->Options[i].Text_0 = fields[cic++].GetCppString();
+ pGText->Options[i].Text_1 = fields[cic++].GetCppString();
+
+ pGText->Options[i].Language = fields[cic++].GetUInt32();
+ pGText->Options[i].Probability = fields[cic++].GetFloat();
+
+ pGText->Options[i].Emotes[0]._Delay = fields[cic++].GetUInt32();
+ pGText->Options[i].Emotes[0]._Emote = fields[cic++].GetUInt32();
+
+ pGText->Options[i].Emotes[1]._Delay = fields[cic++].GetUInt32();
+ pGText->Options[i].Emotes[1]._Emote = fields[cic++].GetUInt32();
+
+ pGText->Options[i].Emotes[2]._Delay = fields[cic++].GetUInt32();
+ pGText->Options[i].Emotes[2]._Emote = fields[cic++].GetUInt32();
+ }
+
+ if ( !pGText->Text_ID ) continue;
+ AddGossipText( pGText );
+
+ } while( result->NextRow() );
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u npc texts", count );
+ delete result;
+}
+
+void ObjectMgr::LoadNpcTextLocales()
+{
+ mNpcTextLocaleMap.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query("SELECT entry,"
+ "Text0_0_loc1,Text0_1_loc1,Text1_0_loc1,Text1_1_loc1,Text2_0_loc1,Text2_1_loc1,Text3_0_loc1,Text3_1_loc1,Text4_0_loc1,Text4_1_loc1,Text5_0_loc1,Text5_1_loc1,Text6_0_loc1,Text6_1_loc1,Text7_0_loc1,Text7_1_loc1,"
+ "Text0_0_loc2,Text0_1_loc2,Text1_0_loc2,Text1_1_loc2,Text2_0_loc2,Text2_1_loc2,Text3_0_loc2,Text3_1_loc1,Text4_0_loc2,Text4_1_loc2,Text5_0_loc2,Text5_1_loc2,Text6_0_loc2,Text6_1_loc2,Text7_0_loc2,Text7_1_loc2,"
+ "Text0_0_loc3,Text0_1_loc3,Text1_0_loc3,Text1_1_loc3,Text2_0_loc3,Text2_1_loc3,Text3_0_loc3,Text3_1_loc1,Text4_0_loc3,Text4_1_loc3,Text5_0_loc3,Text5_1_loc3,Text6_0_loc3,Text6_1_loc3,Text7_0_loc3,Text7_1_loc3,"
+ "Text0_0_loc4,Text0_1_loc4,Text1_0_loc4,Text1_1_loc4,Text2_0_loc4,Text2_1_loc4,Text3_0_loc4,Text3_1_loc1,Text4_0_loc4,Text4_1_loc4,Text5_0_loc4,Text5_1_loc4,Text6_0_loc4,Text6_1_loc4,Text7_0_loc4,Text7_1_loc4,"
+ "Text0_0_loc5,Text0_1_loc5,Text1_0_loc5,Text1_1_loc5,Text2_0_loc5,Text2_1_loc5,Text3_0_loc5,Text3_1_loc1,Text4_0_loc5,Text4_1_loc5,Text5_0_loc5,Text5_1_loc5,Text6_0_loc5,Text6_1_loc5,Text7_0_loc5,Text7_1_loc5,"
+ "Text0_0_loc6,Text0_1_loc6,Text1_0_loc6,Text1_1_loc6,Text2_0_loc6,Text2_1_loc6,Text3_0_loc6,Text3_1_loc1,Text4_0_loc6,Text4_1_loc6,Text5_0_loc6,Text5_1_loc6,Text6_0_loc6,Text6_1_loc6,Text7_0_loc6,Text7_1_loc6,"
+ "Text0_0_loc7,Text0_1_loc7,Text1_0_loc7,Text1_1_loc7,Text2_0_loc7,Text2_1_loc7,Text3_0_loc7,Text3_1_loc1,Text4_0_loc7,Text4_1_loc7,Text5_0_loc7,Text5_1_loc7,Text6_0_loc7,Text6_1_loc7,Text7_0_loc7,Text7_1_loc7, "
+ "Text0_0_loc8,Text0_1_loc8,Text1_0_loc8,Text1_1_loc8,Text2_0_loc8,Text2_1_loc8,Text3_0_loc8,Text3_1_loc1,Text4_0_loc8,Text4_1_loc8,Text5_0_loc8,Text5_1_loc8,Text6_0_loc8,Text6_1_loc8,Text7_0_loc8,Text7_1_loc8 "
+ " FROM locales_npc_text");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString("");
+ sLog.outString(">> Loaded 0 Quest locale strings. DB table `locales_npc_text` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 entry = fields[0].GetUInt32();
+
+ NpcTextLocale& data = mNpcTextLocaleMap[entry];
+
+ for(int i=1; i<MAX_LOCALE; ++i)
+ {
+ for(int j=0; j<8; ++j)
+ {
+ std::string str0 = fields[1+8*2*(i-1)+2*j].GetCppString();
+ if(!str0.empty())
+ {
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.Text_0[j].size() <= idx)
+ data.Text_0[j].resize(idx+1);
+
+ data.Text_0[j][idx] = str0;
+ }
+ }
+ std::string str1 = fields[1+8*2*(i-1)+2*j+1].GetCppString();
+ if(!str1.empty())
+ {
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.Text_1[j].size() <= idx)
+ data.Text_1[j].resize(idx+1);
+
+ data.Text_1[j][idx] = str1;
+ }
+ }
+ }
+ }
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u NpcText locale strings", mNpcTextLocaleMap.size() );
+}
+
+//not very fast function but it is called only once a day, or on starting-up
+void ObjectMgr::ReturnOrDeleteOldMails(bool serverUp)
+{
+ time_t basetime = time(NULL);
+ sLog.outDebug("Returning mails current time: hour: %d, minute: %d, second: %d ", localtime(&basetime)->tm_hour, localtime(&basetime)->tm_min, localtime(&basetime)->tm_sec);
+ //delete all old mails without item and without body immediately, if starting server
+ if (!serverUp)
+ CharacterDatabase.PExecute("DELETE FROM mail WHERE expire_time < '" I64FMTD "' AND has_items = '0' AND itemTextId = 0", (uint64)basetime);
+ // 0 1 2 3 4 5 6 7 8 9
+ QueryResult* result = CharacterDatabase.PQuery("SELECT id,messageType,sender,receiver,itemTextId,has_items,expire_time,cod,checked,mailTemplateId FROM mail WHERE expire_time < '" I64FMTD "'", (uint64)basetime);
+ if ( !result )
+ return; // any mails need to be returned or deleted
+ Field *fields;
+ //std::ostringstream delitems, delmails; //will be here for optimization
+ //bool deletemail = false, deleteitem = false;
+ //delitems << "DELETE FROM item_instance WHERE guid IN ( ";
+ //delmails << "DELETE FROM mail WHERE id IN ( "
+ do
+ {
+ fields = result->Fetch();
+ Mail *m = new Mail;
+ m->messageID = fields[0].GetUInt32();
+ m->messageType = fields[1].GetUInt8();
+ m->sender = fields[2].GetUInt32();
+ m->receiver = fields[3].GetUInt32();
+ m->itemTextId = fields[4].GetUInt32();
+ bool has_items = fields[5].GetBool();
+ m->expire_time = (time_t)fields[6].GetUInt64();
+ m->deliver_time = 0;
+ m->COD = fields[7].GetUInt32();
+ m->checked = fields[8].GetUInt32();
+ m->mailTemplateId = fields[9].GetInt16();
+
+ Player *pl = 0;
+ if (serverUp)
+ pl = GetPlayer((uint64)m->receiver);
+ if (pl && pl->m_mailsLoaded)
+ { //this code will run very improbably (the time is between 4 and 5 am, in game is online a player, who has old mail
+ //his in mailbox and he has already listed his mails )
+ delete m;
+ continue;
+ }
+ //delete or return mail:
+ if (has_items)
+ {
+ QueryResult *resultItems = CharacterDatabase.PQuery("SELECT item_guid,item_template FROM mail_items WHERE mail_id='%u'", m->messageID);
+ if(resultItems)
+ {
+ do
+ {
+ Field *fields2 = resultItems->Fetch();
+
+ uint32 item_guid_low = fields2[0].GetUInt32();
+ uint32 item_template = fields2[1].GetUInt32();
+
+ m->AddItem(item_guid_low, item_template);
+ }
+ while (resultItems->NextRow());
+
+ delete resultItems;
+ }
+ //if it is mail from AH, it shouldn't be returned, but deleted
+ if (m->messageType != MAIL_NORMAL || (m->checked & (MAIL_CHECK_MASK_AUCTION | MAIL_CHECK_MASK_COD_PAYMENT | MAIL_CHECK_MASK_RETURNED)))
+ {
+ // mail open and then not returned
+ for(std::vector<MailItemInfo>::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2)
+ CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", itr2->item_guid);
+ }
+ else
+ {
+ //mail will be returned:
+ CharacterDatabase.PExecute("UPDATE mail SET sender = '%u', receiver = '%u', expire_time = '" I64FMTD "', deliver_time = '" I64FMTD "',cod = '0', checked = '%u' WHERE id = '%u'", m->receiver, m->sender, (uint64)(basetime + 30*DAY), (uint64)basetime, MAIL_CHECK_MASK_RETURNED, m->messageID);
+ delete m;
+ continue;
+ }
+ }
+
+ if (m->itemTextId)
+ CharacterDatabase.PExecute("DELETE FROM item_text WHERE id = '%u'", m->itemTextId);
+
+ //deletemail = true;
+ //delmails << m->messageID << ", ";
+ CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", m->messageID);
+ delete m;
+ } while (result->NextRow());
+ delete result;
+}
+
+void ObjectMgr::LoadQuestAreaTriggers()
+{
+ mQuestAreaTriggerMap.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query( "SELECT id,quest FROM areatrigger_involvedrelation" );
+
+ uint32 count = 0;
+
+ if( !result )
+ {
+ barGoLink bar( 1 );
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u quest trigger points", count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ ++count;
+ bar.step();
+
+ Field *fields = result->Fetch();
+
+ uint32 trigger_ID = fields[0].GetUInt32();
+ uint32 quest_ID = fields[1].GetUInt32();
+
+ AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(trigger_ID);
+ if(!atEntry)
+ {
+ sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",trigger_ID);
+ continue;
+ }
+
+ Quest const* quest = GetQuestTemplate(quest_ID);
+
+ if(!quest)
+ {
+ sLog.outErrorDb("Table `areatrigger_involvedrelation` has record (id: %u) for not existing quest %u",trigger_ID,quest_ID);
+ continue;
+ }
+
+ if(!quest->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
+ {
+ sLog.outErrorDb("Table `areatrigger_involvedrelation` has record (id: %u) for not quest %u, but quest not have flag QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT. Trigger or quest flags must be fixed, quest modified to require objective.",trigger_ID,quest_ID);
+
+ // this will prevent quest completing without objective
+ const_cast<Quest*>(quest)->SetFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT);
+
+ // continue; - quest modified to required objective and trigger can be allowed.
+ }
+
+ mQuestAreaTriggerMap[trigger_ID] = quest_ID;
+
+ } while( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u quest trigger points", count );
+}
+
+void ObjectMgr::LoadTavernAreaTriggers()
+{
+ mTavernAreaTriggerSet.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query("SELECT id FROM areatrigger_tavern");
+
+ uint32 count = 0;
+
+ if( !result )
+ {
+ barGoLink bar( 1 );
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u tavern triggers", count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ ++count;
+ bar.step();
+
+ Field *fields = result->Fetch();
+
+ uint32 Trigger_ID = fields[0].GetUInt32();
+
+ AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
+ if(!atEntry)
+ {
+ sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID);
+ continue;
+ }
+
+ mTavernAreaTriggerSet.insert(Trigger_ID);
+ } while( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u tavern triggers", count );
+}
+
+void ObjectMgr::LoadAreaTriggerScripts()
+{
+ mAreaTriggerScripts.clear(); // need for reload case
+ QueryResult *result = WorldDatabase.Query("SELECT entry, ScriptName FROM areatrigger_scripts");
+
+ uint32 count = 0;
+
+ if( !result )
+ {
+ barGoLink bar( 1 );
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u areatrigger scripts", count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ ++count;
+ bar.step();
+
+ Field *fields = result->Fetch();
+
+ uint32 Trigger_ID = fields[0].GetUInt32();
+ const char *scriptName = fields[1].GetString();
+
+ AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
+ if(!atEntry)
+ {
+ sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID);
+ continue;
+ }
+ mAreaTriggerScripts[Trigger_ID] = GetScriptId(scriptName);
+ } while( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u areatrigger scripts", count );
+}
+
+uint32 ObjectMgr::GetNearestTaxiNode( float x, float y, float z, uint32 mapid )
+{
+ bool found = false;
+ float dist;
+ uint32 id = 0;
+
+ for(uint32 i = 1; i < sTaxiNodesStore.GetNumRows(); ++i)
+ {
+ TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(i);
+ if(node && node->map_id == mapid)
+ {
+ float dist2 = (node->x - x)*(node->x - x)+(node->y - y)*(node->y - y)+(node->z - z)*(node->z - z);
+ if(found)
+ {
+ if(dist2 < dist)
+ {
+ dist = dist2;
+ id = i;
+ }
+ }
+ else
+ {
+ found = true;
+ dist = dist2;
+ id = i;
+ }
+ }
+ }
+
+ return id;
+}
+
+void ObjectMgr::GetTaxiPath( uint32 source, uint32 destination, uint32 &path, uint32 &cost)
+{
+ TaxiPathSetBySource::iterator src_i = sTaxiPathSetBySource.find(source);
+ if(src_i==sTaxiPathSetBySource.end())
+ {
+ path = 0;
+ cost = 0;
+ return;
+ }
+
+ TaxiPathSetForSource& pathSet = src_i->second;
+
+ TaxiPathSetForSource::iterator dest_i = pathSet.find(destination);
+ if(dest_i==pathSet.end())
+ {
+ path = 0;
+ cost = 0;
+ return;
+ }
+
+ cost = dest_i->second.price;
+ path = dest_i->second.ID;
+}
+
+uint16 ObjectMgr::GetTaxiMount( uint32 id, uint32 team )
+{
+ uint16 mount_entry = 0;
+ uint16 mount_id = 0;
+
+ TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(id);
+ if(node)
+ {
+ if (team == ALLIANCE) mount_entry = node->alliance_mount_type;
+ else mount_entry = node->horde_mount_type;
+
+ CreatureInfo const *cinfo = GetCreatureTemplate(mount_entry);
+ if (cinfo)
+ {
+ if(! (mount_id = cinfo->GetRandomValidModelId()))
+ {
+ sLog.outErrorDb("No displayid found for the taxi mount with the entry %u! Can't load it!", mount_entry);
+ return false;
+ }
+ }
+ }
+
+ CreatureModelInfo const *minfo = GetCreatureModelInfo(mount_id);
+ if(!minfo)
+ {
+ sLog.outErrorDb("Taxi mount (Entry: %u) for taxi node (Id: %u) for team %u has model %u not found in table `creature_model_info`, can't load. ",
+ mount_entry,id,team,mount_id);
+
+ return false;
+ }
+ if(minfo->modelid_other_gender!=0)
+ mount_id = urand(0,1) ? mount_id : minfo->modelid_other_gender;
+
+ return mount_id;
+}
+
+void ObjectMgr::GetTaxiPathNodes( uint32 path, Path &pathnodes, std::vector<uint32>& mapIds)
+{
+ if(path >= sTaxiPathNodesByPath.size())
+ return;
+
+ TaxiPathNodeList& nodeList = sTaxiPathNodesByPath[path];
+
+ pathnodes.Resize(nodeList.size());
+ mapIds.resize(nodeList.size());
+
+ for(size_t i = 0; i < nodeList.size(); ++i)
+ {
+ pathnodes[ i ].x = nodeList[i].x;
+ pathnodes[ i ].y = nodeList[i].y;
+ pathnodes[ i ].z = nodeList[i].z;
+
+ mapIds[i] = nodeList[i].mapid;
+ }
+}
+
+void ObjectMgr::GetTransportPathNodes( uint32 path, TransportPath &pathnodes )
+{
+ if(path >= sTaxiPathNodesByPath.size())
+ return;
+
+ TaxiPathNodeList& nodeList = sTaxiPathNodesByPath[path];
+
+ pathnodes.Resize(nodeList.size());
+
+ for(size_t i = 0; i < nodeList.size(); ++i)
+ {
+ pathnodes[ i ].mapid = nodeList[i].mapid;
+ pathnodes[ i ].x = nodeList[i].x;
+ pathnodes[ i ].y = nodeList[i].y;
+ pathnodes[ i ].z = nodeList[i].z;
+ pathnodes[ i ].actionFlag = nodeList[i].actionFlag;
+ pathnodes[ i ].delay = nodeList[i].delay;
+ }
+}
+
+void ObjectMgr::LoadGraveyardZones()
+{
+ mGraveYardMap.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query("SELECT id,ghost_zone,faction FROM game_graveyard_zone");
+
+ uint32 count = 0;
+
+ if( !result )
+ {
+ barGoLink bar( 1 );
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u graveyard-zone links", count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ ++count;
+ bar.step();
+
+ Field *fields = result->Fetch();
+
+ uint32 safeLocId = fields[0].GetUInt32();
+ uint32 zoneId = fields[1].GetUInt32();
+ uint32 team = fields[2].GetUInt32();
+
+ WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(safeLocId);
+ if(!entry)
+ {
+ sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing graveyard (WorldSafeLocs.dbc id) %u, skipped.",safeLocId);
+ continue;
+ }
+
+ AreaTableEntry const *areaEntry = GetAreaEntryByAreaID(zoneId);
+ if(!areaEntry)
+ {
+ sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing zone id (%u), skipped.",zoneId);
+ continue;
+ }
+
+ if(areaEntry->zone != 0)
+ {
+ sLog.outErrorDb("Table `game_graveyard_zone` has record subzone id (%u) instead of zone, skipped.",zoneId);
+ continue;
+ }
+
+ if(team!=0 && team!=HORDE && team!=ALLIANCE)
+ {
+ sLog.outErrorDb("Table `game_graveyard_zone` has record for non player faction (%u), skipped.",team);
+ continue;
+ }
+
+ if(!AddGraveYardLink(safeLocId,zoneId,team,false))
+ sLog.outErrorDb("Table `game_graveyard_zone` has a duplicate record for Graveyard (ID: %u) and Zone (ID: %u), skipped.",safeLocId,zoneId);
+ } while( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u graveyard-zone links", count );
+}
+
+WorldSafeLocsEntry const *ObjectMgr::GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team)
+{
+ // search for zone associated closest graveyard
+ uint32 zoneId = MapManager::Instance().GetZoneId(MapId,x,y);
+
+ // Simulate std. algorithm:
+ // found some graveyard associated to (ghost_zone,ghost_map)
+ //
+ // if mapId == graveyard.mapId (ghost in plain zone or city or battleground) and search graveyard at same map
+ // then check faction
+ // if mapId != graveyard.mapId (ghost in instance) and search any graveyard associated
+ // then check faction
+ GraveYardMap::const_iterator graveLow = mGraveYardMap.lower_bound(zoneId);
+ GraveYardMap::const_iterator graveUp = mGraveYardMap.upper_bound(zoneId);
+ if(graveLow==graveUp)
+ {
+ sLog.outErrorDb("Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.",zoneId,team);
+ return NULL;
+ }
+
+ // at corpse map
+ bool foundNear = false;
+ float distNear;
+ WorldSafeLocsEntry const* entryNear = NULL;
+
+ // at entrance map for corpse map
+ bool foundEntr = false;
+ float distEntr;
+ WorldSafeLocsEntry const* entryEntr = NULL;
+
+ // some where other
+ WorldSafeLocsEntry const* entryFar = NULL;
+
+ MapEntry const* mapEntry = sMapStore.LookupEntry(MapId);
+
+ for(GraveYardMap::const_iterator itr = graveLow; itr != graveUp; ++itr)
+ {
+ GraveYardData const& data = itr->second;
+
+ WorldSafeLocsEntry const* entry = sWorldSafeLocsStore.LookupEntry(data.safeLocId);
+ if(!entry)
+ {
+ sLog.outErrorDb("Table `game_graveyard_zone` has record for not existing graveyard (WorldSafeLocs.dbc id) %u, skipped.",data.safeLocId);
+ continue;
+ }
+
+ // skip enemy faction graveyard
+ // team == 0 case can be at call from .neargrave
+ if(data.team != 0 && team != 0 && data.team != team)
+ continue;
+
+ // find now nearest graveyard at other map
+ if(MapId != entry->map_id)
+ {
+ // if find graveyard at different map from where entrance placed (or no entrance data), use any first
+ if (!mapEntry || mapEntry->entrance_map < 0 || mapEntry->entrance_map != entry->map_id ||
+ mapEntry->entrance_x == 0 && mapEntry->entrance_y == 0)
+ {
+ // not have any corrdinates for check distance anyway
+ entryFar = entry;
+ continue;
+ }
+
+ // at entrance map calculate distance (2D);
+ float dist2 = (entry->x - mapEntry->entrance_x)*(entry->x - mapEntry->entrance_x)
+ +(entry->y - mapEntry->entrance_y)*(entry->y - mapEntry->entrance_y);
+ if(foundEntr)
+ {
+ if(dist2 < distEntr)
+ {
+ distEntr = dist2;
+ entryEntr = entry;
+ }
+ }
+ else
+ {
+ foundEntr = true;
+ distEntr = dist2;
+ entryEntr = entry;
+ }
+ }
+ // find now nearest graveyard at same map
+ else
+ {
+ float dist2 = (entry->x - x)*(entry->x - x)+(entry->y - y)*(entry->y - y)+(entry->z - z)*(entry->z - z);
+ if(foundNear)
+ {
+ if(dist2 < distNear)
+ {
+ distNear = dist2;
+ entryNear = entry;
+ }
+ }
+ else
+ {
+ foundNear = true;
+ distNear = dist2;
+ entryNear = entry;
+ }
+ }
+ }
+
+ if(entryNear)
+ return entryNear;
+
+ if(entryEntr)
+ return entryEntr;
+
+ return entryFar;
+}
+
+GraveYardData const* ObjectMgr::FindGraveYardData(uint32 id, uint32 zoneId)
+{
+ GraveYardMap::const_iterator graveLow = mGraveYardMap.lower_bound(zoneId);
+ GraveYardMap::const_iterator graveUp = mGraveYardMap.upper_bound(zoneId);
+
+ for(GraveYardMap::const_iterator itr = graveLow; itr != graveUp; ++itr)
+ {
+ if(itr->second.safeLocId==id)
+ return &itr->second;
+ }
+
+ return NULL;
+}
+
+bool ObjectMgr::AddGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool inDB)
+{
+ if(FindGraveYardData(id,zoneId))
+ return false;
+
+ // add link to loaded data
+ GraveYardData data;
+ data.safeLocId = id;
+ data.team = team;
+
+ mGraveYardMap.insert(GraveYardMap::value_type(zoneId,data));
+
+ // add link to DB
+ if(inDB)
+ {
+ WorldDatabase.PExecuteLog("INSERT INTO game_graveyard_zone ( id,ghost_zone,faction) "
+ "VALUES ('%u', '%u','%u')",id,zoneId,team);
+ }
+
+ return true;
+}
+
+void ObjectMgr::RemoveGraveYardLink(uint32 id, uint32 zoneId, uint32 team, bool inDB)
+{
+ GraveYardMap::iterator graveLow = mGraveYardMap.lower_bound(zoneId);
+ GraveYardMap::iterator graveUp = mGraveYardMap.upper_bound(zoneId);
+ if(graveLow==graveUp)
+ {
+ //sLog.outErrorDb("Table `game_graveyard_zone` incomplete: Zone %u Team %u does not have a linked graveyard.",zoneId,team);
+ return;
+ }
+
+ bool found = false;
+
+ GraveYardMap::iterator itr;
+
+ for(itr = graveLow; itr != graveUp; ++itr)
+ {
+ GraveYardData & data = itr->second;
+
+ // skip not matching safezone id
+ if(data.safeLocId != id)
+ continue;
+
+ // skip enemy faction graveyard at same map (normal area, city, or battleground)
+ // team == 0 case can be at call from .neargrave
+ if(data.team != 0 && team != 0 && data.team != team)
+ continue;
+
+ found = true;
+ break;
+ }
+
+ // no match, return
+ if(!found)
+ return;
+
+ // remove from links
+ mGraveYardMap.erase(itr);
+
+ // remove link from DB
+ if(inDB)
+ {
+ WorldDatabase.PExecute("DELETE FROM game_graveyard_zone WHERE id = '%u' AND ghost_zone = '%u' AND faction = '%u'",id,zoneId,team);
+ }
+
+ return;
+}
+
+
+void ObjectMgr::LoadAreaTriggerTeleports()
+{
+ mAreaTriggers.clear(); // need for reload case
+
+ uint32 count = 0;
+
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12
+ QueryResult *result = WorldDatabase.Query("SELECT id, required_level, required_item, required_item2, heroic_key, heroic_key2, required_quest_done, required_failed_text, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM areatrigger_teleport");
+ if( !result )
+ {
+
+ barGoLink bar( 1 );
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u area trigger teleport definitions", count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ Field *fields = result->Fetch();
+
+ bar.step();
+
+ ++count;
+
+ uint32 Trigger_ID = fields[0].GetUInt32();
+
+ AreaTrigger at;
+
+ at.requiredLevel = fields[1].GetUInt8();
+ at.requiredItem = fields[2].GetUInt32();
+ at.requiredItem2 = fields[3].GetUInt32();
+ at.heroicKey = fields[4].GetUInt32();
+ at.heroicKey2 = fields[5].GetUInt32();
+ at.requiredQuest = fields[6].GetUInt32();
+ at.requiredFailedText = fields[7].GetCppString();
+ at.target_mapId = fields[8].GetUInt32();
+ at.target_X = fields[9].GetFloat();
+ at.target_Y = fields[10].GetFloat();
+ at.target_Z = fields[11].GetFloat();
+ at.target_Orientation = fields[12].GetFloat();
+
+ AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
+ if(!atEntry)
+ {
+ sLog.outErrorDb("Area trigger (ID:%u) does not exist in `AreaTrigger.dbc`.",Trigger_ID);
+ continue;
+ }
+
+ if(at.requiredItem)
+ {
+ ItemPrototype const *pProto = GetItemPrototype(at.requiredItem);
+ if(!pProto)
+ {
+ sLog.outError("Key item %u does not exist for trigger %u, removing key requirement.", at.requiredItem, Trigger_ID);
+ at.requiredItem = 0;
+ }
+ }
+ if(at.requiredItem2)
+ {
+ ItemPrototype const *pProto = GetItemPrototype(at.requiredItem2);
+ if(!pProto)
+ {
+ sLog.outError("Second item %u not exist for trigger %u, remove key requirement.", at.requiredItem2, Trigger_ID);
+ at.requiredItem2 = 0;
+ }
+ }
+
+ if(at.heroicKey)
+ {
+ ItemPrototype const *pProto = GetItemPrototype(at.heroicKey);
+ if(!pProto)
+ {
+ sLog.outError("Heroic key item %u not exist for trigger %u, remove key requirement.", at.heroicKey, Trigger_ID);
+ at.heroicKey = 0;
+ }
+ }
+
+ if(at.heroicKey2)
+ {
+ ItemPrototype const *pProto = GetItemPrototype(at.heroicKey2);
+ if(!pProto)
+ {
+ sLog.outError("Heroic second key item %u not exist for trigger %u, remove key requirement.", at.heroicKey2, Trigger_ID);
+ at.heroicKey2 = 0;
+ }
+ }
+
+ if(at.requiredQuest)
+ {
+ if(!mQuestTemplates[at.requiredQuest])
+ {
+ sLog.outErrorDb("Required Quest %u not exist for trigger %u, remove quest done requirement.",at.requiredQuest,Trigger_ID);
+ at.requiredQuest = 0;
+ }
+ }
+
+ MapEntry const* mapEntry = sMapStore.LookupEntry(at.target_mapId);
+ if(!mapEntry)
+ {
+ sLog.outErrorDb("Area trigger (ID:%u) target map (ID: %u) does not exist in `Map.dbc`.",Trigger_ID,at.target_mapId);
+ continue;
+ }
+
+ if(at.target_X==0 && at.target_Y==0 && at.target_Z==0)
+ {
+ sLog.outErrorDb("Area trigger (ID:%u) target coordinates not provided.",Trigger_ID);
+ continue;
+ }
+
+ mAreaTriggers[Trigger_ID] = at;
+
+ } while( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u area trigger teleport definitions", count );
+}
+
+AreaTrigger const* ObjectMgr::GetGoBackTrigger(uint32 Map) const
+{
+ const MapEntry *mapEntry = sMapStore.LookupEntry(Map);
+ if(!mapEntry) return NULL;
+ for (AreaTriggerMap::const_iterator itr = mAreaTriggers.begin(); itr != mAreaTriggers.end(); itr++)
+ {
+ if(itr->second.target_mapId == mapEntry->entrance_map)
+ {
+ AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(itr->first);
+ if(atEntry && atEntry->mapid == Map)
+ return &itr->second;
+ }
+ }
+ return NULL;
+}
+
+void ObjectMgr::SetHighestGuids()
+{
+ QueryResult *result = CharacterDatabase.Query( "SELECT MAX(guid) FROM characters" );
+ if( result )
+ {
+ m_hiCharGuid = (*result)[0].GetUInt32()+1;
+ delete result;
+ }
+
+ result = WorldDatabase.Query( "SELECT MAX(guid) FROM creature" );
+ if( result )
+ {
+ m_hiCreatureGuid = (*result)[0].GetUInt32()+1;
+ delete result;
+ }
+
+ // pet guids are not saved to DB, set to 0 (pet guid != pet id)
+ m_hiPetGuid = 0;
+
+ result = CharacterDatabase.Query( "SELECT MAX(guid) FROM item_instance" );
+ if( result )
+ {
+ m_hiItemGuid = (*result)[0].GetUInt32()+1;
+ delete result;
+ }
+
+ // Cleanup other tables from not existed guids (>=m_hiItemGuid)
+ CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item >= '%u'", m_hiItemGuid);
+ CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid >= '%u'", m_hiItemGuid);
+ CharacterDatabase.PExecute("DELETE FROM auctionhouse WHERE itemguid >= '%u'", m_hiItemGuid);
+ CharacterDatabase.PExecute("DELETE FROM guild_bank_item WHERE item_guid >= '%u'", m_hiItemGuid);
+
+ result = WorldDatabase.Query("SELECT MAX(guid) FROM gameobject" );
+ if( result )
+ {
+ m_hiGoGuid = (*result)[0].GetUInt32()+1;
+ delete result;
+ }
+
+ result = CharacterDatabase.Query("SELECT MAX(id) FROM auctionhouse" );
+ if( result )
+ {
+ m_auctionid = (*result)[0].GetUInt32()+1;
+ delete result;
+ }
+
+ result = CharacterDatabase.Query( "SELECT MAX(id) FROM mail" );
+ if( result )
+ {
+ m_mailid = (*result)[0].GetUInt32()+1;
+ delete result;
+ }
+
+ result = CharacterDatabase.Query( "SELECT MAX(id) FROM item_text" );
+ if( result )
+ {
+ m_ItemTextId = (*result)[0].GetUInt32()+1;
+ delete result;
+ }
+
+ result = CharacterDatabase.Query( "SELECT MAX(guid) FROM corpse" );
+ if( result )
+ {
+ m_hiCorpseGuid = (*result)[0].GetUInt32()+1;
+ delete result;
+ }
+
+ result = CharacterDatabase.Query("SELECT MAX(arenateamid) FROM arena_team");
+ if (result)
+ {
+ m_arenaTeamId = (*result)[0].GetUInt32()+1;
+ delete result;
+ }
+
+ result = CharacterDatabase.Query( "SELECT MAX(guildid) FROM guild" );
+ if (result)
+ {
+ m_guildId = (*result)[0].GetUInt32()+1;
+ delete result;
+ }
+}
+
+uint32 ObjectMgr::GenerateArenaTeamId()
+{
+ if(m_arenaTeamId>=0xFFFFFFFE)
+ {
+ sLog.outError("Arena team ids overflow!! Can't continue, shutting down server. ");
+ World::StopNow(ERROR_EXIT_CODE);
+ }
+ return m_arenaTeamId++;
+}
+
+uint32 ObjectMgr::GenerateGuildId()
+{
+ if(m_guildId>=0xFFFFFFFE)
+ {
+ sLog.outError("Guild ids overflow!! Can't continue, shutting down server. ");
+ World::StopNow(ERROR_EXIT_CODE);
+ }
+ return m_guildId++;
+}
+
+uint32 ObjectMgr::GenerateAuctionID()
+{
+ if(m_auctionid>=0xFFFFFFFE)
+ {
+ sLog.outError("Auctions ids overflow!! Can't continue, shutting down server. ");
+ World::StopNow(ERROR_EXIT_CODE);
+ }
+ return m_auctionid++;
+}
+
+uint32 ObjectMgr::GenerateMailID()
+{
+ if(m_mailid>=0xFFFFFFFE)
+ {
+ sLog.outError("Mail ids overflow!! Can't continue, shutting down server. ");
+ World::StopNow(ERROR_EXIT_CODE);
+ }
+ return m_mailid++;
+}
+
+uint32 ObjectMgr::GenerateItemTextID()
+{
+ if(m_ItemTextId>=0xFFFFFFFE)
+ {
+ sLog.outError("Item text ids overflow!! Can't continue, shutting down server. ");
+ World::StopNow(ERROR_EXIT_CODE);
+ }
+ return m_ItemTextId++;
+}
+
+uint32 ObjectMgr::CreateItemText(std::string text)
+{
+ uint32 newItemTextId = GenerateItemTextID();
+ //insert new itempage to container
+ mItemTexts[ newItemTextId ] = text;
+ //save new itempage
+ CharacterDatabase.escape_string(text);
+ //any Delete query needed, itemTextId is maximum of all ids
+ std::ostringstream query;
+ query << "INSERT INTO item_text (id,text) VALUES ( '" << newItemTextId << "', '" << text << "')";
+ CharacterDatabase.Execute(query.str().c_str()); //needs to be run this way, because mail body may be more than 1024 characters
+ return newItemTextId;
+}
+
+uint32 ObjectMgr::GenerateLowGuid(HighGuid guidhigh)
+{
+ switch(guidhigh)
+ {
+ case HIGHGUID_ITEM:
+ if(m_hiItemGuid>=0xFFFFFFFE)
+ {
+ sLog.outError("Item guid overflow!! Can't continue, shutting down server. ");
+ World::StopNow(ERROR_EXIT_CODE);
+ }
+ return m_hiItemGuid++;
+ case HIGHGUID_UNIT:
+ if(m_hiCreatureGuid>=0x00FFFFFE)
+ {
+ sLog.outError("Creature guid overflow!! Can't continue, shutting down server. ");
+ World::StopNow(ERROR_EXIT_CODE);
+ }
+ return m_hiCreatureGuid++;
+ case HIGHGUID_PET:
+ if(m_hiPetGuid>=0x00FFFFFE)
+ {
+ sLog.outError("Pet guid overflow!! Can't continue, shutting down server. ");
+ World::StopNow(ERROR_EXIT_CODE);
+ }
+ return m_hiPetGuid++;
+ case HIGHGUID_PLAYER:
+ if(m_hiCharGuid>=0xFFFFFFFE)
+ {
+ sLog.outError("Players guid overflow!! Can't continue, shutting down server. ");
+ World::StopNow(ERROR_EXIT_CODE);
+ }
+ return m_hiCharGuid++;
+ case HIGHGUID_GAMEOBJECT:
+ if(m_hiGoGuid>=0x00FFFFFE)
+ {
+ sLog.outError("Gameobject guid overflow!! Can't continue, shutting down server. ");
+ World::StopNow(ERROR_EXIT_CODE);
+ }
+ return m_hiGoGuid++;
+ case HIGHGUID_CORPSE:
+ if(m_hiCorpseGuid>=0xFFFFFFFE)
+ {
+ sLog.outError("Corpse guid overflow!! Can't continue, shutting down server. ");
+ World::StopNow(ERROR_EXIT_CODE);
+ }
+ return m_hiCorpseGuid++;
+ case HIGHGUID_DYNAMICOBJECT:
+ if(m_hiDoGuid>=0xFFFFFFFE)
+ {
+ sLog.outError("DynamicObject guid overflow!! Can't continue, shutting down server. ");
+ World::StopNow(ERROR_EXIT_CODE);
+ }
+ return m_hiDoGuid++;
+ default:
+ ASSERT(0);
+ }
+
+ ASSERT(0);
+ return 0;
+}
+
+void ObjectMgr::LoadGameObjectLocales()
+{
+ mGameObjectLocaleMap.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query("SELECT entry,"
+ "name_loc1,name_loc2,name_loc3,name_loc4,name_loc5,name_loc6,name_loc7,name_loc8,"
+ "castbarcaption_loc1,castbarcaption_loc2,castbarcaption_loc3,castbarcaption_loc4,"
+ "castbarcaption_loc5,castbarcaption_loc6,castbarcaption_loc7,castbarcaption_loc8 FROM locales_gameobject");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString("");
+ sLog.outString(">> Loaded 0 gameobject locale strings. DB table `locales_gameobject` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 entry = fields[0].GetUInt32();
+
+ GameObjectLocale& data = mGameObjectLocaleMap[entry];
+
+ for(int i = 1; i < MAX_LOCALE; ++i)
+ {
+ std::string str = fields[i].GetCppString();
+ if(!str.empty())
+ {
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.Name.size() <= idx)
+ data.Name.resize(idx+1);
+
+ data.Name[idx] = str;
+ }
+ }
+ }
+
+ for(int i = MAX_LOCALE; i < MAX_LOCALE*2-1; ++i)
+ {
+ std::string str = fields[i].GetCppString();
+ if(!str.empty())
+ {
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.CastBarCaption.size() <= idx)
+ data.CastBarCaption.resize(idx+1);
+
+ data.CastBarCaption[idx] = str;
+ }
+ }
+ }
+
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u gameobject locale strings", mGameObjectLocaleMap.size() );
+}
+
+struct SQLGameObjectLoader : public SQLStorageLoaderBase<SQLGameObjectLoader>
+{
+ template<class D>
+ void convert_from_str(uint32 field_pos, char *src, D &dst)
+ {
+ dst = D(objmgr.GetScriptId(src));
+ }
+};
+
+void ObjectMgr::LoadGameobjectInfo()
+{
+ SQLGameObjectLoader loader;
+ loader.Load(sGOStorage);
+
+ // some checks
+ for(uint32 id = 1; id < sGOStorage.MaxEntry; id++)
+ {
+ GameObjectInfo const* goInfo = sGOStorage.LookupEntry<GameObjectInfo>(id);
+ if(!goInfo)
+ continue;
+
+ switch(goInfo->type)
+ {
+ case GAMEOBJECT_TYPE_DOOR: //0
+ {
+ if(goInfo->door.lockId)
+ {
+ if(!sLockStore.LookupEntry(goInfo->door.lockId))
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but lock (Id: %u) not found.",
+ id,goInfo->type,goInfo->door.lockId,goInfo->door.lockId);
+ }
+ break;
+ }
+ case GAMEOBJECT_TYPE_BUTTON: //1
+ {
+ if(goInfo->button.lockId)
+ {
+ if(!sLockStore.LookupEntry(goInfo->button.lockId))
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but lock (Id: %u) not found.",
+ id,goInfo->type,goInfo->button.lockId,goInfo->button.lockId);
+ }
+ break;
+ }
+ case GAMEOBJECT_TYPE_CHEST: //3
+ {
+ if(goInfo->chest.lockId)
+ {
+ if(!sLockStore.LookupEntry(goInfo->chest.lockId))
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but lock (Id: %u) not found.",
+ id,goInfo->type,goInfo->chest.lockId,goInfo->chest.lockId);
+ }
+ if(goInfo->chest.linkedTrapId) // linked trap
+ {
+ if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->chest.linkedTrapId))
+ {
+ if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
+ id,goInfo->type,goInfo->chest.linkedTrapId,goInfo->chest.linkedTrapId,GAMEOBJECT_TYPE_TRAP);
+ }
+ /* disable check for while
+ else
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
+ id,goInfo->type,goInfo->chest.linkedTrapId,goInfo->chest.linkedTrapId);
+ */
+ }
+ break;
+ }
+ case GAMEOBJECT_TYPE_TRAP: //6
+ {
+ /* disable check for while
+ if(goInfo->trap.spellId) // spell
+ {
+ if(!sSpellStore.LookupEntry(goInfo->trap.spellId))
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data3=%u but Spell (Entry %u) not exist.",
+ id,goInfo->type,goInfo->trap.spellId,goInfo->trap.spellId);
+ }
+ */
+ break;
+ }
+ case GAMEOBJECT_TYPE_CHAIR: //7
+ if(goInfo->chair.height > 2)
+ {
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but correct chair height in range 0..2.",
+ id,goInfo->type,goInfo->chair.height);
+
+ // prevent client and server unexpected work
+ const_cast<GameObjectInfo*>(goInfo)->chair.height = 0;
+ }
+ break;
+ case GAMEOBJECT_TYPE_SPELL_FOCUS: //8
+ {
+ if(goInfo->spellFocus.focusId)
+ {
+ if(!sSpellFocusObjectStore.LookupEntry(goInfo->spellFocus.focusId))
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but SpellFocus (Id: %u) not exist.",
+ id,goInfo->type,goInfo->spellFocus.focusId,goInfo->spellFocus.focusId);
+ }
+
+ if(goInfo->spellFocus.linkedTrapId) // linked trap
+ {
+ if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->spellFocus.linkedTrapId))
+ {
+ if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
+ id,goInfo->type,goInfo->spellFocus.linkedTrapId,goInfo->spellFocus.linkedTrapId,GAMEOBJECT_TYPE_TRAP);
+ }
+ /* disable check for while
+ else
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
+ id,goInfo->type,goInfo->spellFocus.linkedTrapId,goInfo->spellFocus.linkedTrapId);
+ */
+ }
+ break;
+ }
+ case GAMEOBJECT_TYPE_GOOBER: //10
+ {
+ if(goInfo->goober.pageId) // pageId
+ {
+ if(!sPageTextStore.LookupEntry<PageText>(goInfo->goober.pageId))
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data7=%u but PageText (Entry %u) not exist.",
+ id,goInfo->type,goInfo->goober.pageId,goInfo->goober.pageId);
+ }
+ /* disable check for while
+ if(goInfo->goober.spellId) // spell
+ {
+ if(!sSpellStore.LookupEntry(goInfo->goober.spellId))
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data2=%u but Spell (Entry %u) not exist.",
+ id,goInfo->type,goInfo->goober.spellId,goInfo->goober.spellId);
+ }
+ */
+ if(goInfo->goober.linkedTrapId) // linked trap
+ {
+ if(GameObjectInfo const* trapInfo = sGOStorage.LookupEntry<GameObjectInfo>(goInfo->goober.linkedTrapId))
+ {
+ if(trapInfo->type!=GAMEOBJECT_TYPE_TRAP)
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data12=%u but GO (Entry %u) have not GAMEOBJECT_TYPE_TRAP (%u) type.",
+ id,goInfo->type,goInfo->goober.linkedTrapId,goInfo->goober.linkedTrapId,GAMEOBJECT_TYPE_TRAP);
+ }
+ /* disable check for while
+ else
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data12=%u but trap GO (Entry %u) not exist in `gameobject_template`.",
+ id,goInfo->type,goInfo->goober.linkedTrapId,goInfo->goober.linkedTrapId);
+ */
+ }
+ break;
+ }
+ case GAMEOBJECT_TYPE_MO_TRANSPORT: //15
+ {
+ if(goInfo->moTransport.taxiPathId)
+ {
+ if(goInfo->moTransport.taxiPathId >= sTaxiPathNodesByPath.size() || sTaxiPathNodesByPath[goInfo->moTransport.taxiPathId].empty())
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data0=%u but TaxiPath (Id: %u) not exist.",
+ id,goInfo->type,goInfo->moTransport.taxiPathId,goInfo->moTransport.taxiPathId);
+ }
+ break;
+ }
+ case GAMEOBJECT_TYPE_SUMMONING_RITUAL: //18
+ {
+ /* disabled
+ if(goInfo->summoningRitual.spellId)
+ {
+ if(!sSpellStore.LookupEntry(goInfo->summoningRitual.spellId))
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data1=%u but Spell (Entry %u) not exist.",
+ id,goInfo->type,goInfo->summoningRitual.spellId,goInfo->summoningRitual.spellId);
+ }
+ */
+ break;
+ }
+ case GAMEOBJECT_TYPE_SPELLCASTER: //22
+ {
+ if(goInfo->spellcaster.spellId) // spell
+ {
+ if(!sSpellStore.LookupEntry(goInfo->spellcaster.spellId))
+ sLog.outErrorDb("Gameobject (Entry: %u GoType: %u) have data3=%u but Spell (Entry %u) not exist.",
+ id,goInfo->type,goInfo->spellcaster.spellId,goInfo->spellcaster.spellId);
+ }
+ break;
+ }
+ }
+ }
+
+ sLog.outString( ">> Loaded %u game object templates", sGOStorage.RecordCount );
+ sLog.outString();
+}
+
+void ObjectMgr::LoadExplorationBaseXP()
+{
+ uint32 count = 0;
+ QueryResult *result = WorldDatabase.Query("SELECT level,basexp FROM exploration_basexp");
+
+ if( !result )
+ {
+ barGoLink bar( 1 );
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u BaseXP definitions", count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ bar.step();
+
+ Field *fields = result->Fetch();
+ uint32 level = fields[0].GetUInt32();
+ uint32 basexp = fields[1].GetUInt32();
+ mBaseXPTable[level] = basexp;
+ ++count;
+ }
+ while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u BaseXP definitions", count );
+}
+
+uint32 ObjectMgr::GetBaseXP(uint32 level)
+{
+ return mBaseXPTable[level] ? mBaseXPTable[level] : 0;
+}
+
+void ObjectMgr::LoadPetNames()
+{
+ uint32 count = 0;
+ QueryResult *result = WorldDatabase.Query("SELECT word,entry,half FROM pet_name_generation");
+
+ if( !result )
+ {
+ barGoLink bar( 1 );
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u pet name parts", count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ bar.step();
+
+ Field *fields = result->Fetch();
+ std::string word = fields[0].GetString();
+ uint32 entry = fields[1].GetUInt32();
+ bool half = fields[2].GetBool();
+ if(half)
+ PetHalfName1[entry].push_back(word);
+ else
+ PetHalfName0[entry].push_back(word);
+ ++count;
+ }
+ while (result->NextRow());
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u pet name parts", count );
+}
+
+void ObjectMgr::LoadPetNumber()
+{
+ QueryResult* result = CharacterDatabase.Query("SELECT MAX(id) FROM character_pet");
+ if(result)
+ {
+ Field *fields = result->Fetch();
+ m_hiPetNumber = fields[0].GetUInt32()+1;
+ delete result;
+ }
+
+ barGoLink bar( 1 );
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded the max pet number: %d", m_hiPetNumber-1);
+}
+
+std::string ObjectMgr::GeneratePetName(uint32 entry)
+{
+ std::vector<std::string> & list0 = PetHalfName0[entry];
+ std::vector<std::string> & list1 = PetHalfName1[entry];
+
+ if(list0.empty() || list1.empty())
+ {
+ CreatureInfo const *cinfo = GetCreatureTemplate(entry);
+ char* petname = GetPetName(cinfo->family, sWorld.GetDefaultDbcLocale());
+ if(!petname)
+ petname = cinfo->Name;
+ return std::string(petname);
+ }
+
+ return *(list0.begin()+urand(0, list0.size()-1)) + *(list1.begin()+urand(0, list1.size()-1));
+}
+
+uint32 ObjectMgr::GeneratePetNumber()
+{
+ return ++m_hiPetNumber;
+}
+
+void ObjectMgr::LoadCorpses()
+{
+ uint32 count = 0;
+ // 0 1 2 3 4 5 6 7 8 10
+ QueryResult *result = CharacterDatabase.Query("SELECT position_x, position_y, position_z, orientation, map, data, time, corpse_type, instance, guid FROM corpse WHERE corpse_type <> 0");
+
+ if( !result )
+ {
+ barGoLink bar( 1 );
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u corpses", count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ bar.step();
+
+ Field *fields = result->Fetch();
+
+ uint32 guid = fields[result->GetFieldCount()-1].GetUInt32();
+
+ Corpse *corpse = new Corpse;
+ if(!corpse->LoadFromDB(guid,fields))
+ {
+ delete corpse;
+ continue;
+ }
+
+ ObjectAccessor::Instance().AddCorpse(corpse);
+
+ ++count;
+ }
+ while (result->NextRow());
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u corpses", count );
+}
+
+void ObjectMgr::LoadReputationOnKill()
+{
+ uint32 count = 0;
+
+ // 0 1 2
+ QueryResult *result = WorldDatabase.Query("SELECT creature_id, RewOnKillRepFaction1, RewOnKillRepFaction2,"
+ // 3 4 5 6 7 8 9
+ "IsTeamAward1, MaxStanding1, RewOnKillRepValue1, IsTeamAward2, MaxStanding2, RewOnKillRepValue2, TeamDependent "
+ "FROM creature_onkill_reputation");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded 0 creature award reputation definitions. DB table `creature_onkill_reputation` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 creature_id = fields[0].GetUInt32();
+
+ ReputationOnKillEntry repOnKill;
+ repOnKill.repfaction1 = fields[1].GetUInt32();
+ repOnKill.repfaction2 = fields[2].GetUInt32();
+ repOnKill.is_teamaward1 = fields[3].GetBool();
+ repOnKill.reputation_max_cap1 = fields[4].GetUInt32();
+ repOnKill.repvalue1 = fields[5].GetInt32();
+ repOnKill.is_teamaward2 = fields[6].GetBool();
+ repOnKill.reputation_max_cap2 = fields[7].GetUInt32();
+ repOnKill.repvalue2 = fields[8].GetInt32();
+ repOnKill.team_dependent = fields[9].GetUInt8();
+
+ if(!GetCreatureTemplate(creature_id))
+ {
+ sLog.outErrorDb("Table `creature_onkill_reputation` have data for not existed creature entry (%u), skipped",creature_id);
+ continue;
+ }
+
+ if(repOnKill.repfaction1)
+ {
+ FactionEntry const *factionEntry1 = sFactionStore.LookupEntry(repOnKill.repfaction1);
+ if(!factionEntry1)
+ {
+ sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `creature_onkill_reputation`",repOnKill.repfaction1);
+ continue;
+ }
+ }
+
+ if(repOnKill.repfaction2)
+ {
+ FactionEntry const *factionEntry2 = sFactionStore.LookupEntry(repOnKill.repfaction2);
+ if(!factionEntry2)
+ {
+ sLog.outErrorDb("Faction (faction.dbc) %u does not exist but is used in `creature_onkill_reputation`",repOnKill.repfaction2);
+ continue;
+ }
+ }
+
+ mRepOnKill[creature_id] = repOnKill;
+
+ ++count;
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u creature award reputation definitions", count);
+}
+
+void ObjectMgr::LoadWeatherZoneChances()
+{
+ uint32 count = 0;
+
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12
+ QueryResult *result = WorldDatabase.Query("SELECT zone, spring_rain_chance, spring_snow_chance, spring_storm_chance, summer_rain_chance, summer_snow_chance, summer_storm_chance, fall_rain_chance, fall_snow_chance, fall_storm_chance, winter_rain_chance, winter_snow_chance, winter_storm_chance FROM game_weather");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded 0 weather definitions. DB table `game_weather` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 zone_id = fields[0].GetUInt32();
+
+ WeatherZoneChances& wzc = mWeatherZoneMap[zone_id];
+
+ for(int season = 0; season < WEATHER_SEASONS; ++season)
+ {
+ wzc.data[season].rainChance = fields[season * (MAX_WEATHER_TYPE-1) + 1].GetUInt32();
+ wzc.data[season].snowChance = fields[season * (MAX_WEATHER_TYPE-1) + 2].GetUInt32();
+ wzc.data[season].stormChance = fields[season * (MAX_WEATHER_TYPE-1) + 3].GetUInt32();
+
+ if(wzc.data[season].rainChance > 100)
+ {
+ wzc.data[season].rainChance = 25;
+ sLog.outErrorDb("Weather for zone %u season %u has wrong rain chance > 100%",zone_id,season);
+ }
+
+ if(wzc.data[season].snowChance > 100)
+ {
+ wzc.data[season].snowChance = 25;
+ sLog.outErrorDb("Weather for zone %u season %u has wrong snow chance > 100%",zone_id,season);
+ }
+
+ if(wzc.data[season].stormChance > 100)
+ {
+ wzc.data[season].stormChance = 25;
+ sLog.outErrorDb("Weather for zone %u season %u has wrong storm chance > 100%",zone_id,season);
+ }
+ }
+
+ ++count;
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u weather definitions", count);
+}
+
+void ObjectMgr::SaveCreatureRespawnTime(uint32 loguid, uint32 instance, time_t t)
+{
+ mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)] = t;
+ WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE guid = '%u' AND instance = '%u'", loguid, instance);
+ if(t)
+ WorldDatabase.PExecute("INSERT INTO creature_respawn VALUES ( '%u', '" I64FMTD "', '%u' )", loguid, uint64(t), instance);
+}
+
+void ObjectMgr::DeleteCreatureData(uint32 guid)
+{
+ // remove mapid*cellid -> guid_set map
+ CreatureData const* data = GetCreatureData(guid);
+ if(data)
+ RemoveCreatureFromGrid(guid, data);
+
+ mCreatureDataMap.erase(guid);
+}
+
+void ObjectMgr::SaveGORespawnTime(uint32 loguid, uint32 instance, time_t t)
+{
+ mGORespawnTimes[MAKE_PAIR64(loguid,instance)] = t;
+ WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE guid = '%u' AND instance = '%u'", loguid, instance);
+ if(t)
+ WorldDatabase.PExecute("INSERT INTO gameobject_respawn VALUES ( '%u', '" I64FMTD "', '%u' )", loguid, uint64(t), instance);
+}
+
+void ObjectMgr::DeleteRespawnTimeForInstance(uint32 instance)
+{
+ RespawnTimes::iterator next;
+
+ for(RespawnTimes::iterator itr = mGORespawnTimes.begin(); itr != mGORespawnTimes.end(); itr = next)
+ {
+ next = itr;
+ ++next;
+
+ if(GUID_HIPART(itr->first)==instance)
+ mGORespawnTimes.erase(itr);
+ }
+
+ for(RespawnTimes::iterator itr = mCreatureRespawnTimes.begin(); itr != mCreatureRespawnTimes.end(); itr = next)
+ {
+ next = itr;
+ ++next;
+
+ if(GUID_HIPART(itr->first)==instance)
+ mCreatureRespawnTimes.erase(itr);
+ }
+
+ WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'", instance);
+ WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'", instance);
+}
+
+void ObjectMgr::DeleteGOData(uint32 guid)
+{
+ // remove mapid*cellid -> guid_set map
+ GameObjectData const* data = GetGOData(guid);
+ if(data)
+ RemoveGameobjectFromGrid(guid, data);
+
+ mGameObjectDataMap.erase(guid);
+}
+
+void ObjectMgr::AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance)
+{
+ // corpses are always added to spawn mode 0 and they are spawned by their instance id
+ CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(mapid,0)][cellid];
+ cell_guids.corpses[player_guid] = instance;
+}
+
+void ObjectMgr::DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid)
+{
+ // corpses are always added to spawn mode 0 and they are spawned by their instance id
+ CellObjectGuids& cell_guids = mMapObjectGuids[MAKE_PAIR32(mapid,0)][cellid];
+ cell_guids.corpses.erase(player_guid);
+}
+
+void ObjectMgr::LoadQuestRelationsHelper(QuestRelations& map,char const* table)
+{
+ map.clear(); // need for reload case
+
+ uint32 count = 0;
+
+ QueryResult *result = WorldDatabase.PQuery("SELECT id,quest FROM %s",table);
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded 0 quest relations from %s. DB table `%s` is empty.",table,table);
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 id = fields[0].GetUInt32();
+ uint32 quest = fields[1].GetUInt32();
+
+ if(mQuestTemplates.find(quest) == mQuestTemplates.end())
+ {
+ sLog.outErrorDb("Table `%s: Quest %u listed for entry %u does not exist.",table,quest,id);
+ continue;
+ }
+
+ map.insert(QuestRelations::value_type(id,quest));
+
+ ++count;
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString(">> Loaded %u quest relations from %s", count,table);
+}
+
+void ObjectMgr::LoadGameobjectQuestRelations()
+{
+ LoadQuestRelationsHelper(mGOQuestRelations,"gameobject_questrelation");
+
+ for(QuestRelations::iterator itr = mGOQuestRelations.begin(); itr != mGOQuestRelations.end(); ++itr)
+ {
+ GameObjectInfo const* goInfo = GetGameObjectInfo(itr->first);
+ if(!goInfo)
+ sLog.outErrorDb("Table `gameobject_questrelation` have data for not existed gameobject entry (%u) and existed quest %u",itr->first,itr->second);
+ else if(goInfo->type != GAMEOBJECT_TYPE_QUESTGIVER)
+ sLog.outErrorDb("Table `gameobject_questrelation` have data gameobject entry (%u) for quest %u, but GO is not GAMEOBJECT_TYPE_QUESTGIVER",itr->first,itr->second);
+ }
+}
+
+void ObjectMgr::LoadGameobjectInvolvedRelations()
+{
+ LoadQuestRelationsHelper(mGOQuestInvolvedRelations,"gameobject_involvedrelation");
+
+ for(QuestRelations::iterator itr = mGOQuestInvolvedRelations.begin(); itr != mGOQuestInvolvedRelations.end(); ++itr)
+ {
+ GameObjectInfo const* goInfo = GetGameObjectInfo(itr->first);
+ if(!goInfo)
+ sLog.outErrorDb("Table `gameobject_involvedrelation` have data for not existed gameobject entry (%u) and existed quest %u",itr->first,itr->second);
+ else if(goInfo->type != GAMEOBJECT_TYPE_QUESTGIVER)
+ sLog.outErrorDb("Table `gameobject_involvedrelation` have data gameobject entry (%u) for quest %u, but GO is not GAMEOBJECT_TYPE_QUESTGIVER",itr->first,itr->second);
+ }
+}
+
+void ObjectMgr::LoadCreatureQuestRelations()
+{
+ LoadQuestRelationsHelper(mCreatureQuestRelations,"creature_questrelation");
+
+ for(QuestRelations::iterator itr = mCreatureQuestRelations.begin(); itr != mCreatureQuestRelations.end(); ++itr)
+ {
+ CreatureInfo const* cInfo = GetCreatureTemplate(itr->first);
+ if(!cInfo)
+ sLog.outErrorDb("Table `creature_questrelation` have data for not existed creature entry (%u) and existed quest %u",itr->first,itr->second);
+ else if(!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER))
+ sLog.outErrorDb("Table `creature_questrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER",itr->first,itr->second);
+ }
+}
+
+void ObjectMgr::LoadCreatureInvolvedRelations()
+{
+ LoadQuestRelationsHelper(mCreatureQuestInvolvedRelations,"creature_involvedrelation");
+
+ for(QuestRelations::iterator itr = mCreatureQuestInvolvedRelations.begin(); itr != mCreatureQuestInvolvedRelations.end(); ++itr)
+ {
+ CreatureInfo const* cInfo = GetCreatureTemplate(itr->first);
+ if(!cInfo)
+ sLog.outErrorDb("Table `creature_involvedrelation` have data for not existed creature entry (%u) and existed quest %u",itr->first,itr->second);
+ else if(!(cInfo->npcflag & UNIT_NPC_FLAG_QUESTGIVER))
+ sLog.outErrorDb("Table `creature_involvedrelation` has creature entry (%u) for quest %u, but npcflag does not include UNIT_NPC_FLAG_QUESTGIVER",itr->first,itr->second);
+ }
+}
+
+void ObjectMgr::LoadReservedPlayersNames()
+{
+ m_ReservedNames.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query("SELECT name FROM reserved_name");
+
+ uint32 count = 0;
+
+ if( !result )
+ {
+ barGoLink bar( 1 );
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u reserved player names", count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ Field* fields;
+ do
+ {
+ bar.step();
+ fields = result->Fetch();
+ std::string name= fields[0].GetCppString();
+ if(normalizePlayerName(name))
+ {
+ m_ReservedNames.insert(name);
+ ++count;
+ }
+ } while ( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u reserved player names", count );
+}
+
+enum LanguageType
+{
+ LT_BASIC_LATIN = 0x0000,
+ LT_EXTENDEN_LATIN = 0x0001,
+ LT_CYRILLIC = 0x0002,
+ LT_EAST_ASIA = 0x0004,
+ LT_ANY = 0xFFFF
+};
+
+static LanguageType GetRealmLanguageType(bool create)
+{
+ switch(sWorld.getConfig(CONFIG_REALM_ZONE))
+ {
+ case REALM_ZONE_UNKNOWN: // any language
+ case REALM_ZONE_DEVELOPMENT:
+ case REALM_ZONE_TEST_SERVER:
+ case REALM_ZONE_QA_SERVER:
+ return LT_ANY;
+ case REALM_ZONE_UNITED_STATES: // extended-Latin
+ case REALM_ZONE_OCEANIC:
+ case REALM_ZONE_LATIN_AMERICA:
+ case REALM_ZONE_ENGLISH:
+ case REALM_ZONE_GERMAN:
+ case REALM_ZONE_FRENCH:
+ case REALM_ZONE_SPANISH:
+ return LT_EXTENDEN_LATIN;
+ case REALM_ZONE_KOREA: // East-Asian
+ case REALM_ZONE_TAIWAN:
+ case REALM_ZONE_CHINA:
+ return LT_EAST_ASIA;
+ case REALM_ZONE_RUSSIAN: // Cyrillic
+ return LT_CYRILLIC;
+ default:
+ return create ? LT_BASIC_LATIN : LT_ANY; // basic-Latin at create, any at login
+ }
+}
+
+bool isValidString(std::wstring wstr, uint32 strictMask, bool numericOrSpace, bool create = false)
+{
+ if(strictMask==0) // any language, ignore realm
+ {
+ if(isExtendedLatinString(wstr,numericOrSpace))
+ return true;
+ if(isCyrillicString(wstr,numericOrSpace))
+ return true;
+ if(isEastAsianString(wstr,numericOrSpace))
+ return true;
+ return false;
+ }
+
+ if(strictMask & 0x2) // realm zone specific
+ {
+ LanguageType lt = GetRealmLanguageType(create);
+ if(lt & LT_EXTENDEN_LATIN)
+ if(isExtendedLatinString(wstr,numericOrSpace))
+ return true;
+ if(lt & LT_CYRILLIC)
+ if(isCyrillicString(wstr,numericOrSpace))
+ return true;
+ if(lt & LT_EAST_ASIA)
+ if(isEastAsianString(wstr,numericOrSpace))
+ return true;
+ }
+
+ if(strictMask & 0x1) // basic Latin
+ {
+ if(isBasicLatinString(wstr,numericOrSpace))
+ return true;
+ }
+
+ return false;
+}
+
+bool ObjectMgr::IsValidName( std::string name, bool create )
+{
+ std::wstring wname;
+ if(!Utf8toWStr(name,wname))
+ return false;
+
+ if(wname.size() < 1 || wname.size() > MAX_PLAYER_NAME)
+ return false;
+
+ uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PLAYER_NAMES);
+
+ return isValidString(wname,strictMask,false,create);
+}
+
+bool ObjectMgr::IsValidCharterName( std::string name )
+{
+ std::wstring wname;
+ if(!Utf8toWStr(name,wname))
+ return false;
+
+ if(wname.size() < 1)
+ return false;
+
+ uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_CHARTER_NAMES);
+
+ return isValidString(wname,strictMask,true);
+}
+
+bool ObjectMgr::IsValidPetName( std::string name )
+{
+ std::wstring wname;
+ if(!Utf8toWStr(name,wname))
+ return false;
+
+ if(wname.size() < 1)
+ return false;
+
+ uint32 strictMask = sWorld.getConfig(CONFIG_STRICT_PET_NAMES);
+
+ return isValidString(wname,strictMask,false);
+}
+
+int ObjectMgr::GetIndexForLocale( LocaleConstant loc )
+{
+ if(loc==LOCALE_enUS)
+ return -1;
+
+ for(size_t i=0;i < m_LocalForIndex.size(); ++i)
+ if(m_LocalForIndex[i]==loc)
+ return i;
+
+ return -1;
+}
+
+LocaleConstant ObjectMgr::GetLocaleForIndex(int i)
+{
+ if (i<0 || i>=m_LocalForIndex.size())
+ return LOCALE_enUS;
+
+ return m_LocalForIndex[i];
+}
+
+int ObjectMgr::GetOrNewIndexForLocale( LocaleConstant loc )
+{
+ if(loc==LOCALE_enUS)
+ return -1;
+
+ for(size_t i=0;i < m_LocalForIndex.size(); ++i)
+ if(m_LocalForIndex[i]==loc)
+ return i;
+
+ m_LocalForIndex.push_back(loc);
+ return m_LocalForIndex.size()-1;
+}
+
+void ObjectMgr::LoadBattleMastersEntry()
+{
+ mBattleMastersMap.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query( "SELECT entry,bg_template FROM battlemaster_entry" );
+
+ uint32 count = 0;
+
+ if( !result )
+ {
+ barGoLink bar( 1 );
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded 0 battlemaster entries - table is empty!" );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ ++count;
+ bar.step();
+
+ Field *fields = result->Fetch();
+
+ uint32 entry = fields[0].GetUInt32();
+ uint32 bgTypeId = fields[1].GetUInt32();
+
+ mBattleMastersMap[entry] = bgTypeId;
+
+ } while( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u battlemaster entries", count );
+}
+
+void ObjectMgr::LoadGameObjectForQuests()
+{
+ mGameObjectForQuestSet.clear(); // need for reload case
+
+ uint32 count = 0;
+
+ // collect GO entries for GO that must activated
+ for(uint32 go_entry = 1; go_entry < sGOStorage.MaxEntry; ++go_entry)
+ {
+ GameObjectInfo const* goInfo = sGOStorage.LookupEntry<GameObjectInfo>(go_entry);
+ if(!goInfo)
+ continue;
+
+ switch(goInfo->type)
+ {
+ // scan GO chest with loot including quest items
+ case GAMEOBJECT_TYPE_CHEST:
+ {
+ uint32 loot_id = GameObject::GetLootId(goInfo);
+
+ // find quest loot for GO
+ if(LootTemplates_Gameobject.HaveQuestLootFor(loot_id))
+ {
+ mGameObjectForQuestSet.insert(go_entry);
+ ++count;
+ }
+ break;
+ }
+ case GAMEOBJECT_TYPE_GOOBER:
+ {
+ if(goInfo->goober.questId) //quests objects
+ {
+ mGameObjectForQuestSet.insert(go_entry);
+ count++;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u GameObject for quests", count );
+}
+
+bool ObjectMgr::LoadTrinityStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value)
+{
+ // cleanup affected map part for reloading case
+ for(TrinityStringLocaleMap::iterator itr = mTrinityStringLocaleMap.begin(); itr != mTrinityStringLocaleMap.end();)
+ {
+ if(itr->first >= min_value && itr->first <= max_value)
+ {
+ TrinityStringLocaleMap::iterator itr2 = itr;
+ ++itr;
+ mTrinityStringLocaleMap.erase(itr2);
+ }
+ else
+ ++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);
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString("");
+ if(min_value == MIN_TRINITY_STRING_ID) // error only in case internal strings
+ sLog.outErrorDb(">> Loaded 0 trinity strings. DB table `%s` is empty. Cannot continue.",table);
+ else
+ sLog.outString(">> Loaded 0 string templates. DB table `%s` is empty.",table);
+ return false;
+ }
+
+ uint32 count = 0;
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ int32 entry = fields[0].GetInt32();
+
+ if(entry==0)
+ {
+ sLog.outErrorDb("Table `%s` contain reserved entry 0, ignored.",table);
+ continue;
+ }
+ else if(entry < min_value || entry > max_value)
+ {
+ int32 start = min_value > 0 ? min_value : max_value;
+ int32 end = min_value > 0 ? max_value : min_value;
+ sLog.outErrorDb("Table `%s` contain entry %i out of allowed range (%d - %d), ignored.",table,entry,start,end);
+ continue;
+ }
+
+ TrinityStringLocale& data = mTrinityStringLocaleMap[entry];
+
+ if(data.Content.size() > 0)
+ {
+ sLog.outErrorDb("Table `%s` contain data for already loaded entry %i (from another table?), ignored.",table,entry);
+ continue;
+ }
+
+ data.Content.resize(1);
+ ++count;
+
+ // 0 -> default, idx in to idx+1
+ data.Content[0] = fields[1].GetCppString();
+
+ for(int i = 1; i < MAX_LOCALE; ++i)
+ {
+ std::string str = fields[i+1].GetCppString();
+ if(!str.empty())
+ {
+ int idx = GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ // 0 -> default, idx in to idx+1
+ if(data.Content.size() <= idx+1)
+ data.Content.resize(idx+2);
+
+ data.Content[idx+1] = str;
+ }
+ }
+ }
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ if(min_value == MIN_TRINITY_STRING_ID) // internal Trinity strings
+ sLog.outString( ">> Loaded %u Trinity strings from table %s", count,table);
+ else
+ sLog.outString( ">> Loaded %u string templates from %s", count,table);
+
+ return true;
+}
+
+const char *ObjectMgr::GetTrinityString(int32 entry, int locale_idx) const
+{
+ // locale_idx==-1 -> default, locale_idx >= 0 in to idx+1
+ // Content[0] always exist if exist TrinityStringLocale
+ if(TrinityStringLocale const *msl = GetTrinityStringLocale(entry))
+ {
+ if(msl->Content.size() > locale_idx+1 && !msl->Content[locale_idx+1].empty())
+ return msl->Content[locale_idx+1].c_str();
+ else
+ return msl->Content[0].c_str();
+ }
+
+ if(entry > 0)
+ sLog.outErrorDb("Entry %i not found in `trinity_string` table.",entry);
+ else
+ sLog.outErrorDb("Trinity string entry %i not found in DB.",entry);
+ return "<error>";
+}
+
+void ObjectMgr::LoadSpellDisabledEntrys()
+{
+ m_DisabledPlayerSpells.clear(); // need for reload case
+ m_DisabledCreatureSpells.clear();
+ QueryResult *result = WorldDatabase.Query("SELECT entry, disable_mask FROM spell_disabled");
+
+ uint32 total_count = 0;
+
+ if( !result )
+ {
+ barGoLink bar( 1 );
+ bar.step();
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u disabled spells", total_count );
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ Field* fields;
+ do
+ {
+ bar.step();
+ fields = result->Fetch();
+ uint32 spellid = fields[0].GetUInt32();
+ if(!sSpellStore.LookupEntry(spellid))
+ {
+ sLog.outErrorDb("Spell entry %u from `spell_disabled` doesn't exist in dbc, ignoring.",spellid);
+ continue;
+ }
+ uint32 disable_mask = fields[1].GetUInt32();
+ if(disable_mask & SPELL_DISABLE_PLAYER)
+ m_DisabledPlayerSpells.insert(spellid);
+ if(disable_mask & SPELL_DISABLE_CREATURE)
+ m_DisabledCreatureSpells.insert(spellid);
+ ++total_count;
+ } while ( result->NextRow() );
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u disabled spells from `spell_disabled`", total_count);
+}
+
+void ObjectMgr::LoadFishingBaseSkillLevel()
+{
+ mFishingBaseForArea.clear(); // for reload case
+
+ uint32 count = 0;
+ QueryResult *result = WorldDatabase.Query("SELECT entry,skill FROM skill_fishing_base_level");
+
+ if( !result )
+ {
+ barGoLink bar( 1 );
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded `skill_fishing_base_level`, table is empty!");
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ bar.step();
+
+ Field *fields = result->Fetch();
+ uint32 entry = fields[0].GetUInt32();
+ int32 skill = fields[1].GetInt32();
+
+ AreaTableEntry const* fArea = GetAreaEntryByAreaID(entry);
+ if(!fArea)
+ {
+ sLog.outErrorDb("AreaId %u defined in `skill_fishing_base_level` does not exist",entry);
+ continue;
+ }
+
+ mFishingBaseForArea[entry] = skill;
+ ++count;
+ }
+ while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u areas for fishing base skill level", count );
+}
+
+// Searches for the same condition already in Conditions store
+// Returns Id if found, else adds it to Conditions and returns Id
+uint16 ObjectMgr::GetConditionId( ConditionType condition, uint32 value1, uint32 value2 )
+{
+ PlayerCondition lc = PlayerCondition(condition, value1, value2);
+ for (uint16 i=0; i < mConditions.size(); ++i)
+ {
+ if (lc == mConditions[i])
+ return i;
+ }
+
+ mConditions.push_back(lc);
+
+ if(mConditions.size() > 0xFFFF)
+ {
+ sLog.outError("Conditions store overflow! Current and later loaded conditions will ignored!");
+ return 0;
+ }
+
+ return mConditions.size() - 1;
+}
+
+bool ObjectMgr::CheckDeclinedNames( std::wstring mainpart, DeclinedName const& names )
+{
+ for(int i =0; i < MAX_DECLINED_NAME_CASES; ++i)
+ {
+ std::wstring wname;
+ if(!Utf8toWStr(names.name[i],wname))
+ return false;
+
+ if(mainpart!=GetMainPartOfName(wname,i+1))
+ return false;
+ }
+ return true;
+}
+
+uint32 ObjectMgr::GetAreaTriggerScriptId(uint32 trigger_id)
+{
+ AreaTriggerScriptMap::const_iterator i = mAreaTriggerScripts.find(trigger_id);
+ if(i!= mAreaTriggerScripts.end())
+ return i->second;
+ return 0;
+}
+
+// Checks if player meets the condition
+bool PlayerCondition::Meets(Player const * player) const
+{
+ if( !player )
+ return false; // player not present, return false
+
+ switch (condition)
+ {
+ case CONDITION_NONE:
+ return true; // empty condition, always met
+ case CONDITION_AURA:
+ return player->HasAura(value1, value2);
+ case CONDITION_ITEM:
+ return player->HasItemCount(value1, value2);
+ case CONDITION_ITEM_EQUIPPED:
+ return player->GetItemOrItemWithGemEquipped(value1) != NULL;
+ case CONDITION_ZONEID:
+ return player->GetZoneId() == value1;
+ case CONDITION_REPUTATION_RANK:
+ {
+ FactionEntry const* faction = sFactionStore.LookupEntry(value1);
+ return faction && player->GetReputationRank(faction) >= value2;
+ }
+ case CONDITION_TEAM:
+ return player->GetTeam() == value1;
+ case CONDITION_SKILL:
+ return player->HasSkill(value1) && player->GetBaseSkillValue(value1) >= value2;
+ case CONDITION_QUESTREWARDED:
+ return player->GetQuestRewardStatus(value1);
+ case CONDITION_QUESTTAKEN:
+ {
+ QuestStatus status = player->GetQuestStatus(value1);
+ return (status == QUEST_STATUS_INCOMPLETE);
+ }
+ case CONDITION_AD_COMMISSION_AURA:
+ {
+ Unit::AuraMap const& auras = player->GetAuras();
+ for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
+ if((itr->second->GetSpellProto()->Attributes & 0x1000010) && itr->second->GetSpellProto()->SpellVisual==3580)
+ return true;
+ return false;
+ }
+ case CONDITION_NO_AURA:
+ return !player->HasAura(value1, value2);
+ case CONDITION_ACTIVE_EVENT:
+ return gameeventmgr.IsActiveEvent(value1);
+ case CONDITION_INSTANCE_DATA:
+ {
+ Map *map = player->GetMap();
+ if(map && map->IsDungeon() && ((InstanceMap*)map)->GetInstanceData())
+ return ((InstanceMap*)map)->GetInstanceData()->GetData(value1) == value2;
+ }
+ default:
+ return false;
+ }
+}
+
+// Verification of condition values validity
+bool PlayerCondition::IsValid(ConditionType condition, uint32 value1, uint32 value2)
+{
+ if( condition >= MAX_CONDITION) // Wrong condition type
+ {
+ sLog.outErrorDb("Condition has bad type of %u, skipped ", condition );
+ return false;
+ }
+
+ switch (condition)
+ {
+ case CONDITION_AURA:
+ {
+ if(!sSpellStore.LookupEntry(value1))
+ {
+ sLog.outErrorDb("Aura condition requires to have non existing spell (Id: %d), skipped", value1);
+ return false;
+ }
+ if(value2 > 2)
+ {
+ sLog.outErrorDb("Aura condition requires to have non existing effect index (%u) (must be 0..2), skipped", value2);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_ITEM:
+ {
+ ItemPrototype const *proto = objmgr.GetItemPrototype(value1);
+ if(!proto)
+ {
+ sLog.outErrorDb("Item condition requires to have non existing item (%u), skipped", value1);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_ITEM_EQUIPPED:
+ {
+ ItemPrototype const *proto = objmgr.GetItemPrototype(value1);
+ if(!proto)
+ {
+ sLog.outErrorDb("ItemEquipped condition requires to have non existing item (%u) equipped, skipped", value1);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_ZONEID:
+ {
+ AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(value1);
+ if(!areaEntry)
+ {
+ sLog.outErrorDb("Zone condition requires to be in non existing area (%u), skipped", value1);
+ return false;
+ }
+ if(areaEntry->zone != 0)
+ {
+ sLog.outErrorDb("Zone condition requires to be in area (%u) which is a subzone but zone expected, skipped", value1);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_REPUTATION_RANK:
+ {
+ FactionEntry const* factionEntry = sFactionStore.LookupEntry(value1);
+ if(!factionEntry)
+ {
+ sLog.outErrorDb("Reputation condition requires to have reputation non existing faction (%u), skipped", value1);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_TEAM:
+ {
+ if (value1 != ALLIANCE && value1 != HORDE)
+ {
+ sLog.outErrorDb("Team condition specifies unknown team (%u), skipped", value1);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_SKILL:
+ {
+ SkillLineEntry const *pSkill = sSkillLineStore.LookupEntry(value1);
+ if (!pSkill)
+ {
+ sLog.outErrorDb("Skill condition specifies non-existing skill (%u), skipped", value1);
+ return false;
+ }
+ if (value2 < 1 || value2 > sWorld.GetConfigMaxSkillValue() )
+ {
+ sLog.outErrorDb("Skill condition specifies invalid skill value (%u), skipped", value2);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_QUESTREWARDED:
+ case CONDITION_QUESTTAKEN:
+ {
+ Quest const *Quest = objmgr.GetQuestTemplate(value1);
+ if (!Quest)
+ {
+ sLog.outErrorDb("Quest condition specifies non-existing quest (%u), skipped", value1);
+ return false;
+ }
+ if(value2)
+ sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", value2);
+ break;
+ }
+ case CONDITION_AD_COMMISSION_AURA:
+ {
+ if(value1)
+ sLog.outErrorDb("Quest condition has useless data in value1 (%u)!", value1);
+ if(value2)
+ sLog.outErrorDb("Quest condition has useless data in value2 (%u)!", value2);
+ break;
+ }
+ case CONDITION_NO_AURA:
+ {
+ if(!sSpellStore.LookupEntry(value1))
+ {
+ sLog.outErrorDb("Aura condition requires to have non existing spell (Id: %d), skipped", value1);
+ return false;
+ }
+ if(value2 > 2)
+ {
+ sLog.outErrorDb("Aura condition requires to have non existing effect index (%u) (must be 0..2), skipped", value2);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_ACTIVE_EVENT:
+ {
+ GameEvent::GameEventDataMap const& events = gameeventmgr.GetEventMap();
+ if(value1 >=events.size() || !events[value1].isValid())
+ {
+ sLog.outErrorDb("Active event condition requires existed event id (%u), skipped", value1);
+ return false;
+ }
+ break;
+ }
+ case CONDITION_INSTANCE_DATA:
+ //TODO: need some check
+ break;
+ }
+ return true;
+}
+
+SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial)
+{
+ switch(pSkill->categoryId)
+ {
+ case SKILL_CATEGORY_LANGUAGES: return SKILL_RANGE_LANGUAGE;
+ case SKILL_CATEGORY_WEAPON:
+ if(pSkill->id!=SKILL_FIST_WEAPONS)
+ return SKILL_RANGE_LEVEL;
+ else
+ return SKILL_RANGE_MONO;
+ case SKILL_CATEGORY_ARMOR:
+ case SKILL_CATEGORY_CLASS:
+ if(pSkill->id != SKILL_POISONS && pSkill->id != SKILL_LOCKPICKING)
+ return SKILL_RANGE_MONO;
+ else
+ return SKILL_RANGE_LEVEL;
+ case SKILL_CATEGORY_SECONDARY:
+ case SKILL_CATEGORY_PROFESSION:
+ // not set skills for professions and racial abilities
+ if(IsProfessionSkill(pSkill->id))
+ return SKILL_RANGE_RANK;
+ else if(racial)
+ return SKILL_RANGE_NONE;
+ else
+ return SKILL_RANGE_MONO;
+ default:
+ case SKILL_CATEGORY_ATTRIBUTES: //not found in dbc
+ case SKILL_CATEGORY_NOT_DISPLAYED: //only GENEREC(DND)
+ return SKILL_RANGE_NONE;
+ }
+}
+
+void ObjectMgr::LoadGameTele()
+{
+ m_GameTeleMap.clear(); // for reload case
+
+ uint32 count = 0;
+ QueryResult *result = WorldDatabase.Query("SELECT id, position_x, position_y, position_z, orientation, map, name FROM game_tele");
+
+ if( !result )
+ {
+ barGoLink bar( 1 );
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded `game_tele`, table is empty!");
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ do
+ {
+ bar.step();
+
+ Field *fields = result->Fetch();
+
+ uint32 id = fields[0].GetUInt32();
+
+ GameTele gt;
+
+ gt.position_x = fields[1].GetFloat();
+ gt.position_y = fields[2].GetFloat();
+ gt.position_z = fields[3].GetFloat();
+ gt.orientation = fields[4].GetFloat();
+ gt.mapId = fields[5].GetUInt32();
+ gt.name = fields[6].GetCppString();
+
+ if(!MapManager::IsValidMapCoord(gt.mapId,gt.position_x,gt.position_y,gt.position_z,gt.orientation))
+ {
+ sLog.outErrorDb("Wrong position for id %u (name: %s) in `game_tele` table, ignoring.",id,gt.name.c_str());
+ continue;
+ }
+
+ if(!Utf8toWStr(gt.name,gt.wnameLow))
+ {
+ sLog.outErrorDb("Wrong UTF8 name for id %u in `game_tele` table, ignoring.",id);
+ continue;
+ }
+
+ wstrToLower( gt.wnameLow );
+
+ m_GameTeleMap[id] = gt;
+
+ ++count;
+ }
+ while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u game tele's", count );
+}
+
+GameTele const* ObjectMgr::GetGameTele(std::string name) const
+{
+ // explicit name case
+ std::wstring wname;
+ if(!Utf8toWStr(name,wname))
+ return false;
+
+ // converting string that we try to find to lower case
+ wstrToLower( wname );
+
+ // Alternative first GameTele what contains wnameLow as substring in case no GameTele location found
+ const GameTele* alt = NULL;
+ for(GameTeleMap::const_iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr)
+ {
+ if(itr->second.wnameLow == wname)
+ return &itr->second;
+ else if (alt == NULL && itr->second.wnameLow.find(wname) != std::wstring::npos)
+ alt = &itr->second;
+ }
+
+ return alt;
+}
+
+bool ObjectMgr::AddGameTele(GameTele& tele)
+{
+ // find max id
+ uint32 new_id = 0;
+ for(GameTeleMap::const_iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr)
+ if(itr->first > new_id)
+ new_id = itr->first;
+
+ // use next
+ ++new_id;
+
+ if(!Utf8toWStr(tele.name,tele.wnameLow))
+ return false;
+
+ wstrToLower( tele.wnameLow );
+
+ m_GameTeleMap[new_id] = tele;
+
+ return WorldDatabase.PExecuteLog("INSERT INTO game_tele (id,position_x,position_y,position_z,orientation,map,name) VALUES (%u,%f,%f,%f,%f,%d,'%s')",
+ new_id,tele.position_x,tele.position_y,tele.position_z,tele.orientation,tele.mapId,tele.name.c_str());
+}
+
+bool ObjectMgr::DeleteGameTele(std::string name)
+{
+ // explicit name case
+ std::wstring wname;
+ if(!Utf8toWStr(name,wname))
+ return false;
+
+ // converting string that we try to find to lower case
+ wstrToLower( wname );
+
+ for(GameTeleMap::iterator itr = m_GameTeleMap.begin(); itr != m_GameTeleMap.end(); ++itr)
+ {
+ if(itr->second.wnameLow == wname)
+ {
+ WorldDatabase.PExecuteLog("DELETE FROM game_tele WHERE name = '%s'",itr->second.name.c_str());
+ m_GameTeleMap.erase(itr);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void ObjectMgr::LoadTrainerSpell()
+{
+ // For reload case
+ for (CacheTrainerSpellMap::iterator itr = m_mCacheTrainerSpellMap.begin(); itr != m_mCacheTrainerSpellMap.end(); ++itr)
+ itr->second.Clear();
+ m_mCacheTrainerSpellMap.clear();
+
+ std::set<uint32> skip_trainers;
+
+ QueryResult *result = WorldDatabase.Query("SELECT entry, spell,spellcost,reqskill,reqskillvalue,reqlevel FROM npc_trainer");
+
+ if( !result )
+ {
+ barGoLink bar( 1 );
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded `npc_trainer`, table is empty!");
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ uint32 count = 0;
+ do
+ {
+ bar.step();
+
+ Field* fields = result->Fetch();
+
+ uint32 entry = fields[0].GetUInt32();
+ uint32 spell = fields[1].GetUInt32();
+
+ CreatureInfo const* cInfo = GetCreatureTemplate(entry);
+
+ if(!cInfo)
+ {
+ sLog.outErrorDb("Table `npc_trainer` have entry for not existed creature template (Entry: %u), ignore", entry);
+ continue;
+ }
+
+ if(!(cInfo->npcflag & UNIT_NPC_FLAG_TRAINER))
+ {
+ if(skip_trainers.count(entry) == 0)
+ {
+ sLog.outErrorDb("Table `npc_trainer` have data for not creature template (Entry: %u) without trainer flag, ignore", entry);
+ skip_trainers.insert(entry);
+ }
+ continue;
+ }
+
+ SpellEntry const *spellinfo = sSpellStore.LookupEntry(spell);
+ if(!spellinfo)
+ {
+ sLog.outErrorDb("Table `npc_trainer` for Trainer (Entry: %u ) has non existing spell %u, ignore", entry,spell);
+ continue;
+ }
+
+ if(!SpellMgr::IsSpellValid(spellinfo))
+ {
+ sLog.outErrorDb("Table `npc_trainer` for Trainer (Entry: %u) has broken learning spell %u, ignore", entry, spell);
+ continue;
+ }
+
+ TrainerSpell* pTrainerSpell = new TrainerSpell();
+ pTrainerSpell->spell = spell;
+ pTrainerSpell->spellcost = fields[2].GetUInt32();
+ pTrainerSpell->reqskill = fields[3].GetUInt32();
+ pTrainerSpell->reqskillvalue = fields[4].GetUInt32();
+ pTrainerSpell->reqlevel = fields[5].GetUInt32();
+
+ if(!pTrainerSpell->reqlevel)
+ pTrainerSpell->reqlevel = spellinfo->spellLevel;
+
+
+ TrainerSpellData& data = m_mCacheTrainerSpellMap[entry];
+
+ if(SpellMgr::IsProfessionSpell(spell))
+ data.trainerType = 2;
+
+ data.spellList.push_back(pTrainerSpell);
+ ++count;
+
+ } while (result->NextRow());
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded Trainers %d", count );
+}
+
+void ObjectMgr::LoadVendors()
+{
+ // For reload case
+ for (CacheVendorItemMap::iterator itr = m_mCacheVendorItemMap.begin(); itr != m_mCacheVendorItemMap.end(); ++itr)
+ itr->second.Clear();
+ m_mCacheVendorItemMap.clear();
+
+ std::set<uint32> skip_vendors;
+
+ QueryResult *result = WorldDatabase.Query("SELECT entry, item, maxcount, incrtime, ExtendedCost FROM npc_vendor");
+ if( !result )
+ {
+ barGoLink bar( 1 );
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded `npc_vendor`, table is empty!");
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ uint32 count = 0;
+ do
+ {
+ bar.step();
+ Field* fields = result->Fetch();
+
+ uint32 entry = fields[0].GetUInt32();
+ uint32 item_id = fields[1].GetUInt32();
+ uint32 maxcount = fields[2].GetUInt32();
+ uint32 incrtime = fields[3].GetUInt32();
+ uint32 ExtendedCost = fields[4].GetUInt32();
+
+ if(!IsVendorItemValid(entry,item_id,maxcount,incrtime,ExtendedCost,NULL,&skip_vendors))
+ continue;
+
+ VendorItemData& vList = m_mCacheVendorItemMap[entry];
+
+ vList.AddItem(item_id,maxcount,incrtime,ExtendedCost);
+ ++count;
+
+ } while (result->NextRow());
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %d Vendors ", count );
+}
+
+void ObjectMgr::LoadNpcTextId()
+{
+
+ m_mCacheNpcTextIdMap.clear();
+
+ QueryResult* result = WorldDatabase.Query("SELECT npc_guid, textid FROM npc_gossip");
+ if( !result )
+ {
+ barGoLink bar( 1 );
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded `npc_gossip`, table is empty!");
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ uint32 count = 0;
+ uint32 guid,textid;
+ do
+ {
+ bar.step();
+
+ Field* fields = result->Fetch();
+
+ guid = fields[0].GetUInt32();
+ textid = fields[1].GetUInt32();
+
+ if (!GetCreatureData(guid))
+ {
+ sLog.outErrorDb("Table `npc_gossip` have not existed creature (GUID: %u) entry, ignore. ",guid);
+ continue;
+ }
+ if (!GetGossipText(textid))
+ {
+ sLog.outErrorDb("Table `npc_gossip` for creature (GUID: %u) have wrong Textid (%u), ignore. ", guid, textid);
+ continue;
+ }
+
+ m_mCacheNpcTextIdMap[guid] = textid ;
+ ++count;
+
+ } while (result->NextRow());
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %d NpcTextId ", count );
+}
+
+void ObjectMgr::LoadNpcOptions()
+{
+ m_mCacheNpcOptionList.clear(); // For reload case
+
+ QueryResult *result = WorldDatabase.Query(
+ // 0 1 2 3 4 5 6 7 8
+ "SELECT id,gossip_id,npcflag,icon,action,box_money,coded,option_text,box_text "
+ "FROM npc_option");
+
+ if( !result )
+ {
+ barGoLink bar( 1 );
+
+ bar.step();
+
+ sLog.outString();
+ sLog.outErrorDb(">> Loaded `npc_option`, table is empty!");
+ return;
+ }
+
+ barGoLink bar( result->GetRowCount() );
+
+ uint32 count = 0;
+
+ do
+ {
+ bar.step();
+
+ Field* fields = result->Fetch();
+
+ GossipOption go;
+ go.Id = fields[0].GetUInt32();
+ go.GossipId = fields[1].GetUInt32();
+ go.NpcFlag = fields[2].GetUInt32();
+ go.Icon = fields[3].GetUInt32();
+ go.Action = fields[4].GetUInt32();
+ go.BoxMoney = fields[5].GetUInt32();
+ go.Coded = fields[6].GetUInt8()!=0;
+ go.OptionText = fields[7].GetCppString();
+ go.BoxText = fields[8].GetCppString();
+
+ m_mCacheNpcOptionList.push_back(go);
+
+ ++count;
+
+ } while (result->NextRow());
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %d npc_option entries", count );
+}
+
+void ObjectMgr::AddVendorItem( uint32 entry,uint32 item, uint32 maxcount, uint32 incrtime, uint32 extendedcost, bool savetodb)
+{
+ VendorItemData& vList = m_mCacheVendorItemMap[entry];
+ vList.AddItem(item,maxcount,incrtime,extendedcost);
+
+ if(savetodb) WorldDatabase.PExecuteLog("INSERT INTO npc_vendor (entry,item,maxcount,incrtime,extendedcost) VALUES('%u','%u','%u','%u','%u')",entry, item, maxcount,incrtime,extendedcost);
+}
+
+bool ObjectMgr::RemoveVendorItem( uint32 entry,uint32 item, bool savetodb)
+{
+ CacheVendorItemMap::iterator iter = m_mCacheVendorItemMap.find(entry);
+ if(iter == m_mCacheVendorItemMap.end())
+ return false;
+
+ if(!iter->second.FindItem(item))
+ return false;
+
+ iter->second.RemoveItem(item);
+ if(savetodb) WorldDatabase.PExecuteLog("DELETE FROM npc_vendor WHERE entry='%u' AND item='%u'",entry, item);
+ return true;
+}
+
+bool ObjectMgr::IsVendorItemValid( uint32 vendor_entry, uint32 item_id, uint32 maxcount, uint32 incrtime, uint32 ExtendedCost, Player* pl, std::set<uint32>* skip_vendors, uint32 ORnpcflag ) const
+{
+ CreatureInfo const* cInfo = GetCreatureTemplate(vendor_entry);
+ if(!cInfo)
+ {
+ if(pl)
+ ChatHandler(pl).SendSysMessage(LANG_COMMAND_VENDORSELECTION);
+ else
+ sLog.outErrorDb("Table `(game_event_)npc_vendor` have data for not existed creature template (Entry: %u), ignore", vendor_entry);
+ return false;
+ }
+
+ if(!((cInfo->npcflag | ORnpcflag) & UNIT_NPC_FLAG_VENDOR))
+ {
+ if(!skip_vendors || skip_vendors->count(vendor_entry)==0)
+ {
+ if(pl)
+ ChatHandler(pl).SendSysMessage(LANG_COMMAND_VENDORSELECTION);
+ else
+ sLog.outErrorDb("Table `(game_event_)npc_vendor` have data for not creature template (Entry: %u) without vendor flag, ignore", vendor_entry);
+
+ if(skip_vendors)
+ skip_vendors->insert(vendor_entry);
+ }
+ return false;
+ }
+
+ if(!GetItemPrototype(item_id))
+ {
+ if(pl)
+ ChatHandler(pl).PSendSysMessage(LANG_ITEM_NOT_FOUND, item_id);
+ else
+ sLog.outErrorDb("Table `(game_event_)npc_vendor` for Vendor (Entry: %u) have in item list non-existed item (%u), ignore",vendor_entry,item_id);
+ return false;
+ }
+
+ if(ExtendedCost && !sItemExtendedCostStore.LookupEntry(ExtendedCost))
+ {
+ if(pl)
+ ChatHandler(pl).PSendSysMessage(LANG_EXTENDED_COST_NOT_EXIST,ExtendedCost);
+ else
+ sLog.outErrorDb("Table `(game_event_)npc_vendor` have Item (Entry: %u) with wrong ExtendedCost (%u) for vendor (%u), ignore",item_id,ExtendedCost,vendor_entry);
+ return false;
+ }
+
+ if(maxcount > 0 && incrtime == 0)
+ {
+ if(pl)
+ ChatHandler(pl).PSendSysMessage("MaxCount!=0 (%u) but IncrTime==0", maxcount);
+ else
+ sLog.outErrorDb( "Table `(game_event_)npc_vendor` has `maxcount` (%u) for item %u of vendor (Entry: %u) but `incrtime`=0, ignore", maxcount, item_id, vendor_entry);
+ return false;
+ }
+ else if(maxcount==0 && incrtime > 0)
+ {
+ if(pl)
+ ChatHandler(pl).PSendSysMessage("MaxCount==0 but IncrTime<>=0");
+ else
+ sLog.outErrorDb( "Table `(game_event_)npc_vendor` has `maxcount`=0 for item %u of vendor (Entry: %u) but `incrtime`<>0, ignore", item_id, vendor_entry);
+ return false;
+ }
+
+ VendorItemData const* vItems = GetNpcVendorItemList(vendor_entry);
+ if(!vItems)
+ return true; // later checks for non-empty lists
+
+ if(vItems->FindItem(item_id))
+ {
+ if(pl)
+ ChatHandler(pl).PSendSysMessage(LANG_ITEM_ALREADY_IN_LIST,item_id);
+ else
+ sLog.outErrorDb( "Table `(game_event_)npc_vendor` has duplicate items %u for vendor (Entry: %u), ignore", item_id, vendor_entry);
+ return false;
+ }
+
+ if(vItems->GetItemCount() >= MAX_VENDOR_ITEMS)
+ {
+ if(pl)
+ ChatHandler(pl).SendSysMessage(LANG_COMMAND_ADDVENDORITEMITEMS);
+ else
+ sLog.outErrorDb( "Table `npc_vendor` has too many items (%u >= %i) for vendor (Entry: %u), ignore", vItems->GetItemCount(), MAX_VENDOR_ITEMS, vendor_entry);
+ return false;
+ }
+
+ return true;
+}
+
+void ObjectMgr::LoadScriptNames()
+{
+ m_scriptNames.push_back("");
+ QueryResult *result = WorldDatabase.Query(
+ "SELECT DISTINCT(ScriptName) FROM creature_template WHERE ScriptName <> '' "
+ "UNION "
+ "SELECT DISTINCT(ScriptName) FROM gameobject_template WHERE ScriptName <> '' "
+ "UNION "
+ "SELECT DISTINCT(ScriptName) FROM item_template WHERE ScriptName <> '' "
+ "UNION "
+ "SELECT DISTINCT(ScriptName) FROM areatrigger_scripts WHERE ScriptName <> '' "
+ "UNION "
+ "SELECT DISTINCT(script) FROM instance_template WHERE script <> ''");
+ if(result)
+ {
+ do
+ {
+ m_scriptNames.push_back((*result)[0].GetString());
+ } while (result->NextRow());
+ delete result;
+ }
+
+ std::sort(m_scriptNames.begin(), m_scriptNames.end());
+}
+
+uint32 ObjectMgr::GetScriptId(const char *name)
+{
+ // use binary search to find the script name in the sorted vector
+ // assume "" is the first element
+ if(!name) return 0;
+ ScriptNameMap::const_iterator itr =
+ std::lower_bound(m_scriptNames.begin(), m_scriptNames.end(), name);
+ if(itr == m_scriptNames.end() || *itr != name) return 0;
+ return itr - m_scriptNames.begin();
+}
+
+void ObjectMgr::CheckScripts(ScriptMapMap const& scripts,std::set<int32>& ids)
+{
+ for(ScriptMapMap::const_iterator itrMM = scripts.begin(); itrMM != scripts.end(); ++itrMM)
+ {
+ for(ScriptMap::const_iterator itrM = itrMM->second.begin(); itrM != itrMM->second.end(); ++itrM)
+ {
+ if(itrM->second.dataint)
+ {
+ if(!GetTrinityStringLocale (itrM->second.dataint))
+ sLog.outErrorDb( "Table `db_script_string` has not existed string id %u", itrM->first);
+
+ if(ids.count(itrM->second.dataint))
+ ids.erase(itrM->second.dataint);
+ }
+ }
+ }
+}
+
+void ObjectMgr::LoadDbScriptStrings()
+{
+ LoadTrinityStrings(WorldDatabase,"db_script_string",MIN_DB_SCRIPT_STRING_ID,MAX_DB_SCRIPT_STRING_ID);
+
+ std::set<int32> ids;
+
+ for(int32 i = MIN_DB_SCRIPT_STRING_ID; i < MAX_DB_SCRIPT_STRING_ID; ++i)
+ if(GetTrinityStringLocale(i))
+ ids.insert(i);
+
+ CheckScripts(sQuestEndScripts,ids);
+ CheckScripts(sQuestStartScripts,ids);
+ CheckScripts(sSpellScripts,ids);
+ CheckScripts(sGameObjectScripts,ids);
+ CheckScripts(sEventScripts,ids);
+
+ WaypointMgr.CheckTextsExistance(ids);
+
+ for(std::set<int32>::const_iterator itr = ids.begin(); itr != ids.end(); ++itr)
+ sLog.outErrorDb( "Table `db_script_string` has unused string id %u", *itr);
+}
+
+// Functions for scripting access
+uint32 GetAreaTriggerScriptId(uint32 trigger_id)
+{
+ return objmgr.GetAreaTriggerScriptId(trigger_id);
+}
+
+bool LoadTrinityStrings(DatabaseType& db, char const* table,int32 start_value, int32 end_value)
+{
+ if(start_value >= 0 || start_value <= end_value) // start/end reversed for negative values
+ {
+ sLog.outErrorDb("Table '%s' attempt loaded with invalid range (%d - %d), use (%d - %d) instead.",table,start_value,end_value,-1,std::numeric_limits<int32>::min());
+ start_value = -1;
+ end_value = std::numeric_limits<int32>::min();
+ }
+
+ // for scripting localized strings allowed use _only_ negative entries
+ return objmgr.LoadTrinityStrings(db,table,end_value,start_value);
+}
+
+uint32 TRINITY_DLL_SPEC GetScriptId(const char *name)
+{
+ return objmgr.GetScriptId(name);
+}
+
+ObjectMgr::ScriptNameMap & GetScriptNames()
+{
+ return objmgr.GetScriptNames();
+}
diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h
index bed7eb9fbb8..8c7f8728b0b 100644
--- a/src/game/ObjectMgr.h
+++ b/src/game/ObjectMgr.h
@@ -1,938 +1,939 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
- *
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
- *
- * 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
- */
-
-#ifndef _OBJECTMGR_H
-#define _OBJECTMGR_H
-
-#include "Log.h"
-#include "Object.h"
-#include "Bag.h"
-#include "Creature.h"
-#include "Player.h"
-#include "DynamicObject.h"
-#include "GameObject.h"
-#include "Corpse.h"
-#include "QuestDef.h"
-#include "Path.h"
-#include "ItemPrototype.h"
-#include "NPCHandler.h"
-#include "Database/DatabaseEnv.h"
-#include "AuctionHouseObject.h"
-#include "Mail.h"
-#include "Map.h"
-#include "ObjectAccessor.h"
-#include "ObjectDefines.h"
-#include "Policies/Singleton.h"
-#include "Database/SQLStorage.h"
-
-#include <string>
-#include <map>
-#include <limits>
-
-extern SQLStorage sCreatureStorage;
-extern SQLStorage sCreatureDataAddonStorage;
-extern SQLStorage sCreatureInfoAddonStorage;
-extern SQLStorage sCreatureModelStorage;
-extern SQLStorage sEquipmentStorage;
-extern SQLStorage sGOStorage;
-extern SQLStorage sPageTextStore;
-extern SQLStorage sItemStorage;
-extern SQLStorage sInstanceTemplate;
-
-class Group;
-class Guild;
-class ArenaTeam;
-class Path;
-class TransportPath;
-class Item;
-
-struct GameTele
-{
- float position_x;
- float position_y;
- float position_z;
- float orientation;
- uint32 mapId;
- std::string name;
- std::wstring wnameLow;
-};
-
-typedef UNORDERED_MAP<uint32, GameTele > GameTeleMap;
-typedef std::list<GossipOption> CacheNpcOptionList;
-
-struct ScriptInfo
-{
- uint32 id;
- uint32 delay;
- uint32 command;
- uint32 datalong;
- uint32 datalong2;
- int32 dataint;
- float x;
- float y;
- float z;
- float o;
-};
-
-typedef std::multimap<uint32, ScriptInfo> ScriptMap;
-typedef std::map<uint32, ScriptMap > ScriptMapMap;
-extern ScriptMapMap sQuestEndScripts;
-extern ScriptMapMap sQuestStartScripts;
-extern ScriptMapMap sSpellScripts;
-extern ScriptMapMap sGameObjectScripts;
-extern ScriptMapMap sEventScripts;
-
-struct AreaTrigger
-{
- uint8 requiredLevel;
- uint32 requiredItem;
- uint32 requiredItem2;
- uint32 heroicKey;
- uint32 heroicKey2;
- uint32 requiredQuest;
- std::string requiredFailedText;
- uint32 target_mapId;
- float target_X;
- float target_Y;
- float target_Z;
- float target_Orientation;
-};
-
-typedef std::set<uint32> CellGuidSet;
-typedef std::map<uint32/*player guid*/,uint32/*instance*/> CellCorpseSet;
-struct CellObjectGuids
-{
- CellGuidSet creatures;
- CellGuidSet gameobjects;
- CellCorpseSet corpses;
-};
-typedef UNORDERED_MAP<uint32/*cell_id*/,CellObjectGuids> CellObjectGuidsMap;
-typedef UNORDERED_MAP<uint32/*(mapid,spawnMode) pair*/,CellObjectGuidsMap> MapObjectGuids;
-
-typedef UNORDERED_MAP<uint64/*(instance,guid) pair*/,time_t> RespawnTimes;
-
-
-// mangos string ranges
-#define MIN_TRINITY_STRING_ID 1
-#define MAX_TRINITY_STRING_ID 2000000000
-#define MIN_DB_SCRIPT_STRING_ID MAX_TRINITY_STRING_ID
-#define MAX_DB_SCRIPT_STRING_ID 2000010000
-
-struct TrinityStringLocale
-{
- std::vector<std::string> Content; // 0 -> default, i -> i-1 locale index
-};
-
-typedef UNORDERED_MAP<uint32,CreatureData> CreatureDataMap;
-typedef UNORDERED_MAP<uint32,GameObjectData> GameObjectDataMap;
-typedef UNORDERED_MAP<uint32,CreatureLocale> CreatureLocaleMap;
-typedef UNORDERED_MAP<uint32,GameObjectLocale> GameObjectLocaleMap;
-typedef UNORDERED_MAP<uint32,ItemLocale> ItemLocaleMap;
-typedef UNORDERED_MAP<uint32,QuestLocale> QuestLocaleMap;
-typedef UNORDERED_MAP<uint32,NpcTextLocale> NpcTextLocaleMap;
-typedef UNORDERED_MAP<uint32,PageTextLocale> PageTextLocaleMap;
-typedef UNORDERED_MAP<uint32,TrinityStringLocale> TrinityStringLocaleMap;
-typedef UNORDERED_MAP<uint32,NpcOptionLocale> NpcOptionLocaleMap;
-
-typedef std::multimap<uint32,uint32> QuestRelations;
-
-struct PetLevelInfo
-{
- PetLevelInfo() : health(0), mana(0) { for(int i=0; i < MAX_STATS; ++i ) stats[i] = 0; }
-
- uint16 stats[MAX_STATS];
- uint16 health;
- uint16 mana;
- uint16 armor;
-};
-
-struct ReputationOnKillEntry
-{
- uint32 repfaction1;
- uint32 repfaction2;
- bool is_teamaward1;
- uint32 reputation_max_cap1;
- int32 repvalue1;
- bool is_teamaward2;
- uint32 reputation_max_cap2;
- int32 repvalue2;
- bool team_dependent;
-};
-
-struct PetCreateSpellEntry
-{
- uint32 spellid[4];
-};
-
-#define WEATHER_SEASONS 4
-struct WeatherSeasonChances
-{
- uint32 rainChance;
- uint32 snowChance;
- uint32 stormChance;
-};
-
-struct WeatherZoneChances
-{
- WeatherSeasonChances data[WEATHER_SEASONS];
-};
-
-struct GraveYardData
-{
- uint32 safeLocId;
- uint32 team;
-};
-typedef std::multimap<uint32,GraveYardData> GraveYardMap;
-
-enum ConditionType
-{ // value1 value2 for the Condition enumed
- CONDITION_NONE = 0, // 0 0
- CONDITION_AURA = 1, // spell_id effindex
- CONDITION_ITEM = 2, // item_id count
- CONDITION_ITEM_EQUIPPED = 3, // item_id 0
- CONDITION_ZONEID = 4, // zone_id 0
- CONDITION_REPUTATION_RANK = 5, // faction_id min_rank
- CONDITION_TEAM = 6, // player_team 0, (469 - Alliance 67 - Horde)
- CONDITION_SKILL = 7, // skill_id skill_value
- CONDITION_QUESTREWARDED = 8, // quest_id 0
- CONDITION_QUESTTAKEN = 9, // quest_id 0, for condition true while quest active.
- CONDITION_AD_COMMISSION_AURA = 10, // 0 0, for condition true while one from AD ñommission aura active
- CONDITION_NO_AURA = 11, // spell_id effindex
- CONDITION_ACTIVE_EVENT = 12, // event_id
-};
-
-#define MAX_CONDITION 13 // maximum value in ConditionType enum
-
-//Player's info
-typedef struct _tagCachePlayerInfo
-{
- std::string sPlayerName;
- uint32 unfield;
- uint32 unLevel;
- uint8 unClass;
-//Arena
- uint32 unArenaInfoId0;
- uint32 unArenaInfoId1;
- uint32 unArenaInfoId2;
- uint32 unArenaInfoSlot0;
- uint32 unArenaInfoSlot1;
- uint32 unArenaInfoSlot2;
-}CachePlayerInfo, *PCachePlayerInfo;
-typedef UNORDERED_MAP<uint32, PCachePlayerInfo> CachePlayerInfoMap;
-
-struct PlayerCondition
-{
- ConditionType condition; // additional condition type
- uint32 value1; // data for the condition - see ConditionType definition
- uint32 value2;
-
- PlayerCondition(uint8 _condition = 0, uint32 _value1 = 0, uint32 _value2 = 0)
- : condition(ConditionType(_condition)), value1(_value1), value2(_value2) {}
-
- static bool IsValid(ConditionType condition, uint32 value1, uint32 value2);
- // Checks correctness of values
- bool Meets(Player const * APlayer) const; // Checks if the player meets the condition
- bool operator == (PlayerCondition const& lc) const
- {
- return (lc.condition == condition && lc.value1 == value1 && lc.value2 == value2);
- }
-};
-
-// NPC gossip text id
-typedef UNORDERED_MAP<uint32, uint32> CacheNpcTextIdMap;
-typedef std::list<GossipOption> CacheNpcOptionList;
-
-typedef UNORDERED_MAP<uint32, VendorItemData> CacheVendorItemMap;
-typedef UNORDERED_MAP<uint32, TrainerSpellData> CacheTrainerSpellMap;
-
-enum SkillRangeType
-{
- SKILL_RANGE_LANGUAGE, // 300..300
- SKILL_RANGE_LEVEL, // 1..max skill for level
- SKILL_RANGE_MONO, // 1..1, grey monolite bar
- SKILL_RANGE_RANK, // 1..skill for known rank
- SKILL_RANGE_NONE, // 0..0 always
-};
-
-SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial);
-
-#define MAX_PLAYER_NAME 12 // max allowed by client name length
-#define MAX_INTERNAL_PLAYER_NAME 15 // max server internal player name length ( > MAX_PLAYER_NAME for support declined names )
-
-bool normalizePlayerName(std::string& name);
-
-struct TRINITY_DLL_SPEC LanguageDesc
-{
- Language lang_id;
- uint32 spell_id;
- uint32 skill_id;
-};
-
-extern LanguageDesc lang_description[LANGUAGES_COUNT];
-TRINITY_DLL_SPEC LanguageDesc const* GetLanguageDescByID(uint32 lang);
-
-class PlayerDumpReader;
-
-class ObjectMgr
-{
- friend class PlayerDumpReader;
-
- public:
- ObjectMgr();
- ~ObjectMgr();
-
- typedef UNORDERED_MAP<uint32, Item*> ItemMap;
-
- typedef std::set< Group * > GroupSet;
- typedef std::set< Guild * > GuildSet;
- typedef std::set< ArenaTeam * > ArenaTeamSet;
-
- typedef UNORDERED_MAP<uint32, Quest*> QuestMap;
-
-
- typedef UNORDERED_MAP<uint32, AreaTrigger> AreaTriggerMap;
-
- typedef UNORDERED_MAP<uint32, uint32> AreaTriggerScriptMap;
-
- typedef UNORDERED_MAP<uint32, ReputationOnKillEntry> RepOnKillMap;
-
- typedef UNORDERED_MAP<uint32, WeatherZoneChances> WeatherZoneMap;
-
- typedef UNORDERED_MAP<uint32, PetCreateSpellEntry> PetCreateSpellMap;
-
- typedef std::vector<std::string> ScriptNameMap;
-
- Player* GetPlayer(const char* name) const { return ObjectAccessor::Instance().FindPlayerByName(name);}
- Player* GetPlayer(uint64 guid) const { return ObjectAccessor::FindPlayer(guid); }
-
- static GameObjectInfo const *GetGameObjectInfo(uint32 id) { return sGOStorage.LookupEntry<GameObjectInfo>(id); }
-
- void LoadGameobjectInfo();
- void AddGameobjectInfo(GameObjectInfo *goinfo);
-
- Group * GetGroupByLeader(const uint64 &guid) const;
- void AddGroup(Group* group) { mGroupSet.insert( group ); }
- void RemoveGroup(Group* group) { mGroupSet.erase( group ); }
-
- Guild* GetGuildByLeader(uint64 const&guid) const;
- Guild* GetGuildById(const uint32 GuildId) const;
- Guild* GetGuildByName(std::string guildname) const;
- std::string GetGuildNameById(const uint32 GuildId) const;
- void AddGuild(Guild* guild) { mGuildSet.insert( guild ); }
- void RemoveGuild(Guild* guild) { mGuildSet.erase( guild ); }
-
- ArenaTeam* GetArenaTeamById(const uint32 ArenaTeamId) const;
- ArenaTeam* GetArenaTeamByName(std::string ArenaTeamName) const;
- ArenaTeam* GetArenaTeamByCapitan(uint64 const& guid) const;
- void AddArenaTeam(ArenaTeam* arenateam) { mArenaTeamSet.insert( arenateam ); }
- void RemoveArenaTeam(ArenaTeam* arenateam) { mArenaTeamSet.erase( arenateam ); }
- ArenaTeamSet::iterator GetArenaTeamSetBegin() { return mArenaTeamSet.begin(); }
- ArenaTeamSet::iterator GetArenaTeamSetEnd() { return mArenaTeamSet.end(); }
-
- static CreatureInfo const *GetCreatureTemplate( uint32 id );
- CreatureModelInfo const *GetCreatureModelInfo( uint32 modelid );
- CreatureModelInfo const* GetCreatureModelRandomGender(uint32 display_id);
- uint32 ChooseDisplayId(uint32 team, const CreatureInfo *cinfo, const CreatureData *data = NULL);
- EquipmentInfo const *GetEquipmentInfo( uint32 entry );
- static CreatureDataAddon const *GetCreatureAddon( uint32 lowguid )
- {
- return sCreatureDataAddonStorage.LookupEntry<CreatureDataAddon>(lowguid);
- }
-
- static CreatureDataAddon const *GetCreatureTemplateAddon( uint32 entry )
- {
- return sCreatureInfoAddonStorage.LookupEntry<CreatureDataAddon>(entry);
- }
-
- static ItemPrototype const* GetItemPrototype(uint32 id) { return sItemStorage.LookupEntry<ItemPrototype>(id); }
-
- static InstanceTemplate const* GetInstanceTemplate(uint32 map)
- {
- return sInstanceTemplate.LookupEntry<InstanceTemplate>(map);
- }
-
- Item* GetAItem(uint32 id)
- {
- ItemMap::const_iterator itr = mAitems.find(id);
- if (itr != mAitems.end())
- {
- return itr->second;
- }
- return NULL;
- }
- void AddAItem(Item* it)
- {
- ASSERT( it );
- ASSERT( mAitems.find(it->GetGUIDLow()) == mAitems.end());
- mAitems[it->GetGUIDLow()] = it;
- }
- bool RemoveAItem(uint32 id)
- {
- ItemMap::iterator i = mAitems.find(id);
- if (i == mAitems.end())
- {
- return false;
- }
- mAitems.erase(i);
- return true;
- }
- AuctionHouseObject * GetAuctionsMap( uint32 location );
-
- //auction messages
- void SendAuctionWonMail( AuctionEntry * auction );
- void SendAuctionSalePendingMail( AuctionEntry * auction );
- void SendAuctionSuccessfulMail( AuctionEntry * auction );
- void SendAuctionExpiredMail( AuctionEntry * auction );
- static uint32 GetAuctionCut( uint32 location, uint32 highBid );
- static uint32 GetAuctionDeposit(uint32 location, uint32 time, Item *pItem);
- static uint32 GetAuctionOutBid(uint32 currentBid);
-
- PetLevelInfo const* GetPetLevelInfo(uint32 creature_id, uint32 level) const;
-
- PlayerClassInfo const* GetPlayerClassInfo(uint32 class_) const
- {
- if(class_ >= MAX_CLASSES) return NULL;
- return &playerClassInfo[class_];
- }
- void GetPlayerClassLevelInfo(uint32 class_,uint32 level, PlayerClassLevelInfo* info) const;
-
- PlayerInfo const* GetPlayerInfo(uint32 race, uint32 class_) const
- {
- if(race >= MAX_RACES) return NULL;
- if(class_ >= MAX_CLASSES) return NULL;
- PlayerInfo const* info = &playerInfo[race][class_];
- if(info->displayId_m==0 || info->displayId_f==0) return NULL;
- return info;
- }
- void GetPlayerLevelInfo(uint32 race, uint32 class_,uint32 level, PlayerLevelInfo* info) const;
-
- uint64 GetPlayerGUIDByName(std::string name) const;
- bool GetPlayerNameByGUID(const uint64 &guid, std::string &name) const;
- uint32 GetPlayerTeamByGUID(const uint64 &guid) const;
- uint32 GetPlayerAccountIdByGUID(const uint64 &guid) const;
- uint32 GetPlayerAccountIdByPlayerName(std::string name) const;
-
- uint32 GetNearestTaxiNode( float x, float y, float z, uint32 mapid );
- void GetTaxiPath( uint32 source, uint32 destination, uint32 &path, uint32 &cost);
- uint16 GetTaxiMount( uint32 id, uint32 team );
- void GetTaxiPathNodes( uint32 path, Path &pathnodes, std::vector<uint32>& mapIds );
- void GetTransportPathNodes( uint32 path, TransportPath &pathnodes );
-
- Quest const* GetQuestTemplate(uint32 quest_id) const
- {
- QuestMap::const_iterator itr = mQuestTemplates.find(quest_id);
- return itr != mQuestTemplates.end() ? itr->second : NULL;
- }
- QuestMap const& GetQuestTemplates() const { return mQuestTemplates; }
-
- uint32 GetQuestForAreaTrigger(uint32 Trigger_ID) const
- {
- QuestAreaTriggerMap::const_iterator itr = mQuestAreaTriggerMap.find(Trigger_ID);
- if(itr != mQuestAreaTriggerMap.end())
- return itr->second;
- return 0;
- }
- bool IsTavernAreaTrigger(uint32 Trigger_ID) const { return mTavernAreaTriggerSet.count(Trigger_ID) != 0; }
- bool IsGameObjectForQuests(uint32 entry) const { return mGameObjectForQuestSet.count(entry) != 0; }
- bool IsGuildVaultGameObject(Player *player, uint64 guid) const
- {
- if(GameObject *go = ObjectAccessor::GetGameObject(*player, guid))
- if(go->GetGoType() == GAMEOBJECT_TYPE_GUILD_BANK)
- return true;
- return false;
- }
-
- uint32 GetBattleMasterBG(uint32 entry) const
- {
- BattleMastersMap::const_iterator itr = mBattleMastersMap.find(entry);
- if(itr != mBattleMastersMap.end())
- return itr->second;
- return 2; //BATTLEGROUND_WS - i will not add include only for constant usage!
- }
-
- void AddGossipText(GossipText *pGText);
- GossipText *GetGossipText(uint32 Text_ID);
-
- WorldSafeLocsEntry const *GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team);
- bool AddGraveYardLink(uint32 id, uint32 zone, uint32 team, bool inDB = true);
- void RemoveGraveYardLink(uint32 id, uint32 zone, uint32 team, bool inDB = false);
- void LoadGraveyardZones();
- GraveYardData const* FindGraveYardData(uint32 id, uint32 zone);
-
- AreaTrigger const* GetAreaTrigger(uint32 trigger) const
- {
- AreaTriggerMap::const_iterator itr = mAreaTriggers.find( trigger );
- if( itr != mAreaTriggers.end( ) )
- return &itr->second;
- return NULL;
- }
-
- AreaTrigger const* GetGoBackTrigger(uint32 Map) const;
-
- uint32 GetAreaTriggerScriptId(uint32 trigger_id);
-
- ReputationOnKillEntry const* GetReputationOnKilEntry(uint32 id) const
- {
- RepOnKillMap::const_iterator itr = mRepOnKill.find(id);
- if(itr != mRepOnKill.end())
- return &itr->second;
- return NULL;
- }
-
- PetCreateSpellEntry const* GetPetCreateSpellEntry(uint32 id) const
- {
- PetCreateSpellMap::const_iterator itr = mPetCreateSpell.find(id);
- if(itr != mPetCreateSpell.end())
- return &itr->second;
- return NULL;
- }
-
- void LoadGuilds();
- void LoadArenaTeams();
- void LoadGroups();
- void LoadQuests();
- void LoadQuestRelations()
- {
- LoadGameobjectQuestRelations();
- LoadGameobjectInvolvedRelations();
- LoadCreatureQuestRelations();
- LoadCreatureInvolvedRelations();
- }
- void LoadGameobjectQuestRelations();
- void LoadGameobjectInvolvedRelations();
- void LoadCreatureQuestRelations();
- void LoadCreatureInvolvedRelations();
-
- QuestRelations mGOQuestRelations;
- QuestRelations mGOQuestInvolvedRelations;
- QuestRelations mCreatureQuestRelations;
- QuestRelations mCreatureQuestInvolvedRelations;
-
- void LoadGameObjectScripts();
- void LoadQuestEndScripts();
- void LoadQuestStartScripts();
- void LoadEventScripts();
- void LoadSpellScripts();
-
- bool LoadTrinityStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value);
- bool LoadTrinityStrings() { return LoadTrinityStrings(WorldDatabase,"trinity_string",MIN_TRINITY_STRING_ID,MAX_TRINITY_STRING_ID); }
- void LoadDbScriptStrings();
- void LoadPetCreateSpells();
- void LoadCreatureLocales();
- void LoadCreatureTemplates();
- void LoadCreatures();
- void LoadCreatureRespawnTimes();
- void LoadCreatureAddons();
- void LoadCreatureModelInfo();
- void LoadEquipmentTemplates();
- void LoadGameObjectLocales();
- void LoadGameobjects();
- void LoadGameobjectRespawnTimes();
- void LoadItemPrototypes();
- void LoadItemLocales();
- void LoadQuestLocales();
- void LoadNpcTextLocales();
- void LoadPageTextLocales();
- void LoadNpcOptionLocales();
- void LoadInstanceTemplate();
-
- void LoadGossipText();
-
- void LoadAreaTriggerTeleports();
- void LoadQuestAreaTriggers();
- void LoadAreaTriggerScripts();
- void LoadTavernAreaTriggers();
- void LoadBattleMastersEntry();
- void LoadGameObjectForQuests();
-
- void LoadItemTexts();
- void LoadPageTexts();
-
- //load first auction items, because of check if item exists, when loading
- void LoadAuctionItems();
- void LoadAuctions();
- void LoadPlayerInfo();
- void LoadPetLevelInfo();
- void LoadExplorationBaseXP();
- void LoadPetNames();
- void LoadPetNumber();
- void LoadCorpses();
- void LoadFishingBaseSkillLevel();
-
- void LoadReputationOnKill();
-
- void LoadWeatherZoneChances();
- void LoadGameTele();
-
- void LoadNpcOptions();
- void LoadNpcTextId();
- void LoadVendors();
- void LoadTrainerSpell();
-
- std::string GeneratePetName(uint32 entry);
- uint32 GetBaseXP(uint32 level);
-
- int32 GetFishingBaseSkillLevel(uint32 entry) const
- {
- FishingBaseSkillMap::const_iterator itr = mFishingBaseForArea.find(entry);
- return itr != mFishingBaseForArea.end() ? itr->second : 0;
- }
-
- void ReturnOrDeleteOldMails(bool serverUp);
-
- void SetHighestGuids();
- uint32 GenerateLowGuid(HighGuid guidhigh);
- uint32 GenerateAuctionID();
- uint32 GenerateMailID();
- uint32 GenerateItemTextID();
- uint32 GeneratePetNumber();
- uint32 GenerateArenaTeamId();
- uint32 GenerateGuildId();
-
- void LoadPlayerInfoInCache();
- PCachePlayerInfo GetPlayerInfoFromCache(uint32 unPlayerGuid) const;
- CachePlayerInfoMap m_mPlayerInfoMap;
-
- uint32 CreateItemText(std::string text);
- std::string GetItemText( uint32 id )
- {
- ItemTextMap::const_iterator itr = mItemTexts.find( id );
- if ( itr != mItemTexts.end() )
- return itr->second;
- else
- return "There is no info for this item";
- }
-
- typedef std::multimap<int32, uint32> ExclusiveQuestGroups;
- ExclusiveQuestGroups mExclusiveQuestGroups;
-
- WeatherZoneChances const* GetWeatherChances(uint32 zone_id) const
- {
- WeatherZoneMap::const_iterator itr = mWeatherZoneMap.find(zone_id);
- if(itr != mWeatherZoneMap.end())
- return &itr->second;
- else
- return NULL;
- }
-
- CellObjectGuids const& GetCellObjectGuids(uint16 mapid, uint8 spawnMode, uint32 cell_id)
- {
- return mMapObjectGuids[MAKE_PAIR32(mapid,spawnMode)][cell_id];
- }
-
- CreatureData const* GetCreatureData(uint32 guid) const
- {
- CreatureDataMap::const_iterator itr = mCreatureDataMap.find(guid);
- if(itr==mCreatureDataMap.end()) return NULL;
- return &itr->second;
- }
- CreatureData& NewOrExistCreatureData(uint32 guid) { return mCreatureDataMap[guid]; }
- void DeleteCreatureData(uint32 guid);
- CreatureLocale const* GetCreatureLocale(uint32 entry) const
- {
- CreatureLocaleMap::const_iterator itr = mCreatureLocaleMap.find(entry);
- if(itr==mCreatureLocaleMap.end()) return NULL;
- return &itr->second;
- }
- GameObjectLocale const* GetGameObjectLocale(uint32 entry) const
- {
- GameObjectLocaleMap::const_iterator itr = mGameObjectLocaleMap.find(entry);
- if(itr==mGameObjectLocaleMap.end()) return NULL;
- return &itr->second;
- }
- ItemLocale const* GetItemLocale(uint32 entry) const
- {
- ItemLocaleMap::const_iterator itr = mItemLocaleMap.find(entry);
- if(itr==mItemLocaleMap.end()) return NULL;
- return &itr->second;
- }
- QuestLocale const* GetQuestLocale(uint32 entry) const
- {
- QuestLocaleMap::const_iterator itr = mQuestLocaleMap.find(entry);
- if(itr==mQuestLocaleMap.end()) return NULL;
- return &itr->second;
- }
- NpcTextLocale const* GetNpcTextLocale(uint32 entry) const
- {
- NpcTextLocaleMap::const_iterator itr = mNpcTextLocaleMap.find(entry);
- if(itr==mNpcTextLocaleMap.end()) return NULL;
- return &itr->second;
- }
- PageTextLocale const* GetPageTextLocale(uint32 entry) const
- {
- PageTextLocaleMap::const_iterator itr = mPageTextLocaleMap.find(entry);
- if(itr==mPageTextLocaleMap.end()) return NULL;
- return &itr->second;
- }
- NpcOptionLocale const* GetNpcOptionLocale(uint32 entry) const
- {
- NpcOptionLocaleMap::const_iterator itr = mNpcOptionLocaleMap.find(entry);
- if(itr==mNpcOptionLocaleMap.end()) return NULL;
- return &itr->second;
- }
-
- GameObjectData const* GetGOData(uint32 guid) const
- {
- GameObjectDataMap::const_iterator itr = mGameObjectDataMap.find(guid);
- if(itr==mGameObjectDataMap.end()) return NULL;
- return &itr->second;
- }
- GameObjectData& NewGOData(uint32 guid) { return mGameObjectDataMap[guid]; }
- void DeleteGOData(uint32 guid);
-
- TrinityStringLocale const* GetTrinityStringLocale(int32 entry) const
- {
- TrinityStringLocaleMap::const_iterator itr = mTrinityStringLocaleMap.find(entry);
- if(itr==mTrinityStringLocaleMap.end()) return NULL;
- return &itr->second;
- }
- const char *GetTrinityString(int32 entry, int locale_idx) const;
- const char *GetTrinityStringForDBCLocale(int32 entry) const { return GetTrinityString(entry,DBCLocaleIndex); }
- int32 GetDBCLocaleIndex() const { return DBCLocaleIndex; }
- void SetDBCLocaleIndex(uint32 lang) { DBCLocaleIndex = GetIndexForLocale(LocaleConstant(lang)); }
-
- void AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance);
- void DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid);
-
- time_t GetCreatureRespawnTime(uint32 loguid, uint32 instance) { return mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)]; }
- void SaveCreatureRespawnTime(uint32 loguid, uint32 instance, time_t t);
- time_t GetGORespawnTime(uint32 loguid, uint32 instance) { return mGORespawnTimes[MAKE_PAIR64(loguid,instance)]; }
- void SaveGORespawnTime(uint32 loguid, uint32 instance, time_t t);
- void DeleteRespawnTimeForInstance(uint32 instance);
-
- // grid objects
- void AddCreatureToGrid(uint32 guid, CreatureData const* data);
- void RemoveCreatureFromGrid(uint32 guid, CreatureData const* data);
- void AddGameobjectToGrid(uint32 guid, GameObjectData const* data);
- void RemoveGameobjectFromGrid(uint32 guid, GameObjectData const* data);
-
- // reserved names
- void LoadReservedPlayersNames();
- bool IsReservedName(std::string name) const
- {
- return m_ReservedNames.find(name) != m_ReservedNames.end();
- }
-
- // name with valid structure and symbols
- static bool IsValidName( std::string name, bool create = false );
- static bool IsValidCharterName( std::string name );
- static bool IsValidPetName( std::string name );
-
- static bool CheckDeclinedNames(std::wstring mainpart, DeclinedName const& names);
-
- void LoadSpellDisabledEntrys();
- bool IsPlayerSpellDisabled(uint32 spellid) { return (m_DisabledPlayerSpells.count(spellid) != 0); }
- bool IsCreatureSpellDisabled(uint32 spellid) { return (m_DisabledCreatureSpells.count(spellid) != 0); }
-
- int GetIndexForLocale(LocaleConstant loc);
- LocaleConstant GetLocaleForIndex(int i);
- // guild bank tabs
- uint32 GetGuildBankTabPrice(uint8 Index) const { return Index < GUILD_BANK_MAX_TABS ? mGuildBankTabPrice[Index] : 0; }
-
- uint16 GetConditionId(ConditionType condition, uint32 value1, uint32 value2);
- bool IsPlayerMeetToCondition(Player const* player, uint16 condition_id) const
- {
- if(condition_id >= mConditions.size())
- return false;
-
- return mConditions[condition_id].Meets(player);
- }
-
- GameTele const* GetGameTele(uint32 id) const
- {
- GameTeleMap::const_iterator itr = m_GameTeleMap.find(id);
- if(itr==m_GameTeleMap.end()) return NULL;
- return &itr->second;
- }
- GameTele const* GetGameTele(std::string name) const;
- GameTeleMap const& GetGameTeleMap() const { return m_GameTeleMap; }
- bool AddGameTele(GameTele& data);
- bool DeleteGameTele(std::string name);
-
- CacheNpcOptionList const& GetNpcOptions() const { return m_mCacheNpcOptionList; }
-
- uint32 GetNpcGossip(uint32 entry) const
- {
- CacheNpcTextIdMap::const_iterator iter = m_mCacheNpcTextIdMap.find(entry);
- if(iter == m_mCacheNpcTextIdMap.end())
- return 0;
-
- return iter->second;
- }
-
- TrainerSpellData const* GetNpcTrainerSpells(uint32 entry) const
- {
- CacheTrainerSpellMap::const_iterator iter = m_mCacheTrainerSpellMap.find(entry);
- if(iter == m_mCacheTrainerSpellMap.end())
- return NULL;
-
- return &iter->second;
- }
-
- VendorItemData const* GetNpcVendorItemList(uint32 entry) const
- {
- CacheVendorItemMap::const_iterator iter = m_mCacheVendorItemMap.find(entry);
- if(iter == m_mCacheVendorItemMap.end())
- return NULL;
-
- return &iter->second;
- }
- void AddVendorItem(uint32 entry,uint32 item, uint32 maxcount, uint32 incrtime, uint32 ExtendedCost, bool savetodb = true); // for event
- bool RemoveVendorItem(uint32 entry,uint32 item, bool savetodb = true); // for event
- bool IsVendorItemValid( uint32 vendor_entry, uint32 item, uint32 maxcount, uint32 ptime, uint32 ExtendedCost, Player* pl = NULL, std::set<uint32>* skip_vendors = NULL, uint32 ORnpcflag = 0 ) const;
-
- void LoadScriptNames();
- ScriptNameMap &GetScriptNames() { return m_scriptNames; }
- const char * GetScriptName(uint32 id) { return id < m_scriptNames.size() ? m_scriptNames[id].c_str() : ""; }
- uint32 GetScriptId(const char *name);
- protected:
-
- // first free id for selected id type
- uint32 m_auctionid;
- uint32 m_mailid;
- uint32 m_ItemTextId;
- uint32 m_arenaTeamId;
- uint32 m_guildId;
- uint32 m_hiPetNumber;
-
- // first free low guid for seelcted guid type
- uint32 m_hiCharGuid;
- uint32 m_hiCreatureGuid;
- uint32 m_hiPetGuid;
- uint32 m_hiItemGuid;
- uint32 m_hiGoGuid;
- uint32 m_hiDoGuid;
- uint32 m_hiCorpseGuid;
-
- QuestMap mQuestTemplates;
-
- typedef UNORDERED_MAP<uint32, GossipText*> GossipTextMap;
- typedef UNORDERED_MAP<uint32, uint32> QuestAreaTriggerMap;
- typedef UNORDERED_MAP<uint32, uint32> BattleMastersMap;
- typedef UNORDERED_MAP<uint32, std::string> ItemTextMap;
- typedef std::set<uint32> TavernAreaTriggerSet;
- typedef std::set<uint32> GameObjectForQuestSet;
-
- GroupSet mGroupSet;
- GuildSet mGuildSet;
- ArenaTeamSet mArenaTeamSet;
-
- ItemMap mItems;
- ItemMap mAitems;
-
- ItemTextMap mItemTexts;
-
- AuctionHouseObject mHordeAuctions;
- AuctionHouseObject mAllianceAuctions;
- AuctionHouseObject mNeutralAuctions;
-
- QuestAreaTriggerMap mQuestAreaTriggerMap;
- BattleMastersMap mBattleMastersMap;
- TavernAreaTriggerSet mTavernAreaTriggerSet;
- GameObjectForQuestSet mGameObjectForQuestSet;
- GossipTextMap mGossipText;
- AreaTriggerMap mAreaTriggers;
- AreaTriggerScriptMap mAreaTriggerScripts;
-
- RepOnKillMap mRepOnKill;
-
- WeatherZoneMap mWeatherZoneMap;
-
- PetCreateSpellMap mPetCreateSpell;
-
- //character reserved names
- typedef std::set<std::string> ReservedNamesMap;
- ReservedNamesMap m_ReservedNames;
-
- std::set<uint32> m_DisabledPlayerSpells;
- std::set<uint32> m_DisabledCreatureSpells;
-
- GraveYardMap mGraveYardMap;
-
- GameTeleMap m_GameTeleMap;
-
- ScriptNameMap m_scriptNames;
-
- typedef std::vector<LocaleConstant> LocalForIndex;
- LocalForIndex m_LocalForIndex;
- int GetOrNewIndexForLocale(LocaleConstant loc);
-
- int DBCLocaleIndex;
- private:
- void LoadScripts(ScriptMapMap& scripts, char const* tablename);
- void CheckScripts(ScriptMapMap const& scripts,std::set<int32>& ids);
- void ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr);
- void LoadQuestRelationsHelper(QuestRelations& map,char const* table);
-
- typedef std::map<uint32,PetLevelInfo*> PetLevelInfoMap;
- // PetLevelInfoMap[creature_id][level]
- PetLevelInfoMap petInfo; // [creature_id][level]
-
- PlayerClassInfo playerClassInfo[MAX_CLASSES];
-
- void BuildPlayerLevelInfo(uint8 race, uint8 class_, uint8 level, PlayerLevelInfo* plinfo) const;
- PlayerInfo playerInfo[MAX_RACES][MAX_CLASSES];
-
- typedef std::map<uint32,uint32> BaseXPMap; // [area level][base xp]
- BaseXPMap mBaseXPTable;
-
- typedef std::map<uint32,int32> FishingBaseSkillMap; // [areaId][base skill level]
- FishingBaseSkillMap mFishingBaseForArea;
-
- typedef std::map<uint32,std::vector<std::string> > HalfNameMap;
- HalfNameMap PetHalfName0;
- HalfNameMap PetHalfName1;
-
- MapObjectGuids mMapObjectGuids;
- CreatureDataMap mCreatureDataMap;
- CreatureLocaleMap mCreatureLocaleMap;
- GameObjectDataMap mGameObjectDataMap;
- GameObjectLocaleMap mGameObjectLocaleMap;
- ItemLocaleMap mItemLocaleMap;
- QuestLocaleMap mQuestLocaleMap;
- NpcTextLocaleMap mNpcTextLocaleMap;
- PageTextLocaleMap mPageTextLocaleMap;
- TrinityStringLocaleMap mTrinityStringLocaleMap;
- NpcOptionLocaleMap mNpcOptionLocaleMap;
- RespawnTimes mCreatureRespawnTimes;
- RespawnTimes mGORespawnTimes;
-
- typedef std::vector<uint32> GuildBankTabPriceMap;
- GuildBankTabPriceMap mGuildBankTabPrice;
-
- // Storage for Conditions. First element (index 0) is reserved for zero-condition (nothing required)
- typedef std::vector<PlayerCondition> ConditionStore;
- ConditionStore mConditions;
-
- CacheNpcOptionList m_mCacheNpcOptionList;
- CacheNpcTextIdMap m_mCacheNpcTextIdMap;
- CacheVendorItemMap m_mCacheVendorItemMap;
- CacheTrainerSpellMap m_mCacheTrainerSpellMap;
-};
-
-#define objmgr Trinity::Singleton<ObjectMgr>::Instance()
-
-// scripting access functions
-TRINITY_DLL_SPEC bool LoadTrinityStrings(DatabaseType& db, char const* table,int32 start_value = -1, int32 end_value = std::numeric_limits<int32>::min());
-TRINITY_DLL_SPEC uint32 GetAreaTriggerScriptId(uint32 trigger_id);
-TRINITY_DLL_SPEC uint32 GetScriptId(const char *name);
-TRINITY_DLL_SPEC ObjectMgr::ScriptNameMap& GetScriptNames();
-
-#endif
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ *
+ * 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
+ */
+
+#ifndef _OBJECTMGR_H
+#define _OBJECTMGR_H
+
+#include "Log.h"
+#include "Object.h"
+#include "Bag.h"
+#include "Creature.h"
+#include "Player.h"
+#include "DynamicObject.h"
+#include "GameObject.h"
+#include "Corpse.h"
+#include "QuestDef.h"
+#include "Path.h"
+#include "ItemPrototype.h"
+#include "NPCHandler.h"
+#include "Database/DatabaseEnv.h"
+#include "AuctionHouseObject.h"
+#include "Mail.h"
+#include "Map.h"
+#include "ObjectAccessor.h"
+#include "ObjectDefines.h"
+#include "Policies/Singleton.h"
+#include "Database/SQLStorage.h"
+
+#include <string>
+#include <map>
+#include <limits>
+
+extern SQLStorage sCreatureStorage;
+extern SQLStorage sCreatureDataAddonStorage;
+extern SQLStorage sCreatureInfoAddonStorage;
+extern SQLStorage sCreatureModelStorage;
+extern SQLStorage sEquipmentStorage;
+extern SQLStorage sGOStorage;
+extern SQLStorage sPageTextStore;
+extern SQLStorage sItemStorage;
+extern SQLStorage sInstanceTemplate;
+
+class Group;
+class Guild;
+class ArenaTeam;
+class Path;
+class TransportPath;
+class Item;
+
+struct GameTele
+{
+ float position_x;
+ float position_y;
+ float position_z;
+ float orientation;
+ uint32 mapId;
+ std::string name;
+ std::wstring wnameLow;
+};
+
+typedef UNORDERED_MAP<uint32, GameTele > GameTeleMap;
+typedef std::list<GossipOption> CacheNpcOptionList;
+
+struct ScriptInfo
+{
+ uint32 id;
+ uint32 delay;
+ uint32 command;
+ uint32 datalong;
+ uint32 datalong2;
+ int32 dataint;
+ float x;
+ float y;
+ float z;
+ float o;
+};
+
+typedef std::multimap<uint32, ScriptInfo> ScriptMap;
+typedef std::map<uint32, ScriptMap > ScriptMapMap;
+extern ScriptMapMap sQuestEndScripts;
+extern ScriptMapMap sQuestStartScripts;
+extern ScriptMapMap sSpellScripts;
+extern ScriptMapMap sGameObjectScripts;
+extern ScriptMapMap sEventScripts;
+
+struct AreaTrigger
+{
+ uint8 requiredLevel;
+ uint32 requiredItem;
+ uint32 requiredItem2;
+ uint32 heroicKey;
+ uint32 heroicKey2;
+ uint32 requiredQuest;
+ std::string requiredFailedText;
+ uint32 target_mapId;
+ float target_X;
+ float target_Y;
+ float target_Z;
+ float target_Orientation;
+};
+
+typedef std::set<uint32> CellGuidSet;
+typedef std::map<uint32/*player guid*/,uint32/*instance*/> CellCorpseSet;
+struct CellObjectGuids
+{
+ CellGuidSet creatures;
+ CellGuidSet gameobjects;
+ CellCorpseSet corpses;
+};
+typedef UNORDERED_MAP<uint32/*cell_id*/,CellObjectGuids> CellObjectGuidsMap;
+typedef UNORDERED_MAP<uint32/*(mapid,spawnMode) pair*/,CellObjectGuidsMap> MapObjectGuids;
+
+typedef UNORDERED_MAP<uint64/*(instance,guid) pair*/,time_t> RespawnTimes;
+
+
+// mangos string ranges
+#define MIN_TRINITY_STRING_ID 1
+#define MAX_TRINITY_STRING_ID 2000000000
+#define MIN_DB_SCRIPT_STRING_ID MAX_TRINITY_STRING_ID
+#define MAX_DB_SCRIPT_STRING_ID 2000010000
+
+struct TrinityStringLocale
+{
+ std::vector<std::string> Content; // 0 -> default, i -> i-1 locale index
+};
+
+typedef UNORDERED_MAP<uint32,CreatureData> CreatureDataMap;
+typedef UNORDERED_MAP<uint32,GameObjectData> GameObjectDataMap;
+typedef UNORDERED_MAP<uint32,CreatureLocale> CreatureLocaleMap;
+typedef UNORDERED_MAP<uint32,GameObjectLocale> GameObjectLocaleMap;
+typedef UNORDERED_MAP<uint32,ItemLocale> ItemLocaleMap;
+typedef UNORDERED_MAP<uint32,QuestLocale> QuestLocaleMap;
+typedef UNORDERED_MAP<uint32,NpcTextLocale> NpcTextLocaleMap;
+typedef UNORDERED_MAP<uint32,PageTextLocale> PageTextLocaleMap;
+typedef UNORDERED_MAP<uint32,TrinityStringLocale> TrinityStringLocaleMap;
+typedef UNORDERED_MAP<uint32,NpcOptionLocale> NpcOptionLocaleMap;
+
+typedef std::multimap<uint32,uint32> QuestRelations;
+
+struct PetLevelInfo
+{
+ PetLevelInfo() : health(0), mana(0) { for(int i=0; i < MAX_STATS; ++i ) stats[i] = 0; }
+
+ uint16 stats[MAX_STATS];
+ uint16 health;
+ uint16 mana;
+ uint16 armor;
+};
+
+struct ReputationOnKillEntry
+{
+ uint32 repfaction1;
+ uint32 repfaction2;
+ bool is_teamaward1;
+ uint32 reputation_max_cap1;
+ int32 repvalue1;
+ bool is_teamaward2;
+ uint32 reputation_max_cap2;
+ int32 repvalue2;
+ bool team_dependent;
+};
+
+struct PetCreateSpellEntry
+{
+ uint32 spellid[4];
+};
+
+#define WEATHER_SEASONS 4
+struct WeatherSeasonChances
+{
+ uint32 rainChance;
+ uint32 snowChance;
+ uint32 stormChance;
+};
+
+struct WeatherZoneChances
+{
+ WeatherSeasonChances data[WEATHER_SEASONS];
+};
+
+struct GraveYardData
+{
+ uint32 safeLocId;
+ uint32 team;
+};
+typedef std::multimap<uint32,GraveYardData> GraveYardMap;
+
+enum ConditionType
+{ // value1 value2 for the Condition enumed
+ CONDITION_NONE = 0, // 0 0
+ CONDITION_AURA = 1, // spell_id effindex
+ CONDITION_ITEM = 2, // item_id count
+ CONDITION_ITEM_EQUIPPED = 3, // item_id 0
+ CONDITION_ZONEID = 4, // zone_id 0
+ CONDITION_REPUTATION_RANK = 5, // faction_id min_rank
+ CONDITION_TEAM = 6, // player_team 0, (469 - Alliance 67 - Horde)
+ CONDITION_SKILL = 7, // skill_id skill_value
+ CONDITION_QUESTREWARDED = 8, // quest_id 0
+ CONDITION_QUESTTAKEN = 9, // quest_id 0, for condition true while quest active.
+ CONDITION_AD_COMMISSION_AURA = 10, // 0 0, for condition true while one from AD ñommission aura active
+ CONDITION_NO_AURA = 11, // spell_id effindex
+ CONDITION_ACTIVE_EVENT = 12, // event_id
+ CONDITION_INSTANCE_DATA = 13, // entry data
+};
+
+#define MAX_CONDITION 14 // maximum value in ConditionType enum
+
+//Player's info
+typedef struct _tagCachePlayerInfo
+{
+ std::string sPlayerName;
+ uint32 unfield;
+ uint32 unLevel;
+ uint8 unClass;
+//Arena
+ uint32 unArenaInfoId0;
+ uint32 unArenaInfoId1;
+ uint32 unArenaInfoId2;
+ uint32 unArenaInfoSlot0;
+ uint32 unArenaInfoSlot1;
+ uint32 unArenaInfoSlot2;
+}CachePlayerInfo, *PCachePlayerInfo;
+typedef UNORDERED_MAP<uint32, PCachePlayerInfo> CachePlayerInfoMap;
+
+struct PlayerCondition
+{
+ ConditionType condition; // additional condition type
+ uint32 value1; // data for the condition - see ConditionType definition
+ uint32 value2;
+
+ PlayerCondition(uint8 _condition = 0, uint32 _value1 = 0, uint32 _value2 = 0)
+ : condition(ConditionType(_condition)), value1(_value1), value2(_value2) {}
+
+ static bool IsValid(ConditionType condition, uint32 value1, uint32 value2);
+ // Checks correctness of values
+ bool Meets(Player const * APlayer) const; // Checks if the player meets the condition
+ bool operator == (PlayerCondition const& lc) const
+ {
+ return (lc.condition == condition && lc.value1 == value1 && lc.value2 == value2);
+ }
+};
+
+// NPC gossip text id
+typedef UNORDERED_MAP<uint32, uint32> CacheNpcTextIdMap;
+typedef std::list<GossipOption> CacheNpcOptionList;
+
+typedef UNORDERED_MAP<uint32, VendorItemData> CacheVendorItemMap;
+typedef UNORDERED_MAP<uint32, TrainerSpellData> CacheTrainerSpellMap;
+
+enum SkillRangeType
+{
+ SKILL_RANGE_LANGUAGE, // 300..300
+ SKILL_RANGE_LEVEL, // 1..max skill for level
+ SKILL_RANGE_MONO, // 1..1, grey monolite bar
+ SKILL_RANGE_RANK, // 1..skill for known rank
+ SKILL_RANGE_NONE, // 0..0 always
+};
+
+SkillRangeType GetSkillRangeType(SkillLineEntry const *pSkill, bool racial);
+
+#define MAX_PLAYER_NAME 12 // max allowed by client name length
+#define MAX_INTERNAL_PLAYER_NAME 15 // max server internal player name length ( > MAX_PLAYER_NAME for support declined names )
+
+bool normalizePlayerName(std::string& name);
+
+struct TRINITY_DLL_SPEC LanguageDesc
+{
+ Language lang_id;
+ uint32 spell_id;
+ uint32 skill_id;
+};
+
+extern LanguageDesc lang_description[LANGUAGES_COUNT];
+TRINITY_DLL_SPEC LanguageDesc const* GetLanguageDescByID(uint32 lang);
+
+class PlayerDumpReader;
+
+class ObjectMgr
+{
+ friend class PlayerDumpReader;
+
+ public:
+ ObjectMgr();
+ ~ObjectMgr();
+
+ typedef UNORDERED_MAP<uint32, Item*> ItemMap;
+
+ typedef std::set< Group * > GroupSet;
+ typedef std::set< Guild * > GuildSet;
+ typedef std::set< ArenaTeam * > ArenaTeamSet;
+
+ typedef UNORDERED_MAP<uint32, Quest*> QuestMap;
+
+
+ typedef UNORDERED_MAP<uint32, AreaTrigger> AreaTriggerMap;
+
+ typedef UNORDERED_MAP<uint32, uint32> AreaTriggerScriptMap;
+
+ typedef UNORDERED_MAP<uint32, ReputationOnKillEntry> RepOnKillMap;
+
+ typedef UNORDERED_MAP<uint32, WeatherZoneChances> WeatherZoneMap;
+
+ typedef UNORDERED_MAP<uint32, PetCreateSpellEntry> PetCreateSpellMap;
+
+ typedef std::vector<std::string> ScriptNameMap;
+
+ Player* GetPlayer(const char* name) const { return ObjectAccessor::Instance().FindPlayerByName(name);}
+ Player* GetPlayer(uint64 guid) const { return ObjectAccessor::FindPlayer(guid); }
+
+ static GameObjectInfo const *GetGameObjectInfo(uint32 id) { return sGOStorage.LookupEntry<GameObjectInfo>(id); }
+
+ void LoadGameobjectInfo();
+ void AddGameobjectInfo(GameObjectInfo *goinfo);
+
+ Group * GetGroupByLeader(const uint64 &guid) const;
+ void AddGroup(Group* group) { mGroupSet.insert( group ); }
+ void RemoveGroup(Group* group) { mGroupSet.erase( group ); }
+
+ Guild* GetGuildByLeader(uint64 const&guid) const;
+ Guild* GetGuildById(const uint32 GuildId) const;
+ Guild* GetGuildByName(std::string guildname) const;
+ std::string GetGuildNameById(const uint32 GuildId) const;
+ void AddGuild(Guild* guild) { mGuildSet.insert( guild ); }
+ void RemoveGuild(Guild* guild) { mGuildSet.erase( guild ); }
+
+ ArenaTeam* GetArenaTeamById(const uint32 ArenaTeamId) const;
+ ArenaTeam* GetArenaTeamByName(std::string ArenaTeamName) const;
+ ArenaTeam* GetArenaTeamByCapitan(uint64 const& guid) const;
+ void AddArenaTeam(ArenaTeam* arenateam) { mArenaTeamSet.insert( arenateam ); }
+ void RemoveArenaTeam(ArenaTeam* arenateam) { mArenaTeamSet.erase( arenateam ); }
+ ArenaTeamSet::iterator GetArenaTeamSetBegin() { return mArenaTeamSet.begin(); }
+ ArenaTeamSet::iterator GetArenaTeamSetEnd() { return mArenaTeamSet.end(); }
+
+ static CreatureInfo const *GetCreatureTemplate( uint32 id );
+ CreatureModelInfo const *GetCreatureModelInfo( uint32 modelid );
+ CreatureModelInfo const* GetCreatureModelRandomGender(uint32 display_id);
+ uint32 ChooseDisplayId(uint32 team, const CreatureInfo *cinfo, const CreatureData *data = NULL);
+ EquipmentInfo const *GetEquipmentInfo( uint32 entry );
+ static CreatureDataAddon const *GetCreatureAddon( uint32 lowguid )
+ {
+ return sCreatureDataAddonStorage.LookupEntry<CreatureDataAddon>(lowguid);
+ }
+
+ static CreatureDataAddon const *GetCreatureTemplateAddon( uint32 entry )
+ {
+ return sCreatureInfoAddonStorage.LookupEntry<CreatureDataAddon>(entry);
+ }
+
+ static ItemPrototype const* GetItemPrototype(uint32 id) { return sItemStorage.LookupEntry<ItemPrototype>(id); }
+
+ static InstanceTemplate const* GetInstanceTemplate(uint32 map)
+ {
+ return sInstanceTemplate.LookupEntry<InstanceTemplate>(map);
+ }
+
+ Item* GetAItem(uint32 id)
+ {
+ ItemMap::const_iterator itr = mAitems.find(id);
+ if (itr != mAitems.end())
+ {
+ return itr->second;
+ }
+ return NULL;
+ }
+ void AddAItem(Item* it)
+ {
+ ASSERT( it );
+ ASSERT( mAitems.find(it->GetGUIDLow()) == mAitems.end());
+ mAitems[it->GetGUIDLow()] = it;
+ }
+ bool RemoveAItem(uint32 id)
+ {
+ ItemMap::iterator i = mAitems.find(id);
+ if (i == mAitems.end())
+ {
+ return false;
+ }
+ mAitems.erase(i);
+ return true;
+ }
+ AuctionHouseObject * GetAuctionsMap( uint32 location );
+
+ //auction messages
+ void SendAuctionWonMail( AuctionEntry * auction );
+ void SendAuctionSalePendingMail( AuctionEntry * auction );
+ void SendAuctionSuccessfulMail( AuctionEntry * auction );
+ void SendAuctionExpiredMail( AuctionEntry * auction );
+ static uint32 GetAuctionCut( uint32 location, uint32 highBid );
+ static uint32 GetAuctionDeposit(uint32 location, uint32 time, Item *pItem);
+ static uint32 GetAuctionOutBid(uint32 currentBid);
+
+ PetLevelInfo const* GetPetLevelInfo(uint32 creature_id, uint32 level) const;
+
+ PlayerClassInfo const* GetPlayerClassInfo(uint32 class_) const
+ {
+ if(class_ >= MAX_CLASSES) return NULL;
+ return &playerClassInfo[class_];
+ }
+ void GetPlayerClassLevelInfo(uint32 class_,uint32 level, PlayerClassLevelInfo* info) const;
+
+ PlayerInfo const* GetPlayerInfo(uint32 race, uint32 class_) const
+ {
+ if(race >= MAX_RACES) return NULL;
+ if(class_ >= MAX_CLASSES) return NULL;
+ PlayerInfo const* info = &playerInfo[race][class_];
+ if(info->displayId_m==0 || info->displayId_f==0) return NULL;
+ return info;
+ }
+ void GetPlayerLevelInfo(uint32 race, uint32 class_,uint32 level, PlayerLevelInfo* info) const;
+
+ uint64 GetPlayerGUIDByName(std::string name) const;
+ bool GetPlayerNameByGUID(const uint64 &guid, std::string &name) const;
+ uint32 GetPlayerTeamByGUID(const uint64 &guid) const;
+ uint32 GetPlayerAccountIdByGUID(const uint64 &guid) const;
+ uint32 GetPlayerAccountIdByPlayerName(std::string name) const;
+
+ uint32 GetNearestTaxiNode( float x, float y, float z, uint32 mapid );
+ void GetTaxiPath( uint32 source, uint32 destination, uint32 &path, uint32 &cost);
+ uint16 GetTaxiMount( uint32 id, uint32 team );
+ void GetTaxiPathNodes( uint32 path, Path &pathnodes, std::vector<uint32>& mapIds );
+ void GetTransportPathNodes( uint32 path, TransportPath &pathnodes );
+
+ Quest const* GetQuestTemplate(uint32 quest_id) const
+ {
+ QuestMap::const_iterator itr = mQuestTemplates.find(quest_id);
+ return itr != mQuestTemplates.end() ? itr->second : NULL;
+ }
+ QuestMap const& GetQuestTemplates() const { return mQuestTemplates; }
+
+ uint32 GetQuestForAreaTrigger(uint32 Trigger_ID) const
+ {
+ QuestAreaTriggerMap::const_iterator itr = mQuestAreaTriggerMap.find(Trigger_ID);
+ if(itr != mQuestAreaTriggerMap.end())
+ return itr->second;
+ return 0;
+ }
+ bool IsTavernAreaTrigger(uint32 Trigger_ID) const { return mTavernAreaTriggerSet.count(Trigger_ID) != 0; }
+ bool IsGameObjectForQuests(uint32 entry) const { return mGameObjectForQuestSet.count(entry) != 0; }
+ bool IsGuildVaultGameObject(Player *player, uint64 guid) const
+ {
+ if(GameObject *go = ObjectAccessor::GetGameObject(*player, guid))
+ if(go->GetGoType() == GAMEOBJECT_TYPE_GUILD_BANK)
+ return true;
+ return false;
+ }
+
+ uint32 GetBattleMasterBG(uint32 entry) const
+ {
+ BattleMastersMap::const_iterator itr = mBattleMastersMap.find(entry);
+ if(itr != mBattleMastersMap.end())
+ return itr->second;
+ return 2; //BATTLEGROUND_WS - i will not add include only for constant usage!
+ }
+
+ void AddGossipText(GossipText *pGText);
+ GossipText *GetGossipText(uint32 Text_ID);
+
+ WorldSafeLocsEntry const *GetClosestGraveYard(float x, float y, float z, uint32 MapId, uint32 team);
+ bool AddGraveYardLink(uint32 id, uint32 zone, uint32 team, bool inDB = true);
+ void RemoveGraveYardLink(uint32 id, uint32 zone, uint32 team, bool inDB = false);
+ void LoadGraveyardZones();
+ GraveYardData const* FindGraveYardData(uint32 id, uint32 zone);
+
+ AreaTrigger const* GetAreaTrigger(uint32 trigger) const
+ {
+ AreaTriggerMap::const_iterator itr = mAreaTriggers.find( trigger );
+ if( itr != mAreaTriggers.end( ) )
+ return &itr->second;
+ return NULL;
+ }
+
+ AreaTrigger const* GetGoBackTrigger(uint32 Map) const;
+
+ uint32 GetAreaTriggerScriptId(uint32 trigger_id);
+
+ ReputationOnKillEntry const* GetReputationOnKilEntry(uint32 id) const
+ {
+ RepOnKillMap::const_iterator itr = mRepOnKill.find(id);
+ if(itr != mRepOnKill.end())
+ return &itr->second;
+ return NULL;
+ }
+
+ PetCreateSpellEntry const* GetPetCreateSpellEntry(uint32 id) const
+ {
+ PetCreateSpellMap::const_iterator itr = mPetCreateSpell.find(id);
+ if(itr != mPetCreateSpell.end())
+ return &itr->second;
+ return NULL;
+ }
+
+ void LoadGuilds();
+ void LoadArenaTeams();
+ void LoadGroups();
+ void LoadQuests();
+ void LoadQuestRelations()
+ {
+ LoadGameobjectQuestRelations();
+ LoadGameobjectInvolvedRelations();
+ LoadCreatureQuestRelations();
+ LoadCreatureInvolvedRelations();
+ }
+ void LoadGameobjectQuestRelations();
+ void LoadGameobjectInvolvedRelations();
+ void LoadCreatureQuestRelations();
+ void LoadCreatureInvolvedRelations();
+
+ QuestRelations mGOQuestRelations;
+ QuestRelations mGOQuestInvolvedRelations;
+ QuestRelations mCreatureQuestRelations;
+ QuestRelations mCreatureQuestInvolvedRelations;
+
+ void LoadGameObjectScripts();
+ void LoadQuestEndScripts();
+ void LoadQuestStartScripts();
+ void LoadEventScripts();
+ void LoadSpellScripts();
+
+ bool LoadTrinityStrings(DatabaseType& db, char const* table, int32 min_value, int32 max_value);
+ bool LoadTrinityStrings() { return LoadTrinityStrings(WorldDatabase,"trinity_string",MIN_TRINITY_STRING_ID,MAX_TRINITY_STRING_ID); }
+ void LoadDbScriptStrings();
+ void LoadPetCreateSpells();
+ void LoadCreatureLocales();
+ void LoadCreatureTemplates();
+ void LoadCreatures();
+ void LoadCreatureRespawnTimes();
+ void LoadCreatureAddons();
+ void LoadCreatureModelInfo();
+ void LoadEquipmentTemplates();
+ void LoadGameObjectLocales();
+ void LoadGameobjects();
+ void LoadGameobjectRespawnTimes();
+ void LoadItemPrototypes();
+ void LoadItemLocales();
+ void LoadQuestLocales();
+ void LoadNpcTextLocales();
+ void LoadPageTextLocales();
+ void LoadNpcOptionLocales();
+ void LoadInstanceTemplate();
+
+ void LoadGossipText();
+
+ void LoadAreaTriggerTeleports();
+ void LoadQuestAreaTriggers();
+ void LoadAreaTriggerScripts();
+ void LoadTavernAreaTriggers();
+ void LoadBattleMastersEntry();
+ void LoadGameObjectForQuests();
+
+ void LoadItemTexts();
+ void LoadPageTexts();
+
+ //load first auction items, because of check if item exists, when loading
+ void LoadAuctionItems();
+ void LoadAuctions();
+ void LoadPlayerInfo();
+ void LoadPetLevelInfo();
+ void LoadExplorationBaseXP();
+ void LoadPetNames();
+ void LoadPetNumber();
+ void LoadCorpses();
+ void LoadFishingBaseSkillLevel();
+
+ void LoadReputationOnKill();
+
+ void LoadWeatherZoneChances();
+ void LoadGameTele();
+
+ void LoadNpcOptions();
+ void LoadNpcTextId();
+ void LoadVendors();
+ void LoadTrainerSpell();
+
+ std::string GeneratePetName(uint32 entry);
+ uint32 GetBaseXP(uint32 level);
+
+ int32 GetFishingBaseSkillLevel(uint32 entry) const
+ {
+ FishingBaseSkillMap::const_iterator itr = mFishingBaseForArea.find(entry);
+ return itr != mFishingBaseForArea.end() ? itr->second : 0;
+ }
+
+ void ReturnOrDeleteOldMails(bool serverUp);
+
+ void SetHighestGuids();
+ uint32 GenerateLowGuid(HighGuid guidhigh);
+ uint32 GenerateAuctionID();
+ uint32 GenerateMailID();
+ uint32 GenerateItemTextID();
+ uint32 GeneratePetNumber();
+ uint32 GenerateArenaTeamId();
+ uint32 GenerateGuildId();
+
+ void LoadPlayerInfoInCache();
+ PCachePlayerInfo GetPlayerInfoFromCache(uint32 unPlayerGuid) const;
+ CachePlayerInfoMap m_mPlayerInfoMap;
+
+ uint32 CreateItemText(std::string text);
+ std::string GetItemText( uint32 id )
+ {
+ ItemTextMap::const_iterator itr = mItemTexts.find( id );
+ if ( itr != mItemTexts.end() )
+ return itr->second;
+ else
+ return "There is no info for this item";
+ }
+
+ typedef std::multimap<int32, uint32> ExclusiveQuestGroups;
+ ExclusiveQuestGroups mExclusiveQuestGroups;
+
+ WeatherZoneChances const* GetWeatherChances(uint32 zone_id) const
+ {
+ WeatherZoneMap::const_iterator itr = mWeatherZoneMap.find(zone_id);
+ if(itr != mWeatherZoneMap.end())
+ return &itr->second;
+ else
+ return NULL;
+ }
+
+ CellObjectGuids const& GetCellObjectGuids(uint16 mapid, uint8 spawnMode, uint32 cell_id)
+ {
+ return mMapObjectGuids[MAKE_PAIR32(mapid,spawnMode)][cell_id];
+ }
+
+ CreatureData const* GetCreatureData(uint32 guid) const
+ {
+ CreatureDataMap::const_iterator itr = mCreatureDataMap.find(guid);
+ if(itr==mCreatureDataMap.end()) return NULL;
+ return &itr->second;
+ }
+ CreatureData& NewOrExistCreatureData(uint32 guid) { return mCreatureDataMap[guid]; }
+ void DeleteCreatureData(uint32 guid);
+ CreatureLocale const* GetCreatureLocale(uint32 entry) const
+ {
+ CreatureLocaleMap::const_iterator itr = mCreatureLocaleMap.find(entry);
+ if(itr==mCreatureLocaleMap.end()) return NULL;
+ return &itr->second;
+ }
+ GameObjectLocale const* GetGameObjectLocale(uint32 entry) const
+ {
+ GameObjectLocaleMap::const_iterator itr = mGameObjectLocaleMap.find(entry);
+ if(itr==mGameObjectLocaleMap.end()) return NULL;
+ return &itr->second;
+ }
+ ItemLocale const* GetItemLocale(uint32 entry) const
+ {
+ ItemLocaleMap::const_iterator itr = mItemLocaleMap.find(entry);
+ if(itr==mItemLocaleMap.end()) return NULL;
+ return &itr->second;
+ }
+ QuestLocale const* GetQuestLocale(uint32 entry) const
+ {
+ QuestLocaleMap::const_iterator itr = mQuestLocaleMap.find(entry);
+ if(itr==mQuestLocaleMap.end()) return NULL;
+ return &itr->second;
+ }
+ NpcTextLocale const* GetNpcTextLocale(uint32 entry) const
+ {
+ NpcTextLocaleMap::const_iterator itr = mNpcTextLocaleMap.find(entry);
+ if(itr==mNpcTextLocaleMap.end()) return NULL;
+ return &itr->second;
+ }
+ PageTextLocale const* GetPageTextLocale(uint32 entry) const
+ {
+ PageTextLocaleMap::const_iterator itr = mPageTextLocaleMap.find(entry);
+ if(itr==mPageTextLocaleMap.end()) return NULL;
+ return &itr->second;
+ }
+ NpcOptionLocale const* GetNpcOptionLocale(uint32 entry) const
+ {
+ NpcOptionLocaleMap::const_iterator itr = mNpcOptionLocaleMap.find(entry);
+ if(itr==mNpcOptionLocaleMap.end()) return NULL;
+ return &itr->second;
+ }
+
+ GameObjectData const* GetGOData(uint32 guid) const
+ {
+ GameObjectDataMap::const_iterator itr = mGameObjectDataMap.find(guid);
+ if(itr==mGameObjectDataMap.end()) return NULL;
+ return &itr->second;
+ }
+ GameObjectData& NewGOData(uint32 guid) { return mGameObjectDataMap[guid]; }
+ void DeleteGOData(uint32 guid);
+
+ TrinityStringLocale const* GetTrinityStringLocale(int32 entry) const
+ {
+ TrinityStringLocaleMap::const_iterator itr = mTrinityStringLocaleMap.find(entry);
+ if(itr==mTrinityStringLocaleMap.end()) return NULL;
+ return &itr->second;
+ }
+ const char *GetTrinityString(int32 entry, int locale_idx) const;
+ const char *GetTrinityStringForDBCLocale(int32 entry) const { return GetTrinityString(entry,DBCLocaleIndex); }
+ int32 GetDBCLocaleIndex() const { return DBCLocaleIndex; }
+ void SetDBCLocaleIndex(uint32 lang) { DBCLocaleIndex = GetIndexForLocale(LocaleConstant(lang)); }
+
+ void AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance);
+ void DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid);
+
+ time_t GetCreatureRespawnTime(uint32 loguid, uint32 instance) { return mCreatureRespawnTimes[MAKE_PAIR64(loguid,instance)]; }
+ void SaveCreatureRespawnTime(uint32 loguid, uint32 instance, time_t t);
+ time_t GetGORespawnTime(uint32 loguid, uint32 instance) { return mGORespawnTimes[MAKE_PAIR64(loguid,instance)]; }
+ void SaveGORespawnTime(uint32 loguid, uint32 instance, time_t t);
+ void DeleteRespawnTimeForInstance(uint32 instance);
+
+ // grid objects
+ void AddCreatureToGrid(uint32 guid, CreatureData const* data);
+ void RemoveCreatureFromGrid(uint32 guid, CreatureData const* data);
+ void AddGameobjectToGrid(uint32 guid, GameObjectData const* data);
+ void RemoveGameobjectFromGrid(uint32 guid, GameObjectData const* data);
+
+ // reserved names
+ void LoadReservedPlayersNames();
+ bool IsReservedName(std::string name) const
+ {
+ return m_ReservedNames.find(name) != m_ReservedNames.end();
+ }
+
+ // name with valid structure and symbols
+ static bool IsValidName( std::string name, bool create = false );
+ static bool IsValidCharterName( std::string name );
+ static bool IsValidPetName( std::string name );
+
+ static bool CheckDeclinedNames(std::wstring mainpart, DeclinedName const& names);
+
+ void LoadSpellDisabledEntrys();
+ bool IsPlayerSpellDisabled(uint32 spellid) { return (m_DisabledPlayerSpells.count(spellid) != 0); }
+ bool IsCreatureSpellDisabled(uint32 spellid) { return (m_DisabledCreatureSpells.count(spellid) != 0); }
+
+ int GetIndexForLocale(LocaleConstant loc);
+ LocaleConstant GetLocaleForIndex(int i);
+ // guild bank tabs
+ uint32 GetGuildBankTabPrice(uint8 Index) const { return Index < GUILD_BANK_MAX_TABS ? mGuildBankTabPrice[Index] : 0; }
+
+ uint16 GetConditionId(ConditionType condition, uint32 value1, uint32 value2);
+ bool IsPlayerMeetToCondition(Player const* player, uint16 condition_id) const
+ {
+ if(condition_id >= mConditions.size())
+ return false;
+
+ return mConditions[condition_id].Meets(player);
+ }
+
+ GameTele const* GetGameTele(uint32 id) const
+ {
+ GameTeleMap::const_iterator itr = m_GameTeleMap.find(id);
+ if(itr==m_GameTeleMap.end()) return NULL;
+ return &itr->second;
+ }
+ GameTele const* GetGameTele(std::string name) const;
+ GameTeleMap const& GetGameTeleMap() const { return m_GameTeleMap; }
+ bool AddGameTele(GameTele& data);
+ bool DeleteGameTele(std::string name);
+
+ CacheNpcOptionList const& GetNpcOptions() const { return m_mCacheNpcOptionList; }
+
+ uint32 GetNpcGossip(uint32 entry) const
+ {
+ CacheNpcTextIdMap::const_iterator iter = m_mCacheNpcTextIdMap.find(entry);
+ if(iter == m_mCacheNpcTextIdMap.end())
+ return 0;
+
+ return iter->second;
+ }
+
+ TrainerSpellData const* GetNpcTrainerSpells(uint32 entry) const
+ {
+ CacheTrainerSpellMap::const_iterator iter = m_mCacheTrainerSpellMap.find(entry);
+ if(iter == m_mCacheTrainerSpellMap.end())
+ return NULL;
+
+ return &iter->second;
+ }
+
+ VendorItemData const* GetNpcVendorItemList(uint32 entry) const
+ {
+ CacheVendorItemMap::const_iterator iter = m_mCacheVendorItemMap.find(entry);
+ if(iter == m_mCacheVendorItemMap.end())
+ return NULL;
+
+ return &iter->second;
+ }
+ void AddVendorItem(uint32 entry,uint32 item, uint32 maxcount, uint32 incrtime, uint32 ExtendedCost, bool savetodb = true); // for event
+ bool RemoveVendorItem(uint32 entry,uint32 item, bool savetodb = true); // for event
+ bool IsVendorItemValid( uint32 vendor_entry, uint32 item, uint32 maxcount, uint32 ptime, uint32 ExtendedCost, Player* pl = NULL, std::set<uint32>* skip_vendors = NULL, uint32 ORnpcflag = 0 ) const;
+
+ void LoadScriptNames();
+ ScriptNameMap &GetScriptNames() { return m_scriptNames; }
+ const char * GetScriptName(uint32 id) { return id < m_scriptNames.size() ? m_scriptNames[id].c_str() : ""; }
+ uint32 GetScriptId(const char *name);
+ protected:
+
+ // first free id for selected id type
+ uint32 m_auctionid;
+ uint32 m_mailid;
+ uint32 m_ItemTextId;
+ uint32 m_arenaTeamId;
+ uint32 m_guildId;
+ uint32 m_hiPetNumber;
+
+ // first free low guid for seelcted guid type
+ uint32 m_hiCharGuid;
+ uint32 m_hiCreatureGuid;
+ uint32 m_hiPetGuid;
+ uint32 m_hiItemGuid;
+ uint32 m_hiGoGuid;
+ uint32 m_hiDoGuid;
+ uint32 m_hiCorpseGuid;
+
+ QuestMap mQuestTemplates;
+
+ typedef UNORDERED_MAP<uint32, GossipText*> GossipTextMap;
+ typedef UNORDERED_MAP<uint32, uint32> QuestAreaTriggerMap;
+ typedef UNORDERED_MAP<uint32, uint32> BattleMastersMap;
+ typedef UNORDERED_MAP<uint32, std::string> ItemTextMap;
+ typedef std::set<uint32> TavernAreaTriggerSet;
+ typedef std::set<uint32> GameObjectForQuestSet;
+
+ GroupSet mGroupSet;
+ GuildSet mGuildSet;
+ ArenaTeamSet mArenaTeamSet;
+
+ ItemMap mItems;
+ ItemMap mAitems;
+
+ ItemTextMap mItemTexts;
+
+ AuctionHouseObject mHordeAuctions;
+ AuctionHouseObject mAllianceAuctions;
+ AuctionHouseObject mNeutralAuctions;
+
+ QuestAreaTriggerMap mQuestAreaTriggerMap;
+ BattleMastersMap mBattleMastersMap;
+ TavernAreaTriggerSet mTavernAreaTriggerSet;
+ GameObjectForQuestSet mGameObjectForQuestSet;
+ GossipTextMap mGossipText;
+ AreaTriggerMap mAreaTriggers;
+ AreaTriggerScriptMap mAreaTriggerScripts;
+
+ RepOnKillMap mRepOnKill;
+
+ WeatherZoneMap mWeatherZoneMap;
+
+ PetCreateSpellMap mPetCreateSpell;
+
+ //character reserved names
+ typedef std::set<std::string> ReservedNamesMap;
+ ReservedNamesMap m_ReservedNames;
+
+ std::set<uint32> m_DisabledPlayerSpells;
+ std::set<uint32> m_DisabledCreatureSpells;
+
+ GraveYardMap mGraveYardMap;
+
+ GameTeleMap m_GameTeleMap;
+
+ ScriptNameMap m_scriptNames;
+
+ typedef std::vector<LocaleConstant> LocalForIndex;
+ LocalForIndex m_LocalForIndex;
+ int GetOrNewIndexForLocale(LocaleConstant loc);
+
+ int DBCLocaleIndex;
+ private:
+ void LoadScripts(ScriptMapMap& scripts, char const* tablename);
+ void CheckScripts(ScriptMapMap const& scripts,std::set<int32>& ids);
+ void ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr);
+ void LoadQuestRelationsHelper(QuestRelations& map,char const* table);
+
+ typedef std::map<uint32,PetLevelInfo*> PetLevelInfoMap;
+ // PetLevelInfoMap[creature_id][level]
+ PetLevelInfoMap petInfo; // [creature_id][level]
+
+ PlayerClassInfo playerClassInfo[MAX_CLASSES];
+
+ void BuildPlayerLevelInfo(uint8 race, uint8 class_, uint8 level, PlayerLevelInfo* plinfo) const;
+ PlayerInfo playerInfo[MAX_RACES][MAX_CLASSES];
+
+ typedef std::map<uint32,uint32> BaseXPMap; // [area level][base xp]
+ BaseXPMap mBaseXPTable;
+
+ typedef std::map<uint32,int32> FishingBaseSkillMap; // [areaId][base skill level]
+ FishingBaseSkillMap mFishingBaseForArea;
+
+ typedef std::map<uint32,std::vector<std::string> > HalfNameMap;
+ HalfNameMap PetHalfName0;
+ HalfNameMap PetHalfName1;
+
+ MapObjectGuids mMapObjectGuids;
+ CreatureDataMap mCreatureDataMap;
+ CreatureLocaleMap mCreatureLocaleMap;
+ GameObjectDataMap mGameObjectDataMap;
+ GameObjectLocaleMap mGameObjectLocaleMap;
+ ItemLocaleMap mItemLocaleMap;
+ QuestLocaleMap mQuestLocaleMap;
+ NpcTextLocaleMap mNpcTextLocaleMap;
+ PageTextLocaleMap mPageTextLocaleMap;
+ TrinityStringLocaleMap mTrinityStringLocaleMap;
+ NpcOptionLocaleMap mNpcOptionLocaleMap;
+ RespawnTimes mCreatureRespawnTimes;
+ RespawnTimes mGORespawnTimes;
+
+ typedef std::vector<uint32> GuildBankTabPriceMap;
+ GuildBankTabPriceMap mGuildBankTabPrice;
+
+ // Storage for Conditions. First element (index 0) is reserved for zero-condition (nothing required)
+ typedef std::vector<PlayerCondition> ConditionStore;
+ ConditionStore mConditions;
+
+ CacheNpcOptionList m_mCacheNpcOptionList;
+ CacheNpcTextIdMap m_mCacheNpcTextIdMap;
+ CacheVendorItemMap m_mCacheVendorItemMap;
+ CacheTrainerSpellMap m_mCacheTrainerSpellMap;
+};
+
+#define objmgr Trinity::Singleton<ObjectMgr>::Instance()
+
+// scripting access functions
+TRINITY_DLL_SPEC bool LoadTrinityStrings(DatabaseType& db, char const* table,int32 start_value = -1, int32 end_value = std::numeric_limits<int32>::min());
+TRINITY_DLL_SPEC uint32 GetAreaTriggerScriptId(uint32 trigger_id);
+TRINITY_DLL_SPEC uint32 GetScriptId(const char *name);
+TRINITY_DLL_SPEC ObjectMgr::ScriptNameMap& GetScriptNames();
+
+#endif
diff --git a/src/game/OutdoorPvPObjectiveAI.cpp b/src/game/OutdoorPvPObjectiveAI.cpp
index 9c9603a7f91..e8595e791f7 100644
--- a/src/game/OutdoorPvPObjectiveAI.cpp
+++ b/src/game/OutdoorPvPObjectiveAI.cpp
@@ -28,6 +28,7 @@
OutdoorPvPObjectiveAI::OutdoorPvPObjectiveAI(Creature &c) : i_creature(c)
{
sLog.outDebug("OutdoorPvP objective AI assigned to creature guid %u", c.GetGUIDLow());
+ c.SetAggressive(true);
}
void OutdoorPvPObjectiveAI::MoveInLineOfSight(Unit *u)
diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp
index 987a106a16d..7bd5daac551 100644
--- a/src/game/Pet.cpp
+++ b/src/game/Pet.cpp
@@ -628,7 +628,7 @@ void Pet::RegenerateFocus()
AuraList const& ModPowerRegenPCTAuras = GetAurasByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT);
for(AuraList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
if ((*i)->GetModifier()->m_miscvalue == POWER_FOCUS)
- addvalue *= ((*i)->GetModifier()->m_amount + 100) / 100.0f;
+ addvalue *= ((*i)->GetModifierValue() + 100) / 100.0f;
ModifyPower(POWER_FOCUS, (int32)addvalue);
}
@@ -1015,7 +1015,7 @@ bool Pet::InitStatsForLevel(uint32 petlevel)
SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0);
CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family);
- if(cFamily && cFamily->minScale > 0.0f)
+ if(cFamily && cFamily->minScale > 0.0f && getPetType()==HUNTER_PET)
{
float scale;
if (getLevel() >= cFamily->maxScaleLevel)
@@ -1430,7 +1430,7 @@ void Pet::_SaveAuras()
{
CharacterDatabase.PExecute("INSERT INTO pet_aura (guid,caster_guid,spell,effect_index,stackcount,amount,maxduration,remaintime,remaincharges) "
"VALUES ('%u', '" I64FMTD "', '%u', '%u', '%u', '%d', '%d', '%d', '%d')",
- m_charmInfo->GetPetNumber(), itr2->second->GetCasterGUID(),(uint32)itr2->second->GetId(), (uint32)itr2->second->GetEffIndex(), stackCounter, itr2->second->GetModifier()->m_amount,int(itr2->second->GetAuraMaxDuration()),int(itr2->second->GetAuraDuration()),int(itr2->second->m_procCharges));
+ m_charmInfo->GetPetNumber(), itr2->second->GetCasterGUID(),(uint32)itr2->second->GetId(), (uint32)itr2->second->GetEffIndex(), (uint32)itr2->second->GetStackAmount(), itr2->second->GetModifier()->m_amount,int(itr2->second->GetAuraMaxDuration()),int(itr2->second->GetAuraDuration()),int(itr2->second->m_procCharges));
}
}
}
@@ -1466,7 +1466,8 @@ bool Pet::addSpell(uint16 spell_id, uint16 active, PetSpellState state, uint16 s
}
// same spells don't have autocast option
- if (spellInfo->AttributesEx & SPELL_ATTR_EX_UNAUTOCASTABLE_BY_PET) active = ACT_CAST;
+ if (spellInfo->AttributesEx & SPELL_ATTR_EX_UNAUTOCASTABLE_BY_PET)
+ active = ACT_CAST;
PetSpellMap::iterator itr = m_spells.find(spell_id);
if (itr != m_spells.end())
@@ -1542,7 +1543,7 @@ bool Pet::addSpell(uint16 spell_id, uint16 active, PetSpellState state, uint16 s
if (IsPassiveSpell(spell_id))
CastSpell(this, spell_id, true);
else if(state == PETSPELL_NEW)
- m_charmInfo->AddSpellToAB(oldspell_id, spell_id, active);
+ m_charmInfo->AddSpellToAB(oldspell_id, spell_id, (ActiveStates)active);
if(newspell->active == ACT_ENABLED)
ToggleAutocast(spell_id, true);
diff --git a/src/game/PetAI.cpp b/src/game/PetAI.cpp
index e8fa449fe61..449d8b9924a 100644
--- a/src/game/PetAI.cpp
+++ b/src/game/PetAI.cpp
@@ -57,7 +57,7 @@ void PetAI::MoveInLineOfSight(Unit *u)
if(i_pet.IsWithinLOSInMap(u))
{
AttackStart(u);
- u->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
+ //u->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
}
}
}
diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp
index f95be3a9352..7950db27464 100644
--- a/src/game/PetHandler.cpp
+++ b/src/game/PetHandler.cpp
@@ -97,6 +97,13 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
break;
case COMMAND_ATTACK: //spellid=1792 //ATTACK
{
+ // Can't attack if owner is pacified
+ if (_player->HasAuraType(SPELL_AURA_MOD_PACIFY))
+ {
+ //pet->SendPetCastFail(spellid, SPELL_FAILED_PACIFIED);
+ //TODO: Send proper error message to client
+ return;
+ }
// only place where pet can be player
pet->clearUnitState(UNIT_STAT_FOLLOW);
uint64 selguid = _player->GetSelection();
@@ -105,7 +112,10 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data )
return;
// not let attack friendly units.
- if( GetPlayer()->IsFriendlyTo(TargetUnit))
+ if(GetPlayer()->IsFriendlyTo(TargetUnit))
+ return;
+ // Not let attack through obstructions
+ if(!pet->IsWithinLOSInMap(TargetUnit))
return;
if(pet->GetTypeId() != TYPEID_PLAYER)
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index 11ffba972a3..b00273b65c4 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -54,6 +54,7 @@
#include "Transports.h"
#include "Weather.h"
#include "BattleGround.h"
+#include "BattleGroundAV.h"
#include "BattleGroundMgr.h"
#include "OutdoorPvP.h"
#include "OutdoorPvPMgr.h"
@@ -545,7 +546,7 @@ bool Player::Create( uint32 guidlow, std::string name, uint8 race, uint8 class_,
}
SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, DEFAULT_WORLD_OBJECT_SIZE );
- SetFloatValue(UNIT_FIELD_COMBATREACH, 1.5f );
+ SetFloatValue(UNIT_FIELD_COMBATREACH, DEFAULT_WORLD_OBJECT_SIZE );
switch(gender)
{
@@ -565,7 +566,9 @@ bool Player::Create( uint32 guidlow, std::string name, uint8 race, uint8 class_,
setFactionForRace(m_race);
- SetUInt32Value(UNIT_FIELD_BYTES_0, ( ( race ) | ( class_ << 8 ) | ( gender << 16 ) | ( powertype << 24 ) ) );
+ uint32 RaceClassGender = ( race ) | ( class_ << 8 ) | ( gender << 16 );
+
+ SetUInt32Value(UNIT_FIELD_BYTES_0, ( RaceClassGender | ( powertype << 24 ) ) );
SetUInt32Value(UNIT_FIELD_BYTES_1, unitfield);
SetByteValue(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_UNK3 | UNIT_BYTE2_FLAG_UNK5 );
SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE );
@@ -590,18 +593,14 @@ bool Player::Create( uint32 guidlow, std::string name, uint8 race, uint8 class_,
SetUInt32Value( PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0 );
// set starting level
- if(GetSession()->GetSecurity() >= SEC_MODERATOR)
- SetUInt32Value( UNIT_FIELD_LEVEL, sWorld.getConfig(CONFIG_GM_START_LEVEL) );
+ if (GetSession()->GetSecurity() >= SEC_MODERATOR)
+ SetUInt32Value (UNIT_FIELD_LEVEL, sWorld.getConfig(CONFIG_START_GM_LEVEL));
else
- SetUInt32Value( UNIT_FIELD_LEVEL, sWorld.getConfig(CONFIG_START_PLAYER_LEVEL) );
- // set starting gold
- SetUInt32Value( PLAYER_FIELD_COINAGE, sWorld.getConfig(CONFIG_PLAYER_START_GOLD) );
-
- // set starting honor
- SetUInt32Value( PLAYER_FIELD_HONOR_CURRENCY, sWorld.getConfig(CONFIG_PLAYER_START_HONOR) );
+ SetUInt32Value (UNIT_FIELD_LEVEL, sWorld.getConfig(CONFIG_START_PLAYER_LEVEL));
- // set starting arena pts
- SetUInt32Value( PLAYER_FIELD_ARENA_CURRENCY, sWorld.getConfig(CONFIG_PLAYER_START_ARENAPTS) );
+ SetUInt32Value (PLAYER_FIELD_COINAGE, sWorld.getConfig(CONFIG_START_PLAYER_MONEY));
+ SetUInt32Value (PLAYER_FIELD_HONOR_CURRENCY, sWorld.getConfig(CONFIG_START_HONOR_POINTS));
+ SetUInt32Value (PLAYER_FIELD_ARENA_CURRENCY, sWorld.getConfig(CONFIG_START_ARENA_POINTS));
// start with every map explored
if(sWorld.getConfig(CONFIG_START_ALL_EXPLORED))
@@ -673,8 +672,10 @@ bool Player::Create( uint32 guidlow, std::string name, uint8 race, uint8 class_,
SetPower(POWER_MANA,GetMaxPower(POWER_MANA));
}
+ // original spells
learnDefaultSpells(true);
+ // original action bar
std::list<uint16>::const_iterator action_itr[4];
for(int i=0; i<4; i++)
action_itr[i] = info->action[i].begin();
@@ -691,37 +692,59 @@ bool Player::Create( uint32 guidlow, std::string name, uint8 race, uint8 class_,
++action_itr[i];
}
- for (PlayerCreateInfoItems::const_iterator item_id_itr = info->item.begin(); item_id_itr!=info->item.end(); ++item_id_itr++)
+ // original items
+ CharStartOutfitEntry const* oEntry = NULL;
+ for (uint32 i = 1; i < sCharStartOutfitStore.GetNumRows(); ++i)
{
- uint32 titem_id = item_id_itr->item_id;
- uint32 titem_amount = item_id_itr->item_amount;
-
- sLog.outDebug("STORAGE: Creating initial item, itemId = %u, count = %u",titem_id, titem_amount);
-
- // attempt equip
- uint16 eDest;
- uint8 msg = CanEquipNewItem( NULL_SLOT, eDest, titem_id, titem_amount, false );
- if( msg == EQUIP_ERR_OK )
+ if(CharStartOutfitEntry const* entry = sCharStartOutfitStore.LookupEntry(i))
{
- EquipNewItem( eDest, titem_id, titem_amount, true);
- AutoUnequipOffhandIfNeed();
- continue; // equipped, to next
+ if(entry->RaceClassGender == RaceClassGender)
+ {
+ oEntry = entry;
+ break;
+ }
}
+ }
- // attempt store
- ItemPosCountVec sDest;
- // store in main bag to simplify second pass (special bags can be not equipped yet at this moment)
- msg = CanStoreNewItem( INVENTORY_SLOT_BAG_0, NULL_SLOT, sDest, titem_id, titem_amount );
- if( msg == EQUIP_ERR_OK )
+ if(oEntry)
+ {
+ for(int j = 0; j < MAX_OUTFIT_ITEMS; ++j)
{
- StoreNewItem( sDest, titem_id, true, Item::GenerateItemRandomPropertyId(titem_id) );
- continue; // stored, to next
- }
+ if(oEntry->ItemId[j] <= 0)
+ continue;
+
+ uint32 item_id = oEntry->ItemId[j];
- // item can't be added
- sLog.outError("STORAGE: Can't equip or store initial item %u for race %u class %u , error msg = %u",titem_id,race,class_,msg);
+ ItemPrototype const* iProto = objmgr.GetItemPrototype(item_id);
+ if(!iProto)
+ {
+ sLog.outErrorDb("Initial item id %u (race %u class %u) from CharStartOutfit.dbc not listed in `item_template`, ignoring.",item_id,getRace(),getClass());
+ continue;
+ }
+
+ uint32 count = iProto->Stackable; // max stack by default (mostly 1)
+ if(iProto->Class==ITEM_CLASS_CONSUMABLE && iProto->SubClass==ITEM_SUBCLASS_FOOD)
+ {
+ switch(iProto->Spells[0].SpellCategory)
+ {
+ case 11: // food
+ if(iProto->Stackable > 4)
+ count = 4;
+ break;
+ case 59: // drink
+ if(iProto->Stackable > 2)
+ count = 2;
+ break;
+ }
+ }
+
+ StoreNewItemInBestSlot(item_id, count);
+ }
}
+ for (PlayerCreateInfoItems::const_iterator item_id_itr = info->item.begin(); item_id_itr!=info->item.end(); ++item_id_itr++)
+ StoreNewItemInBestSlot(item_id_itr->item_id, item_id_itr->item_amount);
+
// bags and main-hand weapon must equipped at this moment
// now second pass for not equipped (offhand weapon/shield if it attempt equipped before main-hand weapon)
// or ammo not equipped in special bag
@@ -760,6 +783,35 @@ bool Player::Create( uint32 guidlow, std::string name, uint8 race, uint8 class_,
return true;
}
+bool Player::StoreNewItemInBestSlot(uint32 titem_id, uint32 titem_amount)
+{
+ sLog.outDebug("STORAGE: Creating initial item, itemId = %u, count = %u",titem_id, titem_amount);
+
+ // attempt equip
+ uint16 eDest;
+ uint8 msg = CanEquipNewItem( NULL_SLOT, eDest, titem_id, titem_amount, false );
+ if( msg == EQUIP_ERR_OK )
+ {
+ EquipNewItem( eDest, titem_id, titem_amount, true);
+ AutoUnequipOffhandIfNeed();
+ return true; // equipped
+ }
+
+ // attempt store
+ ItemPosCountVec sDest;
+ // store in main bag to simplify second pass (special bags can be not equipped yet at this moment)
+ msg = CanStoreNewItem( INVENTORY_SLOT_BAG_0, NULL_SLOT, sDest, titem_id, titem_amount );
+ if( msg == EQUIP_ERR_OK )
+ {
+ StoreNewItem( sDest, titem_id, true, Item::GenerateItemRandomPropertyId(titem_id) );
+ return true; // stored
+ }
+
+ // item can't be added
+ sLog.outError("STORAGE: Can't equip or store initial item %u for race %u class %u , error msg = %u",titem_id,getRace(),getClass(),msg);
+ return false;
+}
+
void Player::StartMirrorTimer(MirrorTimerType Type, uint32 MaxValue)
{
uint32 BreathRegen = (uint32)-1;
@@ -827,8 +879,8 @@ void Player::HandleDrowning()
if(!m_isunderwater)
return;
- //if players is GM, have waterbreath, dead or breathing is disabled
- if(sWorld.getConfig(CONFIG_DISABLE_BREATHING) || waterbreath || isGameMaster() || !isAlive())
+ //if player is GM, have waterbreath, is dead or if breathing is disabled then return
+ if(waterbreath || isGameMaster() || !isAlive() || GetSession()->GetSecurity() >= sWorld.getConfig(CONFIG_DISABLE_BREATHING))
{
StopMirrorTimer(BREATH_TIMER);
m_isunderwater = 0;
@@ -839,7 +891,7 @@ void Player::HandleDrowning()
AuraList const& mModWaterBreathing = GetAurasByType(SPELL_AURA_MOD_WATER_BREATHING);
for(AuraList::const_iterator i = mModWaterBreathing.begin(); i != mModWaterBreathing.end(); ++i)
- UnderWaterTime = uint32(UnderWaterTime * (100.0f + (*i)->GetModifier()->m_amount) / 100.0f);
+ UnderWaterTime = uint32(UnderWaterTime * (100.0f + (*i)->GetModifierValue()) / 100.0f);
if ((m_isunderwater & 0x01) && !(m_isunderwater & 0x80) && isAlive())
{
@@ -1015,6 +1067,13 @@ void Player::Update( uint32 p_time )
CheckExploreSystem();
+ if(isCharmed())
+ {
+ if(Unit *charmer = GetCharmer())
+ if(charmer->GetTypeId() == TYPEID_UNIT && charmer->isAlive())
+ UpdateCharmedAI();
+ }
+
// Update items that have just a limited lifetime
if (now>m_Last_tick)
UpdateItemDuration(uint32(now- m_Last_tick));
@@ -1040,10 +1099,9 @@ void Player::Update( uint32 p_time )
}
}
- if (hasUnitState(UNIT_STAT_MELEE_ATTACKING))
+ if (hasUnitState(UNIT_STAT_MELEE_ATTACKING) && !hasUnitState(UNIT_STAT_CASTING))
{
- Unit *pVictim = getVictim();
- if( !IsNonMeleeSpellCasted(false) && pVictim)
+ if(Unit *pVictim = getVictim())
{
// default combat reach 10
// TODO add weapon,skill check
@@ -1353,7 +1411,7 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
*p_data << GetPositionY();
*p_data << GetPositionZ();
- *p_data << GetUInt32Value(PLAYER_GUILDID); // guild id
+ *p_data << (result ? result->Fetch()[13].GetUInt32() : 0);
uint32 char_flags = 0;
if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM))
@@ -1366,7 +1424,7 @@ void Player::BuildEnumData( QueryResult * result, WorldPacket * p_data )
char_flags |= CHARACTER_FLAG_RENAME;
// always send the flag if declined names aren't used
// to let the client select a default method of declining the name
- if(!sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) || (result && result->Fetch()[13].GetCppString() != ""))
+ if(!sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) || (result && result->Fetch()[14].GetCppString() != ""))
char_flags |= CHARACTER_FLAG_DECLINED;
*p_data << (uint32)char_flags; // character flags
@@ -1885,7 +1943,7 @@ void Player::Regenerate(Powers power)
AuraList const& ModPowerRegenPCTAuras = GetAurasByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT);
for(AuraList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i)
if ((*i)->GetModifier()->m_miscvalue == power)
- addvalue *= ((*i)->GetModifier()->m_amount + 100) / 100.0f;
+ addvalue *= ((*i)->GetModifierValue() + 100) / 100.0f;
}
if (power != POWER_RAGE)
@@ -1926,7 +1984,7 @@ void Player::RegenerateHealth()
{
AuraList const& mModHealthRegenPct = GetAurasByType(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT);
for(AuraList::const_iterator i = mModHealthRegenPct.begin(); i != mModHealthRegenPct.end(); ++i)
- addvalue *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f;
+ addvalue *= (100.0f + (*i)->GetModifierValue()) / 100.0f;
}
else if(HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT))
addvalue *= GetTotalAuraModifier(SPELL_AURA_MOD_REGEN_DURING_COMBAT) / 100.0f;
@@ -2123,7 +2181,7 @@ void Player::GiveXP(uint32 xp, Unit* victim)
// handle SPELL_AURA_MOD_XP_PCT auras
Unit::AuraList const& ModXPPctAuras = GetAurasByType(SPELL_AURA_MOD_XP_PCT);
for(Unit::AuraList::const_iterator i = ModXPPctAuras.begin();i != ModXPPctAuras.end(); ++i)
- xp = uint32(xp*(1.0f + (*i)->GetModifier()->m_amount / 100.0f));
+ xp = uint32(xp*(1.0f + (*i)->GetModifierValue() / 100.0f));
// XP resting bonus for kill
uint32 rested_bonus_xp = victim ? GetXPRestBonus(xp) : 0;
@@ -2183,7 +2241,7 @@ void Player::GiveLevel(uint32 level)
if(getLevel()!= level)
m_Played_time[1] = 0; // Level Played Time reset
SetLevel(level);
- UpdateMaxSkills();
+ UpdateSkillsForLevel ();
// save base values (bonuses already included in stored stats
for(int i = STAT_STRENGTH; i < MAX_STATS; ++i)
@@ -2259,7 +2317,7 @@ void Player::InitStatsForLevel(bool reapplyMods)
SetUInt32Value(PLAYER_FIELD_MAX_LEVEL, sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL) );
SetUInt32Value(PLAYER_NEXT_LEVEL_XP, Trinity::XP::xp_to_level(getLevel()));
- UpdateMaxSkills ();
+ UpdateSkillsForLevel ();
// set default cast time multiplier
SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f);
@@ -3789,7 +3847,7 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness)
// some items limited to specific map
DestroyZoneLimitedItem( true, GetZoneId());
- if(!applySickness || getLevel() <= 10)
+ if(!applySickness)
return;
//Characters from level 1-10 are not affected by resurrection sickness.
@@ -4160,7 +4218,7 @@ void Player::RepopAtGraveyard()
// Special handle for battleground maps
BattleGround *bg = sBattleGroundMgr.GetBattleGround(GetBattleGroundId());
- if(bg && (bg->GetTypeID() == BATTLEGROUND_AB || bg->GetTypeID() == BATTLEGROUND_EY))
+ if(bg && (bg->GetTypeID() == BATTLEGROUND_AB || bg->GetTypeID() == BATTLEGROUND_EY || bg->GetTypeID() == BATTLEGROUND_AV))
ClosestGrave = bg->GetClosestGraveYard(GetPositionX(), GetPositionY(), GetPositionZ(), GetTeam());
else
ClosestGrave = objmgr.GetClosestGraveYard( GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId(), GetTeam() );
@@ -4842,6 +4900,7 @@ void Player::UpdateWeaponSkill (WeaponAttackType attType)
void Player::UpdateCombatSkills(Unit *pVictim, WeaponAttackType attType, MeleeHitOutcome outcome, bool defence)
{
+/* Not need, this checked on call this func from trigger system
switch(outcome)
{
case MELEE_HIT_CRIT:
@@ -4854,7 +4913,7 @@ void Player::UpdateCombatSkills(Unit *pVictim, WeaponAttackType attType, MeleeHi
default:
break;
}
-
+*/
uint32 plevel = getLevel(); // if defense than pVictim == attacker
uint32 greylevel = Trinity::XP::GetGrayLevel(plevel);
uint32 moblevel = pVictim->getLevelForTarget(this);
@@ -4909,9 +4968,12 @@ void Player::ModifySkillBonus(uint32 skillid,int32 val, bool talent)
}
}
-void Player::UpdateMaxSkills()
+void Player::UpdateSkillsForLevel()
{
uint16 maxconfskill = sWorld.GetConfigMaxSkillValue();
+ uint32 maxSkill = GetMaxSkillValueForLevel();
+
+ bool alwaysMaxSkill = sWorld.getConfig(CONFIG_ALWAYS_MAX_SKILL_FOR_LEVEL);
for (uint16 i=0; i < PLAYER_MAX_SKILLS; i++)
if (GetUInt32Value(PLAYER_SKILL_INDEX(i)))
@@ -4929,11 +4991,15 @@ void Player::UpdateMaxSkills()
uint32 max = SKILL_MAX(data);
uint32 val = SKILL_VALUE(data);
- // update only level dependent max skill values
- if(max!=1 && max != maxconfskill)
+ /// update only level dependent max skill values
+ if(max!=1)
{
- uint32 max_Skill = GetMaxSkillValueForLevel();
- SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(val,max_Skill));
+ /// miximize skill always
+ if(alwaysMaxSkill)
+ SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(maxSkill,maxSkill));
+ /// update max skill value if current max skill not maximized
+ else if(max != maxconfskill)
+ SetUInt32Value(PLAYER_SKILL_VALUE_INDEX(i),MAKE_SKILL_VALUE(val,maxSkill));
}
}
}
@@ -5265,6 +5331,10 @@ bool Player::SetPosition(float x, float y, float z, float orientation, bool tele
x = GetPositionX();
y = GetPositionY();
z = GetPositionZ();
+
+ // group update
+ if(GetGroup() && (old_x != x || old_y != y))
+ SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POSITION);
}
// code block for underwater state update
@@ -5272,10 +5342,6 @@ bool Player::SetPosition(float x, float y, float z, float orientation, bool tele
CheckExploreSystem();
- // group update
- if(GetGroup())
- SetGroupUpdateFlag(GROUP_UPDATE_FLAG_POSITION);
-
return true;
}
@@ -5956,6 +6022,18 @@ void Player::UpdateHonorFields()
///An exact honor value can also be given (overriding the calcs)
bool Player::RewardHonor(Unit *uVictim, uint32 groupsize, float honor, bool pvptoken)
{
+ // do not reward honor in arenas, but enable onkill spellproc
+ if(InArena())
+ {
+ if(!uVictim || uVictim == this || uVictim->GetTypeId() != TYPEID_PLAYER)
+ return false;
+
+ if( GetBGTeam() == ((Player*)uVictim)->GetBGTeam() )
+ return false;
+
+ return true;
+ }
+
// 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
if(GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
return false;
@@ -6758,7 +6836,7 @@ void Player::_ApplyWeaponDependentAuraCritMod(Item *item, WeaponAttackType attac
if (item->IsFitToSpellRequirements(aura->GetSpellProto()))
{
- HandleBaseModValue(mod, FLAT_MOD, float (aura->GetModifier()->m_amount), apply);
+ HandleBaseModValue(mod, FLAT_MOD, float (aura->GetModifierValue()), apply);
}
}
@@ -6792,7 +6870,7 @@ void Player::_ApplyWeaponDependentAuraDamageMod(Item *item, WeaponAttackType att
if (item->IsFitToSpellRequirements(aura->GetSpellProto()))
{
- HandleStatModifier(unitMod, unitModType, float(modifier->m_amount),apply);
+ HandleStatModifier(unitMod, unitModType, float(aura->GetModifierValue()),apply);
}
}
@@ -7215,6 +7293,16 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
{
uint32 lootid = go->GetLootId();
+ //TODO: fix this big hack
+ if((go->GetEntry() == BG_AV_OBJECTID_MINE_N || go->GetEntry() == BG_AV_OBJECTID_MINE_S))
+ if( BattleGround *bg = GetBattleGround())
+ if(bg->GetTypeID() == BATTLEGROUND_AV)
+ if(!(((BattleGroundAV*)bg)->PlayerCanDoMineQuest(go->GetEntry(),GetTeam())))
+ {
+ SendLootRelease(guid);
+ return;
+ }
+
if(lootid)
{
sLog.outDebug(" if(lootid)");
@@ -7291,6 +7379,8 @@ void Player::SendLoot(uint64 guid, LootType loot_type)
bones->lootForBody = true;
uint32 pLevel = bones->loot.gold;
bones->loot.clear();
+ if(GetBattleGround()->GetTypeID() == BATTLEGROUND_AV)
+ loot->FillLoot(1, LootTemplates_Creature, this);
// It may need a better formula
// Now it works like this: lvl10: ~6copper, lvl70: ~9silver
bones->loot.gold = (uint32)( urand(50, 150) * 0.016f * pow( ((float)pLevel)/5.76f, 2.5f) * sWorld.getRate(RATE_DROP_MONEY) );
@@ -7664,81 +7754,86 @@ void Player::SendInitWorldStates(bool forceZone, uint32 forceZoneId)
}
break;
case 2597: // AV
- data << uint32(0x7ae) << uint32(0x1); // 7
- data << uint32(0x532) << uint32(0x1); // 8
- data << uint32(0x531) << uint32(0x0); // 9
- data << uint32(0x52e) << uint32(0x0); // 10
- data << uint32(0x571) << uint32(0x0); // 11
- data << uint32(0x570) << uint32(0x0); // 12
- data << uint32(0x567) << uint32(0x1); // 13
- data << uint32(0x566) << uint32(0x1); // 14
- data << uint32(0x550) << uint32(0x1); // 15
- data << uint32(0x544) << uint32(0x0); // 16
- data << uint32(0x536) << uint32(0x0); // 17
- data << uint32(0x535) << uint32(0x1); // 18
- data << uint32(0x518) << uint32(0x0); // 19
- data << uint32(0x517) << uint32(0x0); // 20
- data << uint32(0x574) << uint32(0x0); // 21
- data << uint32(0x573) << uint32(0x0); // 22
- data << uint32(0x572) << uint32(0x0); // 23
- data << uint32(0x56f) << uint32(0x0); // 24
- data << uint32(0x56e) << uint32(0x0); // 25
- data << uint32(0x56d) << uint32(0x0); // 26
- data << uint32(0x56c) << uint32(0x0); // 27
- data << uint32(0x56b) << uint32(0x0); // 28
- data << uint32(0x56a) << uint32(0x1); // 29
- data << uint32(0x569) << uint32(0x1); // 30
- data << uint32(0x568) << uint32(0x1); // 13
- data << uint32(0x565) << uint32(0x0); // 32
- data << uint32(0x564) << uint32(0x0); // 33
- data << uint32(0x563) << uint32(0x0); // 34
- data << uint32(0x562) << uint32(0x0); // 35
- data << uint32(0x561) << uint32(0x0); // 36
- data << uint32(0x560) << uint32(0x0); // 37
- data << uint32(0x55f) << uint32(0x0); // 38
- data << uint32(0x55e) << uint32(0x0); // 39
- data << uint32(0x55d) << uint32(0x0); // 40
- data << uint32(0x3c6) << uint32(0x4); // 41
- data << uint32(0x3c4) << uint32(0x6); // 42
- data << uint32(0x3c2) << uint32(0x4); // 43
- data << uint32(0x516) << uint32(0x1); // 44
- data << uint32(0x515) << uint32(0x0); // 45
- data << uint32(0x3b6) << uint32(0x6); // 46
- data << uint32(0x55c) << uint32(0x0); // 47
- data << uint32(0x55b) << uint32(0x0); // 48
- data << uint32(0x55a) << uint32(0x0); // 49
- data << uint32(0x559) << uint32(0x0); // 50
- data << uint32(0x558) << uint32(0x0); // 51
- data << uint32(0x557) << uint32(0x0); // 52
- data << uint32(0x556) << uint32(0x0); // 53
- data << uint32(0x555) << uint32(0x0); // 54
- data << uint32(0x554) << uint32(0x1); // 55
- data << uint32(0x553) << uint32(0x1); // 56
- data << uint32(0x552) << uint32(0x1); // 57
- data << uint32(0x551) << uint32(0x1); // 58
- data << uint32(0x54f) << uint32(0x0); // 59
- data << uint32(0x54e) << uint32(0x0); // 60
- data << uint32(0x54d) << uint32(0x1); // 61
- data << uint32(0x54c) << uint32(0x0); // 62
- data << uint32(0x54b) << uint32(0x0); // 63
- data << uint32(0x545) << uint32(0x0); // 64
- data << uint32(0x543) << uint32(0x1); // 65
- data << uint32(0x542) << uint32(0x0); // 66
- data << uint32(0x540) << uint32(0x0); // 67
- data << uint32(0x53f) << uint32(0x0); // 68
- data << uint32(0x53e) << uint32(0x0); // 69
- data << uint32(0x53d) << uint32(0x0); // 70
- data << uint32(0x53c) << uint32(0x0); // 71
- data << uint32(0x53b) << uint32(0x0); // 72
- data << uint32(0x53a) << uint32(0x1); // 73
- data << uint32(0x539) << uint32(0x0); // 74
- data << uint32(0x538) << uint32(0x0); // 75
- data << uint32(0x537) << uint32(0x0); // 76
- data << uint32(0x534) << uint32(0x0); // 77
- data << uint32(0x533) << uint32(0x0); // 78
- data << uint32(0x530) << uint32(0x0); // 79
- data << uint32(0x52f) << uint32(0x0); // 80
- data << uint32(0x52d) << uint32(0x1); // 81
+ if (bg && bg->GetTypeID() == BATTLEGROUND_AV)
+ bg->FillInitialWorldStates(data);
+ else
+ {
+ data << uint32(0x7ae) << uint32(0x1); // 7 snowfall n
+ data << uint32(0x532) << uint32(0x1); // 8 frostwolfhut hc
+ data << uint32(0x531) << uint32(0x0); // 9 frostwolfhut ac
+ data << uint32(0x52e) << uint32(0x0); // 10 stormpike firstaid a_a
+ data << uint32(0x571) << uint32(0x0); // 11 east frostwolf tower horde assaulted -unused
+ data << uint32(0x570) << uint32(0x0); // 12 west frostwolf tower horde assaulted - unused
+ data << uint32(0x567) << uint32(0x1); // 13 frostwolfe c
+ data << uint32(0x566) << uint32(0x1); // 14 frostwolfw c
+ data << uint32(0x550) << uint32(0x1); // 15 irondeep (N) ally
+ data << uint32(0x544) << uint32(0x0); // 16 ice grave a_a
+ data << uint32(0x536) << uint32(0x0); // 17 stormpike grave h_c
+ data << uint32(0x535) << uint32(0x1); // 18 stormpike grave a_c
+ data << uint32(0x518) << uint32(0x0); // 19 stoneheart grave a_a
+ data << uint32(0x517) << uint32(0x0); // 20 stoneheart grave h_a
+ data << uint32(0x574) << uint32(0x0); // 21 1396 unk
+ data << uint32(0x573) << uint32(0x0); // 22 iceblood tower horde assaulted -unused
+ data << uint32(0x572) << uint32(0x0); // 23 towerpoint horde assaulted - unused
+ data << uint32(0x56f) << uint32(0x0); // 24 1391 unk
+ data << uint32(0x56e) << uint32(0x0); // 25 iceblood a
+ data << uint32(0x56d) << uint32(0x0); // 26 towerp a
+ data << uint32(0x56c) << uint32(0x0); // 27 frostwolfe a
+ data << uint32(0x56b) << uint32(0x0); // 28 froswolfw a
+ data << uint32(0x56a) << uint32(0x1); // 29 1386 unk
+ data << uint32(0x569) << uint32(0x1); // 30 iceblood c
+ data << uint32(0x568) << uint32(0x1); // 31 towerp c
+ data << uint32(0x565) << uint32(0x0); // 32 stoneh tower a
+ data << uint32(0x564) << uint32(0x0); // 33 icewing tower a
+ data << uint32(0x563) << uint32(0x0); // 34 dunn a
+ data << uint32(0x562) << uint32(0x0); // 35 duns a
+ data << uint32(0x561) << uint32(0x0); // 36 stoneheart bunker alliance assaulted - unused
+ data << uint32(0x560) << uint32(0x0); // 37 icewing bunker alliance assaulted - unused
+ data << uint32(0x55f) << uint32(0x0); // 38 dunbaldar south alliance assaulted - unused
+ data << uint32(0x55e) << uint32(0x0); // 39 dunbaldar north alliance assaulted - unused
+ data << uint32(0x55d) << uint32(0x0); // 40 stone tower d
+ data << uint32(0x3c6) << uint32(0x0); // 41 966 unk
+ data << uint32(0x3c4) << uint32(0x0); // 42 964 unk
+ data << uint32(0x3c2) << uint32(0x0); // 43 962 unk
+ data << uint32(0x516) << uint32(0x1); // 44 stoneheart grave a_c
+ data << uint32(0x515) << uint32(0x0); // 45 stonheart grave h_c
+ data << uint32(0x3b6) << uint32(0x0); // 46 950 unk
+ data << uint32(0x55c) << uint32(0x0); // 47 icewing tower d
+ data << uint32(0x55b) << uint32(0x0); // 48 dunn d
+ data << uint32(0x55a) << uint32(0x0); // 49 duns d
+ data << uint32(0x559) << uint32(0x0); // 50 1369 unk
+ data << uint32(0x558) << uint32(0x0); // 51 iceblood d
+ data << uint32(0x557) << uint32(0x0); // 52 towerp d
+ data << uint32(0x556) << uint32(0x0); // 53 frostwolfe d
+ data << uint32(0x555) << uint32(0x0); // 54 frostwolfw d
+ data << uint32(0x554) << uint32(0x1); // 55 stoneh tower c
+ data << uint32(0x553) << uint32(0x1); // 56 icewing tower c
+ data << uint32(0x552) << uint32(0x1); // 57 dunn c
+ data << uint32(0x551) << uint32(0x1); // 58 duns c
+ data << uint32(0x54f) << uint32(0x0); // 59 irondeep (N) horde
+ data << uint32(0x54e) << uint32(0x0); // 60 irondeep (N) ally
+ data << uint32(0x54d) << uint32(0x1); // 61 mine (S) neutral
+ data << uint32(0x54c) << uint32(0x0); // 62 mine (S) horde
+ data << uint32(0x54b) << uint32(0x0); // 63 mine (S) ally
+ data << uint32(0x545) << uint32(0x0); // 64 iceblood h_a
+ data << uint32(0x543) << uint32(0x1); // 65 iceblod h_c
+ data << uint32(0x542) << uint32(0x0); // 66 iceblood a_c
+ data << uint32(0x540) << uint32(0x0); // 67 snowfall h_a
+ data << uint32(0x53f) << uint32(0x0); // 68 snowfall a_a
+ data << uint32(0x53e) << uint32(0x0); // 69 snowfall h_c
+ data << uint32(0x53d) << uint32(0x0); // 70 snowfall a_c
+ data << uint32(0x53c) << uint32(0x0); // 71 frostwolf g h_a
+ data << uint32(0x53b) << uint32(0x0); // 72 frostwolf g a_a
+ data << uint32(0x53a) << uint32(0x1); // 73 frostwolf g h_c
+ data << uint32(0x539) << uint32(0x0); // 74 frostwolf g a_c
+ data << uint32(0x538) << uint32(0x0); // 75 stormpike grave h_a
+ data << uint32(0x537) << uint32(0x0); // 76 stormpike grave a_a
+ data << uint32(0x534) << uint32(0x0); // 77 frostwolf hut h_a
+ data << uint32(0x533) << uint32(0x0); // 78 frostwolf hut a_a
+ data << uint32(0x530) << uint32(0x0); // 79 stormpike first aid h_a
+ data << uint32(0x52f) << uint32(0x0); // 80 stormpike first aid h_c
+ data << uint32(0x52d) << uint32(0x1); // 81 stormpike first aid a_c
+ }
break;
case 3277: // WS
if (bg && bg->GetTypeID() == BATTLEGROUND_WS)
@@ -11911,7 +12006,7 @@ void Player::SendPreparedQuest( uint64 guid )
else if( status == DIALOG_STATUS_INCOMPLETE )
PlayerTalkClass->SendQuestGiverRequestItems( pQuest, guid, false, true );
// Send completable on repeatable quest if player don't have quest
- else if( pQuest->IsRepeatable() )
+ else if( pQuest->IsRepeatable() && !pQuest->IsDaily() )
PlayerTalkClass->SendQuestGiverRequestItems( pQuest, guid, CanCompleteRepeatableQuest(pQuest), true );
else
PlayerTalkClass->SendQuestGiverQuestDetails( pQuest, guid, true );
@@ -12153,7 +12248,7 @@ bool Player::CanRewardQuest( Quest const *pQuest, bool msg )
if(!pQuest->IsAutoComplete() && GetQuestStatus(pQuest->GetQuestId()) != QUEST_STATUS_COMPLETE)
return false;
- // daily quest can't be rewarded (10 daily quest already completed)
+ // daily quest can't be rewarded (25 daily quest already completed)
if(!SatisfyQuestDay(pQuest,true))
return false;
@@ -12754,6 +12849,15 @@ bool Player::SatisfyQuestExclusiveGroup( Quest const* qInfo, bool msg )
if(exclude_Id == qInfo->GetQuestId())
continue;
+ // not allow have daily quest if daily quest from exclusive group already recently completed
+ Quest const* Nquest = objmgr.GetQuestTemplate(exclude_Id);
+ if( !SatisfyQuestDay(Nquest, false) )
+ {
+ if( msg )
+ SendCanTakeQuestResponse( INVALIDREASON_DONT_HAVE_REQ );
+ return false;
+ }
+
QuestStatusMap::iterator i_exstatus = mQuestStatus.find( exclude_Id );
// alternative quest already started or completed
@@ -13350,7 +13454,8 @@ bool Player::HasQuestForItem( uint32 itemid ) const
// hide quest if player is in raid-group and quest is no raid quest
if(GetGroup() && GetGroup()->isRaidGroup() && qinfo->GetType() != QUEST_TYPE_RAID)
- continue;
+ if(!InBattleGround()) //there are two ways.. we can make every bg-quest a raidquest, or add this code here.. i don't know if this can be exploited by other quests, but i think all other quests depend on a specific area.. but keep this in mind, if something strange happens later
+ continue;
// There should be no mixed ReqItem/ReqSource drop
// This part for ReqItem drop
@@ -14266,7 +14371,7 @@ void Player::_LoadAuras(QueryResult *result, uint32 timediff)
damage = aura->GetModifier()->m_amount;
aura->SetLoadedState(caster_guid,damage,maxduration,remaintime,remaincharges);
AddAura(aura);
- sLog.outString("Added aura spellid %u, effect %u", spellproto->Id, effindex);
+ sLog.outDetail("Added aura spellid %u, effect %u", spellproto->Id, effindex);
}
}
while( result->NextRow() );
@@ -14632,7 +14737,8 @@ void Player::_LoadQuestStatus(QueryResult *result)
// add to quest log
if( slot < MAX_QUEST_LOG_SIZE &&
( questStatusData.m_status==QUEST_STATUS_INCOMPLETE ||
- questStatusData.m_status==QUEST_STATUS_COMPLETE && !questStatusData.m_rewarded ) )
+ questStatusData.m_status==QUEST_STATUS_COMPLETE &&
+ (!questStatusData.m_rewarded || pQuest->IsDaily()) ) )
{
SetQuestSlot(slot,quest_id,quest_time);
@@ -15289,7 +15395,8 @@ void Player::SaveToDB()
void Player::SaveInventoryAndGoldToDB()
{
_SaveInventory();
- SetUInt32ValueInDB(PLAYER_FIELD_COINAGE,GetMoney(),GetGUID());
+ //money is in data field
+ SaveDataFieldToDB();
}
void Player::_SaveActions()
@@ -15359,7 +15466,7 @@ void Player::_SaveAuras()
{
CharacterDatabase.PExecute("INSERT INTO character_aura (guid,caster_guid,spell,effect_index,stackcount,amount,maxduration,remaintime,remaincharges) "
"VALUES ('%u', '" I64FMTD "' ,'%u', '%u', '%u', '%d', '%d', '%d', '%d')",
- GetGUIDLow(), itr2->second->GetCasterGUID(), (uint32)itr2->second->GetId(), (uint32)itr2->second->GetEffIndex(), stackCounter, itr2->second->GetModifier()->m_amount,int(itr2->second->GetAuraMaxDuration()),int(itr2->second->GetAuraDuration()),int(itr2->second->m_procCharges));
+ GetGUIDLow(), itr2->second->GetCasterGUID(), (uint32)itr2->second->GetId(), (uint32)itr2->second->GetEffIndex(), (uint32)itr2->second->GetStackAmount(), itr2->second->GetModifier()->m_amount,int(itr2->second->GetAuraMaxDuration()),int(itr2->second->GetAuraDuration()),int(itr2->second->m_procCharges));
}
}
}
@@ -15368,6 +15475,7 @@ void Player::_SaveAuras()
break;
}
+ //TODO: if need delete this
if (lastEffectPair == itr->first)
stackCounter++;
else
@@ -15680,6 +15788,20 @@ void Player::SavePositionInDB(uint32 mapid, float x,float y,float z,float o,uint
CharacterDatabase.Execute(ss.str().c_str());
}
+void Player::SaveDataFieldToDB()
+{
+ std::ostringstream ss;
+ ss<<"UPDATE characters SET data='";
+
+ for(uint16 i = 0; i < m_valuesCount; i++ )
+ {
+ ss << GetUInt32Value(i) << " ";
+ }
+ ss<<"' WHERE guid='"<< GUID_LOPART(GetGUIDLow()) <<"'";
+
+ CharacterDatabase.Execute(ss.str().c_str());
+}
+
bool Player::SaveValuesArrayInDB(Tokens const& tokens, uint64 guid)
{
std::ostringstream ss2;
@@ -17376,17 +17498,18 @@ bool Player::canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList) cons
return false;
}
- // GMs see any players, not higher GMs and all units
- if(isGameMaster())
- {
- if(u->GetTypeId() == TYPEID_PLAYER)
- return ((Player *)u)->GetSession()->GetSecurity() <= GetSession()->GetSecurity();
- else
- return true;
- }
-
if(u->GetVisibility() == VISIBILITY_OFF)
+ {
+ // GMs see any players, not higher GMs and all units
+ if(isGameMaster())
+ {
+ if(u->GetTypeId() == TYPEID_PLAYER)
+ return ((Player *)u)->GetSession()->GetSecurity() <= GetSession()->GetSecurity();
+ else
+ return true;
+ }
return false;
+ }
// player see other player with stealth/invisibility only if he in same group or raid or same team (raid/team case dependent from conf setting)
if((m_invisibilityMask || u->m_invisibilityMask) && !canDetectInvisibilityOf(u))
@@ -18045,6 +18168,7 @@ uint32 Player::GetMaxLevelForBattleGroundQueueId(uint32 queue_id)
return 10*(queue_id+2)-1;
}
+//TODO make this more generic - current implementation is wrong
uint32 Player::GetBattleGroundQueueIdFromLevel() const
{
uint32 level = getLevel();
@@ -18700,70 +18824,70 @@ bool ItemPosCount::isContainedIn(ItemPosCountVec const& vec) const
//-------------TRINITY---------------
//***********************************
-void Player::HandleFallDamage(MovementInfo& movementInfo)
-{
- //Players with Feather Fall or low fall time, or physical immunity (charges used) are ignored
- if (!isInFlight() && movementInfo.fallTime > 1100 && !isDead() && !isGameMaster() &&
- !HasAuraType(SPELL_AURA_HOVER) && !HasAuraType(SPELL_AURA_FEATHER_FALL) &&
- !HasAuraType(SPELL_AURA_FLY) && !IsImmunedToDamage(SPELL_SCHOOL_MASK_NORMAL,true) )
- {
- //Safe fall, fall time reduction
- int32 safe_fall = GetTotalAuraModifier(SPELL_AURA_SAFE_FALL);
- uint32 fall_time = (movementInfo.fallTime > (safe_fall*10)) ? movementInfo.fallTime - (safe_fall*10) : 0;
-
- if(fall_time > 1100) //Prevent damage if fall time < 1100
- {
- //Fall Damage calculation
- float fallperc = float(fall_time)/1100;
- uint32 damage = (uint32)(((fallperc*fallperc -1) / 9 * GetMaxHealth())*sWorld.getRate(RATE_DAMAGE_FALL));
-
- float height = movementInfo.z;
- UpdateGroundPositionZ(movementInfo.x,movementInfo.y,height);
-
- if (damage > 0)
- {
- //Prevent fall damage from being more than the player maximum health
- if (damage > GetMaxHealth())
- damage = GetMaxHealth();
-
- // Gust of Wind
- if (GetDummyAura(43621))
- damage = GetMaxHealth()/2;
-
- EnvironmentalDamage(GetGUID(), DAMAGE_FALL, damage);
- }
-
- //Z given by moveinfo, LastZ, FallTime, WaterZ, MapZ, Damage, Safefall reduction
- DEBUG_LOG("FALLDAMAGE z=%f sz=%f pZ=%f FallTime=%d mZ=%f damage=%d SF=%d" , movementInfo.z, height, GetPositionZ(), movementInfo.fallTime, height, damage, safe_fall);
- }
- }
-}
-
-void Player::HandleFallUnderMap()
-{
- if(InBattleGround() && GetBattleGround()
- && GetBattleGround()->HandlePlayerUnderMap(this))
- {
- // do nothing, the handle already did if returned true
- }
- else
- {
- // NOTE: this is actually called many times while falling
- // even after the player has been teleported away
- // TODO: discard movement packets after the player is rooted
- if(isAlive())
- {
- EnvironmentalDamage(GetGUID(),DAMAGE_FALL_TO_VOID, GetMaxHealth());
- // change the death state to CORPSE to prevent the death timer from
- // starting in the next player update
- KillPlayer();
- BuildPlayerRepop();
- }
-
- // cancel the death timer here if started
- RepopAtGraveyard();
- }
-}
+void Player::HandleFallDamage(MovementInfo& movementInfo)
+{
+ //Players with Feather Fall or low fall time, or physical immunity (charges used) are ignored
+ if (!isInFlight() && movementInfo.fallTime > 1100 && !isDead() && !isGameMaster() &&
+ !HasAuraType(SPELL_AURA_HOVER) && !HasAuraType(SPELL_AURA_FEATHER_FALL) &&
+ !HasAuraType(SPELL_AURA_FLY) && !IsImmunedToDamage(SPELL_SCHOOL_MASK_NORMAL,true) )
+ {
+ //Safe fall, fall time reduction
+ int32 safe_fall = GetTotalAuraModifier(SPELL_AURA_SAFE_FALL);
+ uint32 fall_time = (movementInfo.fallTime > (safe_fall*10)) ? movementInfo.fallTime - (safe_fall*10) : 0;
+
+ if(fall_time > 1100) //Prevent damage if fall time < 1100
+ {
+ //Fall Damage calculation
+ float fallperc = float(fall_time)/1100;
+ uint32 damage = (uint32)(((fallperc*fallperc -1) / 9 * GetMaxHealth())*sWorld.getRate(RATE_DAMAGE_FALL));
+
+ float height = movementInfo.z;
+ UpdateGroundPositionZ(movementInfo.x,movementInfo.y,height);
+
+ if (damage > 0)
+ {
+ //Prevent fall damage from being more than the player maximum health
+ if (damage > GetMaxHealth())
+ damage = GetMaxHealth();
+
+ // Gust of Wind
+ if (GetDummyAura(43621))
+ damage = GetMaxHealth()/2;
+
+ EnvironmentalDamage(GetGUID(), DAMAGE_FALL, damage);
+ }
+
+ //Z given by moveinfo, LastZ, FallTime, WaterZ, MapZ, Damage, Safefall reduction
+ DEBUG_LOG("FALLDAMAGE z=%f sz=%f pZ=%f FallTime=%d mZ=%f damage=%d SF=%d" , movementInfo.z, height, GetPositionZ(), movementInfo.fallTime, height, damage, safe_fall);
+ }
+ }
+}
+
+void Player::HandleFallUnderMap()
+{
+ if(InBattleGround() && GetBattleGround()
+ && GetBattleGround()->HandlePlayerUnderMap(this))
+ {
+ // do nothing, the handle already did if returned true
+ }
+ else
+ {
+ // NOTE: this is actually called many times while falling
+ // even after the player has been teleported away
+ // TODO: discard movement packets after the player is rooted
+ if(isAlive())
+ {
+ EnvironmentalDamage(GetGUID(),DAMAGE_FALL_TO_VOID, GetMaxHealth());
+ // change the death state to CORPSE to prevent the death timer from
+ // starting in the next player update
+ KillPlayer();
+ BuildPlayerRepop();
+ }
+
+ // cancel the death timer here if started
+ RepopAtGraveyard();
+ }
+}
void Player::Possess(Unit *target)
{
@@ -18936,8 +19060,8 @@ void Player::RemovePossess(bool attack)
if(attack)
target->AddThreat(this, 1000000.0f);
}
- // Delete the assigned possessed AI
- ((Creature*)target)->DeletePossessedAI();
+ // Disable the assigned possessed AI
+ ((Creature*)target)->DisablePossessedAI();
}
}
@@ -19024,3 +19148,35 @@ bool Player::isTotalImmunity()
}
return false;
}
+
+void Player::UpdateCharmedAI()
+{
+ //This should only called in Player::Update
+ Creature *charmer = (Creature*)GetCharmer();
+
+ //kill self if charm aura has infinite duration
+ if(charmer->IsInEvadeMode())
+ {
+ AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_CHARM);
+ for(AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter)
+ if((*iter)->GetCasterGUID() == charmer->GetGUID() && (*iter)->IsPermanent())
+ {
+ charmer->DealDamage(this, GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
+ return;
+ }
+ }
+
+ if(!charmer->isInCombat())
+ GetMotionMaster()->MoveFollow(charmer, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE);
+
+ Unit *target = getVictim();
+ if(!target || !charmer->canAttack(target))
+ {
+ target = charmer->SelectNearestTarget();
+ if(!target)
+ return;
+
+ GetMotionMaster()->MoveChase(target);
+ Attack(target, true);
+ }
+} \ No newline at end of file
diff --git a/src/game/Player.h b/src/game/Player.h
index 87f0ad11ae8..df3edc91f4f 100644
--- a/src/game/Player.h
+++ b/src/game/Player.h
@@ -897,8 +897,6 @@ class TRINITY_DLL_SPEC Player : public Unit
void AddToWorld();
void RemoveFromWorld();
- // always active
- void setActive(bool) {}
void SetViewport(uint64 guid, bool movable);
void Possess(Unit *target);
@@ -1083,6 +1081,7 @@ class TRINITY_DLL_SPEC Player : public Unit
Item* EquipNewItem( uint16 pos, uint32 item, uint32 count, bool update );
Item* EquipItem( uint16 pos, Item *pItem, bool update );
void AutoUnequipOffhandIfNeed();
+ bool StoreNewItemInBestSlot(uint32 item_id, uint32 item_count);
uint8 _CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count = NULL) const;
uint8 _CanStoreItem( uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 entry, uint32 count, Item *pItem = NULL, bool swap = false, uint32* no_space_count = NULL ) const;
@@ -1279,7 +1278,7 @@ class TRINITY_DLL_SPEC Player : public Unit
void SaveToDB();
void SaveInventoryAndGoldToDB(); // fast save function for item/money cheating preventing
- void SaveGoldToDB() { SetUInt32ValueInDB(PLAYER_FIELD_COINAGE,GetMoney(),GetGUID()); }
+ void SaveDataFieldToDB();
static bool SaveValuesArrayInDB(Tokens const& data,uint64 guid);
static void SetUInt32ValueInArray(Tokens& data,uint16 index, uint32 value);
static void SetFloatValueInArray(Tokens& data,uint16 index, float value);
@@ -1518,8 +1517,8 @@ class TRINITY_DLL_SPEC Player : public Unit
void RemoveFromGroup() { RemoveFromGroup(GetGroup(),GetGUID()); }
void SendUpdateToOutOfRangeGroupMembers();
- void SetInGuild(uint32 GuildId) { SetUInt32Value(PLAYER_GUILDID, GuildId); Player::SetUInt32ValueInDB(PLAYER_GUILDID, GuildId, GetGUID()); }
- void SetRank(uint32 rankId){ SetUInt32Value(PLAYER_GUILDRANK, rankId); Player::SetUInt32ValueInDB(PLAYER_GUILDRANK, rankId, GetGUID()); }
+ void SetInGuild(uint32 GuildId) { SetUInt32Value(PLAYER_GUILDID, GuildId); }
+ void SetRank(uint32 rankId){ SetUInt32Value(PLAYER_GUILDRANK, rankId); }
void SetGuildIdInvited(uint32 GuildId) { m_GuildIdInvited = GuildId; }
uint32 GetGuildId() { return GetUInt32Value(PLAYER_GUILDID); }
static uint32 GetGuildIdFromDB(uint64 guid);
@@ -1532,7 +1531,7 @@ class TRINITY_DLL_SPEC Player : public Unit
void SetInArenaTeam(uint32 ArenaTeamId, uint8 slot)
{
SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * 6), ArenaTeamId);
- SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * 6), ArenaTeamId, GetGUID());
+ SaveDataFieldToDB(); // needed?
}
uint32 GetArenaTeamId(uint8 slot) { return GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (slot * 6)); }
static uint32 GetArenaTeamIdFromDB(uint64 guid, uint8 slot);
@@ -1727,7 +1726,7 @@ class TRINITY_DLL_SPEC Player : public Unit
void SetFactionVisible(FactionState* faction);
void SetFactionVisibleForFactionTemplateId(uint32 FactionTemplateId);
void SetFactionVisibleForFactionId(uint32 FactionId);
- void UpdateMaxSkills();
+ void UpdateSkillsForLevel();
void UpdateSkillsToMaxSkillsForLevel(); // for .levelup
void ModifySkillBonus(uint32 skillid,int32 val, bool talent);
@@ -2310,6 +2309,8 @@ class TRINITY_DLL_SPEC Player : public Unit
GridReference<Player> m_gridRef;
MapReference m_mapRef;
+
+ void UpdateCharmedAI();
};
void AddItemsSetItem(Player*player,Item *item);
diff --git a/src/game/PlayerDump.cpp b/src/game/PlayerDump.cpp
index cd14d603e92..7b32f547bff 100644
--- a/src/game/PlayerDump.cpp
+++ b/src/game/PlayerDump.cpp
@@ -1,631 +1,631 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
- *
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
- *
- * 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
- */
-
-#include "Common.h"
-#include "PlayerDump.h"
-#include "Database/DatabaseEnv.h"
-#include "Database/SQLStorage.h"
-#include "UpdateFields.h"
-#include "ObjectMgr.h"
-
-// Character Dump tables
-#define DUMP_TABLE_COUNT 19
-
-struct DumpTable
-{
- char const* name;
- DumpTableType type;
-};
-
-static DumpTable dumpTables[DUMP_TABLE_COUNT] =
-{
- { "characters", DTT_CHARACTER },
- { "character_queststatus", DTT_CHAR_TABLE },
- { "character_reputation", DTT_CHAR_TABLE },
- { "character_spell", DTT_CHAR_TABLE },
- { "character_spell_cooldown", DTT_CHAR_TABLE },
- { "character_action", DTT_CHAR_TABLE },
- { "character_aura", DTT_CHAR_TABLE },
- { "character_homebind", DTT_CHAR_TABLE },
- { "character_ticket", DTT_CHAR_TABLE },
- { "character_inventory", DTT_INVENTORY },
- { "mail", DTT_MAIL },
- { "mail_items", DTT_MAIL_ITEM },
- { "item_instance", DTT_ITEM },
- { "character_gifts", DTT_ITEM_GIFT },
- { "item_text", DTT_ITEM_TEXT },
- { "character_pet", DTT_PET },
- { "pet_aura", DTT_PET_TABLE },
- { "pet_spell", DTT_PET_TABLE },
- { "pet_spell_cooldown", DTT_PET_TABLE },
-};
-
-// Low level functions
-static bool findtoknth(std::string &str, int n, std::string::size_type &s, std::string::size_type &e)
-{
- int i; s = e = 0;
- std::string::size_type size = str.size();
- for(i = 1; s < size && i < n; s++) if(str[s] == ' ') ++i;
- if (i < n)
- return false;
-
- e = str.find(' ', s);
-
- return e != std::string::npos;
-}
-
-std::string gettoknth(std::string &str, int n)
-{
- std::string::size_type s = 0, e = 0;
- if(!findtoknth(str, n, s, e))
- return "";
-
- return str.substr(s, e-s);
-}
-
-bool findnth(std::string &str, int n, std::string::size_type &s, std::string::size_type &e)
-{
- s = str.find("VALUES ('")+9;
- if (s == std::string::npos) return false;
-
- do
- {
- e = str.find("'",s);
- if (e == std::string::npos) return false;
- } while(str[e-1] == '\\');
-
- for(int i = 1; i < n; i++)
- {
- do
- {
- s = e+4;
- e = str.find("'",s);
- if (e == std::string::npos) return false;
- } while (str[e-1] == '\\');
- }
- return true;
-}
-
-std::string gettablename(std::string &str)
-{
- std::string::size_type s = 13;
- std::string::size_type e = str.find(_TABLE_SIM_, s);
- if (e == std::string::npos)
- return "";
-
- return str.substr(s, e-s);
-}
-
-bool changenth(std::string &str, int n, const char *with, bool insert = false, bool nonzero = false)
-{
- std::string::size_type s, e;
- if(!findnth(str,n,s,e))
- return false;
-
- if(nonzero && str.substr(s,e-s) == "0")
- return true; // not an error
- if(!insert)
- str.replace(s,e-s, with);
- else
- str.insert(s, with);
-
- return true;
-}
-
-std::string getnth(std::string &str, int n)
-{
- std::string::size_type s, e;
- if(!findnth(str,n,s,e))
- return "";
-
- return str.substr(s, e-s);
-}
-
-bool changetoknth(std::string &str, int n, const char *with, bool insert = false, bool nonzero = false)
-{
- std::string::size_type s = 0, e = 0;
- if(!findtoknth(str, n, s, e))
- return false;
- if(nonzero && str.substr(s,e-s) == "0")
- return true; // not an error
- if(!insert)
- str.replace(s, e-s, with);
- else
- str.insert(s, with);
-
- return true;
-}
-
-uint32 registerNewGuid(uint32 oldGuid, std::map<uint32, uint32> &guidMap, uint32 hiGuid)
-{
- std::map<uint32, uint32>::iterator itr = guidMap.find(oldGuid);
- if(itr != guidMap.end())
- return itr->second;
-
- uint32 newguid = hiGuid + guidMap.size();
- guidMap[oldGuid] = newguid;
- return newguid;
-}
-
-bool changeGuid(std::string &str, int n, std::map<uint32, uint32> &guidMap, uint32 hiGuid, bool nonzero = false)
-{
- char chritem[20];
- uint32 oldGuid = atoi(getnth(str, n).c_str());
- if (nonzero && oldGuid == 0)
- return true; // not an error
-
- uint32 newGuid = registerNewGuid(oldGuid, guidMap, hiGuid);
- snprintf(chritem, 20, "%d", newGuid);
-
- return changenth(str, n, chritem, false, nonzero);
-}
-
-bool changetokGuid(std::string &str, int n, std::map<uint32, uint32> &guidMap, uint32 hiGuid, bool nonzero = false)
-{
- char chritem[20];
- uint32 oldGuid = atoi(gettoknth(str, n).c_str());
- if (nonzero && oldGuid == 0)
- return true; // not an error
-
- uint32 newGuid = registerNewGuid(oldGuid, guidMap, hiGuid);
- snprintf(chritem, 20, "%d", newGuid);
-
- return changetoknth(str, n, chritem, false, nonzero);
-}
-
-std::string CreateDumpString(char const* tableName, QueryResult *result)
-{
- if(!tableName || !result) return "";
- std::ostringstream ss;
- ss << "INSERT INTO "<< _TABLE_SIM_ << tableName << _TABLE_SIM_ << " VALUES (";
- Field *fields = result->Fetch();
- for(uint32 i = 0; i < result->GetFieldCount(); i++)
- {
- if (i == 0) ss << "'";
- else ss << ", '";
-
- std::string s = fields[i].GetCppString();
- CharacterDatabase.escape_string(s);
- ss << s;
-
- ss << "'";
- }
- ss << ");";
- return ss.str();
-}
-
-std::string PlayerDumpWriter::GenerateWhereStr(char const* field, uint32 guid)
-{
- std::ostringstream wherestr;
- wherestr << field << " = '" << guid << "'";
- return wherestr.str();
-}
-
-std::string PlayerDumpWriter::GenerateWhereStr(char const* field, GUIDs const& guids, GUIDs::const_iterator& itr)
-{
- std::ostringstream wherestr;
- wherestr << field << " IN ('";
- for(; itr != guids.end(); ++itr)
- {
- wherestr << *itr;
-
- if(wherestr.str().size() > MAX_QUERY_LEN - 50) // near to max query
- {
- ++itr;
- break;
- }
-
- GUIDs::const_iterator itr2 = itr;
- if(++itr2 != guids.end())
- wherestr << "','";
- }
- wherestr << "')";
- return wherestr.str();
-}
-
-void StoreGUID(QueryResult *result,uint32 field,std::set<uint32>& guids)
-{
- Field* fields = result->Fetch();
- uint32 guid = fields[field].GetUInt32();
- if(guid)
- guids.insert(guid);
-}
-
-void StoreGUID(QueryResult *result,uint32 data,uint32 field, std::set<uint32>& guids)
-{
- Field* fields = result->Fetch();
- std::string dataStr = fields[data].GetCppString();
- uint32 guid = atoi(gettoknth(dataStr, field).c_str());
- if(guid)
- guids.insert(guid);
-}
-
-// Writing - High-level functions
-void PlayerDumpWriter::DumpTable(std::string& dump, uint32 guid, char const*tableFrom, char const*tableTo, DumpTableType type)
-{
- GUIDs const* guids = NULL;
- char const* fieldname = NULL;
-
- switch ( type )
- {
- case DTT_ITEM: fieldname = "guid"; guids = &items; break;
- case DTT_ITEM_GIFT: fieldname = "item_guid"; guids = &items; break;
- case DTT_PET: fieldname = "owner"; break;
- case DTT_PET_TABLE: fieldname = "guid"; guids = &pets; break;
- case DTT_MAIL: fieldname = "receiver"; break;
- case DTT_MAIL_ITEM: fieldname = "mail_id"; guids = &mails; break;
- case DTT_ITEM_TEXT: fieldname = "id"; guids = &texts; break;
- default: fieldname = "guid"; break;
- }
-
- // for guid set stop if set is empty
- if(guids && guids->empty())
- return; // nothing to do
-
- // setup for guids case start position
- GUIDs::const_iterator guids_itr;
- if(guids)
- guids_itr = guids->begin();
-
- do
- {
- std::string wherestr;
-
- if(guids) // set case, get next guids string
- wherestr = GenerateWhereStr(fieldname,*guids,guids_itr);
- else // not set case, get single guid string
- wherestr = GenerateWhereStr(fieldname,guid);
-
- QueryResult *result = CharacterDatabase.PQuery("SELECT * FROM %s WHERE %s", tableFrom, wherestr.c_str());
- if(!result)
- return;
-
- do
- {
- // collect guids
- switch ( type )
- {
- case DTT_INVENTORY:
- StoreGUID(result,3,items); break; // item guid collection
- case DTT_ITEM:
- StoreGUID(result,0,ITEM_FIELD_ITEM_TEXT_ID,texts); break;
- // item text id collection
- case DTT_PET:
- StoreGUID(result,0,pets); break; // pet guid collection
- case DTT_MAIL:
- StoreGUID(result,0,mails); // mail id collection
- StoreGUID(result,6,texts); break; // item text id collection
- case DTT_MAIL_ITEM:
- StoreGUID(result,1,items); break; // item guid collection
- default: break;
- }
-
- dump += CreateDumpString(tableTo, result);
- dump += "\n";
- }
- while (result->NextRow());
-
- delete result;
- }
- while(guids && guids_itr != guids->end()); // not set case iterate single time, set case iterate for all guids
-}
-
-std::string PlayerDumpWriter::GetDump(uint32 guid)
-{
- std::string dump;
- for(int i = 0; i < DUMP_TABLE_COUNT; i++)
- DumpTable(dump, guid, dumpTables[i].name, dumpTables[i].name, dumpTables[i].type);
-
- // TODO: Add instance/group..
- // TODO: Add a dump level option to skip some non-important tables
-
- return dump;
-}
-
-DumpReturn PlayerDumpWriter::WriteDump(std::string file, uint32 guid)
-{
- FILE *fout = fopen(file.c_str(), "w");
- if (!fout)
- return DUMP_FILE_OPEN_ERROR;
-
- std::string dump = GetDump(guid);
-
- fprintf(fout,"%s\n",dump.c_str());
- fclose(fout);
- return DUMP_SUCCESS;
-}
-
-// Reading - High-level functions
-#define ROLLBACK(DR) {CharacterDatabase.RollbackTransaction(); fclose(fin); return (DR);}
-
-DumpReturn PlayerDumpReader::LoadDump(std::string file, uint32 account, std::string name, uint32 guid)
-{
- // check character count
- {
- QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(guid) FROM characters WHERE account = '%d'", account);
- uint8 charcount = 0;
- if ( result )
- {
- Field *fields=result->Fetch();
- charcount = fields[0].GetUInt8();
- delete result;
-
- if (charcount >= 10)
- return DUMP_TOO_MANY_CHARS;
- }
- }
-
- FILE *fin = fopen(file.c_str(), "r");
- if(!fin)
- return DUMP_FILE_OPEN_ERROR;
-
- QueryResult * result = NULL;
- char newguid[20], chraccount[20], newpetid[20], currpetid[20], lastpetid[20];
-
- // make sure the same guid doesn't already exist and is safe to use
- bool incHighest = true;
- if(guid != 0 && guid < objmgr.m_hiCharGuid)
- {
- result = CharacterDatabase.PQuery("SELECT * FROM characters WHERE guid = '%d'", guid);
- if (result)
- {
- guid = objmgr.m_hiCharGuid; // use first free if exists
- delete result;
- }
- else incHighest = false;
- }
- else
- guid = objmgr.m_hiCharGuid;
-
- // normalize the name if specified and check if it exists
- if(!normalizePlayerName(name))
- name = "";
-
- if(ObjectMgr::IsValidName(name,true))
- {
- CharacterDatabase.escape_string(name); // for safe, we use name only for sql quearies anyway
- result = CharacterDatabase.PQuery("SELECT * FROM characters WHERE name = '%s'", name.c_str());
- if (result)
- {
- name = ""; // use the one from the dump
- delete result;
- }
- }
- else name = "";
-
- // name encoded or empty
-
- snprintf(newguid, 20, "%d", guid);
- snprintf(chraccount, 20, "%d", account);
- snprintf(newpetid, 20, "%d", objmgr.GeneratePetNumber());
- snprintf(lastpetid, 20, "%s", "");
-
- std::map<uint32,uint32> items;
- std::map<uint32,uint32> mails;
- char buf[32000] = "";
-
- typedef std::map<uint32, uint32> PetIds; // old->new petid relation
- typedef PetIds::value_type PetIdsPair;
- PetIds petids;
-
- CharacterDatabase.BeginTransaction();
- while(!feof(fin))
- {
- if(!fgets(buf, 32000, fin))
- {
- if(feof(fin)) break;
- ROLLBACK(DUMP_FILE_BROKEN);
- }
-
- std::string line; line.assign(buf);
-
- // skip empty strings
- if(line.find_first_not_of(" \t\n\r\7")==std::string::npos)
- continue;
-
- // determine table name and load type
- std::string tn = gettablename(line);
- if(tn.empty())
- {
- sLog.outError("LoadPlayerDump: Can't extract table name from line: '%s'!", line.c_str());
- ROLLBACK(DUMP_FILE_BROKEN);
- }
-
- DumpTableType type;
- uint8 i;
- for(i = 0; i < DUMP_TABLE_COUNT; i++)
- {
- if (tn == dumpTables[i].name)
- {
- type = dumpTables[i].type;
- break;
- }
- }
-
- if (i == DUMP_TABLE_COUNT)
- {
- sLog.outError("LoadPlayerDump: Unknown table: '%s'!", tn.c_str());
- ROLLBACK(DUMP_FILE_BROKEN);
- }
-
- // change the data to server values
- switch(type)
- {
- case DTT_CHAR_TABLE:
- if(!changenth(line, 1, newguid))
- ROLLBACK(DUMP_FILE_BROKEN);
- break;
-
- case DTT_CHARACTER: // character t.
- {
- if(!changenth(line, 1, newguid))
- ROLLBACK(DUMP_FILE_BROKEN);
-
- // guid, data field:guid, items
- if(!changenth(line, 2, chraccount))
- ROLLBACK(DUMP_FILE_BROKEN);
- std::string vals = getnth(line, 3);
- if(!changetoknth(vals, OBJECT_FIELD_GUID+1, newguid))
- ROLLBACK(DUMP_FILE_BROKEN);
- for(uint16 field = PLAYER_FIELD_INV_SLOT_HEAD; field < PLAYER_FARSIGHT; field++)
- if(!changetokGuid(vals, field+1, items, objmgr.m_hiItemGuid, true))
- ROLLBACK(DUMP_FILE_BROKEN);
- if(!changenth(line, 3, vals.c_str()))
- ROLLBACK(DUMP_FILE_BROKEN);
- if (name == "")
- {
- // check if the original name already exists
- name = getnth(line, 4);
- CharacterDatabase.escape_string(name);
-
- result = CharacterDatabase.PQuery("SELECT * FROM characters WHERE name = '%s'", name.c_str());
- if (result)
- {
- delete result;
- // rename on login: `at_login` field 30 in raw field list
- if(!changenth(line, 30, "1"))
- ROLLBACK(DUMP_FILE_BROKEN);
- }
- }
- else if(!changenth(line, 4, name.c_str()))
- ROLLBACK(DUMP_FILE_BROKEN);
-
- break;
- }
- case DTT_INVENTORY: // character_inventory t.
- {
- if(!changenth(line, 1, newguid))
- ROLLBACK(DUMP_FILE_BROKEN);
-
- // bag, item
- if(!changeGuid(line, 2, items, objmgr.m_hiItemGuid, true))
- ROLLBACK(DUMP_FILE_BROKEN);
- if(!changeGuid(line, 4, items, objmgr.m_hiItemGuid))
- ROLLBACK(DUMP_FILE_BROKEN);
- break;
- }
- case DTT_ITEM: // item_instance t.
- {
- // item, owner, data field:item, owner guid
- if(!changeGuid(line, 1, items, objmgr.m_hiItemGuid))
- ROLLBACK(DUMP_FILE_BROKEN);
- if(!changenth(line, 2, newguid))
- ROLLBACK(DUMP_FILE_BROKEN);
- std::string vals = getnth(line,3);
- if(!changetokGuid(vals, OBJECT_FIELD_GUID+1, items, objmgr.m_hiItemGuid))
- ROLLBACK(DUMP_FILE_BROKEN);
- if(!changetoknth(vals, ITEM_FIELD_OWNER+1, newguid))
- ROLLBACK(DUMP_FILE_BROKEN);
- if(!changenth(line, 3, vals.c_str()))
- ROLLBACK(DUMP_FILE_BROKEN);
- break;
- }
- case DTT_ITEM_GIFT: // character_gift
- {
- // guid,item_guid,
- if(!changenth(line, 1, newguid))
- ROLLBACK(DUMP_FILE_BROKEN);
- if(!changeGuid(line, 2, items, objmgr.m_hiItemGuid))
- ROLLBACK(DUMP_FILE_BROKEN);
- break;
- }
- case DTT_PET: // character_pet t
- {
- //store a map of old pet id to new inserted pet id for use by type 5 tables
- snprintf(currpetid, 20, "%s", getnth(line, 1).c_str());
- if(strlen(lastpetid)==0) snprintf(lastpetid, 20, "%s", currpetid);
- if(strcmp(lastpetid,currpetid)!=0)
- {
- snprintf(newpetid, 20, "%d", objmgr.GeneratePetNumber());
- snprintf(lastpetid, 20, "%s", currpetid);
- }
-
- std::map<uint32, uint32> :: const_iterator petids_iter = petids.find(atoi(currpetid));
-
- if(petids_iter == petids.end())
- {
- petids.insert(PetIdsPair(atoi(currpetid), atoi(newpetid)));
- }
-
- // item, entry, owner, ...
- if(!changenth(line, 1, newpetid))
- ROLLBACK(DUMP_FILE_BROKEN);
- if(!changenth(line, 3, newguid))
- ROLLBACK(DUMP_FILE_BROKEN);
-
- break;
- }
- case DTT_PET_TABLE: // pet_aura, pet_spell, pet_spell_cooldown t
- {
- snprintf(currpetid, 20, "%s", getnth(line, 1).c_str());
-
- // lookup currpetid and match to new inserted pet id
- std::map<uint32, uint32> :: const_iterator petids_iter = petids.find(atoi(currpetid));
- if(petids_iter == petids.end()) // couldn't find new inserted id
- ROLLBACK(DUMP_FILE_BROKEN);
-
- snprintf(newpetid, 20, "%d", petids_iter->second);
-
- if(!changenth(line, 1, newpetid))
- ROLLBACK(DUMP_FILE_BROKEN);
-
- break;
- }
- case DTT_MAIL: // mail
- {
- // id,messageType,stationery,sender,receiver
- if(!changeGuid(line, 1, mails, objmgr.m_mailid))
- ROLLBACK(DUMP_FILE_BROKEN);
- if(!changenth(line, 5, newguid))
- ROLLBACK(DUMP_FILE_BROKEN);
- break;
- }
- case DTT_MAIL_ITEM: // mail_items
- {
- // mail_id,item_guid,item_template,receiver
- if(!changeGuid(line, 1, mails, objmgr.m_mailid))
- ROLLBACK(DUMP_FILE_BROKEN);
- if(!changeGuid(line, 2, items, objmgr.m_hiItemGuid))
- ROLLBACK(DUMP_FILE_BROKEN);
- if(!changenth(line, 4, newguid))
- ROLLBACK(DUMP_FILE_BROKEN);
- break;
- }
- default:
- sLog.outError("Unknown dump table type: %u",type);
- break;
- }
-
- if(!CharacterDatabase.Execute(line.c_str()))
- ROLLBACK(DUMP_FILE_BROKEN);
- }
-
- CharacterDatabase.CommitTransaction();
-
- objmgr.m_hiItemGuid += items.size();
- objmgr.m_mailid += mails.size();
-
- if(incHighest)
- ++objmgr.m_hiCharGuid;
-
- fclose(fin);
-
- return DUMP_SUCCESS;
-}
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ *
+ * 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
+ */
+
+#include "Common.h"
+#include "PlayerDump.h"
+#include "Database/DatabaseEnv.h"
+#include "Database/SQLStorage.h"
+#include "UpdateFields.h"
+#include "ObjectMgr.h"
+
+// Character Dump tables
+#define DUMP_TABLE_COUNT 19
+
+struct DumpTable
+{
+ char const* name;
+ DumpTableType type;
+};
+
+static DumpTable dumpTables[DUMP_TABLE_COUNT] =
+{
+ { "characters", DTT_CHARACTER },
+ { "character_queststatus", DTT_CHAR_TABLE },
+ { "character_reputation", DTT_CHAR_TABLE },
+ { "character_spell", DTT_CHAR_TABLE },
+ { "character_spell_cooldown", DTT_CHAR_TABLE },
+ { "character_action", DTT_CHAR_TABLE },
+ { "character_aura", DTT_CHAR_TABLE },
+ { "character_homebind", DTT_CHAR_TABLE },
+ { "character_ticket", DTT_CHAR_TABLE },
+ { "character_inventory", DTT_INVENTORY },
+ { "mail", DTT_MAIL },
+ { "mail_items", DTT_MAIL_ITEM },
+ { "item_instance", DTT_ITEM },
+ { "character_gifts", DTT_ITEM_GIFT },
+ { "item_text", DTT_ITEM_TEXT },
+ { "character_pet", DTT_PET },
+ { "pet_aura", DTT_PET_TABLE },
+ { "pet_spell", DTT_PET_TABLE },
+ { "pet_spell_cooldown", DTT_PET_TABLE },
+};
+
+// Low level functions
+static bool findtoknth(std::string &str, int n, std::string::size_type &s, std::string::size_type &e)
+{
+ int i; s = e = 0;
+ std::string::size_type size = str.size();
+ for(i = 1; s < size && i < n; s++) if(str[s] == ' ') ++i;
+ if (i < n)
+ return false;
+
+ e = str.find(' ', s);
+
+ return e != std::string::npos;
+}
+
+std::string gettoknth(std::string &str, int n)
+{
+ std::string::size_type s = 0, e = 0;
+ if(!findtoknth(str, n, s, e))
+ return "";
+
+ return str.substr(s, e-s);
+}
+
+bool findnth(std::string &str, int n, std::string::size_type &s, std::string::size_type &e)
+{
+ s = str.find("VALUES ('")+9;
+ if (s == std::string::npos) return false;
+
+ do
+ {
+ e = str.find("'",s);
+ if (e == std::string::npos) return false;
+ } while(str[e-1] == '\\');
+
+ for(int i = 1; i < n; i++)
+ {
+ do
+ {
+ s = e+4;
+ e = str.find("'",s);
+ if (e == std::string::npos) return false;
+ } while (str[e-1] == '\\');
+ }
+ return true;
+}
+
+std::string gettablename(std::string &str)
+{
+ std::string::size_type s = 13;
+ std::string::size_type e = str.find(_TABLE_SIM_, s);
+ if (e == std::string::npos)
+ return "";
+
+ return str.substr(s, e-s);
+}
+
+bool changenth(std::string &str, int n, const char *with, bool insert = false, bool nonzero = false)
+{
+ std::string::size_type s, e;
+ if(!findnth(str,n,s,e))
+ return false;
+
+ if(nonzero && str.substr(s,e-s) == "0")
+ return true; // not an error
+ if(!insert)
+ str.replace(s,e-s, with);
+ else
+ str.insert(s, with);
+
+ return true;
+}
+
+std::string getnth(std::string &str, int n)
+{
+ std::string::size_type s, e;
+ if(!findnth(str,n,s,e))
+ return "";
+
+ return str.substr(s, e-s);
+}
+
+bool changetoknth(std::string &str, int n, const char *with, bool insert = false, bool nonzero = false)
+{
+ std::string::size_type s = 0, e = 0;
+ if(!findtoknth(str, n, s, e))
+ return false;
+ if(nonzero && str.substr(s,e-s) == "0")
+ return true; // not an error
+ if(!insert)
+ str.replace(s, e-s, with);
+ else
+ str.insert(s, with);
+
+ return true;
+}
+
+uint32 registerNewGuid(uint32 oldGuid, std::map<uint32, uint32> &guidMap, uint32 hiGuid)
+{
+ std::map<uint32, uint32>::iterator itr = guidMap.find(oldGuid);
+ if(itr != guidMap.end())
+ return itr->second;
+
+ uint32 newguid = hiGuid + guidMap.size();
+ guidMap[oldGuid] = newguid;
+ return newguid;
+}
+
+bool changeGuid(std::string &str, int n, std::map<uint32, uint32> &guidMap, uint32 hiGuid, bool nonzero = false)
+{
+ char chritem[20];
+ uint32 oldGuid = atoi(getnth(str, n).c_str());
+ if (nonzero && oldGuid == 0)
+ return true; // not an error
+
+ uint32 newGuid = registerNewGuid(oldGuid, guidMap, hiGuid);
+ snprintf(chritem, 20, "%d", newGuid);
+
+ return changenth(str, n, chritem, false, nonzero);
+}
+
+bool changetokGuid(std::string &str, int n, std::map<uint32, uint32> &guidMap, uint32 hiGuid, bool nonzero = false)
+{
+ char chritem[20];
+ uint32 oldGuid = atoi(gettoknth(str, n).c_str());
+ if (nonzero && oldGuid == 0)
+ return true; // not an error
+
+ uint32 newGuid = registerNewGuid(oldGuid, guidMap, hiGuid);
+ snprintf(chritem, 20, "%d", newGuid);
+
+ return changetoknth(str, n, chritem, false, nonzero);
+}
+
+std::string CreateDumpString(char const* tableName, QueryResult *result)
+{
+ if(!tableName || !result) return "";
+ std::ostringstream ss;
+ ss << "INSERT INTO "<< _TABLE_SIM_ << tableName << _TABLE_SIM_ << " VALUES (";
+ Field *fields = result->Fetch();
+ for(uint32 i = 0; i < result->GetFieldCount(); i++)
+ {
+ if (i == 0) ss << "'";
+ else ss << ", '";
+
+ std::string s = fields[i].GetCppString();
+ CharacterDatabase.escape_string(s);
+ ss << s;
+
+ ss << "'";
+ }
+ ss << ");";
+ return ss.str();
+}
+
+std::string PlayerDumpWriter::GenerateWhereStr(char const* field, uint32 guid)
+{
+ std::ostringstream wherestr;
+ wherestr << field << " = '" << guid << "'";
+ return wherestr.str();
+}
+
+std::string PlayerDumpWriter::GenerateWhereStr(char const* field, GUIDs const& guids, GUIDs::const_iterator& itr)
+{
+ std::ostringstream wherestr;
+ wherestr << field << " IN ('";
+ for(; itr != guids.end(); ++itr)
+ {
+ wherestr << *itr;
+
+ if(wherestr.str().size() > MAX_QUERY_LEN - 50) // near to max query
+ {
+ ++itr;
+ break;
+ }
+
+ GUIDs::const_iterator itr2 = itr;
+ if(++itr2 != guids.end())
+ wherestr << "','";
+ }
+ wherestr << "')";
+ return wherestr.str();
+}
+
+void StoreGUID(QueryResult *result,uint32 field,std::set<uint32>& guids)
+{
+ Field* fields = result->Fetch();
+ uint32 guid = fields[field].GetUInt32();
+ if(guid)
+ guids.insert(guid);
+}
+
+void StoreGUID(QueryResult *result,uint32 data,uint32 field, std::set<uint32>& guids)
+{
+ Field* fields = result->Fetch();
+ std::string dataStr = fields[data].GetCppString();
+ uint32 guid = atoi(gettoknth(dataStr, field).c_str());
+ if(guid)
+ guids.insert(guid);
+}
+
+// Writing - High-level functions
+void PlayerDumpWriter::DumpTable(std::string& dump, uint32 guid, char const*tableFrom, char const*tableTo, DumpTableType type)
+{
+ GUIDs const* guids = NULL;
+ char const* fieldname = NULL;
+
+ switch ( type )
+ {
+ case DTT_ITEM: fieldname = "guid"; guids = &items; break;
+ case DTT_ITEM_GIFT: fieldname = "item_guid"; guids = &items; break;
+ case DTT_PET: fieldname = "owner"; break;
+ case DTT_PET_TABLE: fieldname = "guid"; guids = &pets; break;
+ case DTT_MAIL: fieldname = "receiver"; break;
+ case DTT_MAIL_ITEM: fieldname = "mail_id"; guids = &mails; break;
+ case DTT_ITEM_TEXT: fieldname = "id"; guids = &texts; break;
+ default: fieldname = "guid"; break;
+ }
+
+ // for guid set stop if set is empty
+ if(guids && guids->empty())
+ return; // nothing to do
+
+ // setup for guids case start position
+ GUIDs::const_iterator guids_itr;
+ if(guids)
+ guids_itr = guids->begin();
+
+ do
+ {
+ std::string wherestr;
+
+ if(guids) // set case, get next guids string
+ wherestr = GenerateWhereStr(fieldname,*guids,guids_itr);
+ else // not set case, get single guid string
+ wherestr = GenerateWhereStr(fieldname,guid);
+
+ QueryResult *result = CharacterDatabase.PQuery("SELECT * FROM %s WHERE %s", tableFrom, wherestr.c_str());
+ if(!result)
+ return;
+
+ do
+ {
+ // collect guids
+ switch ( type )
+ {
+ case DTT_INVENTORY:
+ StoreGUID(result,3,items); break; // item guid collection
+ case DTT_ITEM:
+ StoreGUID(result,0,ITEM_FIELD_ITEM_TEXT_ID,texts); break;
+ // item text id collection
+ case DTT_PET:
+ StoreGUID(result,0,pets); break; // pet guid collection
+ case DTT_MAIL:
+ StoreGUID(result,0,mails); // mail id collection
+ StoreGUID(result,6,texts); break; // item text id collection
+ case DTT_MAIL_ITEM:
+ StoreGUID(result,1,items); break; // item guid collection
+ default: break;
+ }
+
+ dump += CreateDumpString(tableTo, result);
+ dump += "\n";
+ }
+ while (result->NextRow());
+
+ delete result;
+ }
+ while(guids && guids_itr != guids->end()); // not set case iterate single time, set case iterate for all guids
+}
+
+std::string PlayerDumpWriter::GetDump(uint32 guid)
+{
+ std::string dump;
+ for(int i = 0; i < DUMP_TABLE_COUNT; i++)
+ DumpTable(dump, guid, dumpTables[i].name, dumpTables[i].name, dumpTables[i].type);
+
+ // TODO: Add instance/group..
+ // TODO: Add a dump level option to skip some non-important tables
+
+ return dump;
+}
+
+DumpReturn PlayerDumpWriter::WriteDump(std::string file, uint32 guid)
+{
+ FILE *fout = fopen(file.c_str(), "w");
+ if (!fout)
+ return DUMP_FILE_OPEN_ERROR;
+
+ std::string dump = GetDump(guid);
+
+ fprintf(fout,"%s\n",dump.c_str());
+ fclose(fout);
+ return DUMP_SUCCESS;
+}
+
+// Reading - High-level functions
+#define ROLLBACK(DR) {CharacterDatabase.RollbackTransaction(); fclose(fin); return (DR);}
+
+DumpReturn PlayerDumpReader::LoadDump(std::string file, uint32 account, std::string name, uint32 guid)
+{
+ // check character count
+ {
+ QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(guid) FROM characters WHERE account = '%d'", account);
+ uint8 charcount = 0;
+ if ( result )
+ {
+ Field *fields=result->Fetch();
+ charcount = fields[0].GetUInt8();
+ delete result;
+
+ if (charcount >= 10)
+ return DUMP_TOO_MANY_CHARS;
+ }
+ }
+
+ FILE *fin = fopen(file.c_str(), "r");
+ if(!fin)
+ return DUMP_FILE_OPEN_ERROR;
+
+ QueryResult * result = NULL;
+ char newguid[20], chraccount[20], newpetid[20], currpetid[20], lastpetid[20];
+
+ // make sure the same guid doesn't already exist and is safe to use
+ bool incHighest = true;
+ if(guid != 0 && guid < objmgr.m_hiCharGuid)
+ {
+ result = CharacterDatabase.PQuery("SELECT * FROM characters WHERE guid = '%d'", guid);
+ if (result)
+ {
+ guid = objmgr.m_hiCharGuid; // use first free if exists
+ delete result;
+ }
+ else incHighest = false;
+ }
+ else
+ guid = objmgr.m_hiCharGuid;
+
+ // normalize the name if specified and check if it exists
+ if(!normalizePlayerName(name))
+ name = "";
+
+ if(ObjectMgr::IsValidName(name,true))
+ {
+ CharacterDatabase.escape_string(name); // for safe, we use name only for sql quearies anyway
+ result = CharacterDatabase.PQuery("SELECT * FROM characters WHERE name = '%s'", name.c_str());
+ if (result)
+ {
+ name = ""; // use the one from the dump
+ delete result;
+ }
+ }
+ else name = "";
+
+ // name encoded or empty
+
+ snprintf(newguid, 20, "%d", guid);
+ snprintf(chraccount, 20, "%d", account);
+ snprintf(newpetid, 20, "%d", objmgr.GeneratePetNumber());
+ snprintf(lastpetid, 20, "%s", "");
+
+ std::map<uint32,uint32> items;
+ std::map<uint32,uint32> mails;
+ char buf[32000] = "";
+
+ typedef std::map<uint32, uint32> PetIds; // old->new petid relation
+ typedef PetIds::value_type PetIdsPair;
+ PetIds petids;
+
+ CharacterDatabase.BeginTransaction();
+ while(!feof(fin))
+ {
+ if(!fgets(buf, 32000, fin))
+ {
+ if(feof(fin)) break;
+ ROLLBACK(DUMP_FILE_BROKEN);
+ }
+
+ std::string line; line.assign(buf);
+
+ // skip empty strings
+ if(line.find_first_not_of(" \t\n\r\7")==std::string::npos)
+ continue;
+
+ // determine table name and load type
+ std::string tn = gettablename(line);
+ if(tn.empty())
+ {
+ sLog.outError("LoadPlayerDump: Can't extract table name from line: '%s'!", line.c_str());
+ ROLLBACK(DUMP_FILE_BROKEN);
+ }
+
+ DumpTableType type;
+ uint8 i;
+ for(i = 0; i < DUMP_TABLE_COUNT; i++)
+ {
+ if (tn == dumpTables[i].name)
+ {
+ type = dumpTables[i].type;
+ break;
+ }
+ }
+
+ if (i == DUMP_TABLE_COUNT)
+ {
+ sLog.outError("LoadPlayerDump: Unknown table: '%s'!", tn.c_str());
+ ROLLBACK(DUMP_FILE_BROKEN);
+ }
+
+ // change the data to server values
+ switch(type)
+ {
+ case DTT_CHAR_TABLE:
+ if(!changenth(line, 1, newguid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ break;
+
+ case DTT_CHARACTER: // character t.
+ {
+ if(!changenth(line, 1, newguid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+
+ // guid, data field:guid, items
+ if(!changenth(line, 2, chraccount))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ std::string vals = getnth(line, 3);
+ if(!changetoknth(vals, OBJECT_FIELD_GUID+1, newguid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ for(uint16 field = PLAYER_FIELD_INV_SLOT_HEAD; field < PLAYER_FARSIGHT; field++)
+ if(!changetokGuid(vals, field+1, items, objmgr.m_hiItemGuid, true))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ if(!changenth(line, 3, vals.c_str()))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ if (name == "")
+ {
+ // check if the original name already exists
+ name = getnth(line, 4);
+ CharacterDatabase.escape_string(name);
+
+ result = CharacterDatabase.PQuery("SELECT * FROM characters WHERE name = '%s'", name.c_str());
+ if (result)
+ {
+ delete result;
+ // rename on login: `at_login` field 30 in raw field list
+ if(!changenth(line, 30, "1"))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ }
+ }
+ else if(!changenth(line, 4, name.c_str()))
+ ROLLBACK(DUMP_FILE_BROKEN);
+
+ break;
+ }
+ case DTT_INVENTORY: // character_inventory t.
+ {
+ if(!changenth(line, 1, newguid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+
+ // bag, item
+ if(!changeGuid(line, 2, items, objmgr.m_hiItemGuid, true))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ if(!changeGuid(line, 4, items, objmgr.m_hiItemGuid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ break;
+ }
+ case DTT_ITEM: // item_instance t.
+ {
+ // item, owner, data field:item, owner guid
+ if(!changeGuid(line, 1, items, objmgr.m_hiItemGuid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ if(!changenth(line, 2, newguid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ std::string vals = getnth(line,3);
+ if(!changetokGuid(vals, OBJECT_FIELD_GUID+1, items, objmgr.m_hiItemGuid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ if(!changetoknth(vals, ITEM_FIELD_OWNER+1, newguid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ if(!changenth(line, 3, vals.c_str()))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ break;
+ }
+ case DTT_ITEM_GIFT: // character_gift
+ {
+ // guid,item_guid,
+ if(!changenth(line, 1, newguid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ if(!changeGuid(line, 2, items, objmgr.m_hiItemGuid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ break;
+ }
+ case DTT_PET: // character_pet t
+ {
+ //store a map of old pet id to new inserted pet id for use by type 5 tables
+ snprintf(currpetid, 20, "%s", getnth(line, 1).c_str());
+ if(strlen(lastpetid)==0) snprintf(lastpetid, 20, "%s", currpetid);
+ if(strcmp(lastpetid,currpetid)!=0)
+ {
+ snprintf(newpetid, 20, "%d", objmgr.GeneratePetNumber());
+ snprintf(lastpetid, 20, "%s", currpetid);
+ }
+
+ std::map<uint32, uint32> :: const_iterator petids_iter = petids.find(atoi(currpetid));
+
+ if(petids_iter == petids.end())
+ {
+ petids.insert(PetIdsPair(atoi(currpetid), atoi(newpetid)));
+ }
+
+ // item, entry, owner, ...
+ if(!changenth(line, 1, newpetid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ if(!changenth(line, 3, newguid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+
+ break;
+ }
+ case DTT_PET_TABLE: // pet_aura, pet_spell, pet_spell_cooldown t
+ {
+ snprintf(currpetid, 20, "%s", getnth(line, 1).c_str());
+
+ // lookup currpetid and match to new inserted pet id
+ std::map<uint32, uint32> :: const_iterator petids_iter = petids.find(atoi(currpetid));
+ if(petids_iter == petids.end()) // couldn't find new inserted id
+ ROLLBACK(DUMP_FILE_BROKEN);
+
+ snprintf(newpetid, 20, "%d", petids_iter->second);
+
+ if(!changenth(line, 1, newpetid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+
+ break;
+ }
+ case DTT_MAIL: // mail
+ {
+ // id,messageType,stationery,sender,receiver
+ if(!changeGuid(line, 1, mails, objmgr.m_mailid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ if(!changenth(line, 5, newguid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ break;
+ }
+ case DTT_MAIL_ITEM: // mail_items
+ {
+ // mail_id,item_guid,item_template,receiver
+ if(!changeGuid(line, 1, mails, objmgr.m_mailid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ if(!changeGuid(line, 2, items, objmgr.m_hiItemGuid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ if(!changenth(line, 4, newguid))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ break;
+ }
+ default:
+ sLog.outError("Unknown dump table type: %u",type);
+ break;
+ }
+
+ if(!CharacterDatabase.Execute(line.c_str()))
+ ROLLBACK(DUMP_FILE_BROKEN);
+ }
+
+ CharacterDatabase.CommitTransaction();
+
+ objmgr.m_hiItemGuid += items.size();
+ objmgr.m_mailid += mails.size();
+
+ if(incHighest)
+ ++objmgr.m_hiCharGuid;
+
+ fclose(fin);
+
+ return DUMP_SUCCESS;
+}
diff --git a/src/game/PossessedAI.cpp b/src/game/PossessedAI.cpp
index 6b803303185..17dd28f0b0f 100644
--- a/src/game/PossessedAI.cpp
+++ b/src/game/PossessedAI.cpp
@@ -1,127 +1,127 @@
-/*
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
- *
- * Thanks to the original authors: MaNGOS <http://www.mangosproject.org/>
- *
- * 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
- */
-
-#include "PossessedAI.h"
-#include "Creature.h"
-#include "World.h"
-
-void PossessedAI::AttackStart(Unit *u)
-{
- if( !u )
- return;
-
- if (i_pet.getVictim() && u != i_pet.getVictim())
- i_pet.AttackStop();
-
- if(i_pet.Attack(u, true))
- i_victimGuid = u->GetGUID();
-
- // Do not autochase our target, and also make sure our current movement generator
- // is removed since the motion master is reset before this function is called
- i_pet.GetMotionMaster()->Clear(false);
- i_pet.GetMotionMaster()->MoveIdle();
-}
-
-bool PossessedAI::_needToStop() const
-{
- if(!i_pet.getVictim() || !i_pet.isAlive())
- return true;
-
- // This is needed for charmed creatures, as once their target was reset other effects can trigger threat
- if(i_pet.getVictim() == i_pet.GetCharmer())
- return true;
-
- return !i_pet.canAttack(i_pet.getVictim());
-}
-
-void PossessedAI::_stopAttack()
-{
- if( !i_victimGuid )
- return;
-
- Unit* victim = Unit::GetUnit(i_pet, i_victimGuid );
-
- if ( !victim )
- return;
-
- assert(!i_pet.getVictim() || i_pet.getVictim() == victim);
-
- if( !i_pet.isAlive() )
- {
- i_pet.StopMoving();
- i_pet.GetMotionMaster()->Clear(false);
- i_pet.GetMotionMaster()->MoveIdle();
- i_victimGuid = 0;
- i_pet.CombatStop();
- i_pet.getHostilRefManager().deleteReferences();
-
- return;
- }
-
- i_pet.GetMotionMaster()->Clear(false);
- i_pet.GetMotionMaster()->MoveIdle();
- i_victimGuid = 0;
- i_pet.AttackStop();
-}
-
-void PossessedAI::UpdateAI(const uint32 diff)
-{
- // update i_victimGuid if i_pet.getVictim() !=0 and changed
- if(i_pet.getVictim())
- i_victimGuid = i_pet.getVictim()->GetGUID();
-
- // i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc.
- if( i_victimGuid )
- {
- if( _needToStop() )
- {
- _stopAttack(); // i_victimGuid == 0 && i_pet.getVictim() == NULL now
- return;
- }
- else if(i_pet.IsWithinCombatDist(i_pet.getVictim(), ATTACK_DISTANCE) && i_pet.isAttackReady())
- {
- i_pet.AttackerStateUpdate(i_pet.getVictim());
-
- i_pet.resetAttackTimer();
-
- if( _needToStop() )
- _stopAttack();
- }
- }
-}
-
-bool PossessedAI::_isVisible(Unit *u) const
-{
- return i_pet.GetDistance(u) < sWorld.getConfig(CONFIG_SIGHT_MONSTER)
- && u->isVisibleForOrDetect(&i_pet,true);
-}
-
-void PossessedAI::JustDied(Unit *u)
-{
- // We died while possessed, disable our loot
- i_pet.RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
-}
-
-void PossessedAI::KilledUnit(Unit* victim)
-{
- // We killed a creature, disable victim's loot
- if (victim->GetTypeId() == TYPEID_UNIT)
- victim->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
-}
+/*
+ * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ *
+ * Thanks to the original authors: MaNGOS <http://www.mangosproject.org/>
+ *
+ * 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
+ */
+
+#include "PossessedAI.h"
+#include "Creature.h"
+#include "World.h"
+
+void PossessedAI::AttackStart(Unit *u)
+{
+ if( !u || i_pet.GetCharmer()->HasAuraType(SPELL_AURA_MOD_PACIFY))
+ return;
+
+ if (i_pet.getVictim() && u != i_pet.getVictim())
+ i_pet.AttackStop();
+
+ if(i_pet.Attack(u, true))
+ i_victimGuid = u->GetGUID();
+
+ // Do not autochase our target, and also make sure our current movement generator
+ // is removed since the motion master is reset before this function is called
+ i_pet.GetMotionMaster()->Clear(false);
+ i_pet.GetMotionMaster()->MoveIdle();
+}
+
+bool PossessedAI::_needToStop() const
+{
+ if(!i_pet.getVictim() || !i_pet.isAlive())
+ return true;
+
+ // This is needed for charmed creatures, as once their target was reset other effects can trigger threat
+ if(i_pet.getVictim() == i_pet.GetCharmer())
+ return true;
+
+ return !i_pet.canAttack(i_pet.getVictim());
+}
+
+void PossessedAI::_stopAttack()
+{
+ if( !i_victimGuid )
+ return;
+
+ Unit* victim = Unit::GetUnit(i_pet, i_victimGuid );
+
+ if ( !victim )
+ return;
+
+ assert(!i_pet.getVictim() || i_pet.getVictim() == victim);
+
+ if( !i_pet.isAlive() )
+ {
+ i_pet.StopMoving();
+ i_pet.GetMotionMaster()->Clear(false);
+ i_pet.GetMotionMaster()->MoveIdle();
+ i_victimGuid = 0;
+ i_pet.CombatStop();
+ i_pet.getHostilRefManager().deleteReferences();
+
+ return;
+ }
+
+ i_pet.GetMotionMaster()->Clear(false);
+ i_pet.GetMotionMaster()->MoveIdle();
+ i_victimGuid = 0;
+ i_pet.AttackStop();
+}
+
+void PossessedAI::UpdateAI(const uint32 diff)
+{
+ // update i_victimGuid if i_pet.getVictim() !=0 and changed
+ if(i_pet.getVictim())
+ i_victimGuid = i_pet.getVictim()->GetGUID();
+
+ // i_pet.getVictim() can't be used for check in case stop fighting, i_pet.getVictim() clear at Unit death etc.
+ if( i_victimGuid )
+ {
+ if( _needToStop() )
+ {
+ _stopAttack(); // i_victimGuid == 0 && i_pet.getVictim() == NULL now
+ return;
+ }
+ else if(i_pet.IsWithinCombatDist(i_pet.getVictim(), ATTACK_DISTANCE) && i_pet.isAttackReady() && !i_pet.GetCharmer()->HasAuraType(SPELL_AURA_MOD_PACIFY))
+ {
+ i_pet.AttackerStateUpdate(i_pet.getVictim());
+
+ i_pet.resetAttackTimer();
+
+ if( _needToStop() )
+ _stopAttack();
+ }
+ }
+}
+
+bool PossessedAI::_isVisible(Unit *u) const
+{
+ return i_pet.GetDistance(u) < sWorld.getConfig(CONFIG_SIGHT_MONSTER)
+ && u->isVisibleForOrDetect(&i_pet,true);
+}
+
+void PossessedAI::JustDied(Unit *u)
+{
+ // We died while possessed, disable our loot
+ i_pet.RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
+}
+
+void PossessedAI::KilledUnit(Unit* victim)
+{
+ // We killed a creature, disable victim's loot
+ if (victim->GetTypeId() == TYPEID_UNIT)
+ victim->RemoveFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_LOOTABLE);
+}
diff --git a/src/game/QuestHandler.cpp b/src/game/QuestHandler.cpp
index 1dbb8e92b38..abb285e6dbb 100644
--- a/src/game/QuestHandler.cpp
+++ b/src/game/QuestHandler.cpp
@@ -31,6 +31,8 @@
#include "ObjectAccessor.h"
#include "ScriptCalls.h"
#include "Group.h"
+#include "BattleGround.h"
+#include "BattleGroundAV.h"
void WorldSession::HandleQuestgiverStatusQueryOpcode( WorldPacket & recv_data )
{
@@ -401,6 +403,12 @@ void WorldSession::HandleQuestComplete(WorldPacket& recv_data)
Quest const *pQuest = objmgr.GetQuestTemplate(quest);
if( pQuest )
{
+ // TODO: need a virtual function
+ if(GetPlayer()->InBattleGround())
+ if(BattleGround* bg = GetPlayer()->GetBattleGround())
+ if(bg->GetTypeID() == BATTLEGROUND_AV)
+ ((BattleGroundAV*)bg)->HandleQuestComplete(quest, GetPlayer());
+
if( _player->GetQuestStatus( quest ) != QUEST_STATUS_COMPLETE )
{
if( pQuest->IsRepeatable() )
diff --git a/src/game/ReactorAI.cpp b/src/game/ReactorAI.cpp
index 41e5fb51f10..9d596751075 100644
--- a/src/game/ReactorAI.cpp
+++ b/src/game/ReactorAI.cpp
@@ -123,7 +123,12 @@ ReactorAI::EnterEvadeMode()
i_creature.CombatStop();
i_creature.SetLootRecipient(NULL);
- // Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead
- if( i_creature.GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE )
- i_creature.GetMotionMaster()->MoveTargetedHome();
+ if(!i_creature.GetCharmerOrOwner())
+ {
+ // Remove TargetedMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead
+ if( i_creature.GetMotionMaster()->GetCurrentMovementGeneratorType() == TARGETED_MOTION_TYPE )
+ i_creature.GetMotionMaster()->MoveTargetedHome();
+ }
+ else if (i_creature.GetOwner() && i_creature.GetOwner()->isAlive())
+ i_creature.GetMotionMaster()->MoveFollow(i_creature.GetOwner(),PET_FOLLOW_DIST,PET_FOLLOW_ANGLE);
}
diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h
index 37dca1aa656..e57c4caf1d0 100644
--- a/src/game/SharedDefines.h
+++ b/src/game/SharedDefines.h
@@ -194,6 +194,19 @@ enum ItemQualities
#define MAX_ITEM_QUALITY 7
+enum SpellCategory
+{
+ SPELL_CATEGORY_FOOD = 11,
+ SPELL_CATEGORY_DRINK = 59,
+};
+
+enum SpellRangeFlag
+{
+ SPELL_RANGE_DEFAULT = 0,
+ SPELL_RANGE_MEELE = 1, //unused
+ SPELL_RANGE_RANGED = 2, //hunters' shoots, auto shoot, shoot, deadly throw, throw
+};
+
// ***********************************
// Spell Attributes definitions
// ***********************************
@@ -280,8 +293,8 @@ enum ItemQualities
#define SPELL_ATTR_EX2_UNK13 0x00002000 // 13
#define SPELL_ATTR_EX2_UNK14 0x00004000 // 14
#define SPELL_ATTR_EX2_UNK15 0x00008000 // 15 not set in 2.4.2
-#define SPELL_ATTR_EX2_UNK16 0x00010000 // 16
-#define SPELL_ATTR_EX2_UNK17 0x00020000 // 17 Hunters Shot and Stings only have this flag
+#define SPELL_ATTR_EX2_TAME_BEAST 0x00010000 // 16
+#define SPELL_ATTR_EX2_NOT_RESET_AUTOSHOT 0x00020000 // 17 Hunters Shot and Stings only have this flag
#define SPELL_ATTR_EX2_UNK18 0x00040000 // 18 Only Revive pet - possible req dead pet
#define SPELL_ATTR_EX2_NOT_NEED_SHAPESHIFT 0x00080000 // 19 does not necessarly need shapeshift
#define SPELL_ATTR_EX2_UNK20 0x00100000 // 20
@@ -295,7 +308,7 @@ enum ItemQualities
#define SPELL_ATTR_EX2_UNK28 0x10000000 // 28
#define SPELL_ATTR_EX2_CANT_CRIT 0x20000000 // 29 Spell can't crit
#define SPELL_ATTR_EX2_UNK30 0x40000000 // 30
-#define SPELL_ATTR_EX2_UNK31 0x80000000 // 31
+#define SPELL_ATTR_EX2_FOOD 0x80000000 // 31 food, well-fed, and a few others
#define SPELL_ATTR_EX3_UNK0 0x00000001 // 0
#define SPELL_ATTR_EX3_UNK1 0x00000002 // 1
@@ -2069,7 +2082,7 @@ enum SummonType
SUMMON_TYPE_CRITTER2 = 407,
SUMMON_TYPE_CRITTER3 = 307,
SUMMON_TYPE_UNKNOWN5 = 409,
- SUMMON_TYPE_UNKNOWN2 = 427,
+ SUMMON_TYPE_POSESSED3 = 427,
SUMMON_TYPE_POSESSED2 = 428
};
diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp
index da6d67a3c6c..c1c00944b99 100644
--- a/src/game/Spell.cpp
+++ b/src/game/Spell.cpp
@@ -48,6 +48,7 @@
#include "VMapFactory.h"
#include "BattleGround.h"
#include "Util.h"
+#include "TemporarySummon.h"
#define SPELL_CHANNEL_UPDATE_INTERVAL 1000
@@ -325,6 +326,8 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi
m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetProto()->Damage->DamageType);
}
}
+ // Set health leech amount to zero
+ m_healthLeech = 0;
if(originalCasterGUID)
m_originalCasterGUID = originalCasterGUID;
@@ -444,6 +447,7 @@ void Spell::FillTargetMap()
case SPELL_EFFECT_SUMMON_DEMON:
case SPELL_EFFECT_ADD_FARSIGHT:
case SPELL_EFFECT_TRIGGER_SPELL_2: //ritual of summon
+ case SPELL_EFFECT_TRIGGER_MISSILE:
{
tmpUnitMap.clear();
tmpUnitMap.push_back(m_caster);
@@ -675,6 +679,77 @@ void Spell::FillTargetMap()
}
}
+void Spell::prepareDataForTriggerSystem()
+{
+ //==========================================================================================
+ // Now fill data for trigger system, need know:
+ // Ñan spell trigger another or not ( m_canTrigger )
+ // Create base triggers flags for Attacker and Victim ( m_procAttacker and m_procVictim)
+ //==========================================================================================
+
+ // Fill flag can spell trigger or not
+ if (!m_IsTriggeredSpell)
+ m_canTrigger = true; // Normal cast - can trigger
+ else if (!m_triggeredByAuraSpell)
+ m_canTrigger = true; // Triggered from SPELL_EFFECT_TRIGGER_SPELL - can trigger
+ else // Exceptions (some periodic triggers)
+ {
+ m_canTrigger = false; // Triggered spells can`t trigger another
+ switch (m_spellInfo->SpellFamilyName)
+ {
+ case SPELLFAMILY_MAGE: // Arcane Missles triggers need do it
+ if (m_spellInfo->SpellFamilyFlags & 0x0000000000200000LL) m_canTrigger = true;
+ break;
+ case SPELLFAMILY_WARLOCK: // For Hellfire Effect / Rain of Fire / Seed of Corruption triggers need do it
+ if (m_spellInfo->SpellFamilyFlags & 0x0000800000000060LL) m_canTrigger = true;
+ break;
+ case SPELLFAMILY_HUNTER: // Hunter Explosive Trap Effect/Immolation Trap Effect/Frost Trap Aura/Snake Trap Effect
+ if (m_spellInfo->SpellFamilyFlags & 0x0000200000000014LL) m_canTrigger = true;
+ break;
+ case SPELLFAMILY_PALADIN: // For Holy Shock triggers need do it
+ if (m_spellInfo->SpellFamilyFlags & 0x0001000000200000LL) m_canTrigger = true;
+ break;
+ }
+ }
+ // Do not trigger from item cast spell
+ if (m_CastItem)
+ m_canTrigger = false;
+
+ // Get data for type of attack and fill base info for trigger
+ switch (m_spellInfo->DmgClass)
+ {
+ case SPELL_DAMAGE_CLASS_MELEE:
+ m_procAttacker = PROC_FLAG_SUCCESSFUL_MELEE_SPELL_HIT;
+ m_procVictim = PROC_FLAG_TAKEN_MELEE_SPELL_HIT;
+ break;
+ case SPELL_DAMAGE_CLASS_RANGED:
+ m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT;
+ m_procVictim = PROC_FLAG_TAKEN_RANGED_SPELL_HIT;
+ break;
+ default:
+ if (IsPositiveSpell(m_spellInfo->Id)) // Check for positive spell
+ {
+ m_procAttacker = PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL;
+ m_procVictim = PROC_FLAG_TAKEN_POSITIVE_SPELL;
+ }
+ else if (m_spellInfo->Id == 5019) // Wands
+ {
+ m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT;
+ m_procVictim = PROC_FLAG_TAKEN_RANGED_SPELL_HIT;
+ }
+ else
+ {
+ m_procAttacker = PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT;
+ m_procVictim = PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT;
+ }
+ break;
+ }
+ // Hunter traps spells (for Entrapment trigger)
+ // Gives your Immolation Trap, Frost Trap, Explosive Trap, and Snake Trap ....
+ if (m_spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && m_spellInfo->SpellFamilyFlags & 0x0000200000000014LL)
+ m_procAttacker |= PROC_FLAG_ON_TRAP_ACTIVATION;
+}
+
void Spell::CleanupTargetList()
{
m_UniqueTargetInfo.clear();
@@ -714,7 +789,8 @@ void Spell::AddUnitTarget(Unit* pVictim, uint32 effIndex)
if(m_originalCaster)
target.missCondition = m_originalCaster->SpellHitResult(pVictim, m_spellInfo, m_canReflect);
else
- target.missCondition = SPELL_MISS_NONE;
+ target.missCondition = SPELL_MISS_EVADE; //SPELL_MISS_NONE;
+
if (target.missCondition == SPELL_MISS_NONE)
++m_countOfHit;
else
@@ -833,7 +909,7 @@ void Spell::AddItemTarget(Item* pitem, uint32 effIndex)
target.effectMask = 1<<effIndex;
m_UniqueItemInfo.push_back(target);
}
-
+/*
void Spell::doTriggers(SpellMissInfo missInfo, uint32 damage, SpellSchoolMask damageSchoolMask, uint32 block, uint32 absorb, bool crit)
{
// Do triggers depends from hit result (triggers on hit do in effects)
@@ -909,7 +985,7 @@ void Spell::doTriggers(SpellMissInfo missInfo, uint32 damage, SpellSchoolMask da
break;
}
}
-}
+}*/
void Spell::DoAllEffectOnTarget(TargetInfo *target)
{
@@ -926,11 +1002,28 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
if (!unit)
return;
+ // Get original caster (if exist) and calculate damage/healing from him data
+ Unit *caster = m_originalCasterGUID ? m_originalCaster : m_caster;
+
+ // Skip if m_originalCaster not avaiable
+ if (!caster)
+ return;
+
SpellMissInfo missInfo = target->missCondition;
+
// Need init unitTarget by default unit (can changed in code on reflect)
// Or on missInfo!=SPELL_MISS_NONE unitTarget undefined (but need in trigger subsystem)
unitTarget = unit;
+ // Reset damage/healing counter
+ m_damage = 0;
+ m_healing = 0;
+
+ // Fill base trigger info
+ uint32 procAttacker = m_procAttacker;
+ uint32 procVictim = m_procVictim;
+ uint32 procEx = PROC_EX_NONE;
+
if (missInfo==SPELL_MISS_NONE) // In case spell hit target, do all effect on that target
DoSpellHitOnUnit(unit, mask);
else if (missInfo == SPELL_MISS_REFLECT) // In case spell reflect from target, do all effect on caster (if hit)
@@ -938,10 +1031,114 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
if (target->reflectResult == SPELL_MISS_NONE) // If reflected spell hit caster -> do all effect on him
DoSpellHitOnUnit(m_caster, mask);
}
+ else //TODO: This is a hack. need fix
+ {
+ uint32 tempMask = 0;
+ for(uint32 i = 0; i < 3; ++i)
+ if(m_spellInfo->Effect[i] == SPELL_EFFECT_DUMMY
+ || m_spellInfo->Effect[i] == SPELL_EFFECT_TRIGGER_SPELL)
+ tempMask |= 1<<i;
+ if(tempMask &= mask)
+ DoSpellHitOnUnit(unit, tempMask);
+ }
- // Do triggers only on miss/resist/parry/dodge
- if (missInfo!=SPELL_MISS_NONE)
- doTriggers(missInfo);
+ // All calculated do it!
+ // Do healing and triggers
+ if (m_healing)
+ {
+ bool crit = caster->isSpellCrit(NULL, m_spellInfo, m_spellSchoolMask);
+ uint32 addhealth = m_healing;
+ if (crit)
+ {
+ procEx |= PROC_EX_CRITICAL_HIT;
+ addhealth = caster->SpellCriticalBonus(m_spellInfo, addhealth, NULL);
+ }
+ else
+ procEx |= PROC_EX_NORMAL_HIT;
+
+ caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, crit);
+
+ // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
+ if (m_canTrigger && missInfo != SPELL_MISS_REFLECT)
+ caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, addhealth, m_attackType, m_spellInfo);
+
+ int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
+
+ unitTarget->getHostilRefManager().threatAssist(caster, float(gain) * 0.5f, m_spellInfo);
+ if(caster->GetTypeId()==TYPEID_PLAYER)
+ if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
+ bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
+ }
+ // Do damage and triggers
+ else if (m_damage)
+ {
+ // Fill base damage struct (unitTarget - is real spell target)
+ SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask);
+
+ // Add bonuses and fill damageInfo struct
+ caster->CalculateSpellDamage(&damageInfo, m_damage, m_spellInfo);
+
+ // Send log damage message to client
+ caster->SendSpellNonMeleeDamageLog(&damageInfo);
+
+ procEx = createProcExtendMask(&damageInfo, missInfo);
+ procVictim |= PROC_FLAG_TAKEN_ANY_DAMAGE;
+
+ // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
+ if (m_canTrigger && missInfo != SPELL_MISS_REFLECT)
+ caster->ProcDamageAndSpell(unitTarget, procAttacker, procVictim, procEx, damageInfo.damage, m_attackType, m_spellInfo);
+
+ caster->DealSpellDamage(&damageInfo, true);
+
+ // Shadow Word: Death - deals damage equal to damage done to caster if victim is not killed
+ if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && m_spellInfo->SpellFamilyFlags&0x0000000200000000LL &&
+ caster != unitTarget && unitTarget->isAlive())
+ {
+ // Redirect damage to caster if victim Alive
+ damageInfo.target = caster;
+ damageInfo.absorb = 0;
+ damageInfo.resist = 0;
+ damageInfo.blocked = 0;
+ // Send log damage message to client
+ caster->SendSpellNonMeleeDamageLog(&damageInfo);
+ caster->DealSpellDamage(&damageInfo, true);
+ }
+ // Judgement of Blood
+ else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && m_spellInfo->SpellFamilyFlags & 0x0000000800000000LL && m_spellInfo->SpellIconID==153)
+ {
+ int32 damagePoint = damageInfo.damage * 33 / 100;
+ m_caster->CastCustomSpell(m_caster, 32220, &damagePoint, NULL, NULL, true);
+ }
+ // Bloodthirst
+ else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR && m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
+ {
+ uint32 BTAura = 0;
+ switch(m_spellInfo->Id)
+ {
+ case 23881: BTAura = 23885; break;
+ case 23892: BTAura = 23886; break;
+ case 23893: BTAura = 23887; break;
+ case 23894: BTAura = 23888; break;
+ case 25251: BTAura = 25252; break;
+ case 30335: BTAura = 30339; break;
+ default:
+ sLog.outError("Spell::EffectSchoolDMG: Spell %u not handled in BTAura",m_spellInfo->Id);
+ break;
+ }
+ if (BTAura)
+ m_caster->CastSpell(m_caster,BTAura,true);
+ }
+ }
+ // Passive spell hits/misses or active spells only misses (only triggers)
+ else
+ {
+ // Fill base damage struct (unitTarget - is real spell target)
+ SpellNonMeleeDamage damageInfo(caster, unitTarget, m_spellInfo->Id, m_spellSchoolMask);
+ procEx = createProcExtendMask(&damageInfo, missInfo);
+ // Do triggers for unit (reflect triggers passed on hit phase for correct drop charge)
+ if (m_canTrigger && missInfo != SPELL_MISS_REFLECT)
+ caster->ProcDamageAndSpell(unit, procAttacker, procVictim, procEx, 0, m_attackType, m_spellInfo);
+ }
// Call scripted function for AI if this spell is casted upon a creature (except pets)
if(IS_CREATURE_GUID(target->targetGUID))
@@ -1063,14 +1260,15 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
}
}
- if(spellmgr.GetSpellCustomAttr(m_spellInfo->Id) && m_originalCaster)
+ //This is not needed with procflag patch
+ /*if(spellmgr.GetSpellCustomAttr(m_spellInfo->Id) && m_originalCaster)
{
uint32 flag = spellmgr.GetSpellCustomAttr(m_spellInfo->Id);
if(flag & SPELL_ATTR_CU_EFFECT_HEAL)
m_originalCaster->ProcDamageAndSpell(unit, PROC_FLAG_HEAL, PROC_FLAG_NONE, 0, GetSpellSchoolMask(m_spellInfo), m_spellInfo);
if(m_originalCaster != unit && (flag & SPELL_ATTR_CU_EFFECT_DAMAGE))
m_originalCaster->ProcDamageAndSpell(unit, PROC_FLAG_HIT_SPELL, PROC_FLAG_STRUCK_SPELL, 0, GetSpellSchoolMask(m_spellInfo), m_spellInfo);
- }
+ }*/
}
void Spell::DoAllEffectOnTarget(GOTargetInfo *target)
@@ -1279,7 +1477,7 @@ void Spell::SearchAreaTarget(std::list<Unit*> &TagUnitMap, float radius, const u
Trinity::SpellNotifierCreatureAndPlayer notifier(*this, TagUnitMap, radius, type, TargetType, entry);
- if(TargetType != SPELL_TARGETS_ENTRY)
+ //if(TargetType != SPELL_TARGETS_ENTRY)
{
TypeContainerVisitor<Trinity::SpellNotifierCreatureAndPlayer, WorldTypeMapContainer > world_object_notifier(notifier);
cell_lock->Visit(cell_lock, world_object_notifier, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
@@ -1307,7 +1505,9 @@ Unit* Spell::SearchNearbyTarget(float radius, SpellTargets TargetType, uint32 en
Creature* target = NULL;
Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_caster, entry, true, radius);
Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(target, u_check);
+ TypeContainerVisitor<Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher);
TypeContainerVisitor<Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, GridTypeMapContainer > grid_unit_searcher(searcher);
+ cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
return target;
}break;
@@ -1488,7 +1688,7 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
if(lower==upper)
{
SearchAreaTarget(TagUnitMap, radius, PUSH_DEST_CENTER, SPELL_TARGETS_AOE_DAMAGE);
- //sLog.outErrorDb("Spell (ID: %u) has effect EffectImplicitTargetA/EffectImplicitTargetB = TARGET_SCRIPT, but does not have record in `spell_script_target`",m_spellInfo->Id);
+ sLog.outErrorDb("Spell (ID: %u) (caster Entry: %u) does not have record in `spell_script_target`", m_spellInfo->Id, m_caster->GetEntry());
break;
}
// let it be done in one check?
@@ -1533,11 +1733,16 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
}break;
case TARGET_SCRIPT:
case TARGET_SCRIPT_COORDINATES:
+ case TARGET_UNIT_AREA_SCRIPT:
{
SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(m_spellInfo->Id);
SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id);
if(lower==upper)
- sLog.outErrorDb("Spell (ID: %u) has effect EffectImplicitTargetA/EffectImplicitTargetB = TARGET_SCRIPT or TARGET_SCRIPT_COORDINATES, but does not have record in `spell_script_target`",m_spellInfo->Id);
+ {
+ sLog.outErrorDb("Spell (ID: %u) (caster Entry: %u) does not have record in `spell_script_target`", m_spellInfo->Id, m_caster->GetEntry());
+ TagUnitMap.push_back(m_caster);
+ break;
+ }
SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex);
float range = GetSpellMaxRange(srange);
@@ -1600,9 +1805,11 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_caster,i_spellST->second.targetEntry,i_spellST->second.type!=SPELL_TARGET_TYPE_DEAD,range);
Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(p_Creature, u_check);
+ TypeContainerVisitor<Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, WorldTypeMapContainer > world_creature_searcher(searcher);
TypeContainerVisitor<Trinity::CreatureLastSearcher<Trinity::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, GridTypeMapContainer > grid_creature_searcher(searcher);
CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, world_creature_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
cell_lock->Visit(cell_lock, grid_creature_searcher, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster));
if(p_Creature )
@@ -2132,6 +2339,9 @@ void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura)
return;
}
+ // Prepare data for triggers
+ prepareDataForTriggerSystem();
+
// calculate cast time (calculated after first CanCast check to prevent charge counting for first CanCast fail)
m_casttime = GetSpellCastTime(m_spellInfo, this);
@@ -2142,6 +2352,11 @@ void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura)
cast(true);
else
{
+ // stealth must be removed at cast starting (at show channel bar)
+ // skip triggered spell (item equip spell casting and other not explicit character casts/item uses)
+ if(isSpellBreakStealth(m_spellInfo) )
+ m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CAST);
+
m_caster->SetCurrentCastedSpell( this );
m_selfContainer = &(m_caster->m_currentSpells[GetCurrentContainer()]);
SendSpellStart();
@@ -2186,6 +2401,20 @@ void Spell::cancel()
} break;
}
+ // Unsummon summon as possessed creatures on spell cancel
+ for (int i = 0; i < 3; i++)
+ {
+ if (m_spellInfo->Effect[i] == SPELL_EFFECT_SUMMON &&
+ (m_spellInfo->EffectMiscValueB[i] == SUMMON_TYPE_POSESSED ||
+ m_spellInfo->EffectMiscValueB[i] == SUMMON_TYPE_POSESSED2 ||
+ m_spellInfo->EffectMiscValueB[i] == SUMMON_TYPE_POSESSED3))
+ {
+ // Possession is removed in the UnSummon function
+ if (m_caster->GetCharm())
+ ((TemporarySummon*)m_caster->GetCharm())->UnSummon();
+ }
+ }
+
finish(false);
m_caster->RemoveDynObject(m_spellInfo->Id);
m_caster->RemoveGameObject(m_spellInfo->Id,true);
@@ -2235,13 +2464,6 @@ void Spell::cast(bool skipCheck)
FillTargetMap();
- // stealth must be removed at cast starting (at show channel bar)
- // skip triggered spell (item equip spell casting and other not explicit character casts/item uses)
- if ( !m_IsTriggeredSpell && isSpellBreakStealth(m_spellInfo) )
- {
- m_caster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CAST);
- }
-
// who did this hack?
// Conflagrate - consumes immolate
if ((m_spellInfo->TargetAuraState == AURA_STATE_IMMOLATE) && m_targets.getUnitTarget())
@@ -2277,8 +2499,11 @@ void Spell::cast(bool skipCheck)
// CAST SPELL
SendSpellCooldown();
- TakePower();
- TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot
+ if(!m_IsTriggeredSpell)
+ {
+ TakePower();
+ TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot
+ }
if(m_spellState == SPELL_STATE_FINISHED) // stop cast if spell marked as finish somewhere in Take*/FillTargetMap
{
@@ -2289,15 +2514,6 @@ void Spell::cast(bool skipCheck)
SendCastResult(castResult);
SendSpellGo(); // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()...
- // Pass cast spell event to handler (not send triggered by aura spells)
- if (m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE && m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_RANGED && !m_triggeredByAuraSpell)
- {
- m_caster->ProcDamageAndSpell(m_targets.getUnitTarget(), PROC_FLAG_CAST_SPELL, PROC_FLAG_NONE, 0, SPELL_SCHOOL_MASK_NONE, m_spellInfo, m_IsTriggeredSpell);
-
- // update pointers base at GUIDs to prevent access to non-existed already object
- UpdatePointers(); // pointers can be invalidate at triggered spell casting
- }
-
// Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
if (m_spellInfo->speed > 0.0f && !IsChanneledSpell(m_spellInfo))
{
@@ -2707,21 +2923,31 @@ void Spell::finish(bool ok)
int32 chance = m_caster->CalculateSpellDamage(auraSpellInfo, auraSpellIdx, (*i)->GetBasePoints(),unit);
if(roll_chance_i(chance))
- m_caster->CastSpell(unit, auraSpellInfo->EffectTriggerSpell[auraSpellIdx], true, NULL, (*i));
+ for (int j=0; j != (*i)->GetStackAmount(); ++j)
+ m_caster->CastSpell(unit, auraSpellInfo->EffectTriggerSpell[auraSpellIdx], true, NULL, (*i));
}
}
}
}
- /*if (IsMeleeAttackResetSpell())
+ // Heal caster for all health leech from all targets
+ if (m_healthLeech)
+ {
+ m_caster->ModifyHealth(m_healthLeech);
+ m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(m_healthLeech));
+ }
+
+ if (IsMeleeAttackResetSpell())
{
m_caster->resetAttackTimer(BASE_ATTACK);
if(m_caster->haveOffhandWeapon())
m_caster->resetAttackTimer(OFF_ATTACK);
- }*/
+ if(!(m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_NOT_RESET_AUTOSHOT))
+ m_caster->resetAttackTimer(RANGED_ATTACK);
+ }
- /*if (IsRangedAttackResetSpell())
- m_caster->resetAttackTimer(RANGED_ATTACK);*/
+ //if (IsRangedAttackResetSpell())
+ // m_caster->resetAttackTimer(RANGED_ATTACK);
// Clear combo at finish state
if(m_caster->GetTypeId() == TYPEID_PLAYER && NeedsComboPoints(m_spellInfo))
@@ -2768,13 +2994,23 @@ void Spell::SendCastResult(uint8 result)
break;
case SPELL_FAILED_REQUIRES_AREA:
// hardcode areas limitation case
- if( m_spellInfo->Id==41618 || m_spellInfo->Id==41620 )
- data << uint32(3842);
- else if( m_spellInfo->Id==41617 || m_spellInfo->Id==41619 )
- data << uint32(3905);
- // normal case
- else
- data << uint32(m_spellInfo->AreaId);
+ switch(m_spellInfo->Id)
+ {
+ case 41617: // Cenarion Mana Salve
+ case 41619: // Cenarion Healing Salve
+ data << uint32(3905);
+ break;
+ case 41618: // Bottled Nethergon Energy
+ case 41620: // Bottled Nethergon Vapor
+ data << uint32(3842);
+ break;
+ case 45373: // Bloodberry Elixir
+ data << uint32(4075);
+ break;
+ default: // default case
+ data << uint32(m_spellInfo->AreaId);
+ break;
+ }
break;
case SPELL_FAILED_TOTEMS:
if(m_spellInfo->Totem[0])
@@ -3540,8 +3776,144 @@ uint8 Spell::CanCast(bool strict)
if(uint8 castResult = CheckItems())
return castResult;
- if(uint8 castResult = CheckRange(strict))
- return castResult;
+ /*//ImpliciteTargetA-B = 38, If fact there is 0 Spell with ImpliciteTargetB=38
+ if(m_UniqueTargetInfo.empty()) // skip second canCast apply (for delayed spells for example)
+ {
+ for(uint8 j = 0; j < 3; j++)
+ {
+ if( m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT ||
+ m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT && m_spellInfo->EffectImplicitTargetA[j] != TARGET_SELF ||
+ m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES ||
+ m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES )
+ {
+ SpellScriptTarget::const_iterator lower = spellmgr.GetBeginSpellScriptTarget(m_spellInfo->Id);
+ SpellScriptTarget::const_iterator upper = spellmgr.GetEndSpellScriptTarget(m_spellInfo->Id);
+ if(lower==upper)
+ sLog.outErrorDb("Spell (ID: %u) has effect EffectImplicitTargetA/EffectImplicitTargetB = TARGET_SCRIPT or TARGET_SCRIPT_COORDINATES, but does not have record in `spell_script_target`",m_spellInfo->Id);
+
+ SpellRangeEntry const* srange = sSpellRangeStore.LookupEntry(m_spellInfo->rangeIndex);
+ float range = GetSpellMaxRange(srange);
+
+ Creature* creatureScriptTarget = NULL;
+ GameObject* goScriptTarget = NULL;
+
+ for(SpellScriptTarget::const_iterator i_spellST = lower; i_spellST != upper; ++i_spellST)
+ {
+ switch(i_spellST->second.type)
+ {
+ case SPELL_TARGET_TYPE_GAMEOBJECT:
+ {
+ GameObject* p_GameObject = NULL;
+
+ if(i_spellST->second.targetEntry)
+ {
+ CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+
+ MaNGOS::NearestGameObjectEntryInObjectRangeCheck go_check(*m_caster,i_spellST->second.targetEntry,range);
+ MaNGOS::GameObjectLastSearcher<MaNGOS::NearestGameObjectEntryInObjectRangeCheck> checker(p_GameObject,go_check);
+
+ TypeContainerVisitor<MaNGOS::GameObjectLastSearcher<MaNGOS::NearestGameObjectEntryInObjectRangeCheck>, GridTypeMapContainer > object_checker(checker);
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, object_checker, *m_caster->GetMap());
+
+ if(p_GameObject)
+ {
+ // remember found target and range, next attempt will find more near target with another entry
+ creatureScriptTarget = NULL;
+ goScriptTarget = p_GameObject;
+ range = go_check.GetLastRange();
+ }
+ }
+ else if( focusObject ) //Focus Object
+ {
+ float frange = m_caster->GetDistance(focusObject);
+ if(range >= frange)
+ {
+ creatureScriptTarget = NULL;
+ goScriptTarget = focusObject;
+ range = frange;
+ }
+ }
+ break;
+ }
+ case SPELL_TARGET_TYPE_CREATURE:
+ case SPELL_TARGET_TYPE_DEAD:
+ default:
+ {
+ Creature *p_Creature = NULL;
+
+ CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY()));
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+ cell.SetNoCreate(); // Really don't know what is that???
+
+ MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*m_caster,i_spellST->second.targetEntry,i_spellST->second.type!=SPELL_TARGET_TYPE_DEAD,range);
+ MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(p_Creature, u_check);
+
+ TypeContainerVisitor<MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck>, GridTypeMapContainer > grid_creature_searcher(searcher);
+
+ CellLock<GridReadGuard> cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, grid_creature_searcher, *m_caster->GetMap());
+
+ if(p_Creature )
+ {
+ creatureScriptTarget = p_Creature;
+ goScriptTarget = NULL;
+ range = u_check.GetLastRange();
+ }
+ break;
+ }
+ }
+ }
+
+ if(creatureScriptTarget)
+ {
+ // store coordinates for TARGET_SCRIPT_COORDINATES
+ if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES ||
+ m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES )
+ {
+ m_targets.setDestination(creatureScriptTarget->GetPositionX(),creatureScriptTarget->GetPositionY(),creatureScriptTarget->GetPositionZ());
+
+ if(m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES && m_spellInfo->EffectImplicitTargetB[j] == 0 && m_spellInfo->Effect[j]!=SPELL_EFFECT_PERSISTENT_AREA_AURA)
+ AddUnitTarget(creatureScriptTarget, j);
+ }
+ // store explicit target for TARGET_SCRIPT
+ else
+ AddUnitTarget(creatureScriptTarget, j);
+ }
+ else if(goScriptTarget)
+ {
+ // store coordinates for TARGET_SCRIPT_COORDINATES
+ if (m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES ||
+ m_spellInfo->EffectImplicitTargetB[j] == TARGET_SCRIPT_COORDINATES )
+ {
+ m_targets.setDestination(goScriptTarget->GetPositionX(),goScriptTarget->GetPositionY(),goScriptTarget->GetPositionZ());
+
+ if(m_spellInfo->EffectImplicitTargetA[j] == TARGET_SCRIPT_COORDINATES && m_spellInfo->EffectImplicitTargetB[j] == 0 && m_spellInfo->Effect[j]!=SPELL_EFFECT_PERSISTENT_AREA_AURA)
+ AddGOTarget(goScriptTarget, j);
+ }
+ // store explicit target for TARGET_SCRIPT
+ else
+ AddGOTarget(goScriptTarget, j);
+ }
+ //Missing DB Entry or targets for this spellEffect.
+ else
+ {
+ // not report target not existence for triggered spells
+ if(m_triggeredByAuraSpell || m_IsTriggeredSpell)
+ return SPELL_FAILED_DONT_REPORT;
+ else
+ return SPELL_FAILED_BAD_TARGETS;
+ }
+ }
+ }
+ }*/
+
+ if(!m_triggeredByAuraSpell)
+ if(uint8 castResult = CheckRange(strict))
+ return castResult;
{
if(uint8 castResult = CheckPower())
@@ -3865,6 +4237,7 @@ uint8 Spell::CanCast(bool strict)
{
case SUMMON_TYPE_POSESSED:
case SUMMON_TYPE_POSESSED2:
+ case SUMMON_TYPE_POSESSED3:
case SUMMON_TYPE_DEMON:
case SUMMON_TYPE_SUMMON:
{
@@ -4134,7 +4507,8 @@ int16 Spell::PetCanCast(Unit* target)
duelvsplayertar |= (m_spellInfo->EffectImplicitTargetA[j] == TARGET_DUELVSPLAYER);
}
// AoE spells have the caster as their target
- if(m_caster->IsFriendlyTo(target) && m_caster != target && !duelvsplayertar)
+ // AOE spells should not have target
+ if(m_caster->IsFriendlyTo(target) /*&& m_caster != target*/ && !duelvsplayertar)
{
return SPELL_FAILED_BAD_TARGETS;
}
diff --git a/src/game/Spell.h b/src/game/Spell.h
index 2a724d41b68..365acb93ce9 100644
--- a/src/game/Spell.h
+++ b/src/game/Spell.h
@@ -395,7 +395,7 @@ class Spell
}
bool IsChannelActive() const { return m_caster->GetUInt32Value(UNIT_CHANNEL_SPELL) != 0; }
bool IsMeleeAttackResetSpell() const { return !m_IsTriggeredSpell && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_AUTOATTACK); }
- bool IsRangedAttackResetSpell() const { return !m_IsTriggeredSpell && IsRangedSpell() && (m_spellInfo->InterruptFlags & SPELL_INTERRUPT_FLAG_AUTOATTACK); }
+ bool IsRangedAttackResetSpell() const { return !m_IsTriggeredSpell && /*IsRangedSpell() &&*/ !(m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_NOT_RESET_AUTOSHOT); }
bool IsDeletable() const { return !m_referencedFromCurrentSpell && !m_executedCurrently; }
void SetReferencedFromCurrent(bool yes) { m_referencedFromCurrentSpell = yes; }
@@ -470,10 +470,18 @@ class Spell
// -------------------------------------------
GameObject* focusObject;
+ // Damage and healing in effects need just calculate
+ int32 m_damage; // Damge in effects count here
+ int32 m_healing; // Healing in effects count here
+ int32 m_healthLeech; // Health leech in effects for all targets count here
+
//******************************************
// Spell trigger system
//******************************************
- void doTriggers(SpellMissInfo missInfo, uint32 damage=0, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NONE, uint32 block=0, uint32 absorb=0, bool crit=false);
+ bool m_canTrigger; // Can start trigger (m_IsTriggeredSpell can`t use for this)
+ uint32 m_procAttacker; // Attacker trigger flags
+ uint32 m_procVictim; // Victim trigger flags
+ void prepareDataForTriggerSystem();
//*****************************************
// Spell target subsystem
diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp
index 55203554665..490bd630006 100644
--- a/src/game/SpellAuras.cpp
+++ b/src/game/SpellAuras.cpp
@@ -49,7 +49,6 @@
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
-#include "TemporarySummon.h"
#define NULL_AURA_SLOT 0xFF
@@ -258,8 +257,8 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleNoImmediateEffect, //200 SPELL_AURA_MOD_XP_PCT implemented in Player::GiveXP
&Aura::HandleAuraAllowFlight, //201 SPELL_AURA_FLY this aura enable flight mode...
&Aura::HandleNoImmediateEffect, //202 SPELL_AURA_CANNOT_BE_DODGED implemented in Unit::RollPhysicalOutcomeAgainst
- &Aura::HandleNoImmediateEffect, //203 SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE implemented in Unit::DoAttackDamage
- &Aura::HandleNoImmediateEffect, //204 SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE implemented in Unit::DoAttackDamage
+ &Aura::HandleNoImmediateEffect, //203 SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE implemented in Unit::CalculateMeleeDamage and Unit::CalculateSpellDamage
+ &Aura::HandleNoImmediateEffect, //204 SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE implemented in Unit::CalculateMeleeDamage and Unit::CalculateSpellDamage
&Aura::HandleNULL, //205 vulnerable to school dmg?
&Aura::HandleNULL, //206 SPELL_AURA_MOD_SPEED_MOUNTED
&Aura::HandleAuraModIncreaseFlightSpeed, //207 SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
@@ -320,7 +319,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
};
Aura::Aura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target, Unit *caster, Item* castItem) :
-m_procCharges(0), m_spellmod(NULL), m_effIndex(eff), m_caster_guid(0), m_target(target),
+m_procCharges(0), m_stackAmount(1), m_spellmod(NULL), m_effIndex(eff), m_caster_guid(0), m_target(target),
m_timeCla(1000), m_castItemGuid(castItem?castItem->GetGUID():0), m_auraSlot(MAX_AURAS),
m_positive(false), m_permanent(false), m_isPeriodic(false), m_isTrigger(false), m_isAreaAura(false),
m_isPersistent(false), m_updated(false), m_removeMode(AURA_REMOVE_BY_DEFAULT), m_isRemovedOnShapeLost(true), m_in_use(false),
@@ -837,7 +836,6 @@ void Aura::_AddAura()
return;
// we can found aura in NULL_AURA_SLOT and then need store state instead check slot != NULL_AURA_SLOT
- bool samespell = false;
bool secondaura = false;
uint8 slot = NULL_AURA_SLOT;
@@ -849,15 +847,13 @@ void Aura::_AddAura()
// allow use single slot only by auras from same caster
if(itr->second->GetCasterGUID()==GetCasterGUID())
{
- samespell = true;
- if (m_effIndex > itr->second->GetEffIndex())
- secondaura = true;
+ secondaura = true;
slot = itr->second->GetAuraSlot();
break;
}
}
- if(samespell)
+ if(secondaura)
break;
}
@@ -886,7 +882,7 @@ void Aura::_AddAura()
if((!m_isPassive || (caster && caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->isTotem())) &&
(m_spellProto->Effect[GetEffIndex()] != SPELL_EFFECT_APPLY_AREA_AURA_ENEMY || m_target != caster))
{
- if(!samespell) // new slot need
+ if(!secondaura) // new slot need
{
if (IsPositive()) // empty positive slot
{
@@ -914,29 +910,23 @@ void Aura::_AddAura()
SetAuraSlot( slot );
// Not update fields for not first spell's aura, all data already in fields
- if(!secondaura)
+ if(slot < MAX_AURAS) // slot found
{
- if(slot < MAX_AURAS) // slot found
- {
- SetAura(slot, false);
- SetAuraFlag(slot, true);
- SetAuraLevel(slot,caster ? caster->getLevel() : sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL));
- UpdateAuraCharges();
-
- // update for out of range group members
- m_target->UpdateAuraForGroup(slot);
- }
-
- UpdateAuraDuration();
+ SetAura(slot, false);
+ SetAuraFlag(slot, true);
+ SetAuraLevel(slot,caster ? caster->getLevel() : sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL));
+ UpdateAuraCharges();
+
+ // update for out of range group members
+ m_target->UpdateAuraForGroup(slot);
}
}
else // use found slot
{
SetAuraSlot( slot );
- // Not recalculate stack count for second aura of the same spell
- if (!secondaura)
- UpdateSlotCounterAndDuration(true);
}
+
+ UpdateSlotCounterAndDuration();
// Update Seals information
if( IsSealSpell(GetSpellProto()) )
@@ -988,7 +978,6 @@ void Aura::_RemoveAura()
return;
bool samespell = false;
- bool sameaura = false;
// find other aura in same slot (current already removed from list)
for(uint8 i = 0; i < 3; i++)
@@ -1000,9 +989,6 @@ void Aura::_RemoveAura()
{
samespell = true;
- if(GetEffIndex()==i)
- sameaura = true;
-
break;
}
}
@@ -1054,8 +1040,6 @@ void Aura::_RemoveAura()
((Player*)caster)->SendCooldownEvent(GetSpellProto());
}
}
- else if(sameaura) // decrease count for spell, only for same aura effect, or this spell auras in remove process.
- UpdateSlotCounterAndDuration(false);
}
void Aura::SetAuraFlag(uint32 slot, bool add)
@@ -1094,35 +1078,13 @@ void Aura::SetAuraApplication(uint32 slot, int8 count)
m_target->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS + index, val);
}
-void Aura::UpdateSlotCounterAndDuration(bool add)
+void Aura::UpdateSlotCounterAndDuration()
{
uint8 slot = GetAuraSlot();
if(slot >= MAX_AURAS)
return;
- // calculate amount of similar auras by same effect index (similar different spells)
- int8 count = 0;
-
- // calculate auras and update durations in case aura adding
- Unit::AuraList const& aura_list = m_target->GetAurasByType(GetModifier()->m_auraname);
- for(Unit::AuraList::const_iterator i = aura_list.begin();i != aura_list.end(); ++i)
- {
- if( (*i)->GetId()==GetId() && (*i)->GetEffIndex()==m_effIndex &&
- (*i)->GetCasterGUID()==GetCasterGUID() )
- {
- ++count;
-
- if(add)
- (*i)->SetAuraDuration(GetAuraDuration());
- }
- }
-
- // at aura add aura not added yet, at aura remove aura already removed
- // in field stored (count-1)
- if(!add)
- --count;
-
- SetAuraApplication(slot, count);
+ SetAuraApplication(slot, m_stackAmount-1);
UpdateAuraDuration();
}
@@ -1156,7 +1118,7 @@ void Aura::HandleAddModifier(bool apply, bool Real)
SpellModifier *mod = new SpellModifier;
mod->op = SpellModOp(m_modifier.m_miscvalue);
- mod->value = m_modifier.m_amount;
+ mod->value = GetModifierValue();
mod->type = SpellModType(m_modifier.m_auraname); // SpellModType value == spell aura types
mod->spellId = GetId();
mod->effectId = m_effIndex;
@@ -1340,8 +1302,19 @@ void Aura::TriggerSpell()
// case 27601: break;
// // Five Fat Finger Exploding Heart Technique
// case 27673: break;
-// // Nitrous Boost
-// case 27746: break;
+ // Nitrous Boost
+ case 27746:
+ {
+ if (caster->GetPower(POWER_MANA) >= 10)
+ {
+ caster->ModifyPower( POWER_MANA, -10 );
+ caster->SendEnergizeSpellLog(caster, 27746, -10, POWER_MANA);
+ } else
+ {
+ caster->RemoveAurasDueToSpell(27746);
+ return;
+ }
+ } break;
// // Steam Tank Passive
// case 27747: break;
// // Frost Blast
@@ -1859,8 +1832,8 @@ void Aura::TriggerSpell()
{
switch((*i)->GetModifier()->m_miscvalue)
{
- case STAT_INTELLECT: intellectLoss += (*i)->GetModifier()->m_amount; break;
- case STAT_SPIRIT: spiritLoss += (*i)->GetModifier()->m_amount; break;
+ case STAT_INTELLECT: intellectLoss += (*i)->GetModifierValue(); break;
+ case STAT_SPIRIT: spiritLoss += (*i)->GetModifierValue(); break;
default: break;
}
}
@@ -2024,13 +1997,6 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
m_target->CastSpell(m_target,47287,true,NULL,this);
return;
}
-
- // Eye of Kilrogg, unsummon eye when aura is gone
- if(GetId() == 126 && caster->GetTypeId() == TYPEID_PLAYER && caster->GetCharm())
- {
- ((TemporarySummon*)caster->GetCharm())->UnSummon();
- return;
- }
}
// AT APPLY & REMOVE
@@ -2128,21 +2094,26 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
if(m_target->GetTypeId()!=TYPEID_PLAYER || !((Player*)m_target)->GetSession()->PlayerLoading())
m_modifier.m_amount = caster->SpellHealingBonus(GetSpellProto(), m_modifier.m_amount, SPELL_DIRECT_DAMAGE, m_target);
}
- else
+ // Do final heal for real apply
+ else if (Real)
{
- // Final heal only on dispelled or duration end
- if ( !(GetAuraDuration() <= 0 || m_removeMode==AURA_REMOVE_BY_DISPEL) )
- return;
- // have a look if there is still some other Lifebloom dummy aura
- Unit::AuraList auras = m_target->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraList::iterator itr = auras.begin(); itr!=auras.end(); itr++)
- if((*itr)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID &&
- (*itr)->GetSpellProto()->SpellFamilyFlags & 0x1000000000LL)
- return;
-
- // final heal
- m_target->CastCustomSpell(m_target,33778,&m_modifier.m_amount,NULL,NULL,true,NULL,this,GetCasterGUID());
+ // Final heal only on dispelled or duration end or 1 stack
+ if (!(GetAuraDuration() <= 0 || (m_removeMode==AURA_REMOVE_BY_DISPEL)))
+ {
+ // have a look if there is still some other Lifebloom dummy aura
+ Unit::AuraList auras = m_target->GetAurasByType(SPELL_AURA_DUMMY);
+ for(Unit::AuraList::iterator itr = auras.begin(); itr!=auras.end(); itr++)
+ if((*itr)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID &&
+ (*itr)->GetSpellProto()->SpellFamilyFlags & 0x1000000000LL)
+ if((*itr)->GetCasterGUID() == GetCasterGUID())
+ return;
+ }
+ else
+ {
+ // final heal
+ m_target->CastCustomSpell(m_target,33778,&m_modifier.m_amount,NULL,NULL,true,NULL,this,GetCasterGUID());
+ }
}
return;
}
@@ -2814,7 +2785,7 @@ void Aura::HandleAuraModSkill(bool apply, bool Real)
return;
uint32 prot=GetSpellProto()->EffectMiscValue[m_effIndex];
- int32 points = GetModifier()->m_amount;
+ int32 points = GetModifierValue();
((Player*)m_target)->ModifySkillBonus(prot,(apply ? points: -points),m_modifier.m_auraname==SPELL_AURA_MOD_SKILL_TALENT);
if(prot == SKILL_DEFENSE)
@@ -2827,7 +2798,12 @@ void Aura::HandleChannelDeathItem(bool apply, bool Real)
{
Unit* caster = GetCaster();
Unit* victim = GetTarget();
- if(!caster || caster->GetTypeId() != TYPEID_PLAYER || !victim || m_removeMode!=AURA_REMOVE_BY_DEATH)
+ if(!caster || caster->GetTypeId() != TYPEID_PLAYER || !victim)// || m_removeMode!=AURA_REMOVE_BY_DEATH)
+ return;
+
+ //we cannot check removemode = death
+ //talent will remove the caster's aura->interrupt channel->remove victim aura
+ if(victim->GetHealth() > 0)
return;
SpellEntry const *spellInfo = GetSpellProto();
@@ -2906,7 +2882,7 @@ void Aura::HandleAuraTrackStealthed(bool apply, bool Real)
void Aura::HandleAuraModScale(bool apply, bool Real)
{
- m_target->ApplyPercentModFloatValue(OBJECT_FIELD_SCALE_X,m_modifier.m_amount,apply);
+ m_target->ApplyPercentModFloatValue(OBJECT_FIELD_SCALE_X,GetModifierValue(),apply);
}
void Aura::HandleModPossess(bool apply, bool Real)
@@ -3094,6 +3070,9 @@ void Aura::HandleFeignDeath(bool apply, bool Real)
data<<uint8(0);
m_target->SendMessageToSet(&data,true);
*/
+
+ m_target->SetVisibility(VISIBILITY_OFF);
+ m_target->SetVisibility(VISIBILITY_ON);
// blizz like 2.0.x
m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN6);
// blizz like 2.0.x
@@ -3144,18 +3123,23 @@ void Aura::HandleAuraModDisarm(bool apply, bool Real)
else
m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED);
- // only at real add/remove aura
- if (m_target->GetTypeId() != TYPEID_PLAYER)
- return;
-
- // main-hand attack speed already set to special value for feral form already and don't must change and reset at remove.
- if (((Player *)m_target)->IsInFeralForm())
- return;
+ if (m_target->GetTypeId() == TYPEID_PLAYER)
+ {
+ // main-hand attack speed already set to special value for feral form already and don't must change and reset at remove.
+ if (((Player *)m_target)->IsInFeralForm())
+ return;
- if (apply)
- m_target->SetAttackTime(BASE_ATTACK,BASE_ATTACK_TIME);
+ if (apply)
+ m_target->SetAttackTime(BASE_ATTACK,BASE_ATTACK_TIME);
+ else
+ ((Player *)m_target)->SetRegularAttackTime();
+ }
else
- ((Player *)m_target)->SetRegularAttackTime();
+ {
+ // creature does not have equipment
+ if(apply && !((Creature*)m_target)->GetCurrentEquipmentId())
+ return;
+ }
m_target->UpdateDamagePhysical(BASE_ATTACK);
}
@@ -3490,15 +3474,11 @@ void Aura::HandleAuraModSilence(bool apply, bool Real)
return;
// Search Mana Tap auras on caster
- int32 energy = 0;
- Unit::AuraList const& m_dummyAuras = caster->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraList::const_iterator i = m_dummyAuras.begin(); i != m_dummyAuras.end(); ++i)
- if ((*i)->GetId() == 28734)
- ++energy;
- if (energy)
+ Aura * dummy = caster->GetDummyAura(28734);
+ if (dummy)
{
- energy *= 10;
- caster->CastCustomSpell(caster, 25048, &energy, NULL, NULL, true);
+ int32 bp = dummy->m_stackAmount * 10;
+ caster->CastCustomSpell(caster, 25048, &bp, NULL, NULL, true);
caster->RemoveAurasDueToSpell(28734);
}
}
@@ -3551,7 +3531,7 @@ void Aura::HandleModThreat(bool apply, bool Real)
if(m_modifier.m_miscvalue & int32(1<<x))
{
if(m_target->GetTypeId() == TYPEID_PLAYER)
- ApplyPercentModFloatVar(m_target->m_threatModifier[x], m_positive ? m_modifier.m_amount : -m_modifier.m_amount, apply);
+ ApplyPercentModFloatVar(m_target->m_threatModifier[x], m_positive ? GetModifierValue() : -GetModifierValue(), apply);
}
}
}
@@ -3572,9 +3552,9 @@ void Aura::HandleAuraModTotalThreat(bool apply, bool Real)
float threatMod = 0.0f;
if(apply)
- threatMod = float(m_modifier.m_amount);
+ threatMod = float(GetModifierValue());
else
- threatMod = float(-m_modifier.m_amount);
+ threatMod = float(-GetModifierValue());
m_target->getHostilRefManager().threatAssist(caster, threatMod);
}
@@ -4234,9 +4214,9 @@ void Aura::HandleAuraModResistanceExclusive(bool apply, bool Real)
{
if(m_modifier.m_miscvalue & int32(1<<x))
{
- m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_VALUE, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_VALUE, float(GetModifierValue()), apply);
if(m_target->GetTypeId() == TYPEID_PLAYER)
- m_target->ApplyResistanceBuffModsMod(SpellSchools(x),m_positive,m_modifier.m_amount, apply);
+ m_target->ApplyResistanceBuffModsMod(SpellSchools(x),m_positive,GetModifierValue(), apply);
}
}
}
@@ -4247,9 +4227,9 @@ void Aura::HandleAuraModResistance(bool apply, bool Real)
{
if(m_modifier.m_miscvalue & int32(1<<x))
{
- m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), TOTAL_VALUE, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), TOTAL_VALUE, float(GetModifierValue()), apply);
if(m_target->GetTypeId() == TYPEID_PLAYER || ((Creature*)m_target)->isPet())
- m_target->ApplyResistanceBuffModsMod(SpellSchools(x),m_positive,m_modifier.m_amount, apply);
+ m_target->ApplyResistanceBuffModsMod(SpellSchools(x),m_positive,GetModifierValue(), apply);
}
}
@@ -4269,14 +4249,14 @@ void Aura::HandleAuraModBaseResistancePCT(bool apply, bool Real)
{
//pets only have base armor
if(((Creature*)m_target)->isPet() && (m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_NORMAL))
- m_target->HandleStatModifier(UNIT_MOD_ARMOR, BASE_PCT, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UNIT_MOD_ARMOR, BASE_PCT, float(GetModifierValue()), apply);
}
else
{
for(int8 x = SPELL_SCHOOL_NORMAL; x < MAX_SPELL_SCHOOL;x++)
{
if(m_modifier.m_miscvalue & int32(1<<x))
- m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + x), BASE_PCT, float(GetModifierValue()), apply);
}
}
}
@@ -4287,11 +4267,11 @@ void Aura::HandleModResistancePercent(bool apply, bool Real)
{
if(m_modifier.m_miscvalue & int32(1<<i))
{
- m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_PCT, float(GetModifierValue()), apply);
if(m_target->GetTypeId() == TYPEID_PLAYER || ((Creature*)m_target)->isPet())
{
- m_target->ApplyResistanceBuffModsPercentMod(SpellSchools(i),true,m_modifier.m_amount, apply);
- m_target->ApplyResistanceBuffModsPercentMod(SpellSchools(i),false,m_modifier.m_amount, apply);
+ m_target->ApplyResistanceBuffModsPercentMod(SpellSchools(i),true,GetModifierValue(), apply);
+ m_target->ApplyResistanceBuffModsPercentMod(SpellSchools(i),false,GetModifierValue(), apply);
}
}
}
@@ -4304,13 +4284,13 @@ void Aura::HandleModBaseResistance(bool apply, bool Real)
{
//only pets have base stats
if(((Creature*)m_target)->isPet() && (m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_NORMAL))
- m_target->HandleStatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UNIT_MOD_ARMOR, TOTAL_VALUE, float(GetModifierValue()), apply);
}
else
{
for(int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++)
if(m_modifier.m_miscvalue & (1<<i))
- m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_VALUE, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + i), TOTAL_VALUE, float(GetModifierValue()), apply);
}
}
@@ -4332,9 +4312,9 @@ void Aura::HandleAuraModStat(bool apply, bool Real)
if (m_modifier.m_miscvalue < 0 || m_modifier.m_miscvalue == i)
{
//m_target->ApplyStatMod(Stats(i), m_modifier.m_amount,apply);
- m_target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_VALUE, float(GetModifierValue()), apply);
if(m_target->GetTypeId() == TYPEID_PLAYER || ((Creature*)m_target)->isPet())
- m_target->ApplyStatBuffMod(Stats(i),m_modifier.m_amount,apply);
+ m_target->ApplyStatBuffMod(Stats(i),GetModifierValue(),apply);
}
}
}
@@ -4354,7 +4334,7 @@ void Aura::HandleModPercentStat(bool apply, bool Real)
for (int32 i = STAT_STRENGTH; i < MAX_STATS; ++i)
{
if(m_modifier.m_miscvalue == i || m_modifier.m_miscvalue == -1)
- m_target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), BASE_PCT, float(GetModifierValue()), apply);
}
}
@@ -4432,9 +4412,9 @@ void Aura::HandleModTotalPercentStat(bool apply, bool Real)
{
if(m_modifier.m_miscvalue == i || m_modifier.m_miscvalue == -1)
{
- m_target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UnitMods(UNIT_MOD_STAT_START + i), TOTAL_PCT, float(GetModifierValue()), apply);
if(m_target->GetTypeId() == TYPEID_PLAYER || ((Creature*)m_target)->isPet())
- m_target->ApplyStatPercentBuffMod(Stats(i), m_modifier.m_amount, apply );
+ m_target->ApplyStatPercentBuffMod(Stats(i), GetModifierValue(), apply );
}
}
@@ -4532,7 +4512,7 @@ void Aura::HandleModRegen(bool apply, bool Real) // eating
if(m_periodicTimer <= 0)
{
m_periodicTimer += 5000;
- int32 gain = m_target->ModifyHealth(m_modifier.m_amount);
+ int32 gain = m_target->ModifyHealth(GetModifierValue());
Unit *caster = GetCaster();
if (caster)
{
@@ -4623,7 +4603,7 @@ void Aura::HandleAuraModIncreaseHealth(bool apply, bool Real)
{
if(apply)
{
- m_target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetModifierValue()), apply);
m_target->ModifyHealth(m_modifier.m_amount);
}
else
@@ -4632,7 +4612,7 @@ void Aura::HandleAuraModIncreaseHealth(bool apply, bool Real)
m_target->ModifyHealth(-m_modifier.m_amount);
else
m_target->SetHealth(1);
- m_target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_VALUE, float(GetModifierValue()), apply);
}
}
}
@@ -4661,7 +4641,7 @@ void Aura::HandleAuraModIncreaseEnergy(bool apply, bool Real)
if(int32(powerType) != m_modifier.m_miscvalue)
return;
- m_target->HandleStatModifier(UnitMods(UNIT_MOD_POWER_START + powerType), TOTAL_VALUE, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UnitMods(UNIT_MOD_POWER_START + powerType), TOTAL_VALUE, float(GetModifierValue()), apply);
}
void Aura::HandleAuraModIncreaseEnergyPercent(bool apply, bool Real)
@@ -4670,13 +4650,13 @@ void Aura::HandleAuraModIncreaseEnergyPercent(bool apply, bool Real)
if(int32(powerType) != m_modifier.m_miscvalue)
return;
- m_target->HandleStatModifier(UnitMods(UNIT_MOD_POWER_START + powerType), TOTAL_PCT, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UnitMods(UNIT_MOD_POWER_START + powerType), TOTAL_PCT, float(GetModifierValue()), apply);
}
void Aura::HandleAuraModIncreaseHealthPercent(bool apply, bool Real)
{
//m_target->ApplyMaxHealthPercentMod(m_modifier.m_amount,apply);
- m_target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UNIT_MOD_HEALTH, TOTAL_PCT, float(GetModifierValue()), apply);
}
/********************************/
@@ -4740,9 +4720,9 @@ void Aura::HandleAuraModCritPercent(bool apply, bool Real)
if (GetSpellProto()->EquippedItemClass == -1)
{
- ((Player*)m_target)->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (m_modifier.m_amount), apply);
- ((Player*)m_target)->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (m_modifier.m_amount), apply);
- ((Player*)m_target)->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (m_modifier.m_amount), apply);
+ ((Player*)m_target)->HandleBaseModValue(CRIT_PERCENTAGE, FLAT_MOD, float (GetModifierValue()), apply);
+ ((Player*)m_target)->HandleBaseModValue(OFFHAND_CRIT_PERCENTAGE, FLAT_MOD, float (GetModifierValue()), apply);
+ ((Player*)m_target)->HandleBaseModValue(RANGED_CRIT_PERCENTAGE, FLAT_MOD, float (GetModifierValue()), apply);
}
else
{
@@ -4752,13 +4732,13 @@ void Aura::HandleAuraModCritPercent(bool apply, bool Real)
void Aura::HandleModHitChance(bool apply, bool Real)
{
- m_target->m_modMeleeHitChance += apply ? m_modifier.m_amount : (-m_modifier.m_amount);
- m_target->m_modRangedHitChance += apply ? m_modifier.m_amount : (-m_modifier.m_amount);
+ m_target->m_modMeleeHitChance += apply ? GetModifierValue() : -GetModifierValue();
+ m_target->m_modRangedHitChance += apply ? GetModifierValue() : -GetModifierValue();
}
void Aura::HandleModSpellHitChance(bool apply, bool Real)
{
- m_target->m_modSpellHitChance += apply ? m_modifier.m_amount: (-m_modifier.m_amount);
+ m_target->m_modSpellHitChance += apply ? GetModifierValue(): -GetModifierValue();
}
void Aura::HandleModSpellCritChance(bool apply, bool Real)
@@ -4773,7 +4753,7 @@ void Aura::HandleModSpellCritChance(bool apply, bool Real)
}
else
{
- m_target->m_baseSpellCritChance += apply ? m_modifier.m_amount:(-m_modifier.m_amount);
+ m_target->m_baseSpellCritChance += apply ? GetModifierValue():-GetModifierValue();
}
}
@@ -4797,22 +4777,22 @@ void Aura::HandleModSpellCritChanceShool(bool /*apply*/, bool Real)
void Aura::HandleModCastingSpeed(bool apply, bool Real)
{
- m_target->ApplyCastTimePercentMod(m_modifier.m_amount,apply);
+ m_target->ApplyCastTimePercentMod(GetModifierValue(),apply);
}
void Aura::HandleModMeleeRangedSpeedPct(bool apply, bool Real)
{
- m_target->ApplyAttackTimePercentMod(BASE_ATTACK,m_modifier.m_amount,apply);
- m_target->ApplyAttackTimePercentMod(OFF_ATTACK,m_modifier.m_amount,apply);
- m_target->ApplyAttackTimePercentMod(RANGED_ATTACK, m_modifier.m_amount, apply);
+ m_target->ApplyAttackTimePercentMod(BASE_ATTACK,GetModifierValue(),apply);
+ m_target->ApplyAttackTimePercentMod(OFF_ATTACK,GetModifierValue(),apply);
+ m_target->ApplyAttackTimePercentMod(RANGED_ATTACK, GetModifierValue(), apply);
}
void Aura::HandleModCombatSpeedPct(bool apply, bool Real)
{
- m_target->ApplyCastTimePercentMod(m_modifier.m_amount,apply);
- m_target->ApplyAttackTimePercentMod(BASE_ATTACK,m_modifier.m_amount,apply);
- m_target->ApplyAttackTimePercentMod(OFF_ATTACK,m_modifier.m_amount,apply);
- m_target->ApplyAttackTimePercentMod(RANGED_ATTACK, m_modifier.m_amount, apply);
+ m_target->ApplyCastTimePercentMod(GetModifierValue(),apply);
+ m_target->ApplyAttackTimePercentMod(BASE_ATTACK,GetModifierValue(),apply);
+ m_target->ApplyAttackTimePercentMod(OFF_ATTACK,GetModifierValue(),apply);
+ m_target->ApplyAttackTimePercentMod(RANGED_ATTACK, GetModifierValue(), apply);
}
void Aura::HandleModAttackSpeed(bool apply, bool Real)
@@ -4820,26 +4800,26 @@ void Aura::HandleModAttackSpeed(bool apply, bool Real)
if(!m_target->isAlive() )
return;
- m_target->ApplyAttackTimePercentMod(BASE_ATTACK,m_modifier.m_amount,apply);
+ m_target->ApplyAttackTimePercentMod(BASE_ATTACK,GetModifierValue(),apply);
}
void Aura::HandleHaste(bool apply, bool Real)
{
- m_target->ApplyAttackTimePercentMod(BASE_ATTACK, m_modifier.m_amount,apply);
- m_target->ApplyAttackTimePercentMod(OFF_ATTACK, m_modifier.m_amount,apply);
- m_target->ApplyAttackTimePercentMod(RANGED_ATTACK,m_modifier.m_amount,apply);
+ m_target->ApplyAttackTimePercentMod(BASE_ATTACK, GetModifierValue(),apply);
+ m_target->ApplyAttackTimePercentMod(OFF_ATTACK, GetModifierValue(),apply);
+ m_target->ApplyAttackTimePercentMod(RANGED_ATTACK,GetModifierValue(),apply);
}
void Aura::HandleAuraModRangedHaste(bool apply, bool Real)
{
- m_target->ApplyAttackTimePercentMod(RANGED_ATTACK, m_modifier.m_amount, apply);
+ m_target->ApplyAttackTimePercentMod(RANGED_ATTACK, GetModifierValue(), apply);
}
void Aura::HandleRangedAmmoHaste(bool apply, bool Real)
{
if(m_target->GetTypeId() != TYPEID_PLAYER)
return;
- m_target->ApplyAttackTimePercentMod(RANGED_ATTACK,m_modifier.m_amount, apply);
+ m_target->ApplyAttackTimePercentMod(RANGED_ATTACK,GetModifierValue(), apply);
}
/********************************/
@@ -4848,7 +4828,7 @@ void Aura::HandleRangedAmmoHaste(bool apply, bool Real)
void Aura::HandleAuraModAttackPower(bool apply, bool Real)
{
- m_target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_VALUE, float(GetModifierValue()), apply);
}
void Aura::HandleAuraModRangedAttackPower(bool apply, bool Real)
@@ -4856,13 +4836,13 @@ void Aura::HandleAuraModRangedAttackPower(bool apply, bool Real)
if((m_target->getClassMask() & CLASSMASK_WAND_USERS)!=0)
return;
- m_target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_VALUE, float(GetModifierValue()), apply);
}
void Aura::HandleAuraModAttackPowerPercent(bool apply, bool Real)
{
//UNIT_FIELD_ATTACK_POWER_MULTIPLIER = multiplier - 1
- m_target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, float(GetModifierValue()), apply);
}
void Aura::HandleAuraModRangedAttackPowerPercent(bool apply, bool Real)
@@ -4871,7 +4851,7 @@ void Aura::HandleAuraModRangedAttackPowerPercent(bool apply, bool Real)
return;
//UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER = multiplier - 1
- m_target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UNIT_MOD_ATTACK_POWER_RANGED, TOTAL_PCT, float(GetModifierValue()), apply);
}
void Aura::HandleAuraModRangedAttackPowerOfStatPercent(bool apply, bool Real)
@@ -4921,9 +4901,9 @@ void Aura::HandleModDamageDone(bool apply, bool Real)
// apply generic physical damage bonuses including wand case
if (GetSpellProto()->EquippedItemClass == -1 || m_target->GetTypeId() != TYPEID_PLAYER)
{
- m_target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(m_modifier.m_amount), apply);
- m_target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(m_modifier.m_amount), apply);
- m_target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_VALUE, float(GetModifierValue()), apply);
+ m_target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_VALUE, float(GetModifierValue()), apply);
+ m_target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_VALUE, float(GetModifierValue()), apply);
}
else
{
@@ -4933,9 +4913,9 @@ void Aura::HandleModDamageDone(bool apply, bool Real)
if(m_target->GetTypeId() == TYPEID_PLAYER)
{
if(m_positive)
- m_target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS,m_modifier.m_amount,apply);
+ m_target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS,GetModifierValue(),apply);
else
- m_target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG,m_modifier.m_amount,apply);
+ m_target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG,GetModifierValue(),apply);
}
}
@@ -4961,7 +4941,7 @@ void Aura::HandleModDamageDone(bool apply, bool Real)
for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
{
if((m_modifier.m_miscvalue & (1<<i)) != 0)
- m_target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i,m_modifier.m_amount,apply);
+ m_target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i,GetModifierValue(),apply);
}
}
else
@@ -4969,7 +4949,7 @@ void Aura::HandleModDamageDone(bool apply, bool Real)
for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++)
{
if((m_modifier.m_miscvalue & (1<<i)) != 0)
- m_target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG+i,m_modifier.m_amount,apply);
+ m_target->ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG+i,GetModifierValue(),apply);
}
}
Pet* pet = m_target->GetPet();
@@ -5004,9 +4984,9 @@ void Aura::HandleModDamagePercentDone(bool apply, bool Real)
// apply generic physical damage bonuses including wand case
if (GetSpellProto()->EquippedItemClass == -1 || m_target->GetTypeId() != TYPEID_PLAYER)
{
- m_target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(m_modifier.m_amount), apply);
- m_target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(m_modifier.m_amount), apply);
- m_target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UNIT_MOD_DAMAGE_MAINHAND, TOTAL_PCT, float(GetModifierValue()), apply);
+ m_target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetModifierValue()), apply);
+ m_target->HandleStatModifier(UNIT_MOD_DAMAGE_RANGED, TOTAL_PCT, float(GetModifierValue()), apply);
}
else
{
@@ -5045,7 +5025,7 @@ void Aura::HandleModOffhandDamagePercent(bool apply, bool Real)
sLog.outDebug("AURA MOD OFFHAND DAMAGE");
- m_target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(m_modifier.m_amount), apply);
+ m_target->HandleStatModifier(UNIT_MOD_DAMAGE_OFFHAND, TOTAL_PCT, float(GetModifierValue()), apply);
}
/********************************/
@@ -5058,7 +5038,7 @@ void Aura::HandleModPowerCostPCT(bool apply, bool Real)
if(!Real)
return;
- float amount = m_modifier.m_amount/100.0f;
+ float amount = GetModifierValue() /100.0f;
for(int i = 0; i < MAX_SPELL_SCHOOL; ++i)
if(m_modifier.m_miscvalue & (1<<i))
m_target->ApplyModSignedFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER+i,amount,apply);
@@ -5072,7 +5052,7 @@ void Aura::HandleModPowerCost(bool apply, bool Real)
for(int i = 0; i < MAX_SPELL_SCHOOL; ++i)
if(m_modifier.m_miscvalue & (1<<i))
- m_target->ApplyModInt32Value(UNIT_FIELD_POWER_COST_MODIFIER+i,m_modifier.m_amount,apply);
+ m_target->ApplyModInt32Value(UNIT_FIELD_POWER_COST_MODIFIER+i,GetModifierValue(),apply);
}
/*********************************************************/
@@ -5293,7 +5273,7 @@ void Aura::HandleModRating(bool apply, bool Real)
for (uint32 rating = 0; rating < MAX_COMBAT_RATING; ++rating)
if (m_modifier.m_miscvalue & (1 << rating))
- ((Player*)m_target)->ApplyRatingMod(CombatRating(rating), m_modifier.m_amount, apply);
+ ((Player*)m_target)->ApplyRatingMod(CombatRating(rating), GetModifierValue(), apply);
}
void Aura::HandleForceMoveForward(bool apply, bool Real)
@@ -5324,11 +5304,11 @@ void Aura::HandleModTargetResistance(bool apply, bool Real)
// show armor penetration
if (m_target->GetTypeId() == TYPEID_PLAYER && (m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_NORMAL))
- m_target->ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE,m_modifier.m_amount, apply);
+ m_target->ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_PHYSICAL_RESISTANCE,GetModifierValue(), apply);
// show as spell penetration only full spell penetration bonuses (all resistances except armor and holy
if (m_target->GetTypeId() == TYPEID_PLAYER && (m_modifier.m_miscvalue & SPELL_SCHOOL_MASK_SPELL)==SPELL_SCHOOL_MASK_SPELL)
- m_target->ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE,m_modifier.m_amount, apply);
+ m_target->ApplyModInt32Value(PLAYER_FIELD_MOD_TARGET_RESISTANCE,GetModifierValue(), apply);
}
void Aura::HandleShieldBlockValue(bool apply, bool Real)
@@ -5338,7 +5318,7 @@ void Aura::HandleShieldBlockValue(bool apply, bool Real)
modType = PCT_MOD;
if(m_target->GetTypeId() == TYPEID_PLAYER)
- ((Player*)m_target)->HandleBaseModValue(SHIELD_BLOCK_VALUE, modType, float(m_modifier.m_amount), apply);
+ ((Player*)m_target)->HandleBaseModValue(SHIELD_BLOCK_VALUE, modType, float(GetModifierValue()), apply);
}
void Aura::HandleAuraRetainComboPoints(bool apply, bool Real)
@@ -5356,7 +5336,7 @@ void Aura::HandleAuraRetainComboPoints(bool apply, bool Real)
// remove only if aura expire by time (in case combo points amount change aura removed without combo points lost)
if( !apply && m_duration==0 && target->GetComboTarget())
if(Unit* unit = ObjectAccessor::GetUnit(*m_target,target->GetComboTarget()))
- target->AddComboPoints(unit, -m_modifier.m_amount);
+ target->AddComboPoints(unit, -GetModifierValue());
}
void Aura::HandleModUnattackable( bool Apply, bool Real )
@@ -5548,7 +5528,7 @@ void Aura::PeriodicTick()
CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
// ignore non positive values (can be result apply spellmods to aura damage
- uint32 amount = m_modifier.m_amount > 0 ? m_modifier.m_amount : 0;
+ uint32 amount = GetModifierValue() > 0 ? GetModifierValue() : 0;
uint32 pdamage;
@@ -5608,11 +5588,15 @@ void Aura::PeriodicTick()
Unit* target = m_target; // aura can be deleted in DealDamage
SpellEntry const* spellProto = GetSpellProto();
- pCaster->DealDamage(m_target, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), &cleanDamage, DOT, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), true);
-
- // DO NOT ACCESS MEMBERS OF THE AURA FROM NOW ON (DealDamage can delete aura)
+ // Set trigger flag
+ uint32 procAttacker = PROC_FLAG_ON_DO_PERIODIC;// | PROC_FLAG_SUCCESSFUL_HARMFUL_SPELL_HIT;
+ uint32 procVictim = PROC_FLAG_ON_TAKE_PERIODIC;// | PROC_FLAG_TAKEN_HARMFUL_SPELL_HIT;
+ pdamage = (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist);
+ if (pdamage)
+ procVictim|=PROC_FLAG_TAKEN_ANY_DAMAGE;
+ pCaster->ProcDamageAndSpell(target, procAttacker, procVictim, PROC_EX_NORMAL_HIT, pdamage, BASE_ATTACK, spellProto);
- pCaster->ProcDamageAndSpell(target, PROC_FLAG_NONE, PROC_FLAG_TAKE_DAMAGE, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), GetSpellSchoolMask(spellProto), spellProto);
+ pCaster->DealDamage(target, pdamage, &cleanDamage, DOT, GetSpellSchoolMask(spellProto), spellProto, true);
break;
}
case SPELL_AURA_PERIODIC_LEECH:
@@ -5721,11 +5705,15 @@ void Aura::PeriodicTick()
SpellEntry const* spellProto = GetSpellProto();
float multiplier = spellProto->EffectMultipleValue[GetEffIndex()] > 0 ? spellProto->EffectMultipleValue[GetEffIndex()] : 1;
- uint32 new_damage = pCaster->DealDamage(m_target, (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist), &cleanDamage, DOT, GetSpellSchoolMask(GetSpellProto()), GetSpellProto(), false);
-
- // DO NOT ACCESS MEMBERS OF THE AURA FROM NOW ON (DealDamage can delete aura)
+ // Set trigger flag
+ uint32 procAttacker = PROC_FLAG_ON_DO_PERIODIC;// | PROC_FLAG_SUCCESSFUL_HARMFUL_SPELL_HIT;
+ uint32 procVictim = PROC_FLAG_ON_TAKE_PERIODIC;// | PROC_FLAG_TAKEN_HARMFUL_SPELL_HIT;
+ pdamage = (pdamage <= absorb+resist) ? 0 : (pdamage-absorb-resist);
+ if (pdamage)
+ procVictim|=PROC_FLAG_TAKEN_ANY_DAMAGE;
+ pCaster->ProcDamageAndSpell(target, procAttacker, procVictim, PROC_EX_NORMAL_HIT, pdamage, BASE_ATTACK, spellProto);
+ int32 new_damage = pCaster->DealDamage(target, pdamage, &cleanDamage, DOT, GetSpellSchoolMask(spellProto), spellProto, false);
- pCaster->ProcDamageAndSpell(target, PROC_FLAG_HEALED, PROC_FLAG_TAKE_DAMAGE, new_damage, GetSpellSchoolMask(spellProto), spellProto);
if (!target->isAlive() && pCaster->IsNonMeleeSpellCasted(false))
{
for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
@@ -5759,7 +5747,7 @@ void Aura::PeriodicTick()
return;
// ignore non positive values (can be result apply spellmods to aura damage
- uint32 amount = m_modifier.m_amount > 0 ? m_modifier.m_amount : 0;
+ uint32 amount = GetModifierValue() > 0 ? GetModifierValue() : 0;
uint32 pdamage;
@@ -5826,9 +5814,11 @@ void Aura::PeriodicTick()
}
}
+ uint32 procAttacker = PROC_FLAG_ON_DO_PERIODIC;// | PROC_FLAG_SUCCESSFUL_HEAL;
+ uint32 procVictim = 0;//ROC_FLAG_ON_TAKE_PERIODIC | PROC_FLAG_TAKEN_HEAL;
// ignore item heals
- if(procSpell && !haveCastItem)
- pCaster->ProcDamageAndSpell(target,PROC_FLAG_NONE, PROC_FLAG_HEALED, pdamage, SPELL_SCHOOL_MASK_NONE, spellProto);
+// if(procSpell && !haveCastItem)
+// pCaster->ProcDamageAndSpell(target, procAttacker, procVictim, PROC_EX_NORMAL_HIT, pdamage, BASE_ATTACK, spellProto);
break;
}
case SPELL_AURA_PERIODIC_MANA_LEECH:
@@ -5849,7 +5839,7 @@ void Aura::PeriodicTick()
return;
// ignore non positive values (can be result apply spellmods to aura damage
- uint32 pdamage = m_modifier.m_amount > 0 ? m_modifier.m_amount : 0;
+ uint32 pdamage = GetModifierValue() > 0 ? GetModifierValue() : 0;
sLog.outDetail("PeriodicTick: %u (TypeId: %u) power leech of %u (TypeId: %u) for %u dmg inflicted by %u",
GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId());
@@ -5904,7 +5894,7 @@ void Aura::PeriodicTick()
case SPELL_AURA_PERIODIC_ENERGIZE:
{
// ignore non positive values (can be result apply spellmods to aura damage
- uint32 pdamage = m_modifier.m_amount > 0 ? m_modifier.m_amount : 0;
+ uint32 pdamage = GetModifierValue() > 0 ? GetModifierValue() : 0;
sLog.outDetail("PeriodicTick: %u (TypeId: %u) energize %u (TypeId: %u) for %u dmg inflicted by %u",
GUID_LOPART(GetCasterGUID()), GuidHigh2TypeId(GUID_HIPART(GetCasterGUID())), m_target->GetGUIDLow(), m_target->GetTypeId(), pdamage, GetId());
@@ -5936,7 +5926,7 @@ void Aura::PeriodicTick()
case SPELL_AURA_OBS_MOD_MANA:
{
// ignore non positive values (can be result apply spellmods to aura damage
- uint32 amount = m_modifier.m_amount > 0 ? m_modifier.m_amount : 0;
+ uint32 amount = GetModifierValue() > 0 ? GetModifierValue() : 0;
uint32 pdamage = uint32(m_target->GetMaxPower(POWER_MANA) * amount/100);
@@ -5972,7 +5962,7 @@ void Aura::PeriodicTick()
if(m_target->IsImmunedToDamage(GetSpellSchoolMask(GetSpellProto())))
return;
- int32 pdamage = m_modifier.m_amount > 0 ? m_modifier.m_amount : 0;
+ int32 pdamage = GetModifierValue() > 0 ? GetModifierValue() : 0;
Powers powerType = Powers(m_modifier.m_miscvalue);
@@ -5987,8 +5977,22 @@ void Aura::PeriodicTick()
gain = uint32(gain * GetSpellProto()->EffectMultipleValue[GetEffIndex()]);
+ SpellEntry const* spellProto = GetSpellProto();
//maybe has to be sent different to client, but not by SMSG_PERIODICAURALOG
- pCaster->SpellNonMeleeDamageLog(m_target, GetId(), gain);
+ SpellNonMeleeDamage damageInfo(pCaster, m_target, spellProto->Id, spellProto->SchoolMask);
+ pCaster->CalculateSpellDamage(&damageInfo, gain, spellProto);
+ pCaster->SendSpellNonMeleeDamageLog(&damageInfo);
+
+ // Set trigger flag
+ uint32 procAttacker = PROC_FLAG_ON_DO_PERIODIC;// | PROC_FLAG_SUCCESSFUL_HARMFUL_SPELL_HIT;
+ uint32 procVictim = PROC_FLAG_ON_TAKE_PERIODIC;// | PROC_FLAG_TAKEN_HARMFUL_SPELL_HIT;
+ uint32 procEx = createProcExtendMask(&damageInfo, SPELL_MISS_NONE);
+ if (damageInfo.damage)
+ procVictim|=PROC_FLAG_TAKEN_ANY_DAMAGE;
+
+ pCaster->ProcDamageAndSpell(damageInfo.target, procAttacker, procVictim, procEx, damageInfo.damage, BASE_ATTACK, spellProto);
+
+ pCaster->DealSpellDamage(&damageInfo, true);
break;
}
// Here tick dummy auras
diff --git a/src/game/SpellAuras.h b/src/game/SpellAuras.h
index d803d9ede13..4762755bc40 100644
--- a/src/game/SpellAuras.h
+++ b/src/game/SpellAuras.h
@@ -214,6 +214,7 @@ class TRINITY_DLL_SPEC Aura
void SetModifier(AuraType t, int32 a, uint32 pt, int32 miscValue);
Modifier* GetModifier() {return &m_modifier;}
+ int32 GetModifierValue() {return m_modifier.m_amount * m_stackAmount;}
int32 GetMiscValue() {return m_spellProto->EffectMiscValue[m_effIndex];}
int32 GetMiscBValue() {return m_spellProto->EffectMiscValueB[m_effIndex];}
@@ -230,6 +231,7 @@ class TRINITY_DLL_SPEC Aura
time_t GetAuraApplyTime() { return m_applyTime; }
void UpdateAuraDuration();
void SendAuraDurationForCaster(Player* caster);
+ void UpdateSlotCounterAndDuration();
uint64 const& GetCasterGUID() const { return m_caster_guid; }
Unit* GetCaster() const;
@@ -295,6 +297,9 @@ class TRINITY_DLL_SPEC Aura
void PeriodicTick();
void PeriodicDummyTick();
+
+ int32 GetStackAmount() {return m_stackAmount;}
+ void SetStackAmount(int32 amount) {m_stackAmount=amount;}
protected:
Aura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target, Unit *caster = NULL, Item* castItem = NULL);
@@ -330,8 +335,9 @@ class TRINITY_DLL_SPEC Aura
int32 m_periodicTimer;
uint32 m_PeriodicEventId;
DiminishingGroup m_AuraDRGroup;
+
+ int32 m_stackAmount;
private:
- void UpdateSlotCounterAndDuration(bool add);
void CleanupTriggeredSpells();
void SetAura(uint32 slot, bool remove) { m_target->SetUInt32Value(UNIT_FIELD_AURA + slot, remove ? 0 : GetId()); }
void SetAuraFlag(uint32 slot, bool add);
diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp
index a492e06f5b1..809c4cab557 100644
--- a/src/game/SpellEffects.cpp
+++ b/src/game/SpellEffects.cpp
@@ -333,25 +333,25 @@ void Spell::EffectSchoolDMG(uint32 effect_idx)
damage = 200;
break;
}
- // must only affect demons (also undead?)
+ // arcane charge. must only affect demons (also undead?)
case 45072:
{
if(unitTarget->GetCreatureType() != CREATURE_TYPE_DEMON
- || unitTarget->GetCreatureType() != CREATURE_TYPE_UNDEAD)
+ && unitTarget->GetCreatureType() != CREATURE_TYPE_UNDEAD)
return;
break;
}
- // gruul's shatter
- case 33671:
- {
- // don't damage self and only players
- if(unitTarget->GetGUID() == m_caster->GetGUID() || unitTarget->GetTypeId() != TYPEID_PLAYER)
- return;
-
- float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[0]));
- if(!radius) return;
- float distance = m_caster->GetDistance2d(unitTarget);
- damage = (distance > radius ) ? 0 : (int32)(m_spellInfo->EffectBasePoints[0]*((radius - distance)/radius));
+ // gruul's shatter
+ case 33671:
+ {
+ // don't damage self and only players
+ if(unitTarget->GetGUID() == m_caster->GetGUID() || unitTarget->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ float radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellInfo->EffectRadiusIndex[0]));
+ if(!radius) return;
+ float distance = m_caster->GetDistance2d(unitTarget);
+ damage = (distance > radius ) ? 0 : (int32)(m_spellInfo->EffectBasePoints[0]*((radius - distance)/radius));
}break;
}
break;
@@ -559,61 +559,7 @@ void Spell::EffectSchoolDMG(uint32 effect_idx)
}
if(damage >= 0)
- {
- uint32 finalDamage;
- if(m_originalCaster) // m_caster only passive source of cast
- finalDamage = m_originalCaster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
- else
- finalDamage = m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
-
- // post effects
- switch(m_spellInfo->SpellFamilyName)
- {
- case SPELLFAMILY_WARRIOR:
- {
- // Bloodthirst
- if(m_spellInfo->SpellFamilyFlags & 0x40000000000LL)
- {
- uint32 BTAura = 0;
- switch(m_spellInfo->Id)
- {
- case 23881: BTAura = 23885; break;
- case 23892: BTAura = 23886; break;
- case 23893: BTAura = 23887; break;
- case 23894: BTAura = 23888; break;
- case 25251: BTAura = 25252; break;
- case 30335: BTAura = 30339; break;
- default:
- sLog.outError("Spell::EffectSchoolDMG: Spell %u not handled in BTAura",m_spellInfo->Id);
- break;
- }
-
- if (BTAura)
- m_caster->CastSpell(m_caster,BTAura,true);
- }
- break;
- }
- case SPELLFAMILY_PRIEST:
- {
- // Shadow Word: Death
- if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000200000000LL) && unitTarget->isAlive())
- // deals damage equal to damage done to caster if victim is not killed
- m_caster->SpellNonMeleeDamageLog( m_caster, m_spellInfo->Id, finalDamage, m_IsTriggeredSpell, false);
-
- break;
- }
- case SPELLFAMILY_PALADIN:
- {
- // Judgement of Blood
- if(finalDamage > 0 && (m_spellInfo->SpellFamilyFlags & 0x0000000800000000LL) && m_spellInfo->SpellIconID==153)
- {
- int32 damagePoint = finalDamage * 33 / 100;
- m_caster->CastCustomSpell(m_caster, 32220, &damagePoint, NULL, NULL, true);
- }
- break;
- }
- }
- }
+ m_damage+= damage;
}
}
@@ -626,58 +572,9 @@ void Spell::EffectDummy(uint32 i)
switch(m_spellInfo->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
- // Gnomish Poultryizer trinket
+ {
switch(m_spellInfo->Id )
{
- // Mingo's Fortune Giblets
- case 40802:
- {
- if (m_caster->GetTypeId() != TYPEID_PLAYER) return;
-
- Player *player = (Player*)m_caster;
- uint32 newitemid;
-
- switch(urand(1,20))
- {
- case 1: newitemid = 32688; break;
- case 2: newitemid = 32689; break;
- case 3: newitemid = 32690; break;
- case 4: newitemid = 32691; break;
- case 5: newitemid = 32692; break;
- case 6: newitemid = 32693; break;
- case 7: newitemid = 32700; break;
- case 8: newitemid = 32701; break;
- case 9: newitemid = 32702; break;
- case 10: newitemid = 32703; break;
- case 11: newitemid = 32704; break;
- case 12: newitemid = 32705; break;
- case 13: newitemid = 32706; break;
- case 14: newitemid = 32707; break;
- case 15: newitemid = 32708; break;
- case 16: newitemid = 32709; break;
- case 17: newitemid = 32710; break;
- case 18: newitemid = 32711; break;
- case 19: newitemid = 32712; break;
- case 20: newitemid = 32713; break;
- }
- ItemPosCountVec dest;
- uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, newitemid, 1, false);
- if (msg != EQUIP_ERR_OK)
- {
- player->SendEquipError(msg, NULL, NULL);
- return;
- }
- Item *pItem = player->StoreNewItem(dest, newitemid, true, Item::GenerateItemRandomPropertyId(newitemid));
-
- if (!pItem)
- {
- player->SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL);
- return;
- }
- player->SendNewItem(pItem, 1, true, true);
-
- return;
- }
// Encapsulate Voidwalker
case 29364:
{
@@ -1012,16 +909,12 @@ void Spell::EffectDummy(uint32 i)
}
case 28730: // Arcane Torrent (Mana)
{
- int32 count = 0;
- Unit::AuraList const& m_dummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraList::const_iterator i = m_dummyAuras.begin(); i != m_dummyAuras.end(); ++i)
- if ((*i)->GetId() == 28734)
- ++count;
- if (count)
- {
- m_caster->RemoveAurasDueToSpell(28734);
- int32 bp = damage * count;
+ Aura * dummy = m_caster->GetDummyAura(28734);
+ if (dummy)
+ {
+ int32 bp = damage * dummy->GetStackAmount();
m_caster->CastCustomSpell(m_caster, 28733, &bp, NULL, NULL, true);
+ m_caster->RemoveAurasDueToSpell(28734);
}
return;
}
@@ -1036,7 +929,8 @@ void Spell::EffectDummy(uint32 i)
return;
}
case 29858: // Soulshatter
- if (unitTarget && unitTarget->GetTypeId() == TYPEID_UNIT && unitTarget->IsHostileTo(m_caster))
+ if (unitTarget && unitTarget->CanHaveThreatList()
+ && unitTarget->getThreatManager().getThreat(m_caster) > 0.0f)
m_caster->CastSpell(unitTarget,32835,true);
return;
case 30458: // Nigh Invulnerability
@@ -1089,6 +983,50 @@ void Spell::EffectDummy(uint32 i)
if(unitTarget)
m_caster->CastSpell(unitTarget,37675,true);
return;
+ case 40802: // Mingo's Fortune Generator (Mingo's Fortune Giblets)
+ {
+ // selecting one from Bloodstained Fortune item
+ uint32 newitemid;
+ switch(urand(1,20))
+ {
+ case 1: newitemid = 32688; break;
+ case 2: newitemid = 32689; break;
+ case 3: newitemid = 32690; break;
+ case 4: newitemid = 32691; break;
+ case 5: newitemid = 32692; break;
+ case 6: newitemid = 32693; break;
+ case 7: newitemid = 32700; break;
+ case 8: newitemid = 32701; break;
+ case 9: newitemid = 32702; break;
+ case 10: newitemid = 32703; break;
+ case 11: newitemid = 32704; break;
+ case 12: newitemid = 32705; break;
+ case 13: newitemid = 32706; break;
+ case 14: newitemid = 32707; break;
+ case 15: newitemid = 32708; break;
+ case 16: newitemid = 32709; break;
+ case 17: newitemid = 32710; break;
+ case 18: newitemid = 32711; break;
+ case 19: newitemid = 32712; break;
+ case 20: newitemid = 32713; break;
+ default:
+ return;
+ }
+
+ DoCreateItem(i,newitemid);
+ return;
+ }
+ // Demon Broiled Surprise
+ /* FIX ME: Required for correct work implementing implicit target 7 (in pair (22,7))
+ case 43723:
+ {
+ if (m_caster->GetTypeId() != TYPEID_PLAYER)
+ return;
+
+ ((Player*)m_caster)->CastSpell(unitTarget, 43753, true);
+ return;
+ }
+ */
case 44875: // Complete Raptor Capture
{
if(!unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT)
@@ -1236,6 +1174,7 @@ void Spell::EffectDummy(uint32 i)
}
}
break;
+ }
case SPELLFAMILY_MAGE:
switch(m_spellInfo->Id )
{
@@ -1452,7 +1391,7 @@ void Spell::EffectDummy(uint32 i)
}
if(found)
- m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, damage, m_IsTriggeredSpell, true);
+ m_damage+= damage;
return;
}
// Kill command
@@ -1871,16 +1810,18 @@ void Spell::EffectTriggerSpell(uint32 i)
// Cloak of Shadows
case 35729 :
{
+ uint32 dispelMask = GetDispellMask(DISPEL_ALL);
Unit::AuraMap& Auras = m_caster->GetAuras();
for(Unit::AuraMap::iterator iter = Auras.begin(); iter != Auras.end(); ++iter)
{
// remove all harmful spells on you...
- if(// only affect magic spells
- iter->second->GetSpellProto()->DmgClass == SPELL_DAMAGE_CLASS_MAGIC
+ SpellEntry const* spell = iter->second->GetSpellProto();
+ if((spell->DmgClass == SPELL_DAMAGE_CLASS_MAGIC // only affect magic spells
+ || ((1<<spell->Dispel) & dispelMask))
// ignore positive and passive auras
&& !iter->second->IsPositive() && !iter->second->IsPassive())
{
- m_caster->RemoveAurasDueToSpell(iter->second->GetSpellProto()->Id);
+ m_caster->RemoveAurasDueToSpell(spell->Id);
iter = Auras.begin();
}
}
@@ -2187,7 +2128,7 @@ void Spell::EffectApplyAura(uint32 i)
// Prayer of Mending (jump animation), we need formal caster instead original for correct animation
if( m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && (m_spellInfo->SpellFamilyFlags & 0x00002000000000LL))
- m_caster->CastSpell(unitTarget,41637,true,NULL,Aur);
+ m_caster->CastSpell(unitTarget,41637,true,NULL,Aur,m_originalCasterGUID);
}
void Spell::EffectUnlearnSpecialization( uint32 i )
@@ -2346,7 +2287,7 @@ void Spell::EffectPowerBurn(uint32 i)
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_MULTIPLE_VALUE, multiplier);
new_damage = int32(new_damage*multiplier);
- m_caster->SpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, new_damage, m_IsTriggeredSpell, true);
+ m_damage+=new_damage;
}
void Spell::EffectHeal( uint32 /*i*/ )
@@ -2370,7 +2311,7 @@ void Spell::EffectHeal( uint32 /*i*/ )
Unit::AuraList const& mDummyAuras = m_caster->GetAurasByType(SPELL_AURA_DUMMY);
for(Unit::AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i)
if((*i)->GetId() == 45062)
- damageAmount+=(*i)->GetModifier()->m_amount;
+ damageAmount+=(*i)->GetModifierValue();
if (damageAmount)
m_caster->RemoveAurasDueToSpell(45062);
@@ -2414,27 +2355,7 @@ void Spell::EffectHeal( uint32 /*i*/ )
else
addhealth = caster->SpellHealingBonus(m_spellInfo, addhealth,HEAL, unitTarget);
- bool crit = caster->isSpellCrit(unitTarget, m_spellInfo, m_spellSchoolMask, m_attackType);
- if (crit)
- addhealth = caster->SpellCriticalBonus(m_spellInfo, addhealth, unitTarget);
- caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, addhealth, crit);
-
- int32 gain = unitTarget->ModifyHealth( int32(addhealth) );
- unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
-
- if(caster->GetTypeId()==TYPEID_PLAYER)
- if(BattleGround *bg = ((Player*)caster)->GetBattleGround())
- bg->UpdatePlayerScore(((Player*)caster), SCORE_HEALING_DONE, gain);
-
- // ignore item heals
- if(m_CastItem)
- return;
-
- uint32 procHealer = PROC_FLAG_HEAL;
- if (crit)
- procHealer |= PROC_FLAG_CRIT_HEAL;
-
- m_caster->ProcDamageAndSpell(unitTarget,procHealer,PROC_FLAG_HEALED,addhealth,SPELL_SCHOOL_MASK_NONE,m_spellInfo,m_IsTriggeredSpell);
+ m_healing+=addhealth;
}
}
@@ -2511,6 +2432,8 @@ void Spell::EffectHealthLeech(uint32 i)
if(m_caster->GetTypeId() == TYPEID_PLAYER)
m_caster->SendHealSpellLog(m_caster, m_spellInfo->Id, uint32(new_damage));
}
+// m_healthLeech+=tmpvalue;
+// m_damage+=new_damage;
}
void Spell::DoCreateItem(uint32 i, uint32 itemtype)
@@ -2886,7 +2809,7 @@ void Spell::EffectOpenLock(uint32 /*i*/)
if(BattleGround *bg = player->GetBattleGround())
{
// check if it's correct bg
- if(bg && bg->GetTypeID() == BATTLEGROUND_AB)
+ if(bg->GetTypeID() == BATTLEGROUND_AB || bg->GetTypeID() == BATTLEGROUND_AV)
bg->EventPlayerClickedOnFlag(player, gameObjTarget);
return;
}
@@ -3150,6 +3073,7 @@ void Spell::EffectSummonType(uint32 i)
break;
case SUMMON_TYPE_POSESSED:
case SUMMON_TYPE_POSESSED2:
+ case SUMMON_TYPE_POSESSED3:
EffectSummonPossessed(i);
break;
case SUMMON_TYPE_WILD:
@@ -3174,7 +3098,6 @@ void Spell::EffectSummonType(uint32 i)
EffectSummonTotem(i);
break;
case SUMMON_TYPE_UNKNOWN1:
- case SUMMON_TYPE_UNKNOWN2:
case SUMMON_TYPE_UNKNOWN3:
case SUMMON_TYPE_UNKNOWN4:
case SUMMON_TYPE_UNKNOWN5:
@@ -3391,8 +3314,14 @@ void Spell::EffectDispel(uint32 i)
SpellEntry const* spellInfo = sSpellStore.LookupEntry(j->first);
data << uint32(spellInfo->Id); // Spell Id
data << uint8(0); // 0 - dispelled !=0 cleansed
- unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster);
- }
+ if(spellInfo->StackAmount!= 0)
+ {
+ //Why are Aura's Removed by EffIndex? Auras should be removed as a whole.....
+ unitTarget->RemoveSingleAuraFromStackByDispel(spellInfo->Id);
+ }
+ else
+ unitTarget->RemoveAurasDueToSpellByDispel(spellInfo->Id, j->second, m_caster);
+ }
m_caster->SendMessageToSet(&data, true);
// On succes dispel
@@ -3823,10 +3752,12 @@ void Spell::EffectEnchantItemPerm(uint32 i)
return;
if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
- sLog.outCommand("GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
+ {
+ sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(perm): %s (Entry: %d) for player: %s (Account: %u)",
p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
item_owner->GetName(),item_owner->GetSession()->GetAccountId());
+ }
// remove old enchanting before applying new if equipped
item_owner->ApplyEnchantment(itemTarget,PERM_ENCHANTMENT_SLOT,false);
@@ -3952,10 +3883,12 @@ void Spell::EffectEnchantItemTmp(uint32 i)
return;
if(item_owner!=p_caster && p_caster->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
- sLog.outCommand("GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
+ {
+ sLog.outCommand(p_caster->GetSession()->GetAccountId(),"GM %s (Account: %u) enchanting(temp): %s (Entry: %d) for player: %s (Account: %u)",
p_caster->GetName(),p_caster->GetSession()->GetAccountId(),
itemTarget->GetProto()->Name1,itemTarget->GetEntry(),
item_owner->GetName(),item_owner->GetSession()->GetAccountId());
+ }
// remove old enchanting before applying new if equipped
item_owner->ApplyEnchantment(itemTarget,TEMP_ENCHANTMENT_SLOT,false);
@@ -4253,13 +4186,13 @@ void Spell::EffectWeaponDmg(uint32 i)
}
// some spell specific modifiers
- bool customBonusDamagePercentMod = false;
- float bonusDamagePercentMod = 1.0f; // applied to fixed effect damage bonus if set customBonusDamagePercentMod
+ //bool customBonusDamagePercentMod = false;
+ //float bonusDamagePercentMod = 1.0f; // applied to fixed effect damage bonus if set customBonusDamagePercentMod
float weaponDamagePercentMod = 1.0f; // applied to weapon damage (and to fixed effect damage bonus if customBonusDamagePercentMod not set
float totalDamagePercentMod = 1.0f; // applied to final bonus+weapon damage
bool normalized = false;
-
int32 spell_bonus = 0; // bonus specific for spell
+
switch(m_spellInfo->SpellFamilyName)
{
case SPELLFAMILY_WARRIOR:
@@ -4273,19 +4206,53 @@ void Spell::EffectWeaponDmg(uint32 i)
// Devastate bonus and sunder armor refresh
else if(m_spellInfo->SpellVisual == 671 && m_spellInfo->SpellIconID == 1508)
{
- customBonusDamagePercentMod = true;
- bonusDamagePercentMod = 0.0f; // only applied if auras found
+ uint32 stack = 0;
Unit::AuraList const& list = unitTarget->GetAurasByType(SPELL_AURA_MOD_RESISTANCE);
for(Unit::AuraList::const_iterator itr=list.begin();itr!=list.end();++itr)
{
SpellEntry const *proto = (*itr)->GetSpellProto();
- if(proto->SpellVisual == 406 && proto->SpellIconID == 565)
+ if(proto->SpellFamilyName == SPELLFAMILY_WARRIOR
+ && proto->SpellFamilyFlags == SPELLFAMILYFLAG_WARRIOR_SUNDERARMOR)
{
int32 duration = GetSpellDuration(proto);
(*itr)->SetAuraDuration(duration);
(*itr)->UpdateAuraDuration();
- bonusDamagePercentMod += 1.0f; // +100%
+ stack = (*itr)->GetStackAmount();
+ break;
+ }
+ }
+
+ for(int j = 0; j < 3; j++)
+ {
+ if(m_spellInfo->Effect[j] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG)
+ {
+ spell_bonus += (stack - 1) * CalculateDamage(j, unitTarget);
+ break;
+ }
+ }
+
+ if(stack < 5)
+ {
+ // get highest rank of the Sunder Armor spell
+ const PlayerSpellMap& sp_list = ((Player*)m_caster)->GetSpellMap();
+ for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
+ {
+ // only highest rank is shown in spell book, so simply check if shown in spell book
+ if(!itr->second->active || itr->second->disabled || itr->second->state == PLAYERSPELL_REMOVED)
+ continue;
+
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
+ if (!spellInfo)
+ continue;
+
+ if (spellInfo->SpellFamilyFlags == SPELLFAMILYFLAG_WARRIOR_SUNDERARMOR
+ && spellInfo->Id != m_spellInfo->Id
+ && spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR)
+ {
+ m_caster->CastSpell(unitTarget, spellInfo, true);
+ break;
+ }
}
}
}
@@ -4294,13 +4261,13 @@ void Spell::EffectWeaponDmg(uint32 i)
case SPELLFAMILY_ROGUE:
{
// Ambush
- if(m_spellInfo->SpellFamilyFlags & 0x00000200LL)
+ /*if(m_spellInfo->SpellFamilyFlags & 0x00000200LL)
{
customBonusDamagePercentMod = true;
bonusDamagePercentMod = 2.5f; // 250%
- }
+ }*/
// Mutilate (for each hand)
- else if(m_spellInfo->SpellFamilyFlags & 0x600000000LL)
+ if(m_spellInfo->SpellFamilyFlags & 0x600000000LL)
{
bool found = false;
// fast check
@@ -4355,35 +4322,29 @@ void Spell::EffectWeaponDmg(uint32 i)
}
}
- int32 fixed_bonus = 0;
for (int j = 0; j < 3; j++)
{
switch(m_spellInfo->Effect[j])
{
case SPELL_EFFECT_WEAPON_DAMAGE:
case SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL:
- fixed_bonus += CalculateDamage(j,unitTarget);
+ spell_bonus += CalculateDamage(j,unitTarget);
break;
case SPELL_EFFECT_NORMALIZED_WEAPON_DMG:
- fixed_bonus += CalculateDamage(j,unitTarget);
+ spell_bonus += CalculateDamage(j,unitTarget);
normalized = true;
break;
case SPELL_EFFECT_WEAPON_PERCENT_DAMAGE:
weaponDamagePercentMod *= float(CalculateDamage(j,unitTarget)) / 100.0f;
-
- // applied only to prev.effects fixed damage
- if(customBonusDamagePercentMod)
- fixed_bonus = int32(fixed_bonus*bonusDamagePercentMod);
- else
- fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod);
- break;
default:
break; // not weapon damage effect, just skip
}
}
+ //fixed_bonus = int32(fixed_bonus*weaponDamagePercentMod);
+
// non-weapon damage
- int32 bonus = spell_bonus + fixed_bonus;
+ int32 bonus = spell_bonus;// + fixed_bonus;
// apply to non-weapon bonus weapon total pct effect, weapon total flat effect included in weapon damage
if(bonus)
@@ -4410,35 +4371,9 @@ void Spell::EffectWeaponDmg(uint32 i)
// prevent negative damage
uint32 eff_damage = uint32(bonus > 0 ? bonus : 0);
- const uint32 nohitMask = HITINFO_ABSORB | HITINFO_RESIST | HITINFO_MISS;
-
- uint32 hitInfo = 0;
- VictimState victimState = VICTIMSTATE_NORMAL;
- uint32 blocked_dmg = 0;
- uint32 absorbed_dmg = 0;
- uint32 resisted_dmg = 0;
- CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
-
- m_caster->DoAttackDamage(unitTarget, &eff_damage, &cleanDamage, &blocked_dmg, m_spellSchoolMask, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, m_attackType, m_spellInfo, m_IsTriggeredSpell);
-
- if ((hitInfo & nohitMask) && m_attackType != RANGED_ATTACK) // not send ranged miss/etc
- m_caster->SendAttackStateUpdate(hitInfo & nohitMask, unitTarget, 1, m_spellSchoolMask, eff_damage, absorbed_dmg, resisted_dmg, VICTIMSTATE_NORMAL, blocked_dmg);
-
- bool criticalhit = (hitInfo & HITINFO_CRITICALHIT);
- m_caster->SendSpellNonMeleeDamageLog(unitTarget, m_spellInfo->Id, eff_damage, m_spellSchoolMask, absorbed_dmg, resisted_dmg, false, blocked_dmg, criticalhit);
-
- if (eff_damage > (absorbed_dmg + resisted_dmg + blocked_dmg))
- {
- eff_damage -= (absorbed_dmg + resisted_dmg + blocked_dmg);
- }
- else
- {
- cleanDamage.damage += eff_damage;
- eff_damage = 0;
- }
-
- // SPELL_SCHOOL_NORMAL use for weapon-like threat and rage calculation
- m_caster->DealDamage(unitTarget, eff_damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, true);
+ // Add melee damage bonuses (also check for negative)
+ m_caster->MeleeDamageBonus(unitTarget, &eff_damage, m_attackType, m_spellInfo);
+ m_damage+= eff_damage;
// Hemorrhage
if(m_spellInfo->SpellFamilyName==SPELLFAMILY_ROGUE && (m_spellInfo->SpellFamilyFlags & 0x2000000))
@@ -4502,10 +4437,7 @@ void Spell::EffectHealMaxHealth(uint32 /*i*/)
uint32 heal = m_caster->GetMaxHealth();
- int32 gain = unitTarget->ModifyHealth(heal);
- unitTarget->getHostilRefManager().threatAssist(m_caster, float(gain) * 0.5f, m_spellInfo);
-
- m_caster->SendHealSpellLog(unitTarget, m_spellInfo->Id, heal);
+ m_healing+=heal;
}
void Spell::EffectInterruptCast(uint32 /*i*/)
diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp
index 0e318eb5ddc..77f2ab8f1d6 100644
--- a/src/game/SpellHandler.cpp
+++ b/src/game/SpellHandler.cpp
@@ -33,6 +33,7 @@
#include "MapManager.h"
#include "ScriptCalls.h"
#include "Totem.h"
+#include "TemporarySummon.h"
void WorldSession::HandleUseItemOpcode(WorldPacket& recvPacket)
{
@@ -357,40 +358,49 @@ void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket)
if (!spellInfo)
return;
- // Remove possess/charm/sight aura from the possessed/charmed as well
- // TODO: Remove this once the ability to cancel aura sets at once is implemented
- if(_player->GetCharm() || _player->GetFarsightTarget())
+ // not allow remove non positive spells and spells with attr SPELL_ATTR_CANT_CANCEL
+ if(!IsPositiveSpell(spellId) || (spellInfo->Attributes & SPELL_ATTR_CANT_CANCEL))
+ return;
+
+ // lifebloom must delete final heal effect
+ if (spellInfo->SpellFamilyName == SPELLFAMILY_DRUID && (spellInfo->SpellFamilyFlags & 0x1000000000LL) )
+ {
+ Unit::AuraMap::iterator iter;
+ while((iter = _player->m_Auras.find(Unit::spellEffectPair(spellId, 1))) != _player->m_Auras.end())
+ {
+ _player->m_modAuras[SPELL_AURA_DUMMY].remove(iter->second);
+
+ Aura* Aur = iter->second;
+ _player->m_Auras.erase(iter);
+ ++_player->m_removedAuras; // internal count used by unit update
+
+ delete Aur;
+
+ if( _player->m_Auras.empty() )
+ iter = _player->m_Auras.end();
+ else
+ iter = _player->m_Auras.begin();
+
+ }
+ }
+
+ // channeled spell case (it currently casted then)
+ if(IsChanneledSpell(spellInfo))
{
- for (int i = 0; i < 3; ++i)
+ if(Spell* spell = _player->m_currentSpells[CURRENT_CHANNELED_SPELL])
{
- if (spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_POSSESS ||
- spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_POSSESS_PET ||
- spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_CHARM ||
- spellInfo->EffectApplyAuraName[i] == SPELL_AURA_BIND_SIGHT)
+ if(spell->m_spellInfo->Id==spellId)
{
- _player->RemoveAurasDueToSpellByCancel(spellId);
- if (_player->GetCharm())
- _player->GetCharm()->RemoveAurasDueToSpellByCancel(spellId);
- else if (_player->GetFarsightTarget()->GetTypeId() != TYPEID_DYNAMICOBJECT)
- ((Unit*)_player->GetFarsightTarget())->RemoveAurasDueToSpellByCancel(spellId);
- return;
+ spell->cancel();
+ spell->SetReferencedFromCurrent(false);
+ _player->m_currentSpells[CURRENT_CHANNELED_SPELL] = NULL;
}
}
- }
-
- // not allow remove non positive spells and spells with attr SPELL_ATTR_CANT_CANCEL
- if(!IsPositiveSpell(spellId) || (spellInfo->Attributes & SPELL_ATTR_CANT_CANCEL))
return;
+ }
+ // non channeled case
_player->RemoveAurasDueToSpellByCancel(spellId);
-
- if (spellId == 2584) // Waiting to resurrect spell cancel, we must remove player from resurrect queue
- {
- BattleGround *bg = _player->GetBattleGround();
- if(!bg)
- return;
- bg->RemovePlayerFromResurrectQueue(_player->GetGUID());
- }
}
void WorldSession::HandlePetCancelAuraOpcode( WorldPacket& recvPacket)
diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp
index 07a0df04450..2886affc8b6 100644
--- a/src/game/SpellMgr.cpp
+++ b/src/game/SpellMgr.cpp
@@ -90,6 +90,16 @@ uint32 GetSpellCastTime(SpellEntry const* spellInfo, Spell const* spell)
return (castTime > 0) ? uint32(castTime) : 0;
}
+float GetSpellMinRange(SpellRangeEntry const *range)
+{
+ if (!range)
+ return 0;
+ if (!range->minRange)
+ if (range->flags==SPELL_RANGE_RANGED)
+ //return 5.0;
+ return 2.0;//this is a hack, needs fix
+ return range->minRange;
+}
bool IsPassiveSpell(uint32 spellId)
{
@@ -99,7 +109,7 @@ bool IsPassiveSpell(uint32 spellId)
return (spellInfo->Attributes & SPELL_ATTR_PASSIVE) != 0;
}
-bool IsNoStackAuraDueToAura(uint32 spellId_1, uint32 effIndex_1, uint32 spellId_2, uint32 effIndex_2)
+/*bool IsNoStackAuraDueToAura(uint32 spellId_1, uint32 effIndex_1, uint32 spellId_2, uint32 effIndex_2)
{
SpellEntry const *spellInfo_1 = sSpellStore.LookupEntry(spellId_1);
SpellEntry const *spellInfo_2 = sSpellStore.LookupEntry(spellId_2);
@@ -113,7 +123,7 @@ bool IsNoStackAuraDueToAura(uint32 spellId_1, uint32 effIndex_1, uint32 spellId_
return false;
return true;
-}
+}*/
int32 CompareAuraRanks(uint32 spellId_1, uint32 effIndex_1, uint32 spellId_2, uint32 effIndex_2)
{
@@ -135,6 +145,14 @@ SpellSpecific GetSpellSpecific(uint32 spellId)
switch(spellInfo->SpellFamilyName)
{
+ case SPELLFAMILY_GENERIC:
+ {
+ // this may be a hack
+ if((spellInfo->AttributesEx2 & SPELL_ATTR_EX2_FOOD)
+ && !spellInfo->Category)
+ return SPELL_WELL_FED;
+ break;
+ }
case SPELLFAMILY_MAGE:
{
// family flags 18(Molten), 25(Frost/Ice), 28(Mage)
@@ -244,14 +262,25 @@ bool IsSingleFromSpellSpecificPerCaster(uint32 spellSpec1,uint32 spellSpec2)
case SPELL_STING:
case SPELL_CURSE:
case SPELL_ASPECT:
+ case SPELL_POSITIVE_SHOUT:
+ case SPELL_JUDGEMENT:
+ case SPELL_WARLOCK_CORRUPTION:
+ return spellSpec1==spellSpec2;
+ default:
+ return false;
+ }
+}
+
+bool IsSingleFromSpellSpecificPerTarget(uint32 spellSpec1,uint32 spellSpec2)
+{
+ switch(spellSpec1)
+ {
case SPELL_TRACKER:
case SPELL_WARLOCK_ARMOR:
case SPELL_MAGE_ARMOR:
case SPELL_ELEMENTAL_SHIELD:
case SPELL_MAGE_POLYMORPH:
- case SPELL_POSITIVE_SHOUT:
- case SPELL_JUDGEMENT:
- case SPELL_WARLOCK_CORRUPTION:
+ case SPELL_WELL_FED:
return spellSpec1==spellSpec2;
case SPELL_BATTLE_ELIXIR:
return spellSpec2==SPELL_BATTLE_ELIXIR
@@ -537,6 +566,17 @@ bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellI
return false;
}
+bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId)
+{
+ SpellEntry const *spellproto = sSpellStore.LookupEntry(spellId);
+ if (!spellproto) return false;
+
+ for (int i = 0; i < 3; i++)
+ if (spellproto->EffectApplyAuraName[i] == auraType)
+ return true;
+ return false;
+}
+
uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form)
{
// talents that learn spells can have stance requirements that need ignore
@@ -813,8 +853,8 @@ void SpellMgr::LoadSpellProcEvents()
uint32 count = 0;
- // 0 1 2 3 4 5 6 7 8
- QueryResult *result = WorldDatabase.Query("SELECT entry, SchoolMask, Category, SkillID, SpellFamilyName, SpellFamilyMask, procFlags, ppmRate, cooldown FROM spell_proc_event");
+ // 0 1 2 3 4 5 6 7 8
+ QueryResult *result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMask, procFlags, procEx, ppmRate, CustomChance, Cooldown FROM spell_proc_event");
if( !result )
{
@@ -828,7 +868,7 @@ void SpellMgr::LoadSpellProcEvents()
}
barGoLink bar( result->GetRowCount() );
-
+ uint32 customProc = 0;
do
{
Field *fields = result->Fetch();
@@ -837,7 +877,8 @@ void SpellMgr::LoadSpellProcEvents()
uint16 entry = fields[0].GetUInt16();
- if (!sSpellStore.LookupEntry(entry))
+ const SpellEntry *spell = sSpellStore.LookupEntry(entry);
+ if (!spell)
{
sLog.outErrorDb("Spell %u listed in `spell_proc_event` does not exist", entry);
continue;
@@ -846,23 +887,35 @@ void SpellMgr::LoadSpellProcEvents()
SpellProcEventEntry spe;
spe.schoolMask = fields[1].GetUInt32();
- spe.category = fields[2].GetUInt32();
- spe.skillId = fields[3].GetUInt32();
- spe.spellFamilyName = fields[4].GetUInt32();
- spe.spellFamilyMask = fields[5].GetUInt64();
- spe.procFlags = fields[6].GetUInt32();
- spe.ppmRate = fields[7].GetFloat();
+ spe.spellFamilyName = fields[2].GetUInt32();
+ spe.spellFamilyMask = fields[3].GetUInt64();
+ spe.procFlags = fields[4].GetUInt32();
+ spe.procEx = fields[5].GetUInt32();
+ spe.ppmRate = fields[6].GetFloat();
+ spe.customChance = fields[7].GetFloat();
spe.cooldown = fields[8].GetUInt32();
mSpellProcEventMap[entry] = spe;
+ if (spell->procFlags==0)
+ {
+ if (spe.procFlags == 0)
+ {
+ sLog.outErrorDb("Spell %u listed in `spell_proc_event` probally not triggered spell", entry);
+ continue;
+ }
+ customProc++;
+ }
++count;
} while( result->NextRow() );
delete result;
sLog.outString();
- sLog.outString( ">> Loaded %u spell proc event conditions", count );
+ if (customProc)
+ sLog.outString( ">> Loaded %u custom spell proc event conditions +%u custom", count, customProc );
+ else
+ sLog.outString( ">> Loaded %u spell proc event conditions", count );
/*
// Commented for now, as it still produces many errors (still quite many spells miss spell_proc_event)
@@ -894,6 +947,7 @@ void SpellMgr::LoadSpellProcEvents()
*/
}
+/*
bool SpellMgr::IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, SpellEntry const * procSpell, uint32 procFlags )
{
if((procFlags & spellProcEvent->procFlags) == 0)
@@ -932,6 +986,73 @@ bool SpellMgr::IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spell
return true;
}
+*/
+
+bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active)
+{
+ // No extra req need
+ uint32 procEvent_procEx = PROC_EX_NONE;
+
+ // check prockFlags for condition
+ if((procFlags & EventProcFlag) == 0)
+ return false;
+
+ // Always trigger for this
+ if (EventProcFlag & (PROC_FLAG_KILLED | PROC_FLAG_KILL_AND_GET_XP))
+ return true;
+
+ if (spellProcEvent) // Exist event data
+ {
+ // Store extra req
+ procEvent_procEx = spellProcEvent->procEx;
+
+ // For melee triggers
+ if (procSpell == NULL)
+ {
+ // Check (if set) for school (melee attack have Normal school)
+ if(spellProcEvent->schoolMask && (spellProcEvent->schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
+ return false;
+ }
+ else // For spells need check school/spell family/family mask
+ {
+ // Check (if set) for school
+ if(spellProcEvent->schoolMask && (spellProcEvent->schoolMask & procSpell->SchoolMask) == 0)
+ return false;
+
+ // Check (if set) for spellFamilyName
+ if(spellProcEvent->spellFamilyName && (spellProcEvent->spellFamilyName != procSpell->SpellFamilyName))
+ return false;
+
+ // spellFamilyName is Ok need check for spellFamilyMask if present
+ if(spellProcEvent->spellFamilyMask)
+ {
+ if ((spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags) == 0)
+ return false;
+ active = true; // Spell added manualy -> so its active spell
+ }
+ }
+ }
+ // Check for extra req (if none) and hit/crit
+ if (procEvent_procEx == PROC_EX_NONE)
+ {
+ // No extra req, so can trigger only for active (damage/healing present) and hit/crit
+ if((procExtra & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) && active)
+ return true;
+ }
+ else // Passive spells hits here only if resist/reflect/immune/evade
+ {
+ // Exist req for PROC_EX_EX_TRIGGER_ALWAYS
+ if (procEvent_procEx & PROC_EX_EX_TRIGGER_ALWAYS)
+ return true;
+ // Passive spells can`t trigger if need hit
+ if ((procEvent_procEx & PROC_EX_NORMAL_HIT) && !active)
+ return false;
+ // Check Extra Requirement like (hit/crit/miss/resist/parry/dodge/block/immune/reflect/absorb and other)
+ if (procEvent_procEx & procExtra)
+ return true;
+ }
+ return false;
+}
void SpellMgr::LoadSpellElixirs()
{
@@ -1030,10 +1151,10 @@ bool SpellMgr::canStackSpellRanks(SpellEntry const *spellInfo)
return true;
}
-bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) const
+bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2, bool sameCaster) const
{
- if(spellId_1 == spellId_2) // auras due to the same spell
- return false;
+ //if(spellId_1 == spellId_2) // auras due to the same spell
+ // return false;
SpellEntry const *spellInfo_1 = sSpellStore.LookupEntry(spellId_1);
SpellEntry const *spellInfo_2 = sSpellStore.LookupEntry(spellId_2);
@@ -1041,22 +1162,82 @@ bool SpellMgr::IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) cons
if(!spellInfo_1 || !spellInfo_2)
return false;
+ SpellSpecific spellId_spec_1 = GetSpellSpecific(spellId_1);
+ SpellSpecific spellId_spec_2 = GetSpellSpecific(spellId_2);
+ if (spellId_spec_1 && spellId_spec_2)
+ if (IsSingleFromSpellSpecificPerTarget(spellId_spec_1, spellId_spec_2)
+ ||(IsSingleFromSpellSpecificPerCaster(spellId_spec_1, spellId_spec_2) && sameCaster))
+ return true;
+
if(spellInfo_1->SpellFamilyName != spellInfo_2->SpellFamilyName)
return false;
- if(!spellInfo_1->SpellFamilyName) // generic spells
+ // generic spells
+ if(!spellInfo_1->SpellFamilyName)
{
- if(!spellInfo_1->SpellIconID
+ if(spellInfo_1->Category && spellInfo_1->Category == spellInfo_2->Category)
+ {
+ if(spellInfo_1->Category == SPELL_CATEGORY_FOOD ||
+ spellInfo_1->Category == SPELL_CATEGORY_DRINK)
+ return true;
+ }
+
+ if(!spellInfo_1->SpellIconID
|| spellInfo_1->SpellIconID != spellInfo_2->SpellIconID)
return false;
}
- else if (spellInfo_1->SpellFamilyFlags != spellInfo_2->SpellFamilyFlags)
- return false;
+ // if both elixirs are not battle/guardian/potions/flasks then always stack
+ else if(spellInfo_1->SpellFamilyName == SPELLFAMILY_POTION)
+ {
+ if(spellId_spec_1 || spellId_spec_2)
+ return false;
+ }
+
+ // check for class spells
+ else
+ {
+ if (spellInfo_1->SpellFamilyFlags != spellInfo_2->SpellFamilyFlags)
+ return false;
+ }
+
+ if(!sameCaster)
+ {
+ for(uint32 i = 0; i < 3; ++i)
+ if (spellInfo_1->Effect[i] == SPELL_EFFECT_APPLY_AURA
+ || spellInfo_1->Effect[i] == SPELL_EFFECT_PERSISTENT_AREA_AURA)
+ // not area auras (shaman totem)
+ switch(spellInfo_1->EffectApplyAuraName[i])
+ {
+ // DOT or HOT from different casters will stack
+ case SPELL_AURA_PERIODIC_DAMAGE:
+ case SPELL_AURA_PERIODIC_HEAL:
+ case SPELL_AURA_PERIODIC_TRIGGER_SPELL:
+ case SPELL_AURA_PERIODIC_ENERGIZE:
+ case SPELL_AURA_PERIODIC_MANA_LEECH:
+ case SPELL_AURA_PERIODIC_LEECH:
+ return false;
+ default:
+ break;
+ }
+ }
+
+ //not sure if this is correct. maybe some talent buff have same icons?
+ //maybe some creature spells have same visual and same icon but should stack?
+ //spells with the same icon (check needed when spell has different effects in other ranks example:Mark of the wild)
+ //if(spellInfo_1->SpellIconID
+ // && spellInfo_1->SpellIconID == spellInfo_2->SpellIconID)
+ // return true; // maybe change this to IsRankSpellDueToSpell?
+
+ if(spellInfo_1->SpellFamilyName && IsRankSpellDueToSpell(spellInfo_1, spellId_2))
+ return true;
+
+ //if spells have exactly the same effect they cannot stack
for(uint32 i = 0; i < 3; ++i)
if(spellInfo_1->Effect[i] != spellInfo_2->Effect[i]
- || spellInfo_1->EffectApplyAuraName[i] != spellInfo_2->EffectApplyAuraName[i])
- return false;
+ || spellInfo_1->EffectApplyAuraName[i] != spellInfo_2->EffectApplyAuraName[i]
+ || spellInfo_1->EffectMiscValue[i] != spellInfo_2->EffectMiscValue[i]) // paladin resist aura
+ return false; // need itemtype check? need an example to add that check
return true;
}
@@ -1863,6 +2044,11 @@ bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 z
{
if(uint32 mask = spellmgr.GetSpellElixirMask(spellInfo->Id))
{
+ if(mask & ELIXIR_BATTLE_MASK)
+ {
+ if(spellInfo->Id==45373) // Bloodberry Elixir
+ return zone_id==4075;
+ }
if(mask & ELIXIR_UNSTABLE_MASK)
{
// in the Blade's Edge Mountains Plateaus and Gruul's Lair.
@@ -1870,9 +2056,8 @@ bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 z
}
if(mask & ELIXIR_SHATTRATH_MASK)
{
- // in Tempest Keep, Serpentshrine Cavern, Caverns of Time: Mount Hyjal, Black Temple
- // TODO: and the Sunwell Plateau
- if(zone_id ==3607 || map_id==534 || map_id==564)
+ // in Tempest Keep, Serpentshrine Cavern, Caverns of Time: Mount Hyjal, Black Temple, Sunwell Plateau
+ if(zone_id ==3607 || map_id==534 || map_id==564 || zone_id==4075)
return true;
MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
@@ -1890,8 +2075,8 @@ bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 z
// special cases zone check (maps checked by multimap common id)
switch(spellInfo->Id)
{
- case 41618:
- case 41620:
+ case 41618: // Bottled Nethergon Energy
+ case 41620: // Bottled Nethergon Vapor
{
MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
if(!mapEntry)
@@ -1899,9 +2084,8 @@ bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 z
return mapEntry->multimap_id==206;
}
-
- case 41617:
- case 41619:
+ case 41617: // Cenarion Mana Salve
+ case 41619: // Cenarion Healing Salve
{
MapEntry const* mapEntry = sMapStore.LookupEntry(map_id);
if(!mapEntry)
@@ -1909,14 +2093,9 @@ bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 z
return mapEntry->multimap_id==207;
}
- // Dragonmaw Illusion
- case 40216:
- case 42016:
- {
- if ( area_id != 3759 && area_id != 3966 && area_id != 3939 )
- return false;
- break;
- }
+ case 40216: // Dragonmaw Illusion
+ case 42016: // Dragonmaw Illusion
+ return area_id == 3759 || area_id == 3966 || area_id == 3939;
}
return true;
diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h
index 7de9c54c6cb..303f1378c32 100644
--- a/src/game/SpellMgr.h
+++ b/src/game/SpellMgr.h
@@ -241,6 +241,7 @@ enum SpellDisableTypes
#define SPELLFAMILYFLAG_ROGUE_FEINT 0x008000000LL
#define SPELLFAMILYFLAG_ROGUE_KIDNEYSHOT 0x000200000LL
#define SPELLFAMILYFLAG_ROGUE__FINISHING_MOVE 0x9003E0000LL
+#define SPELLFAMILYFLAG_WARRIOR_SUNDERARMOR 0x000004000LL
// Spell clasification
enum SpellSpecific
@@ -262,7 +263,8 @@ enum SpellSpecific
SPELL_BATTLE_ELIXIR = 14,
SPELL_GUARDIAN_ELIXIR = 15,
SPELL_FLASK_ELIXIR = 16,
- SPELL_WARLOCK_CORRUPTION= 17
+ SPELL_WARLOCK_CORRUPTION= 17,
+ SPELL_WELL_FED = 18,
};
SpellSpecific GetSpellSpecific(uint32 spellId);
@@ -270,7 +272,7 @@ SpellSpecific GetSpellSpecific(uint32 spellId);
// Different spell properties
inline float GetSpellRadius(SpellRadiusEntry const *radius) { return (radius ? radius->Radius : 0); }
uint32 GetSpellCastTime(SpellEntry const* spellInfo, Spell const* spell = NULL);
-inline float GetSpellMinRange(SpellRangeEntry const *range) { return (range ? range->minRange : 0); }
+float GetSpellMinRange(SpellRangeEntry const *range);
inline float GetSpellMaxRange(SpellRangeEntry const *range) { return (range ? range->maxRange : 0); }
inline uint32 GetSpellRecoveryTime(SpellEntry const *spellInfo) { return spellInfo->RecoveryTime > spellInfo->CategoryRecoveryTime ? spellInfo->RecoveryTime : spellInfo->CategoryRecoveryTime; }
int32 GetSpellDuration(SpellEntry const *spellInfo);
@@ -284,7 +286,7 @@ inline bool IsSpellHaveEffect(SpellEntry const *spellInfo, SpellEffects effect)
return false;
}
-bool IsNoStackAuraDueToAura(uint32 spellId_1, uint32 effIndex_1, uint32 spellId_2, uint32 effIndex_2);
+//bool IsNoStackAuraDueToAura(uint32 spellId_1, uint32 effIndex_1, uint32 spellId_2, uint32 effIndex_2);
inline bool IsSealSpell(SpellEntry const *spellInfo)
{
@@ -300,7 +302,8 @@ inline bool IsElementalShield(SpellEntry const *spellInfo)
}
int32 CompareAuraRanks(uint32 spellId_1, uint32 effIndex_1, uint32 spellId_2, uint32 effIndex_2);
-bool IsSingleFromSpellSpecificPerCaster(uint32 spellSpec1,uint32 spellSpec2);
+bool IsSingleFromSpellSpecificPerCaster(uint32 spellSpec1, uint32 spellSpec2);
+bool IsSingleFromSpellSpecificPerTarget(uint32 spellSpec1, uint32 spellSpec2);
bool IsPassiveSpell(uint32 spellId);
inline bool IsDeathPersistentSpell(SpellEntry const *spellInfo)
@@ -328,6 +331,8 @@ bool IsPositiveTarget(uint32 targetA, uint32 targetB);
bool IsSingleTargetSpell(SpellEntry const *spellInfo);
bool IsSingleTargetSpells(SpellEntry const *spellInfo1, SpellEntry const *spellInfo2);
+bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId);
+
bool IsSpellAllowedInLocation(SpellEntry const *spellInfo,uint32 map_id,uint32 zone_id,uint32 area_id);
inline bool IsAreaEffectTarget( Targets target )
@@ -446,50 +451,86 @@ typedef std::map<uint32, uint64> SpellAffectMap;
// Spell proc event related declarations (accessed using SpellMgr functions)
enum ProcFlags
{
- PROC_FLAG_NONE = 0x00000000, // None
- PROC_FLAG_HIT_MELEE = 0x00000001, // On melee hit
- PROC_FLAG_STRUCK_MELEE = 0x00000002, // On being struck melee
- PROC_FLAG_KILL_XP_GIVER = 0x00000004, // On kill target giving XP or honor
- PROC_FLAG_SPECIAL_DROP = 0x00000008, //
- PROC_FLAG_DODGE = 0x00000010, // On dodge melee attack
- PROC_FLAG_PARRY = 0x00000020, // On parry melee attack
- PROC_FLAG_BLOCK = 0x00000040, // On block attack
- PROC_FLAG_TOUCH = 0x00000080, // On being touched (for bombs, probably?)
- PROC_FLAG_TARGET_LOW_HEALTH = 0x00000100, // On deal damage to enemy with 20% or less health
- PROC_FLAG_LOW_HEALTH = 0x00000200, // On health dropped below 20%
- PROC_FLAG_STRUCK_RANGED = 0x00000400, // On being struck ranged
- PROC_FLAG_HIT_SPECIAL = 0x00000800, // (!)Removed, may be reassigned in future
- PROC_FLAG_CRIT_MELEE = 0x00001000, // On crit melee
- PROC_FLAG_STRUCK_CRIT_MELEE = 0x00002000, // On being critically struck in melee
- PROC_FLAG_CAST_SPELL = 0x00004000, // On cast spell
- PROC_FLAG_TAKE_DAMAGE = 0x00008000, // On take damage
- PROC_FLAG_CRIT_SPELL = 0x00010000, // On crit spell
- PROC_FLAG_HIT_SPELL = 0x00020000, // On hit spell
- PROC_FLAG_STRUCK_CRIT_SPELL = 0x00040000, // On being critically struck by a spell
- PROC_FLAG_HIT_RANGED = 0x00080000, // On getting ranged hit
- PROC_FLAG_STRUCK_SPELL = 0x00100000, // On being struck by a spell
- PROC_FLAG_TRAP = 0x00200000, // On trap activation (?)
- PROC_FLAG_CRIT_RANGED = 0x00400000, // On getting ranged crit
- PROC_FLAG_STRUCK_CRIT_RANGED = 0x00800000, // On being critically struck by a ranged attack
- PROC_FLAG_RESIST_SPELL = 0x01000000, // On resist enemy spell
- PROC_FLAG_TARGET_RESISTS = 0x02000000, // On enemy resisted spell
- PROC_FLAG_TARGET_DODGE_OR_PARRY = 0x04000000, // On enemy dodges/parries
- PROC_FLAG_HEAL = 0x08000000, // On heal
- PROC_FLAG_CRIT_HEAL = 0x10000000, // On critical healing effect
- PROC_FLAG_HEALED = 0x20000000, // On healing
- PROC_FLAG_TARGET_BLOCK = 0x40000000, // On enemy blocks
- PROC_FLAG_MISS = 0x80000000 // On miss melee attack
+ PROC_FLAG_NONE = 0x00000000,
+
+ PROC_FLAG_KILLED = 0x00000001, // 00 Killed by agressor
+ PROC_FLAG_KILL_AND_GET_XP = 0x00000002, // 01 Kill that yields experience or honor
+
+ PROC_FLAG_SUCCESSFUL_MILEE_HIT = 0x00000004, // 02 Successful melee attack
+ PROC_FLAG_TAKEN_MELEE_HIT = 0x00000008, // 03 Taken damage from melee strike hit
+
+ PROC_FLAG_SUCCESSFUL_MELEE_SPELL_HIT = 0x00000010, // 04 Successful attack by Spell that use melee weapon
+ PROC_FLAG_TAKEN_MELEE_SPELL_HIT = 0x00000020, // 05 Taken damage by Spell that use melee weapon
+
+ PROC_FLAG_SUCCESSFUL_RANGED_HIT = 0x00000040, // 06 Successful Ranged attack (all ranged attack deal as spell so newer set :( )
+ PROC_FLAG_TAKEN_RANGED_HIT = 0x00000080, // 07 Taken damage from ranged attack (all ranged attack deal as spell so newer set :( )
+
+ PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT = 0x00000100, // 08 Successful Ranged attack by Spell that use ranged weapon
+ PROC_FLAG_TAKEN_RANGED_SPELL_HIT = 0x00000200, // 09 Taken damage by Spell that use ranged weapon
+
+ PROC_FLAG_SUCCESSFUL_POSITIVE_AOE_HIT = 0x00000400, // 10 Successful AoE (not 100% shure unused)
+ PROC_FLAG_TAKEN_POSITIVE_AOE = 0x00000800, // 11 Taken AoE (not 100% shure unused)
+
+ PROC_FLAG_SUCCESSFUL_AOE_SPELL_HIT = 0x00001000, // 12 Successful AoE damage spell hit (not 100% shure unused)
+ PROC_FLAG_TAKEN_AOE_SPELL_HIT = 0x00002000, // 13 Taken AoE damage spell hit (not 100% shure unused)
+
+ PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL = 0x00004000, // 14 Successful cast positive spell (by default only on healing)
+ PROC_FLAG_TAKEN_POSITIVE_SPELL = 0x00008000, // 15 Taken positive spell hit (by default only on healing)
+
+ PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT = 0x00010000, // 16 Successful negative spell cast (by default only on damage)
+ PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT = 0x00020000, // 17 Taken negative spell (by default only on damage)
+
+ PROC_FLAG_ON_DO_PERIODIC = 0x00040000, // 18 Successful do periodic (damage / healing, determined from 14-17 flags)
+ PROC_FLAG_ON_TAKE_PERIODIC = 0x00080000, // 19 Taken spell periodic (damage / healing, determined from 14-17 flags)
+
+ PROC_FLAG_TAKEN_ANY_DAMAGE = 0x00100000, // 20 Taken any damage
+ PROC_FLAG_ON_TRAP_ACTIVATION = 0x00200000, // 21 On trap activation
+
+ PROC_FLAG_TAKEN_OFFHAND_HIT = 0x00400000, // 22 Taken off-hand melee attacks(not used)
+ PROC_FLAG_SUCCESSFUL_OFFHAND_HIT = 0x00800000 // 23 Successful off-hand melee attacks
+};
+
+#define MELEE_BASED_TRIGGER_MASK (PROC_FLAG_SUCCESSFUL_MILEE_HIT | \
+ PROC_FLAG_TAKEN_MELEE_HIT | \
+ PROC_FLAG_SUCCESSFUL_MELEE_SPELL_HIT | \
+ PROC_FLAG_TAKEN_MELEE_SPELL_HIT | \
+ PROC_FLAG_SUCCESSFUL_RANGED_HIT | \
+ PROC_FLAG_TAKEN_RANGED_HIT | \
+ PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT | \
+ PROC_FLAG_TAKEN_RANGED_SPELL_HIT)
+
+enum ProcFlagsEx
+{
+ PROC_EX_NONE = 0x0000000, // If none can tigger on Hit/Crit only (passive spells MUST defined by SpellFamily flag)
+ PROC_EX_NORMAL_HIT = 0x0000001, // If set only from normal hit (only damage spells)
+ PROC_EX_CRITICAL_HIT = 0x0000002,
+ PROC_EX_MISS = 0x0000004,
+ PROC_EX_RESIST = 0x0000008,
+ PROC_EX_DODGE = 0x0000010,
+ PROC_EX_PARRY = 0x0000020,
+ PROC_EX_BLOCK = 0x0000040,
+ PROC_EX_EVADE = 0x0000080,
+ PROC_EX_IMMUNE = 0x0000100,
+ PROC_EX_DEFLECT = 0x0000200,
+ PROC_EX_ABSORB = 0x0000400,
+ PROC_EX_REFLECT = 0x0000800,
+ PROC_EX_INTERRUPT = 0x0001000, // Melle hit result can be Interrupt (not used)
+ PROC_EX_RESERVED1 = 0x0002000,
+ PROC_EX_RESERVED2 = 0x0004000,
+ PROC_EX_RESERVED3 = 0x0008000,
+ PROC_EX_EX_TRIGGER_ALWAYS = 0x0010000, // If set trigger always ( no matter another flags) used for drop charges
+ PROC_EX_EX_ONE_TIME_TRIGGER = 0x0020000 // If set trigger always but only one time
};
struct SpellProcEventEntry
{
uint32 schoolMask; // if nonzero - bit mask for matching proc condition based on spell candidate's school: Fire=2, Mask=1<<(2-1)=2
- uint32 category; // if nonzero - match proc condition based on candidate spell's category
- uint32 skillId; // if nonzero - for matching proc condition based on candidate spell's skillId from SkillLineAbility.dbc (Shadow Bolt = Destruction)
uint32 spellFamilyName; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyNamer value
uint64 spellFamilyMask; // if nonzero - for matching proc condition based on candidate spell's SpellFamilyFlags (like auras 107 and 108 do)
uint32 procFlags; // bitmask for matching proc event
+ uint32 procEx; // proc Extend info (see ProcFlagsEx)
float ppmRate; // for melee (ranged?) damage spells - proc rate per minute. if zero, falls back to flat chance from Spell.dbc
+ float customChance; // Owerride chance (in most cases for debug only)
uint32 cooldown; // hidden cooldown used for some spell proc events, applied to _triggered_spell_
};
@@ -699,7 +740,7 @@ class SpellMgr
return NULL;
}
- static bool IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, SpellEntry const * procSpell, uint32 procFlags );
+ static bool IsSpellProcEventCanTriggeredBy( SpellProcEventEntry const * spellProcEvent, uint32 EventProcFlag, SpellEntry const * procSpell, uint32 procFlags, uint32 procExtra, bool active);
// Spell target coordinates
SpellTargetPosition const* GetSpellTargetPosition(uint32 spell_id) const
@@ -768,7 +809,7 @@ class SpellMgr
bool IsRankSpellDueToSpell(SpellEntry const *spellInfo_1,uint32 spellId_2) const;
static bool canStackSpellRanks(SpellEntry const *spellInfo);
- bool IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2) const;
+ bool IsNoStackSpellDueToSpell(uint32 spellId_1, uint32 spellId_2, bool sameCaster) const;
SpellEntry const* SelectAuraRankForPlayerLevel(SpellEntry const* spellInfo, uint32 playerLevel) const;
diff --git a/src/game/StatSystem.cpp b/src/game/StatSystem.cpp
index 3533c5c8a02..ca561dd4b36 100644
--- a/src/game/StatSystem.cpp
+++ b/src/game/StatSystem.cpp
@@ -155,7 +155,7 @@ void Player::UpdateArmor()
{
Modifier* mod = (*i)->GetModifier();
if(mod->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL)
- value += int32(GetStat(Stats((*i)->GetMiscBValue())) * mod->m_amount / 100.0f);
+ value += int32(GetStat(Stats((*i)->GetMiscBValue())) * (*i)->GetModifierValue() / 100.0f);
}
value *= GetModifierValue(unitMod, TOTAL_PCT);
@@ -313,7 +313,7 @@ void Player::UpdateAttackPowerAndDamage(bool ranged )
{
AuraList const& mRAPbyIntellect = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT);
for(AuraList::const_iterator i = mRAPbyIntellect.begin();i != mRAPbyIntellect.end(); ++i)
- attPowerMod += int32(GetStat(Stats((*i)->GetModifier()->m_miscvalue)) * (*i)->GetModifier()->m_amount / 100.0f);
+ attPowerMod += int32(GetStat(Stats((*i)->GetModifier()->m_miscvalue)) * (*i)->GetModifierValue() / 100.0f);
}
float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f;
@@ -572,10 +572,10 @@ void Player::UpdateExpertise(WeaponAttackType attack)
{
// item neutral spell
if((*itr)->GetSpellProto()->EquippedItemClass == -1)
- expertise += (*itr)->GetModifier()->m_amount;
+ expertise += (*itr)->GetModifierValue();
// item dependent spell
else if(weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellProto()))
- expertise += (*itr)->GetModifier()->m_amount;
+ expertise += (*itr)->GetModifierValue();
}
if(expertise < 0)
@@ -605,7 +605,7 @@ void Player::UpdateManaRegen()
for(AuraList::const_iterator i = regenAura.begin();i != regenAura.end(); ++i)
{
Modifier* mod = (*i)->GetModifier();
- power_regen_mp5 += GetStat(Stats(mod->m_miscvalue)) * mod->m_amount / 500.0f;
+ power_regen_mp5 += GetStat(Stats(mod->m_miscvalue)) * (*i)->GetModifierValue() / 500.0f;
}
// Bonus from some dummy auras
@@ -737,15 +737,27 @@ void Creature::UpdateDamagePhysical(WeaponAttackType attType)
break;
}
- float att_speed = float(GetAttackTime(attType))/1000.0f;
+ //float att_speed = float(GetAttackTime(attType))/1000.0f;
- float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
+ float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE);
+ float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE);
+
+ //This formula is not correct
+ //The correct one is (Damage_from_AttackPower + Base_Weapon_Damage) * Multiplier
+ //We do not know the multiplier, so we assume attack power is about 25% damage
+ //float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed;
+ float base_value = GetModifierValue(unitMod, BASE_VALUE)
+ + (weapon_mindamage + weapon_maxdamage) / 6
+ * GetTotalAttackPowerValue(attType) / (getLevel() * 5);
float base_pct = GetModifierValue(unitMod, BASE_PCT);
float total_value = GetModifierValue(unitMod, TOTAL_VALUE);
float total_pct = GetModifierValue(unitMod, TOTAL_PCT);
- float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE);
- float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE);
+ if(attType == BASE_ATTACK && HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED))
+ {
+ weapon_mindamage = 0;
+ weapon_maxdamage = 0;
+ }
float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct ;
float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct ;
diff --git a/src/game/Totem.cpp b/src/game/Totem.cpp
index 4f8b03827ae..26c471d441a 100644
--- a/src/game/Totem.cpp
+++ b/src/game/Totem.cpp
@@ -97,6 +97,9 @@ void Totem::Summon(Unit* owner)
case TOTEM_STATUE: CastSpell(GetOwner(), GetSpell(), true); break;
default: break;
}
+
+ if(GetEntry() == SENTRY_TOTEM_ENTRY)
+ SetAggressive(true);
}
void Totem::UnSummon()
@@ -178,7 +181,7 @@ void Totem::SetTypeBySummonSpell(SpellEntry const * spellProto)
bool Totem::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges)
{
- for (int i=0;i<3;i++)
+/* for (int i=0;i<3;i++)
{
switch(spellInfo->EffectApplyAuraName[i])
{
@@ -188,6 +191,6 @@ bool Totem::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges)
default:
continue;
}
- }
+ }*/
return Creature::IsImmunedToSpell(spellInfo, useCharges);
}
diff --git a/src/game/TradeHandler.cpp b/src/game/TradeHandler.cpp
index 6a6c709a42e..58a18896e9f 100644
--- a/src/game/TradeHandler.cpp
+++ b/src/game/TradeHandler.cpp
@@ -195,10 +195,12 @@ void WorldSession::moveItems(Item* myItems[], Item* hisItems[])
// logging
sLog.outDebug("partner storing: %u",myItems[i]->GetGUIDLow());
if( _player->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
- sLog.outCommand("GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)",
+ {
+ sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)",
_player->GetName(),_player->GetSession()->GetAccountId(),
myItems[i]->GetProto()->Name1,myItems[i]->GetEntry(),myItems[i]->GetCount(),
_player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId());
+ }
// store
_player->pTrader->MoveItemToInventory( traderDst, myItems[i], true, true);
@@ -208,10 +210,12 @@ void WorldSession::moveItems(Item* myItems[], Item* hisItems[])
// logging
sLog.outDebug("player storing: %u",hisItems[i]->GetGUIDLow());
if( _player->pTrader->GetSession()->GetSecurity() > SEC_PLAYER && sWorld.getConfig(CONFIG_GM_LOG_TRADE) )
- sLog.outCommand("GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)",
+ {
+ sLog.outCommand(_player->pTrader->GetSession()->GetAccountId(),"GM %s (Account: %u) trade: %s (Entry: %d Count: %u) to player: %s (Account: %u)",
_player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId(),
hisItems[i]->GetProto()->Name1,hisItems[i]->GetEntry(),hisItems[i]->GetCount(),
_player->GetName(),_player->GetSession()->GetAccountId());
+ }
// store
_player->MoveItemToInventory( playerDst, hisItems[i], true, true);
@@ -378,15 +382,19 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
if(sWorld.getConfig(CONFIG_GM_LOG_TRADE))
{
if( _player->GetSession()->GetSecurity() > SEC_PLAYER && _player->tradeGold > 0)
- sLog.outCommand("GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)",
+ {
+ sLog.outCommand(_player->GetSession()->GetAccountId(),"GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)",
_player->GetName(),_player->GetSession()->GetAccountId(),
_player->tradeGold,
_player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId());
+ }
if( _player->pTrader->GetSession()->GetSecurity() > SEC_PLAYER && _player->pTrader->tradeGold > 0)
- sLog.outCommand("GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)",
+ {
+ sLog.outCommand(_player->pTrader->GetSession()->GetAccountId(),"GM %s (Account: %u) give money (Amount: %u) to player: %s (Account: %u)",
_player->pTrader->GetName(),_player->pTrader->GetSession()->GetAccountId(),
_player->pTrader->tradeGold,
_player->GetName(),_player->GetSession()->GetAccountId());
+ }
}
// update money
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index a78f1ca2c29..6dc5e6201a5 100644
--- a/src/game/Unit.cpp
+++ b/src/game/Unit.cpp
@@ -61,6 +61,8 @@ float baseMoveSpeed[MAX_MOVE_TYPE] =
4.5f, // MOVE_FLYBACK
};
+void InitTriggerAuraData();
+
// auraTypes contains attacker auras capable of proc'ing cast auras
static Unit::AuraTypeSet GenerateAttakerProcCastAuraTypes()
{
@@ -114,6 +116,8 @@ static Unit::AuraTypeSet victimProcEffectAuraTypes = GenerateVictimProcEffectA
// auraTypes contains auras capable of proc'ing for attacker and victim
static Unit::AuraTypeSet GenerateProcAuraTypes()
{
+ InitTriggerAuraData();
+
Unit::AuraTypeSet auraTypes;
auraTypes.insert(attackerProcCastAuraTypes.begin(),attackerProcCastAuraTypes.end());
auraTypes.insert(attackerProcEffectAuraTypes.begin(),attackerProcEffectAuraTypes.end());
@@ -144,6 +148,7 @@ bool IsPassiveStackableSpell( uint32 spellId )
Unit::Unit()
: WorldObject(), i_motionMaster(this), m_ThreatManager(this), m_HostilRefManager(this)
+, m_IsInNotifyList(false), m_Notified(false)
{
m_objectType |= TYPEMASK_UNIT;
m_objectTypeId = TYPEID_UNIT;
@@ -283,7 +288,8 @@ void Unit::Update( uint32 p_time )
}
}
- if(!hasUnitState(UNIT_STAT_CASTING))
+ //not implemented before 3.0.2
+ //if(!hasUnitState(UNIT_STAT_CASTING))
{
if(uint32 base_att = getAttackTimer(BASE_ATTACK))
setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time) );
@@ -472,7 +478,7 @@ void Unit::RemoveSpellsCausingAura(AuraType auraType)
}
}
-void Unit::RemoveAurasWithInterruptFlags(uint32 flag)
+void Unit::RemoveAurasWithInterruptFlags(uint32 flag, uint32 except)
{
if(!(m_interruptMask & flag))
return;
@@ -487,18 +493,27 @@ void Unit::RemoveAurasWithInterruptFlags(uint32 flag)
//sLog.outDetail("auraflag:%u flag:%u = %u",(*iter)->GetSpellProto()->AuraInterruptFlags,flag,(*iter)->GetSpellProto()->AuraInterruptFlags & flag);
if(*iter && ((*iter)->GetSpellProto()->AuraInterruptFlags & flag))
{
- RemoveAurasDueToSpell((*iter)->GetId());
- if (!m_interruptableAuras.empty())
- next = m_interruptableAuras.begin();
- else
- break;
+ if((*iter)->IsInUse())
+ sLog.outError("Aura %u is trying to remove itself! Flag %u. May cause crash!", (*iter)->GetId(), flag);
+ else if(!except || (*iter)->GetId() != except)
+ {
+ RemoveAurasDueToSpell((*iter)->GetId());
+ if (!m_interruptableAuras.empty())
+ next = m_interruptableAuras.begin();
+ else
+ break;
+ }
}
}
// interrupt channeled spell
if(Spell* spell = m_currentSpells[CURRENT_CHANNELED_SPELL])
- if(spell->getState() == SPELL_STATE_CASTING && (spell->m_spellInfo->ChannelInterruptFlags & flag))
+ if(spell->getState() == SPELL_STATE_CASTING
+ && (spell->m_spellInfo->ChannelInterruptFlags & flag)
+ && spell->m_spellInfo->Id != except)
InterruptNonMeleeSpells(false);
+
+ UpdateInterruptMask();
}
void Unit::UpdateInterruptMask()
@@ -666,6 +681,8 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
{
DEBUG_LOG("DealDamage: victim just died");
+ pVictim->SetHealth(0);
+
// find player: owner of controlled `this` or `this` itself maybe
Player *player = GetCharmerOrOwnerPlayerOrPlayerItself();
@@ -674,8 +691,12 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
// Reward player, his pets, and group/raid members
// call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop)
if(player && player!=pVictim)
+ {
if(player->RewardPlayerAndGroupAtKill(pVictim))
- player->ProcDamageAndSpell(pVictim,PROC_FLAG_KILL_XP_GIVER,PROC_FLAG_NONE);
+ player->ProcDamageAndSpell(pVictim, PROC_FLAG_KILL_AND_GET_XP, PROC_FLAG_KILLED, PROC_EX_NONE, 0);
+ else
+ player->ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_KILLED,PROC_EX_NONE, 0);
+ }
DEBUG_LOG("DealDamageAttackStop");
@@ -744,7 +765,8 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
// FORM_SPIRITOFREDEMPTION and related auras
pVictim->CastSpell(pVictim,27827,true,NULL,spiritOfRedemtionTalentReady);
}
- else
+ else //without this when removing IncreaseMaxHealth aura player may stuck with 1 hp
+ //do not why since in IncreaseMaxHealth currenthealth is checked
pVictim->SetHealth(0);
// remember victim PvP death for corpse type and corpse reclaim delay
@@ -829,22 +851,15 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
}
// battleground things (do this at the end, so the death state flag will be properly set to handle in the bg->handlekill)
- if(pVictim->GetTypeId() == TYPEID_PLAYER && (((Player*)pVictim)->InBattleGround()))
+ if(player && player->InBattleGround())
{
- Player *killed = ((Player*)pVictim);
- Player *killer = NULL;
- if(GetTypeId() == TYPEID_PLAYER)
- killer = ((Player*)this);
- else if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())
+ if(BattleGround *bg = player->GetBattleGround())
{
- Unit *owner = GetOwner();
- if(owner && owner->GetTypeId() == TYPEID_PLAYER)
- killer = ((Player*)owner);
+ if(pVictim->GetTypeId() == TYPEID_PLAYER)
+ bg->HandleKillPlayer((Player*)pVictim, player);
+ else
+ bg->HandleKillUnit((Creature*)pVictim, player);
}
-
- if(killer)
- if(BattleGround *bg = killed->GetBattleGround())
- bg->HandleKillPlayer(killed, killer); // drop flags and etc
}
}
else // if (health <= damage)
@@ -853,18 +868,6 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
pVictim->ModifyHealth(- (int32)damage);
- // Check if health is below 20% (apply damage before to prevent case when after ProcDamageAndSpell health < damage
- if(pVictim->GetHealth()*5 < pVictim->GetMaxHealth())
- {
- uint32 procVictim = PROC_FLAG_NONE;
-
- // if just dropped below 20% (for CheatDeath)
- if((pVictim->GetHealth()+damage)*5 > pVictim->GetMaxHealth())
- procVictim = PROC_FLAG_LOW_HEALTH;
-
- ProcDamageAndSpell(pVictim,PROC_FLAG_TARGET_LOW_HEALTH,procVictim);
- }
-
if(damagetype != DOT)
{
if(getVictim())
@@ -881,8 +884,13 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
}
}
- if(damagetype == DIRECT_DAMAGE|| damagetype == SPELL_DIRECT_DAMAGE)
- pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE);
+ if(damagetype == DIRECT_DAMAGE || damagetype == SPELL_DIRECT_DAMAGE)
+ {
+ //TODO: This is from procflag, I do not know which spell needs this
+ //Maim?
+ //if (!spellProto || !(spellProto->AuraInterruptFlags&AURA_INTERRUPT_FLAG_DIRECT_DAMAGE))
+ pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DIRECT_DAMAGE, spellProto ? spellProto->Id : 0);
+ }
if (pVictim->GetTypeId() != TYPEID_PLAYER)
{
@@ -920,10 +928,30 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
if (damagetype != NODAMAGE && damage)// && pVictim->GetTypeId() == TYPEID_PLAYER)
{
- //if (se->procFlags & (1<<3))
- pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DAMAGE);
+ pVictim->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_DAMAGE, spellProto ? spellProto->Id : 0);
pVictim->RemoveSpellbyDamageTaken(damage, spellProto ? spellProto->Id : 0);
+ /*const SpellEntry *se = i->second->GetSpellProto();
+ next = i; ++next;
+ if (spellProto && spellProto->Id == se->Id) // Not drop auras added by self
+ continue;
+ if( se->AuraInterruptFlags & AURA_INTERRUPT_FLAG_DAMAGE )
+ {
+ bool remove = true;
+ if (se->procFlags & (1<<3))
+ {
+ if (!roll_chance_i(se->procChance))
+ remove = false;
+ }
+ if (remove)
+ {
+ pVictim->RemoveAurasDueToSpell(i->second->GetId());
+ // FIXME: this may cause the auras with proc chance to be rerolled several times
+ next = vAuras.begin();
+ }
+ }
+ }*/
+
if(pVictim != this && pVictim->GetTypeId() == TYPEID_PLAYER) // does not support creature push_back
{
if(damagetype != DOT)
@@ -1101,6 +1129,7 @@ void Unit::CastSpell(float x, float y, float z, SpellEntry const *spellInfo, boo
spell->prepare(&targets, triggeredByAura);
}
+/*
void Unit::DealFlatDamage(Unit *pVictim, SpellEntry const *spellInfo, uint32 *damage, CleanDamage *cleanDamage, bool *crit, bool isTriggeredSpell)
{
// TODO this in only generic way, check for exceptions
@@ -1187,7 +1216,7 @@ void Unit::DealFlatDamage(Unit *pVictim, SpellEntry const *spellInfo, uint32 *da
AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS);
for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i)
if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- bonusDmg = uint32(bonusDmg * ((*i)->GetModifier()->m_amount+100.0f)/100.0f);
+ bonusDmg = uint32(bonusDmg * ((*i)->GetModifierValue()+100.0f)/100.0f);
*damage += bonusDmg;
@@ -1482,7 +1511,7 @@ uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage
GetGUIDLow(), GetTypeId(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, spellID, absorb,resist);
// Actual log sent to client
- SendSpellNonMeleeDamageLog(pVictim, spellID, damage, GetSpellSchoolMask(spellInfo), absorb, resist, false, 0, crit);
+ SendSpellNonMeleeDamageLog(pVictim, spellID, damage + resist, GetSpellSchoolMask(spellInfo), absorb, resist, false, 0, crit);
// Procflags
uint32 procAttacker = PROC_FLAG_HIT_SPELL;
@@ -1511,6 +1540,577 @@ uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage
return 0;
}
}
+*/
+
+// Obsolete func need remove, here only for comotability vs another patches
+uint32 Unit::SpellNonMeleeDamageLog(Unit *pVictim, uint32 spellID, uint32 damage, bool isTriggeredSpell, bool useSpellDamage)
+{
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellID);
+ SpellNonMeleeDamage damageInfo(this, pVictim, spellInfo->Id, spellInfo->SchoolMask);
+ CalculateSpellDamage(&damageInfo, damage, spellInfo);
+ SendSpellNonMeleeDamageLog(&damageInfo);
+ DealSpellDamage(&damageInfo, true);
+ return damageInfo.damage;
+}
+
+void Unit::CalculateSpellDamage(SpellNonMeleeDamage *damageInfo, int32 damage, SpellEntry const *spellInfo, WeaponAttackType attackType)
+{
+ SpellSchoolMask damageSchoolMask = SpellSchoolMask(damageInfo->schoolMask);
+ Unit *pVictim = damageInfo->target;
+
+ if (damage < 0)
+ return;
+
+ if(!this || !pVictim)
+ return;
+ if(!this->isAlive() || !pVictim->isAlive())
+ return;
+
+ uint32 crTypeMask = pVictim->GetCreatureTypeMask();
+ // Check spell crit chance
+ bool crit = isSpellCrit(pVictim, spellInfo, damageSchoolMask, attackType);
+ bool blocked = false;
+ // Per-school calc
+ switch (spellInfo->DmgClass)
+ {
+ // Melee and Ranged Spells
+ case SPELL_DAMAGE_CLASS_RANGED:
+ case SPELL_DAMAGE_CLASS_MELEE:
+ {
+ // Physical Damage
+ if ( damageSchoolMask & SPELL_SCHOOL_MASK_NORMAL )
+ {
+ //Calculate armor mitigation
+ damage = CalcArmorReducedDamage(pVictim, damage);
+ // Get blocked status
+ blocked = isSpellBlocked(pVictim, spellInfo, attackType);
+ }
+ // Magical Damage
+ else
+ {
+ // Calculate damage bonus
+ damage = SpellDamageBonus(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE);
+ }
+ if (crit)
+ {
+ damageInfo->HitInfo|= SPELL_HIT_TYPE_CRIT;
+
+ // Calculate crit bonus
+ uint32 crit_bonus = damage;
+ // Apply crit_damage bonus for melee spells
+ if(Player* modOwner = GetSpellModOwner())
+ modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CRIT_DAMAGE_BONUS, crit_bonus);
+ damage += crit_bonus;
+
+ // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
+ int32 critPctDamageMod=0;
+ if(attackType == RANGED_ATTACK)
+ critPctDamageMod += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE);
+ else
+ {
+ critPctDamageMod += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
+ critPctDamageMod += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE);
+ }
+ // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
+ critPctDamageMod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask);
+
+ if (critPctDamageMod!=0)
+ damage = int32((damage) * float((100.0f + critPctDamageMod)/100.0f));
+
+ // Resilience - reduce crit damage
+ if (pVictim->GetTypeId()==TYPEID_PLAYER)
+ damage -= ((Player*)pVictim)->GetMeleeCritDamageReduction(damage);
+ }
+ // Spell weapon based damage CAN BE crit & blocked at same time
+ if (blocked)
+ {
+ damageInfo->blocked = uint32(pVictim->GetShieldBlockValue());
+ if (damage < damageInfo->blocked)
+ damageInfo->blocked = damage;
+ damage-=damageInfo->blocked;
+ }
+ }
+ break;
+ // Magical Attacks
+ case SPELL_DAMAGE_CLASS_NONE:
+ case SPELL_DAMAGE_CLASS_MAGIC:
+ {
+ // Calculate damage bonus
+ damage = SpellDamageBonus(pVictim, spellInfo, damage, SPELL_DIRECT_DAMAGE);
+ // If crit add critical bonus
+ if (crit)
+ {
+ damageInfo->HitInfo|= SPELL_HIT_TYPE_CRIT;
+ damage = SpellCriticalBonus(spellInfo, damage, pVictim);
+ // Resilience - reduce crit damage
+ if (pVictim->GetTypeId()==TYPEID_PLAYER)
+ damage -= ((Player*)pVictim)->GetSpellCritDamageReduction(damage);
+ }
+ }
+ break;
+ }
+
+ // Calculate absorb resist
+ if(damage > 0)
+ {
+ CalcAbsorbResist(pVictim, damageSchoolMask, SPELL_DIRECT_DAMAGE, damage, &damageInfo->absorb, &damageInfo->resist);
+ damage-= damageInfo->absorb + damageInfo->resist;
+ }
+ else
+ damage = 0;
+ damageInfo->damage = damage;
+}
+
+void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss)
+{
+ if (damageInfo==0)
+ return;
+
+ Unit *pVictim = damageInfo->target;
+
+ if(!this || !pVictim)
+ return;
+
+ if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
+ return;
+
+ SpellEntry const *spellProto = sSpellStore.LookupEntry(damageInfo->SpellID);
+ if (spellProto == NULL)
+ {
+ sLog.outDebug("Unit::DealSpellDamage have wrong damageInfo->SpellID: %u", damageInfo->SpellID);
+ return;
+ }
+
+ //You don't lose health from damage taken from another player while in a sanctuary
+ //You still see it in the combat log though
+ if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
+ {
+ const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
+ if(area && area->flags & 0x800) //sanctuary
+ return;
+ }
+
+ // update at damage Judgement aura duration that applied by attacker at victim
+ if(damageInfo->damage && spellProto->Id == 35395)
+ {
+ AuraMap& vAuras = pVictim->GetAuras();
+ for(AuraMap::iterator itr = vAuras.begin(); itr != vAuras.end(); ++itr)
+ {
+ SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
+ if( spellInfo->AttributesEx3 & 0x40000 && spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && ((*itr).second->GetCasterGUID() == GetGUID()))
+ {
+ (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration());
+ (*itr).second->UpdateAuraDuration();
+ }
+ }
+ }
+ // Call default DealDamage
+ CleanDamage cleanDamage(damageInfo->cleanDamage, BASE_ATTACK, MELEE_HIT_NORMAL);
+ DealDamage(pVictim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss);
+}
+
+//TODO for melee need create structure as in
+void Unit::CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *damageInfo, WeaponAttackType attackType)
+{
+ damageInfo->attacker = this;
+ damageInfo->target = pVictim;
+ damageInfo->damageSchoolMask = GetMeleeDamageSchoolMask();
+ damageInfo->attackType = attackType;
+ damageInfo->damage = 0;
+ damageInfo->cleanDamage = 0;
+ damageInfo->absorb = 0;
+ damageInfo->resist = 0;
+ damageInfo->blocked_amount = 0;
+
+ damageInfo->TargetState = 0;
+ damageInfo->HitInfo = 0;
+ damageInfo->procAttacker = PROC_FLAG_NONE;
+ damageInfo->procVictim = PROC_FLAG_NONE;
+ damageInfo->procEx = PROC_EX_NONE;
+ damageInfo->hitOutCome = MELEE_HIT_EVADE;
+
+ if(!this || !pVictim)
+ return;
+ if(!this->isAlive() || !pVictim->isAlive())
+ return;
+
+ // Select HitInfo/procAttacker/procVictim flag based on attack type
+ switch (attackType)
+ {
+ case BASE_ATTACK:
+ damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MILEE_HIT;
+ damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT;
+ damageInfo->HitInfo = HITINFO_NORMALSWING2;
+ break;
+ case OFF_ATTACK:
+ damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_MILEE_HIT | PROC_FLAG_SUCCESSFUL_OFFHAND_HIT;
+ damageInfo->procVictim = PROC_FLAG_TAKEN_MELEE_HIT;//|PROC_FLAG_TAKEN_OFFHAND_HIT // not used
+ damageInfo->HitInfo = HITINFO_LEFTSWING;
+ break;
+ case RANGED_ATTACK:
+ damageInfo->procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_HIT;
+ damageInfo->procVictim = PROC_FLAG_TAKEN_RANGED_HIT;
+ damageInfo->HitInfo = 0x08;// test
+ break;
+ default:
+ break;
+ }
+
+ // Physical Immune check
+ if(damageInfo->target->IsImmunedToDamage(SpellSchoolMask(damageInfo->damageSchoolMask),true))
+ {
+ damageInfo->HitInfo |= HITINFO_NORMALSWING;
+ damageInfo->TargetState = VICTIMSTATE_IS_IMMUNE;
+
+ damageInfo->procEx |=PROC_EX_IMMUNE;
+ damageInfo->damage = 0;
+ damageInfo->cleanDamage = 0;
+ return;
+ }
+ damage += CalculateDamage (damageInfo->attackType, false);
+ // Add melee damage bonus
+ MeleeDamageBonus(damageInfo->target, &damage, damageInfo->attackType);
+ // Calculate armor reduction
+ damageInfo->damage = CalcArmorReducedDamage(damageInfo->target, damage);
+ damageInfo->cleanDamage += damage - damageInfo->damage;
+
+ damageInfo->hitOutCome = RollMeleeOutcomeAgainst(damageInfo->target, damageInfo->attackType);
+
+ // Disable parry or dodge for ranged attack
+ if(damageInfo->attackType == RANGED_ATTACK)
+ {
+ if (damageInfo->hitOutCome == MELEE_HIT_PARRY) damageInfo->hitOutCome = MELEE_HIT_NORMAL;
+ if (damageInfo->hitOutCome == MELEE_HIT_DODGE) damageInfo->hitOutCome = MELEE_HIT_MISS;
+ }
+
+ switch(damageInfo->hitOutCome)
+ {
+ case MELEE_HIT_EVADE:
+ {
+ damageInfo->HitInfo |= HITINFO_MISS|HITINFO_SWINGNOHITSOUND;
+ damageInfo->TargetState = VICTIMSTATE_EVADES;
+
+ damageInfo->procEx|=PROC_EX_EVADE;
+ damageInfo->damage = 0;
+ damageInfo->cleanDamage = 0;
+ return;
+ }
+ case MELEE_HIT_MISS:
+ {
+ damageInfo->HitInfo |= HITINFO_MISS;
+ damageInfo->TargetState = VICTIMSTATE_NORMAL;
+
+ damageInfo->procEx|=PROC_EX_MISS;
+ damageInfo->damage = 0;
+ damageInfo->cleanDamage = 0;
+ break;
+ }
+ case MELEE_HIT_NORMAL:
+ damageInfo->TargetState = VICTIMSTATE_NORMAL;
+ damageInfo->procEx|=PROC_EX_NORMAL_HIT;
+ break;
+ case MELEE_HIT_CRIT:
+ {
+ damageInfo->HitInfo |= HITINFO_CRITICALHIT;
+ damageInfo->TargetState = VICTIMSTATE_NORMAL;
+
+ damageInfo->procEx|=PROC_EX_CRITICAL_HIT;
+ // Crit bonus calc
+ damageInfo->damage += damageInfo->damage;
+ int32 mod=0;
+ // Apply SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE or SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE
+ if(damageInfo->attackType == RANGED_ATTACK)
+ mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_DAMAGE);
+ else
+ {
+ mod += damageInfo->target->GetTotalAuraModifier(SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_DAMAGE);
+ mod += GetTotalAuraModifier(SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE);
+ }
+
+ uint32 crTypeMask = damageInfo->target->GetCreatureTypeMask();
+
+ // Increase crit damage from SPELL_AURA_MOD_CRIT_PERCENT_VERSUS
+ mod += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS, crTypeMask);
+ if (mod!=0)
+ damageInfo->damage = int32((damageInfo->damage) * float((100.0f + mod)/100.0f));
+
+ // Resilience - reduce crit damage
+ if (pVictim->GetTypeId()==TYPEID_PLAYER)
+ {
+ uint32 resilienceReduction = ((Player*)pVictim)->GetMeleeCritDamageReduction(damageInfo->damage);
+ damageInfo->damage -= resilienceReduction;
+ damageInfo->cleanDamage += resilienceReduction;
+ }
+ break;
+ }
+ case MELEE_HIT_PARRY:
+ damageInfo->TargetState = VICTIMSTATE_PARRY;
+ damageInfo->procEx|=PROC_EX_PARRY;
+ damageInfo->cleanDamage += damageInfo->damage;
+ damageInfo->damage = 0;
+ break;
+
+ case MELEE_HIT_DODGE:
+ damageInfo->TargetState = VICTIMSTATE_DODGE;
+ damageInfo->procEx|=PROC_EX_DODGE;
+ damageInfo->cleanDamage += damageInfo->damage;
+ damageInfo->damage = 0;
+ break;
+ case MELEE_HIT_BLOCK:
+ {
+ damageInfo->TargetState = VICTIMSTATE_NORMAL;
+ damageInfo->procEx|=PROC_EX_BLOCK;
+ damageInfo->blocked_amount = damageInfo->target->GetShieldBlockValue();
+ if (damageInfo->blocked_amount >= damageInfo->damage)
+ {
+ damageInfo->TargetState = VICTIMSTATE_BLOCKS;
+ damageInfo->blocked_amount = damageInfo->damage;
+ }
+ damageInfo->damage -= damageInfo->blocked_amount;
+ damageInfo->cleanDamage += damageInfo->blocked_amount;
+ break;
+ }
+ case MELEE_HIT_GLANCING:
+ {
+ damageInfo->HitInfo |= HITINFO_GLANCING;
+ damageInfo->TargetState = VICTIMSTATE_NORMAL;
+ damageInfo->procEx|=PROC_EX_NORMAL_HIT;
+ float reducePercent = 1.0f; //damage factor
+ // calculate base values and mods
+ float baseLowEnd = 1.3;
+ float baseHighEnd = 1.2;
+ switch(getClass()) // lowering base values for casters
+ {
+ case CLASS_SHAMAN:
+ case CLASS_PRIEST:
+ case CLASS_MAGE:
+ case CLASS_WARLOCK:
+ case CLASS_DRUID:
+ baseLowEnd -= 0.7;
+ baseHighEnd -= 0.3;
+ break;
+ }
+
+ float maxLowEnd = 0.6;
+ switch(getClass()) // upper for melee classes
+ {
+ case CLASS_WARRIOR:
+ case CLASS_ROGUE:
+ maxLowEnd = 0.91; //If the attacker is a melee class then instead the lower value of 0.91
+ }
+
+ // calculate values
+ int32 diff = damageInfo->target->GetDefenseSkillValue() - GetWeaponSkillValue(damageInfo->attackType);
+ float lowEnd = baseLowEnd - ( 0.05f * diff );
+ float highEnd = baseHighEnd - ( 0.03f * diff );
+
+ // apply max/min bounds
+ if ( lowEnd < 0.01f ) //the low end must not go bellow 0.01f
+ lowEnd = 0.01f;
+ else if ( lowEnd > maxLowEnd ) //the smaller value of this and 0.6 is kept as the low end
+ lowEnd = maxLowEnd;
+
+ if ( highEnd < 0.2f ) //high end limits
+ highEnd = 0.2f;
+ if ( highEnd > 0.99f )
+ highEnd = 0.99f;
+
+ if(lowEnd > highEnd) // prevent negative range size
+ lowEnd = highEnd;
+
+ reducePercent = lowEnd + rand_norm() * ( highEnd - lowEnd );
+
+ damageInfo->cleanDamage += damageInfo->damage-uint32(reducePercent * damageInfo->damage);
+ damageInfo->damage = uint32(reducePercent * damageInfo->damage);
+ break;
+ }
+ case MELEE_HIT_CRUSHING:
+ {
+ damageInfo->HitInfo |= HITINFO_CRUSHING;
+ damageInfo->TargetState = VICTIMSTATE_NORMAL;
+ damageInfo->procEx|=PROC_EX_NORMAL_HIT;
+ // 150% normal damage
+ damageInfo->damage += (damageInfo->damage / 2);
+ break;
+ }
+ default:
+
+ break;
+ }
+
+ // Calculate absorb resist
+ if(int32(damageInfo->damage) > 0)
+ {
+ damageInfo->procVictim |= PROC_FLAG_TAKEN_ANY_DAMAGE;
+ // Calculate absorb & resists
+ CalcAbsorbResist(damageInfo->target, SpellSchoolMask(damageInfo->damageSchoolMask), DIRECT_DAMAGE, damageInfo->damage, &damageInfo->absorb, &damageInfo->resist);
+ damageInfo->damage-=damageInfo->absorb + damageInfo->resist;
+ if (damageInfo->absorb)
+ {
+ damageInfo->HitInfo|=HITINFO_ABSORB;
+ damageInfo->procEx|=PROC_EX_ABSORB;
+ }
+ if (damageInfo->resist)
+ damageInfo->HitInfo|=HITINFO_RESIST;
+
+ }
+ else // Umpossible get negative result but....
+ damageInfo->damage = 0;
+}
+
+void Unit::DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss)
+{
+ if (damageInfo==0) return;
+ Unit *pVictim = damageInfo->target;
+
+ if(!this || !pVictim)
+ return;
+
+ if (!pVictim->isAlive() || pVictim->isInFlight() || pVictim->GetTypeId() == TYPEID_UNIT && ((Creature*)pVictim)->IsInEvadeMode())
+ return;
+
+ //You don't lose health from damage taken from another player while in a sanctuary
+ //You still see it in the combat log though
+ if(pVictim != this && GetTypeId() == TYPEID_PLAYER && pVictim->GetTypeId() == TYPEID_PLAYER)
+ {
+ const AreaTableEntry *area = GetAreaEntryByAreaID(pVictim->GetAreaId());
+ if(area && area->flags & 0x800) //sanctuary
+ return;
+ }
+
+ // Hmmmm dont like this emotes cloent must by self do all animations
+ if (damageInfo->HitInfo&HITINFO_CRITICALHIT)
+ pVictim->HandleEmoteCommand(EMOTE_ONESHOT_WOUNDCRITICAL);
+ if(damageInfo->blocked_amount && damageInfo->TargetState!=VICTIMSTATE_BLOCKS)
+ pVictim->HandleEmoteCommand(EMOTE_ONESHOT_PARRYSHIELD);
+
+ if(damageInfo->TargetState == VICTIMSTATE_PARRY)
+ {
+ // Get attack timers
+ float offtime = float(pVictim->getAttackTimer(OFF_ATTACK));
+ float basetime = float(pVictim->getAttackTimer(BASE_ATTACK));
+ // Reduce attack time
+ if (pVictim->haveOffhandWeapon() && offtime < basetime)
+ {
+ float percent20 = pVictim->GetAttackTime(OFF_ATTACK) * 0.20;
+ float percent60 = 3 * percent20;
+ if(offtime > percent20 && offtime <= percent60)
+ {
+ pVictim->setAttackTimer(OFF_ATTACK, uint32(percent20));
+ }
+ else if(offtime > percent60)
+ {
+ offtime -= 2 * percent20;
+ pVictim->setAttackTimer(OFF_ATTACK, uint32(offtime));
+ }
+ }
+ else
+ {
+ float percent20 = pVictim->GetAttackTime(BASE_ATTACK) * 0.20;
+ float percent60 = 3 * percent20;
+ if(basetime > percent20 && basetime <= percent60)
+ {
+ pVictim->setAttackTimer(BASE_ATTACK, uint32(percent20));
+ }
+ else if(basetime > percent60)
+ {
+ basetime -= 2 * percent20;
+ pVictim->setAttackTimer(BASE_ATTACK, uint32(basetime));
+ }
+ }
+ }
+
+ // Call default DealDamage
+ CleanDamage cleanDamage(damageInfo->cleanDamage,damageInfo->attackType,damageInfo->hitOutCome);
+ DealDamage(pVictim, damageInfo->damage, &cleanDamage, DIRECT_DAMAGE, SpellSchoolMask(damageInfo->damageSchoolMask), NULL, durabilityLoss);
+
+ // If this is a creature and it attacks from behind it has a probability to daze it's victim
+ if( (damageInfo->hitOutCome==MELEE_HIT_CRIT || damageInfo->hitOutCome==MELEE_HIT_CRUSHING || damageInfo->hitOutCome==MELEE_HIT_NORMAL || damageInfo->hitOutCome==MELEE_HIT_GLANCING) &&
+ GetTypeId() != TYPEID_PLAYER && !((Creature*)this)->GetCharmerOrOwnerGUID() && !pVictim->HasInArc(M_PI, this) )
+ {
+ // -probability is between 0% and 40%
+ // 20% base chance
+ float Probability = 20;
+
+ //there is a newbie protection, at level 10 just 7% base chance; assuming linear function
+ if( pVictim->getLevel() < 30 )
+ Probability = 0.65f*pVictim->getLevel()+0.5;
+
+ uint32 VictimDefense=pVictim->GetDefenseSkillValue();
+ uint32 AttackerMeleeSkill=GetUnitMeleeSkill();
+
+ Probability *= AttackerMeleeSkill/(float)VictimDefense;
+
+ if(Probability > 40)
+ Probability = 40;
+
+ if(roll_chance_f(Probability))
+ CastSpell(pVictim, 1604, true);
+ }
+
+ // update at damage Judgement aura duration that applied by attacker at victim
+ if(damageInfo->damage)
+ {
+ AuraMap& vAuras = pVictim->GetAuras();
+ for(AuraMap::iterator itr = vAuras.begin(); itr != vAuras.end(); ++itr)
+ {
+ SpellEntry const *spellInfo = (*itr).second->GetSpellProto();
+ if( spellInfo->AttributesEx3 & 0x40000 && spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && ((*itr).second->GetCasterGUID() == GetGUID()))
+ {
+ (*itr).second->SetAuraDuration((*itr).second->GetAuraMaxDuration());
+ (*itr).second->UpdateAuraDuration();
+ }
+ }
+ }
+
+ // If not miss
+ if (!(damageInfo->HitInfo & HITINFO_MISS))
+ {
+ if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive())
+ {
+ for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
+ ((Player*)this)->CastItemCombatSpell(((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i), pVictim, damageInfo->attackType);
+ }
+
+ // victim's damage shield
+ std::set<Aura*> alreadyDone;
+ uint32 removedAuras = pVictim->m_removedAuras;
+ AuraList const& vDamageShields = pVictim->GetAurasByType(SPELL_AURA_DAMAGE_SHIELD);
+ for(AuraList::const_iterator i = vDamageShields.begin(), next = vDamageShields.begin(); i != vDamageShields.end(); i = next)
+ {
+ next++;
+ if (alreadyDone.find(*i) == alreadyDone.end())
+ {
+ alreadyDone.insert(*i);
+ uint32 damage=(*i)->GetModifier()->m_amount;
+ SpellEntry const *spellProto = sSpellStore.LookupEntry((*i)->GetId());
+ if(!spellProto)
+ continue;
+ //Calculate absorb resist ??? no data in opcode for this possibly unable to absorb or resist?
+ //uint32 absorb;
+ //uint32 resist;
+ //CalcAbsorbResist(pVictim, SpellSchools(spellProto->School), SPELL_DIRECT_DAMAGE, damage, &absorb, &resist);
+ //damage-=absorb + resist;
+
+ WorldPacket data(SMSG_SPELLDAMAGESHIELD,(8+8+4+4));
+ data << uint64(pVictim->GetGUID());
+ data << uint64(GetGUID());
+ data << uint32(spellProto->SchoolMask);
+ data << uint32(damage);
+ pVictim->SendMessageToSet(&data, true );
+
+ pVictim->DealDamage(this, damage, 0, SPELL_DIRECT_DAMAGE, GetSpellSchoolMask(spellProto), spellProto, true);
+
+ if (pVictim->m_removedAuras > removedAuras)
+ {
+ removedAuras = pVictim->m_removedAuras;
+ next = vDamageShields.begin();
+ }
+ }
+ }
+ }
+}
+
void Unit::HandleEmoteCommand(uint32 anim_id)
{
@@ -1769,6 +2369,7 @@ void Unit::CalcAbsorbResist(Unit *pVictim,SpellSchoolMask schoolMask, DamageEffe
*absorb = damage - RemainingDamage - *resist;
}
+/*
void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDamage, uint32 *blocked_amount, SpellSchoolMask damageSchoolMask, uint32 *hitInfo, VictimState *victimState, uint32 *absorbDamage, uint32 *resistDamage, WeaponAttackType attType, SpellEntry const *spellCasted, bool isTriggeredSpell)
{
MeleeHitOutcome outcome;
@@ -1870,7 +2471,7 @@ void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDama
AuraList const& mDamageDoneVersus = GetAurasByType(SPELL_AURA_MOD_CRIT_PERCENT_VERSUS);
for(AuraList::const_iterator i = mDamageDoneVersus.begin();i != mDamageDoneVersus.end(); ++i)
if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- crit_bonus = uint32(crit_bonus * ((*i)->GetModifier()->m_amount+100.0f)/100.0f);
+ crit_bonus = uint32(crit_bonus * ((*i)->GetModifierValue()+100.0f)/100.0f);
}
*damage += crit_bonus;
@@ -2148,9 +2749,7 @@ void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDama
}
}
- CastMeleeProcDamageAndSpell(pVictim, (*damage - *absorbDamage - *resistDamage - *blocked_amount), damageSchoolMask, attType, outcome, spellCasted, isTriggeredSpell);
-
- // victim's damage shield
+ CastMeleeProcDamageAndSpell(pVictim, (*damage - *absorbDamage pVictim->SpellNonMeleeDamageLog(this, (*i)->GetId(), (*i)->GetModifier()->m_amount, false, false);eld
// yet another hack to fix crashes related to the aura getting removed during iteration
std::set<Aura*> alreadyDone;
uint32 removedAuras = pVictim->m_removedAuras;
@@ -2161,7 +2760,7 @@ void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDama
if (alreadyDone.find(*i) == alreadyDone.end())
{
alreadyDone.insert(*i);
- pVictim->SpellNonMeleeDamageLog(this, (*i)->GetId(), (*i)->GetModifier()->m_amount, false, false);
+ pVictim->SpellNonMeleeDamageLog(this, (*i)->GetId(), (*i)->GetModifierValue(), false, false);
if (pVictim->m_removedAuras > removedAuras)
{
removedAuras = pVictim->m_removedAuras;
@@ -2169,7 +2768,7 @@ void Unit::DoAttackDamage (Unit *pVictim, uint32 *damage, CleanDamage *cleanDama
}
}
}
-}
+}*/
void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool extra )
{
@@ -2183,6 +2782,7 @@ void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool ex
return;
CombatStart(pVictim);
+ RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ATTACK);
uint32 hitInfo;
if (attType == BASE_ATTACK)
@@ -2213,65 +2813,19 @@ void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool ex
return;
}
- VictimState victimState = VICTIMSTATE_NORMAL;
-
- CleanDamage cleanDamage = CleanDamage(0, BASE_ATTACK, MELEE_HIT_NORMAL );
- uint32 blocked_dmg = 0;
- uint32 absorbed_dmg = 0;
- uint32 resisted_dmg = 0;
-
- SpellSchoolMask meleeSchoolMask = GetMeleeDamageSchoolMask();
-
- if(pVictim->IsImmunedToDamage(meleeSchoolMask,true)) // use charges
- {
- SendAttackStateUpdate (HITINFO_NORMALSWING, pVictim, 1, meleeSchoolMask, 0, 0, 0, VICTIMSTATE_IS_IMMUNE, 0);
-
- // not recent extra attack only at any non extra attack (miss case)
- if(!extra && extraAttacks)
- {
- while(m_extraAttacks)
- {
- AttackerStateUpdate(pVictim, BASE_ATTACK, true);
- if(m_extraAttacks > 0)
- --m_extraAttacks;
- }
- }
-
- return;
- }
-
- uint32 damage = CalculateDamage (attType, false);
-
- DoAttackDamage (pVictim, &damage, &cleanDamage, &blocked_dmg, meleeSchoolMask, &hitInfo, &victimState, &absorbed_dmg, &resisted_dmg, attType);
-
- if (hitInfo & HITINFO_MISS)
- //send miss
- SendAttackStateUpdate (hitInfo, pVictim, 1, meleeSchoolMask, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg);
- else
- {
- //do animation
- SendAttackStateUpdate (hitInfo, pVictim, 1, meleeSchoolMask, damage, absorbed_dmg, resisted_dmg, victimState, blocked_dmg);
-
- if (damage > (absorbed_dmg + resisted_dmg + blocked_dmg))
- damage -= (absorbed_dmg + resisted_dmg + blocked_dmg);
- else
- damage = 0;
-
- DealDamage (pVictim, damage, &cleanDamage, DIRECT_DAMAGE, meleeSchoolMask, NULL, true);
-
- if(GetTypeId() == TYPEID_PLAYER && pVictim->isAlive())
- {
- for(int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
- ((Player*)this)->CastItemCombatSpell(((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0,i),pVictim,attType);
- }
- }
+ CalcDamageInfo damageInfo;
+ CalculateMeleeDamage(pVictim, 0, &damageInfo, attType);
+ // Send log damage message to client
+ SendAttackStateUpdate(&damageInfo);
+ ProcDamageAndSpell(damageInfo.target, damageInfo.procAttacker, damageInfo.procVictim, damageInfo.procEx, damageInfo.damage, damageInfo.attackType);
+ DealMeleeDamage(&damageInfo,true);
if (GetTypeId() == TYPEID_PLAYER)
DEBUG_LOG("AttackerStateUpdate: (Player) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
- GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, absorbed_dmg, blocked_dmg, resisted_dmg);
+ GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist);
else
DEBUG_LOG("AttackerStateUpdate: (NPC) %u attacked %u (TypeId: %u) for %u dmg, absorbed %u, blocked %u, resisted %u.",
- GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damage, absorbed_dmg, blocked_dmg, resisted_dmg);
+ GetGUIDLow(), pVictim->GetGUIDLow(), pVictim->GetTypeId(), damageInfo.damage, damageInfo.absorb, damageInfo.blocked_amount, damageInfo.resist);
// extra attack only at any non extra attack (normal case)
if(!extra && extraAttacks)
@@ -2285,6 +2839,7 @@ void Unit::AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType, bool ex
}
}
+/*
MeleeHitOutcome Unit::RollPhysicalOutcomeAgainst (Unit const *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo)
{
// Miss chance based on melee
@@ -2343,7 +2898,7 @@ MeleeHitOutcome Unit::RollPhysicalOutcomeAgainst (Unit const *pVictim, WeaponAtt
DEBUG_LOG("PHYSICAL OUTCOME: miss %f crit %f dodge %f parry %f block %f",miss_chance,crit_chance,dodge_chance,parry_chance, block_chance);
return RollMeleeOutcomeAgainst(pVictim, attType, int32(crit_chance*100), int32(miss_chance*100),int32(dodge_chance*100),int32(parry_chance*100),int32(block_chance*100), true);
-}
+}*/
MeleeHitOutcome Unit::RollMeleeOutcomeAgainst(const Unit *pVictim, WeaponAttackType attType) const
{
@@ -2614,7 +3169,18 @@ void Unit::SendAttackStop(Unit* victim)
((Creature*)victim)->AI().EnterEvadeMode(this);*/
}
-/*
+bool Unit::isSpellBlocked(Unit *pVictim, SpellEntry const *spellProto, WeaponAttackType attackType)
+{
+ if (pVictim->HasInArc(M_PI,this))
+ {
+ float blockChance = GetUnitBlockChance();
+ blockChance += (GetWeaponSkillValue(attackType) - pVictim->GetMaxSkillValueForLevel() )*0.04;
+ if (roll_chance_f(blockChance))
+ return true;
+ }
+ return false;
+}
+
// Melee based spells can be miss, parry or dodge on this step
// Crit or block - determined on damage calculation phase! (and can be both in some time)
float Unit::MeleeSpellMissChance(Unit *pVictim, WeaponAttackType attType, int32 skillDiff, SpellEntry const *spell)
@@ -2738,7 +3304,7 @@ SpellMissInfo Unit::MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell)
return SPELL_MISS_PARRY;
return SPELL_MISS_NONE;
-}*/
+}
// TODO need use unit spell resistances in calculations
SpellMissInfo Unit::MagicSpellHitResult(Unit *pVictim, SpellEntry const *spell)
@@ -2808,6 +3374,14 @@ SpellMissInfo Unit::MagicSpellHitResult(Unit *pVictim, SpellEntry const *spell)
return SPELL_MISS_NONE;
}
+// Calculate spell hit result can be:
+// Every spell can: Evade/Immune/Reflect/Sucesful hit
+// For melee based spells:
+// Miss
+// Dodge
+// Parry
+// For spells
+// Resist
SpellMissInfo Unit::SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool CanReflect)
{
// Return evade for units in evade mode
@@ -2832,65 +3406,30 @@ SpellMissInfo Unit::SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool
if (pVictim->IsImmunedToDamage(GetSpellSchoolMask(spell),true))
return SPELL_MISS_IMMUNE;
+ if(this == pVictim)
+ return SPELL_MISS_NONE;
+
// Try victim reflect spell
if (CanReflect)
{
- // specialized first
+ int32 reflectchance = pVictim->GetTotalAuraModifier(SPELL_AURA_REFLECT_SPELLS);
Unit::AuraList const& mReflectSpellsSchool = pVictim->GetAurasByType(SPELL_AURA_REFLECT_SPELLS_SCHOOL);
for(Unit::AuraList::const_iterator i = mReflectSpellsSchool.begin(); i != mReflectSpellsSchool.end(); ++i)
- {
if((*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spell))
- {
- int32 reflectchance = (*i)->GetModifier()->m_amount;
- if (reflectchance > 0 && roll_chance_i(reflectchance))
- {
- if((*i)->m_procCharges > 0)
- {
- --(*i)->m_procCharges;
- if((*i)->m_procCharges==0)
- pVictim->RemoveAurasDueToSpell((*i)->GetId());
- }
- return SPELL_MISS_REFLECT;
- }
- }
- }
-
- // generic reflection
- Unit::AuraList const& mReflectSpells = pVictim->GetAurasByType(SPELL_AURA_REFLECT_SPELLS);
- for(Unit::AuraList::const_iterator i = mReflectSpells.begin(); i != mReflectSpells.end(); ++i)
+ reflectchance = (*i)->GetModifierValue();
+ if (reflectchance > 0 && roll_chance_i(reflectchance))
{
- int32 reflectchance = (*i)->GetModifier()->m_amount;
- if (reflectchance > 0 && roll_chance_i(reflectchance))
- {
- if((*i)->m_procCharges > 0)
- {
- --(*i)->m_procCharges;
- if((*i)->m_procCharges==0)
- pVictim->RemoveAurasDueToSpell((*i)->GetId());
- }
- return SPELL_MISS_REFLECT;
- }
+ // Start triggers for remove charges if need (trigger only for victim, and mark as active spell)
+ ProcDamageAndSpell(pVictim, PROC_FLAG_NONE, PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT, PROC_EX_REFLECT, 1, BASE_ATTACK, spell);
+ return SPELL_MISS_REFLECT;
}
}
- // Temporary solution for melee based spells and spells vs SPELL_SCHOOL_NORMAL (hit result calculated after)
- for (int i=0;i<3;i++)
- {
- if (spell->Effect[i] == SPELL_EFFECT_WEAPON_DAMAGE ||
- spell->Effect[i] == SPELL_EFFECT_WEAPON_PERCENT_DAMAGE ||
- spell->Effect[i] == SPELL_EFFECT_NORMALIZED_WEAPON_DMG ||
- spell->Effect[i] == SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL)
- return SPELL_MISS_NONE;
- }
-
- // TODO need use this code for spell hit result calculation
- // now code commented for computability
switch (spell->DmgClass)
{
case SPELL_DAMAGE_CLASS_RANGED:
case SPELL_DAMAGE_CLASS_MELEE:
-// return MeleeSpellHitResult(pVictim, spell);
- return SPELL_MISS_NONE;
+ return MeleeSpellHitResult(pVictim, spell);
case SPELL_DAMAGE_CLASS_NONE:
return SPELL_MISS_NONE;
case SPELL_DAMAGE_CLASS_MAGIC:
@@ -3486,7 +4025,7 @@ int32 Unit::GetTotalAuraModifier(AuraType auratype) const
AuraList const& mTotalAuraList = GetAurasByType(auratype);
for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
- modifier += (*i)->GetModifier()->m_amount;
+ modifier += (*i)->GetModifierValue();
return modifier;
}
@@ -3497,7 +4036,7 @@ float Unit::GetTotalAuraMultiplier(AuraType auratype) const
AuraList const& mTotalAuraList = GetAurasByType(auratype);
for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
- multiplier *= (100.0f + (*i)->GetModifier()->m_amount)/100.0f;
+ multiplier *= (100.0f + (*i)->GetModifierValue())/100.0f;
return multiplier;
}
@@ -3508,8 +4047,11 @@ int32 Unit::GetMaxPositiveAuraModifier(AuraType auratype) const
AuraList const& mTotalAuraList = GetAurasByType(auratype);
for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
- if ((*i)->GetModifier()->m_amount > modifier)
- modifier = (*i)->GetModifier()->m_amount;
+ {
+ int32 amount = (*i)->GetModifierValue();
+ if (amount > modifier)
+ modifier = amount;
+ }
return modifier;
}
@@ -3520,8 +4062,11 @@ int32 Unit::GetMaxNegativeAuraModifier(AuraType auratype) const
AuraList const& mTotalAuraList = GetAurasByType(auratype);
for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
- if ((*i)->GetModifier()->m_amount < modifier)
- modifier = (*i)->GetModifier()->m_amount;
+ {
+ int32 amount = (*i)->GetModifierValue();
+ if (amount < modifier)
+ modifier = amount;
+ }
return modifier;
}
@@ -3535,7 +4080,7 @@ int32 Unit::GetTotalAuraModifierByMiscMask(AuraType auratype, uint32 misc_mask)
{
Modifier* mod = (*i)->GetModifier();
if (mod->m_miscvalue & misc_mask)
- modifier += mod->m_amount;
+ modifier += (*i)->GetModifierValue();
}
return modifier;
}
@@ -3549,7 +4094,7 @@ float Unit::GetTotalAuraMultiplierByMiscMask(AuraType auratype, uint32 misc_mask
{
Modifier* mod = (*i)->GetModifier();
if (mod->m_miscvalue & misc_mask)
- multiplier *= (100.0f + mod->m_amount)/100.0f;
+ multiplier *= (100.0f + (*i)->GetModifierValue())/100.0f;
}
return multiplier;
}
@@ -3562,8 +4107,9 @@ int32 Unit::GetMaxPositiveAuraModifierByMiscMask(AuraType auratype, uint32 misc_
for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
{
Modifier* mod = (*i)->GetModifier();
- if (mod->m_miscvalue & misc_mask && mod->m_amount > modifier)
- modifier = mod->m_amount;
+ int32 amount = (*i)->GetModifierValue();
+ if (mod->m_miscvalue & misc_mask && amount > modifier)
+ modifier = amount;
}
return modifier;
@@ -3577,8 +4123,9 @@ int32 Unit::GetMaxNegativeAuraModifierByMiscMask(AuraType auratype, uint32 misc_
for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
{
Modifier* mod = (*i)->GetModifier();
- if (mod->m_miscvalue & misc_mask && mod->m_amount < modifier)
- modifier = mod->m_amount;
+ int32 amount = (*i)->GetModifierValue();
+ if (mod->m_miscvalue & misc_mask && amount < modifier)
+ modifier = amount;
}
return modifier;
@@ -3593,7 +4140,7 @@ int32 Unit::GetTotalAuraModifierByMiscValue(AuraType auratype, int32 misc_value)
{
Modifier* mod = (*i)->GetModifier();
if (mod->m_miscvalue == misc_value)
- modifier += mod->m_amount;
+ modifier += (*i)->GetModifierValue();
}
return modifier;
}
@@ -3607,7 +4154,7 @@ float Unit::GetTotalAuraMultiplierByMiscValue(AuraType auratype, int32 misc_valu
{
Modifier* mod = (*i)->GetModifier();
if (mod->m_miscvalue == misc_value)
- multiplier *= (100.0f + mod->m_amount)/100.0f;
+ multiplier *= (100.0f + (*i)->GetModifierValue())/100.0f;
}
return multiplier;
}
@@ -3620,8 +4167,9 @@ int32 Unit::GetMaxPositiveAuraModifierByMiscValue(AuraType auratype, int32 misc_
for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
{
Modifier* mod = (*i)->GetModifier();
- if (mod->m_miscvalue == misc_value && mod->m_amount > modifier)
- modifier = mod->m_amount;
+ int32 amount = (*i)->GetModifierValue();
+ if (mod->m_miscvalue == misc_value && amount > modifier)
+ modifier = amount;
}
return modifier;
@@ -3635,8 +4183,9 @@ int32 Unit::GetMaxNegativeAuraModifierByMiscValue(AuraType auratype, int32 misc_
for(AuraList::const_iterator i = mTotalAuraList.begin();i != mTotalAuraList.end(); ++i)
{
Modifier* mod = (*i)->GetModifier();
- if (mod->m_miscvalue == misc_value && mod->m_amount < modifier)
- modifier = mod->m_amount;
+ int32 amount = (*i)->GetModifierValue();
+ if (mod->m_miscvalue == misc_value && amount < modifier)
+ modifier = amount;
}
return modifier;
@@ -3675,8 +4224,10 @@ bool Unit::AddAura(Aura *Aur)
// replace aura if next will > spell StackAmount
if(aurSpellInfo->StackAmount)
{
- if(m_Auras.count(spair) >= aurSpellInfo->StackAmount)
- RemoveAura(i,AURA_REMOVE_BY_STACK);
+ Aur->SetStackAmount(i->second->GetStackAmount());
+ if(Aur->GetStackAmount() < aurSpellInfo->StackAmount)
+ Aur->SetStackAmount(Aur->GetStackAmount()+1);
+ RemoveAura(i,AURA_REMOVE_BY_STACK);
}
// if StackAmount==0 not allow auras from same caster
else
@@ -3895,32 +4446,18 @@ bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur)
if(!is_triggered_by_spell)
{
- SpellSpecific i_spellId_spec = GetSpellSpecific(i_spellId);
-
- bool is_sspc = IsSingleFromSpellSpecificPerCaster(spellId_spec,i_spellId_spec);
-
- if( is_sspc && Aur->GetCasterGUID() == (*i).second->GetCasterGUID() )
+ bool sameCaster = Aur->GetCasterGUID() == (*i).second->GetCasterGUID();
+ if( spellmgr.IsNoStackSpellDueToSpell(spellId, i_spellId, sameCaster) )
{
- // cannot remove higher rank
- if (spellmgr.IsRankSpellDueToSpell(spellProto, i_spellId))
- if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
- return false;
-
- // Its a parent aura (create this aura in ApplyModifier)
- if ((*i).second->IsInUse())
- {
- sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i->second->GetId(), i->second->GetEffIndex(),Aur->GetId(), Aur->GetEffIndex());
- continue;
- }
- RemoveAurasDueToSpell(i_spellId);
+ //some spells should be not removed by lower rank of them
+ // what is this spell?
+ if (!sameCaster
+ &&(spellProto->Effect[effIndex]==SPELL_EFFECT_APPLY_AREA_AURA_PARTY)
+ &&(spellProto->DurationIndex==21)
+ &&(spellmgr.IsRankSpellDueToSpell(spellProto, i_spellId))
+ &&(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0))
+ return false;
- if( m_Auras.empty() )
- break;
- else
- next = m_Auras.begin();
- }
- else if( !is_sspc && spellmgr.IsNoStackSpellDueToSpell(spellId, i_spellId) )
- {
// Its a parent aura (create this aura in ApplyModifier)
if ((*i).second->IsInUse())
{
@@ -3934,24 +4471,6 @@ bool Unit::RemoveNoStackAurasDueToAura(Aura *Aur)
else
next = m_Auras.begin();
}
- // Potions stack aura by aura (elixirs/flask already checked)
- else if( spellProto->SpellFamilyName == SPELLFAMILY_POTION && i_spellProto->SpellFamilyName == SPELLFAMILY_POTION )
- {
- if (IsNoStackAuraDueToAura(spellId, effIndex, i_spellId, i_effIndex))
- {
- if(CompareAuraRanks(spellId, effIndex, i_spellId, i_effIndex) < 0)
- return false; // cannot remove higher rank
-
- // Its a parent aura (create this aura in ApplyModifier)
- if ((*i).second->IsInUse())
- {
- sLog.outError("Aura (Spell %u Effect %u) is in process but attempt removed at aura (Spell %u Effect %u) adding, need add stack rule for Unit::RemoveNoStackAurasDueToAura", i->second->GetId(), i->second->GetEffIndex(),Aur->GetId(), Aur->GetEffIndex());
- continue;
- }
- RemoveAura(i);
- next = i;
- }
- }
}
}
return true;
@@ -4064,11 +4583,48 @@ void Unit::RemoveAurasWithDispelType( DispelType type )
}
}
+void Unit::RemoveSingleAuraFromStackByDispel(uint32 spellId)
+{
+ for (AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end(); )
+ {
+ Aura *aur = iter->second;
+ if (aur->GetId() == spellId)
+ {
+ if(iter->second->GetStackAmount() > 1)
+ {
+ // reapply modifier with reduced stack amount
+ iter->second->ApplyModifier(false,true);
+ iter->second->SetStackAmount(iter->second->GetStackAmount()-1);
+ iter->second->ApplyModifier(true,true);
+
+ iter->second->UpdateSlotCounterAndDuration();
+ return; // not remove aura if stack amount > 1
+ }
+ else
+ RemoveAura(iter,AURA_REMOVE_BY_DISPEL);
+ }
+ else
+ ++iter;
+ }
+}
+
void Unit::RemoveSingleAuraFromStack(uint32 spellId, uint32 effindex)
{
AuraMap::iterator iter = m_Auras.find(spellEffectPair(spellId, effindex));
if(iter != m_Auras.end())
+ {
+ if(iter->second->GetStackAmount() > 1)
+ {
+ // reapply modifier with reduced stack amount
+ iter->second->ApplyModifier(false,true);
+ iter->second->SetStackAmount(iter->second->GetStackAmount()-1);
+ iter->second->ApplyModifier(true,true);
+
+ iter->second->UpdateSlotCounterAndDuration();
+ return; // not remove aura if stack amount > 1
+ }
RemoveAura(iter);
+ }
}
void Unit::RemoveAurasDueToSpell(uint32 spellId, Aura* except)
@@ -4193,7 +4749,11 @@ void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode)
}
sLog.outDebug("Aura %u now is remove mode %d",Aur->GetModifier()->m_auraname, mode);
+ assert(!Aur->IsInUse());
Aur->ApplyModifier(false,true);
+
+ Aur->SetStackAmount(0);
+
Aur->_RemoveAura();
delete Aur;
@@ -4423,6 +4983,24 @@ void Unit::RemoveAllGameObjects()
}
}
+void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage *log)
+{
+ WorldPacket data(SMSG_SPELLNONMELEEDAMAGELOG, (16+4+4+1+4+4+1+1+4+4+1)); // we guess size
+ data.append(log->target->GetPackGUID());
+ data.append(log->attacker->GetPackGUID());
+ data << uint32(log->SpellID);
+ data << uint32(log->damage); //damage amount
+ data << uint8 (log->schoolMask); //damage school
+ data << uint32(log->absorb); //AbsorbedDamage
+ data << uint32(log->resist); //resist
+ data << uint8 (log->phusicalLog); // damsge type? flag
+ data << uint8 (log->unused); //unused
+ data << uint32(log->blocked); //blocked
+ data << uint32(log->HitInfo);
+ data << uint8 (0); // flag to use extend data
+ SendMessageToSet( &data, true );
+}
+
void Unit::SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, SpellSchoolMask damageSchoolMask,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit)
{
sLog.outDebug("Sending: SMSG_SPELLNONMELEEDAMAGELOG");
@@ -4442,6 +5020,17 @@ void Unit::SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage,
SendMessageToSet( &data, true );
}
+void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 procExtra, uint32 amount, WeaponAttackType attType, SpellEntry const *procSpell)
+{
+ // Not much to do if no flags are set.
+ if (procAttacker)
+ ProcDamageAndSpellFor(false,pVictim,procAttacker, procExtra,attType, procSpell, amount);
+ // Now go on with a victim's events'n'auras
+ // Not much to do if no flags are set or there is no victim
+ if(pVictim && pVictim->isAlive() && procVictim)
+ pVictim->ProcDamageAndSpellFor(true,this,procVictim, procExtra, attType, procSpell, amount);
+}
+
void Unit::SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
{
WorldPacket data(SMSG_SPELLLOGMISS, (4+8+1+4+8+1));
@@ -4456,6 +5045,29 @@ void Unit::SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
SendMessageToSet(&data, true);
}
+void Unit::SendAttackStateUpdate(CalcDamageInfo *damageInfo)
+{
+ WorldPacket data(SMSG_ATTACKERSTATEUPDATE, (16+84)); // we guess size
+ data << (uint32)damageInfo->HitInfo;
+ data.append(GetPackGUID());
+ data.append(damageInfo->target->GetPackGUID());
+ data << (uint32)(damageInfo->damage); // Full damage
+
+ data << (uint8)1; // Sub damage count
+ //=== Sub damage description
+ data << (uint32)(damageInfo->damageSchoolMask); // School of sub damage
+ data << (float)damageInfo->damage; // sub damage
+ data << (uint32)damageInfo->damage; // Sub Damage
+ data << (uint32)damageInfo->absorb; // Absorb
+ data << (uint32)damageInfo->resist; // Resist
+ //=================================================
+ data << (uint32)damageInfo->TargetState;
+ data << (uint32)0;
+ data << (uint32)0;
+ data << (uint32)damageInfo->blocked_amount;
+ SendMessageToSet( &data, true );/**/
+}
+
void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount)
{
sLog.outDebug("WORLD: Sending SMSG_ATTACKERSTATEUPDATE");
@@ -4489,7 +5101,7 @@ void Unit::SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType,
SendMessageToSet( &data, true );
}
-
+/*
void Unit::ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 damage, SpellSchoolMask damageSchoolMask, SpellEntry const *procSpell, bool isTriggeredSpell, WeaponAttackType attType)
{
sLog.outDebug("ProcDamageAndSpell: attacker flags are 0x%x, victim flags 0x%x", procAttacker, procVictim);
@@ -4623,9 +5235,9 @@ void Unit::CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, SpellSchool
if(procAttacker != PROC_FLAG_NONE || procVictim != PROC_FLAG_NONE)
ProcDamageAndSpell(pVictim, procAttacker, procVictim, damage, damageSchoolMask, spellCasted, isTriggeredSpell, attType);
-}
+}*/
-bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * /*procSpell*/, uint32 /*procFlag*/, uint32 cooldown)
+bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 /*procFlag*/, uint32 /*procEx*/, uint32 cooldown)
{
SpellEntry const *hasteSpell = triggeredByAura->GetSpellProto();
@@ -4688,7 +5300,7 @@ bool Unit::HandleHasteAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
return true;
}
-bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 cooldown)
+bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const * procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown)
{
SpellEntry const *dummySpell = triggeredByAura->GetSpellProto ();
uint32 effIndex = triggeredByAura->GetEffIndex ();
@@ -4801,19 +5413,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
if(!procSpell)
return false;
- // not from DoT
- bool found = false;
- for(int j = 0; j < 3; ++j)
- {
- if(procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE||procSpell->EffectApplyAuraName[j]==SPELL_AURA_PERIODIC_DAMAGE_PERCENT)
- {
- found = true;
- break;
- }
- }
- if(found)
- return false;
-
switch(GetFirstSchoolInMask(GetSpellSchoolMask(procSpell)))
{
case SPELL_SCHOOL_NORMAL:
@@ -5079,6 +5678,16 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
triggered_spell_id = 29077;
break;
}
+ // Incanter's Regalia set (add trigger chance to Mana Shield)
+ if (dummySpell->SpellFamilyFlags & 0x0000000000008000LL)
+ {
+ if(GetTypeId() != TYPEID_PLAYER)
+ return false;
+
+ target = this;
+ triggered_spell_id = 37436;
+ break;
+ }
switch(dummySpell->Id)
{
// Ignite
@@ -5107,14 +5716,14 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
case 11129:
{
//last charge and crit
- if( triggeredByAura->m_procCharges <= 1 && (procFlag & PROC_FLAG_CRIT_SPELL) )
+ if (triggeredByAura->m_procCharges <= 1 && (procEx & PROC_EX_CRITICAL_HIT) )
{
RemoveAurasDueToSpell(28682); //-> remove Combustion auras
return true; // charge counting (will removed)
}
CastSpell(this, 28682, true, castItem, triggeredByAura);
- return(procFlag & PROC_FLAG_CRIT_SPELL);// charge update only at crit hits, no hidden cooldowns
+ return (procEx & PROC_EX_CRITICAL_HIT);// charge update only at crit hits, no hidden cooldowns
}
}
break;
@@ -5131,6 +5740,34 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
triggered_spell_id = 22858;
break;
}
+ else if (dummySpell->SpellIconID == 1697) // Second Wind
+ {
+ // only for spells and hit/crit (trigger start always) and not start from self casted spells (5530 Mace Stun Effect for example)
+ if (procSpell == 0 || !(procEx & (PROC_EX_NORMAL_HIT|PROC_EX_CRITICAL_HIT)) || this == pVictim)
+ return false;
+ // Need stun or root mechanic
+ if (procSpell->Mechanic != MECHANIC_ROOT && procSpell->Mechanic != MECHANIC_STUN)
+ {
+ int32 i;
+ for (i=0; i<3; i++)
+ if (procSpell->EffectMechanic[i] == MECHANIC_ROOT || procSpell->EffectMechanic[i] == MECHANIC_STUN)
+ break;
+ if (i == 3)
+ return false;
+ }
+
+ switch (dummySpell->Id)
+ {
+ case 29838: triggered_spell_id=29842; break;
+ case 29834: triggered_spell_id=29841; break;
+ default:
+ sLog.outError("Unit::HandleDummyAuraProc: non handled spell id: %u (SW)",dummySpell->Id);
+ return false;
+ }
+
+ target = this;
+ break;
+ }
break;
}
case SPELLFAMILY_WARLOCK:
@@ -5140,7 +5777,6 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
{
Modifier* mod = triggeredByAura->GetModifier();
// if damage is more than need or target die from damage deal finish spell
- // FIX ME: not triggered currently at death
if( mod->m_amount <= damage || GetHealth() <= damage )
{
// remember guid before aura delete
@@ -5484,16 +6120,14 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
switch(triggeredByAura->GetEffIndex())
{
case 0:
- // prevent chain triggering
- if(procSpell && procSpell->Id==31893 )
- return false;
-
triggered_spell_id = 31893;
break;
case 1:
{
// damage
- basepoints0 = triggeredByAura->GetModifier()->m_amount * damage / 100;
+ damage += CalculateDamage(BASE_ATTACK, false) * 35 / 100; // add spell damage from prev effect (35%)
+ basepoints0 = triggeredByAura->GetModifier()->m_amount * damage / 100;
+
target = this;
triggered_spell_id = 32221;
break;
@@ -5841,7 +6475,7 @@ bool Unit::HandleDummyAuraProc(Unit *pVictim, uint32 damage, Aura* triggeredByAu
return true;
}
-
+/*
bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 procFlags,WeaponAttackType attackType, uint32 cooldown)
{
SpellEntry const* auraSpellInfo = triggeredByAura->GetSpellProto();
@@ -6178,14 +6812,12 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB
((Player*)this)->AddSpellCooldown(37657,0,time(NULL)+(roll_chance_i(50) ? 2 : 3));
// counting
- uint32 count = 0;
- AuraList const& dummyAura = GetAurasByType(SPELL_AURA_DUMMY);
- for(AuraList::const_iterator itr = dummyAura.begin(); itr != dummyAura.end(); ++itr)
- if((*itr)->GetId()==37658)
- ++count;
+ Aura * dummy = GetDummyAura(37658);
+ if (!dummy)
+ return false;
// release at 3 aura in stack
- if(count <= 2)
+ if(dummy->GetStackAmount() <= 2)
return true; // main triggered spell casted anyway
RemoveAurasDueToSpell(37658);
@@ -6507,6 +7139,650 @@ bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredB
return true;
}
+*/
+
+bool Unit::HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 procFlags, uint32 procEx, uint32 cooldown)
+{
+ // Get triggered aura spell info
+ SpellEntry const* auraSpellInfo = triggeredByAura->GetSpellProto();
+
+ // Basepoints of trigger aura
+ int32 triggerAmount = triggeredByAura->GetModifier()->m_amount;
+
+ // Set trigger spell id, target, custom basepoints
+ uint32 trigger_spell_id = auraSpellInfo->EffectTriggerSpell[triggeredByAura->GetEffIndex()];
+ Unit* target = NULL;
+ int32 basepoints0 = 0;
+
+ Item* castItem = triggeredByAura->GetCastItemGUID() && GetTypeId()==TYPEID_PLAYER
+ ? ((Player*)this)->GetItemByGuid(triggeredByAura->GetCastItemGUID()) : NULL;
+
+ // Try handle uncnown trigger spells
+ if (sSpellStore.LookupEntry(trigger_spell_id)==NULL)
+ switch (auraSpellInfo->SpellFamilyName)
+ {
+ //=====================================================================
+ // Generic class
+ // ====================================================================
+ // .....
+ //=====================================================================
+ case SPELLFAMILY_GENERIC:
+// if (auraSpellInfo->Id==34082) // Advantaged State (DND)
+// trigger_spell_id = ???;
+ if (auraSpellInfo->Id == 23780) // Aegis of Preservation (Aegis of Preservation trinket)
+ trigger_spell_id = 23781;
+// else if (auraSpellInfo->Id==43504) // Alterac Valley OnKill Proc Aura
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==37030) // Chaotic Temperament
+// trigger_spell_id = ;
+ else if (auraSpellInfo->Id==43820) // Charm of the Witch Doctor (Amani Charm of the Witch Doctor trinket)
+ {
+ // Pct value stored in dummy
+ basepoints0 = pVictim->GetCreateHealth() * auraSpellInfo->EffectBasePoints[1] / 100;
+ target = pVictim;
+ break;
+ }
+// else if (auraSpellInfo->Id==41248) // Consuming Strikes
+// trigger_spell_id = 41249;
+// else if (auraSpellInfo->Id==41054) // Copy Weapon
+// trigger_spell_id = 41055;
+// else if (auraSpellInfo->Id==31255) // Deadly Swiftness (Rank 1)
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==5301) // Defensive State (DND)
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==13358) // Defensive State (DND)
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==16092) // Defensive State (DND)
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==24949) // Defensive State 2 (DND)
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==40329) // Demo Shout Sensor
+// trigger_spell_id = ;
+ // Desperate Defense (Stonescythe Whelp, Stonescythe Alpha, Stonescythe Ambusher)
+ else if (auraSpellInfo->Id == 33896)
+ trigger_spell_id = 33898;
+// else if (auraSpellInfo->Id==18943) // Double Attack
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==19194) // Double Attack
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==19817) // Double Attack
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==19818) // Double Attack
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==22835) // Drunken Rage
+// trigger_spell_id = 14822;
+ /*
+ else if (auraSpellInfo->SpellIconID==191) // Elemental Response
+ {
+ switch (auraSpellInfo->Id && auraSpellInfo->AttributesEx==0)
+ {
+ case 34191:
+ case 34329:
+ case 34524:
+ case 34582:
+ case 36733:break;
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Elemental Response",auraSpellInfo->Id);
+ return false;
+ }
+ //This generic aura self-triggers a different spell for each school of magic that lands on the wearer:
+ switch (procSpell->School)
+ {
+ case SPELL_SCHOOL_FIRE: trigger_spell_id = 34192;break;//Fire: 34192
+ case SPELL_SCHOOL_FROST: trigger_spell_id = 34193;break;//Frost: 34193
+ case SPELL_SCHOOL_ARCANE: trigger_spell_id = 34194;break;//Arcane: 34194
+ case SPELL_SCHOOL_NATURE: trigger_spell_id = 34195;break;//Nature: 34195
+ case SPELL_SCHOOL_SHADOW: trigger_spell_id = 34196;break;//Shadow: 34196
+ case SPELL_SCHOOL_HOLY: trigger_spell_id = 34197;break;//Holy: 34197
+ case SPELL_SCHOOL_NORMAL: trigger_spell_id = 34198;break;//Physical: 34198
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u Elemental Response wrong school",auraSpellInfo->Id);
+ return false;
+ }
+ }*/
+// else if (auraSpellInfo->Id==6542) // Enraged Defense
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==40364) // Entangling Roots Sensor
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==33207) // Gossip NPC Periodic - Fidget
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==35321) // Gushing Wound
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==38363) // Gushing Wound
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==39215) // Gushing Wound
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==40250) // Improved Duration
+// trigger_spell_id = ;
+ else if (auraSpellInfo->Id==27522) // Mana Drain Trigger
+ {
+ // On successful melee or ranged attack gain $29471s1 mana and if possible drain $27526s1 mana from the target.
+ if (this && this->isAlive())
+ CastSpell(this, 29471, true, castItem, triggeredByAura);
+ if (pVictim && pVictim->isAlive())
+ CastSpell(pVictim, 27526, true, castItem, triggeredByAura);
+ return true;
+ }
+ else if (auraSpellInfo->Id==24905) // Moonkin Form (Passive)
+ {
+ // Elune's Touch (instead non-existed triggered spell) 30% from AP
+ trigger_spell_id = 33926;
+ basepoints0 = GetTotalAttackPowerValue(BASE_ATTACK) * 30 / 100;
+ target = this;
+ }
+// else if (auraSpellInfo->Id==43453) // Rune Ward
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==7137) // Shadow Charge (Rank 1)
+// trigger_spell_id = ;
+ // Shaleskin (Shaleskin Flayer, Shaleskin Ripper) 30023 trigger
+// else if (auraSpellInfo->Id==36576)
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==34783) // Spell Reflection
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==36096) // Spell Reflection
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==36207) // Steal Weapon
+// trigger_spell_id = ;
+// else if (auraSpellInfo->Id==35205) // Vanish
+ break;
+ //=====================================================================
+ // Mage
+ //=====================================================================
+ // Blazing Speed (Rank 1,2) trigger = 18350
+ //=====================================================================
+ case SPELLFAMILY_MAGE:
+ // Blazing Speed
+ if (auraSpellInfo->SpellIconID == 2127)
+ {
+ switch (auraSpellInfo->Id)
+ {
+ case 31641: // Rank 1
+ case 31642: // Rank 2
+ trigger_spell_id = 31643;
+ break;
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Blazing Speed",auraSpellInfo->Id);
+ return false;
+ }
+ }
+ break;
+ //=====================================================================
+ // Warrior
+ //=====================================================================
+ // Rampage (Rank 1-3) trigger = 18350
+ //=====================================================================
+ case SPELLFAMILY_WARRIOR:
+ // Rampage
+ if (auraSpellInfo->SpellIconID == 2006 && auraSpellInfo->SpellFamilyFlags==0x100000)
+ {
+ switch(auraSpellInfo->Id)
+ {
+ case 29801: trigger_spell_id = 30029; break; // Rank 1
+ case 30030: trigger_spell_id = 30031; break; // Rank 2
+ case 30033: trigger_spell_id = 30032; break; // Rank 3
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in Rampage",auraSpellInfo->Id);
+ return false;
+ }
+ }
+ break;
+ //=====================================================================
+ // Warlock
+ //=====================================================================
+ // Pyroclasm trigger = 18350
+ // Drain Soul (Rank 1-5) trigger = 0
+ //=====================================================================
+ case SPELLFAMILY_WARLOCK:
+ {
+ // Pyroclasm
+ if (auraSpellInfo->SpellIconID == 1137)
+ {
+ if(!pVictim || !pVictim->isAlive() || pVictim == this || procSpell == NULL)
+ return false;
+ // Calculate spell tick count for spells
+ uint32 tick = 1; // Default tick = 1
+
+ // Hellfire have 15 tick
+ if (procSpell->SpellFamilyFlags&0x0000000000000040LL)
+ tick = 15;
+ // Rain of Fire have 4 tick
+ else if (procSpell->SpellFamilyFlags&0x0000000000000020LL)
+ tick = 4;
+ else
+ return false;
+
+ // Calculate chance = baseChance / tick
+ float chance = 0;
+ switch (auraSpellInfo->Id)
+ {
+ case 18096: chance = 13.0f / tick; break;
+ case 18073: chance = 26.0f / tick; break;
+ }
+ // Roll chance
+ if (!roll_chance_f(chance))
+ return false;
+
+ trigger_spell_id = 18093;
+ }
+ // Drain Soul
+ else if (auraSpellInfo->SpellFamilyFlags & 0x0000000000004000LL)
+ {
+ Unit::AuraList const& mAddFlatModifier = GetAurasByType(SPELL_AURA_ADD_FLAT_MODIFIER);
+ for(Unit::AuraList::const_iterator i = mAddFlatModifier.begin(); i != mAddFlatModifier.end(); ++i)
+ {
+ if ((*i)->GetModifier()->m_miscvalue == SPELLMOD_CHANCE_OF_SUCCESS && (*i)->GetSpellProto()->SpellIconID == 113)
+ {
+ int32 value2 = CalculateSpellDamage((*i)->GetSpellProto(),2,(*i)->GetSpellProto()->EffectBasePoints[2],this);
+ basepoints0 = value2 * GetMaxPower(POWER_MANA) / 100;
+ }
+ }
+ if ( basepoints0 == 0 )
+ return false;
+ trigger_spell_id = 18371;
+ }
+ break;
+ }
+ //=====================================================================
+ // Priest
+ //=====================================================================
+ // Greater Heal Refund trigger = 18350
+ // Blessed Recovery (Rank 1-3) trigger = 18350
+ // Shadowguard (1-7) trigger = 28376
+ //=====================================================================
+ case SPELLFAMILY_PRIEST:
+ {
+ // Greater Heal Refund
+ if (auraSpellInfo->Id==37594)
+ trigger_spell_id = 37595;
+ // Shadowguard
+ else if(auraSpellInfo->SpellFamilyFlags==0x100080000000LL && auraSpellInfo->SpellVisual==7958)
+ {
+ switch(auraSpellInfo->Id)
+ {
+ case 18137: trigger_spell_id = 28377; break; // Rank 1
+ case 19308: trigger_spell_id = 28378; break; // Rank 2
+ case 19309: trigger_spell_id = 28379; break; // Rank 3
+ case 19310: trigger_spell_id = 28380; break; // Rank 4
+ case 19311: trigger_spell_id = 28381; break; // Rank 5
+ case 19312: trigger_spell_id = 28382; break; // Rank 6
+ case 25477: trigger_spell_id = 28385; break; // Rank 7
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in SG", auraSpellInfo->Id);
+ return false;
+ }
+ }
+ // Blessed Recovery
+ else if (auraSpellInfo->SpellIconID == 1875)
+ {
+ switch (auraSpellInfo->Id)
+ {
+ case 27811: trigger_spell_id = 27813; break;
+ case 27815: trigger_spell_id = 27817; break;
+ case 27816: trigger_spell_id = 27818; break;
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in BR", auraSpellInfo->Id);
+ return false;
+ }
+ basepoints0 = damage * triggerAmount / 100 / 3;
+ target = this;
+ }
+ break;
+ }
+ //=====================================================================
+ // Druid
+ // ====================================================================
+ // Druid Forms Trinket trigger = 18350
+ // Entangling Roots trigger = 30023
+ // Leader of the Pack trigger = 18350
+ //=====================================================================
+ case SPELLFAMILY_DRUID:
+ {
+ // Druid Forms Trinket
+ if (auraSpellInfo->Id==37336)
+ {
+ switch(m_form)
+ {
+ case 0: trigger_spell_id = 37344;break;
+ case FORM_CAT: trigger_spell_id = 37341;break;
+ case FORM_BEAR:
+ case FORM_DIREBEAR: trigger_spell_id = 37340;break;
+ case FORM_TREE: trigger_spell_id = 37342;break;
+ case FORM_MOONKIN: trigger_spell_id = 37343;break;
+ default:
+ return false;
+ }
+ }
+// else if (auraSpellInfo->Id==40363)// Entangling Roots ()
+// trigger_spell_id = ????;
+ // Leader of the Pack
+ else if (auraSpellInfo->Id == 24932)
+ {
+ if (triggerAmount == 0)
+ return false;
+ basepoints0 = triggerAmount * GetMaxHealth() / 100;
+ trigger_spell_id = 34299;
+ }
+ break;
+ }
+ //=====================================================================
+ // Hunter
+ // ====================================================================
+ // ......
+ //=====================================================================
+ case SPELLFAMILY_HUNTER:
+ break;
+ //=====================================================================
+ // Paladin
+ // ====================================================================
+ // Blessed Life trigger = 31934
+ // Healing Discount trigger = 18350
+ // Illumination (Rank 1-5) trigger = 18350
+ // Judgement of Light (Rank 1-5) trigger = 5373
+ // Judgement of Wisdom (Rank 1-4) trigger = 1826
+ // Lightning Capacitor trigger = 18350
+ //=====================================================================
+ case SPELLFAMILY_PALADIN:
+ {
+ /* // Blessed Life
+ if (auraSpellInfo->SpellIconID == 2137)
+ {
+ switch (auraSpellInfo->Id)
+ {
+ case 31828: // Rank 1
+ case 31829: // Rank 2
+ case 31830: // Rank 3
+ break;
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Blessed Life", auraSpellInfo->Id);
+ return false;
+ }
+ }*/
+ // Healing Discount
+ if (auraSpellInfo->Id==37705)
+ {
+ trigger_spell_id = 37706;
+ target = this;
+ }
+ // Judgement of Light and Judgement of Wisdom
+ else if (auraSpellInfo->SpellFamilyFlags & 0x0000000000080000LL)
+ {
+ switch (auraSpellInfo->Id)
+ {
+ // Judgement of Light
+ case 20185: trigger_spell_id = 20267;break; // Rank 1
+ case 20344: trigger_spell_id = 20341;break; // Rank 2
+ case 20345: trigger_spell_id = 20342;break; // Rank 3
+ case 20346: trigger_spell_id = 20343;break; // Rank 4
+ case 27162: trigger_spell_id = 27163;break; // Rank 5
+ // Judgement of Wisdom
+ case 20186: trigger_spell_id = 20268;break; // Rank 1
+ case 20354: trigger_spell_id = 20352;break; // Rank 2
+ case 20355: trigger_spell_id = 20353;break; // Rank 3
+ case 27164: trigger_spell_id = 27165;break; // Rank 4
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u miss posibly Judgement of Light/Wisdom", auraSpellInfo->Id);
+ return false;
+ }
+ pVictim->CastSpell(pVictim, trigger_spell_id, true, castItem, triggeredByAura);
+ return true; // no hidden cooldown
+ }
+ // Illumination
+ else if (auraSpellInfo->SpellIconID==241)
+ {
+ if(!procSpell)
+ return false;
+ // procspell is triggered spell but we need mana cost of original casted spell
+ uint32 originalSpellId = procSpell->Id;
+ // Holy Shock
+ if(procSpell->SpellFamilyFlags & 0x00200000)
+ {
+ switch(procSpell->Id)
+ {
+ case 25914: originalSpellId = 20473; break;
+ case 25913: originalSpellId = 20929; break;
+ case 25903: originalSpellId = 20930; break;
+ case 27175: originalSpellId = 27174; break;
+ case 33074: originalSpellId = 33072; break;
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in HShock",procSpell->Id);
+ return false;
+ }
+ }
+ SpellEntry const *originalSpell = sSpellStore.LookupEntry(originalSpellId);
+ if(!originalSpell)
+ {
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u unknown but selected as original in Illu",originalSpellId);
+ return false;
+ }
+ // percent stored in effect 1 (class scripts) base points
+ basepoints0 = originalSpell->manaCost*(auraSpellInfo->EffectBasePoints[1]+1)/100;
+ trigger_spell_id = 20272;
+ target = this;
+ }
+ // Lightning Capacitor
+ else if (auraSpellInfo->Id==37657)
+ {
+ if(!pVictim || !pVictim->isAlive())
+ return false;
+ // stacking
+ CastSpell(this, 37658, true, NULL, triggeredByAura);
+ // counting
+ Aura * dummy = GetDummyAura(37658);
+ if (!dummy)
+ return false;
+ // release at 3 aura in stack (cont contain in basepoint of trigger aura)
+ if(dummy->GetStackAmount() <= 2)
+ return false;
+
+ RemoveAurasDueToSpell(37658);
+ trigger_spell_id = 37661;
+ target = pVictim;
+ }
+ break;
+ }
+ //=====================================================================
+ // Shaman
+ //====================================================================
+ // Lightning Shield trigger = 18350
+ // Mana Surge trigger = 18350
+ // Nature's Guardian (Rank 1-5) trigger = 18350
+ //=====================================================================
+ case SPELLFAMILY_SHAMAN:
+ {
+ //Lightning Shield (overwrite non existing triggered spell call in spell.dbc
+ if(auraSpellInfo->SpellFamilyFlags==0x00000400 && auraSpellInfo->SpellVisual==37)
+ {
+ switch(auraSpellInfo->Id)
+ {
+ case 324: trigger_spell_id = 26364; break; // Rank 1
+ case 325: trigger_spell_id = 26365; break; // Rank 2
+ case 905: trigger_spell_id = 26366; break; // Rank 3
+ case 945: trigger_spell_id = 26367; break; // Rank 4
+ case 8134: trigger_spell_id = 26369; break; // Rank 5
+ case 10431: trigger_spell_id = 26370; break; // Rank 6
+ case 10432: trigger_spell_id = 26363; break; // Rank 7
+ case 25469: trigger_spell_id = 26371; break; // Rank 8
+ case 25472: trigger_spell_id = 26372; break; // Rank 9
+ default:
+ sLog.outError("Unit::HandleProcTriggerSpell: Spell %u not handled in LShield", auraSpellInfo->Id);
+ return false;
+ }
+ }
+ // Lightning Shield (The Ten Storms set)
+ else if (auraSpellInfo->Id == 23551)
+ {
+ trigger_spell_id = 23552;
+ target = pVictim;
+ }
+ // Damage from Lightning Shield (The Ten Storms set)
+ else if (auraSpellInfo->Id == 23552)
+ trigger_spell_id = 27635;
+ // Mana Surge (The Earthfury set)
+ else if (auraSpellInfo->Id == 23572)
+ {
+ if(!procSpell)
+ return false;
+ basepoints0 = procSpell->manaCost * 35 / 100;
+ trigger_spell_id = 23571;
+ target = this;
+ }
+ else if (auraSpellInfo->SpellIconID == 2013) //Nature's Guardian
+ {
+ // Check health condition - should drop to less 30% (damage deal after this!)
+ if (!(10*(int32(GetHealth() - damage)) < 3 * GetMaxHealth()))
+ return false;
+
+ if(pVictim && pVictim->isAlive())
+ pVictim->getThreatManager().modifyThreatPercent(this,-10);
+
+ basepoints0 = triggerAmount * GetMaxHealth() / 100;
+ trigger_spell_id = 31616;
+ target = this;
+ }
+ break;
+ }
+ // default
+ default:
+ break;
+ }
+
+ // All ok. Check current trigger spell
+ SpellEntry const* triggerEntry = sSpellStore.LookupEntry(trigger_spell_id);
+ if ( triggerEntry == NULL )
+ {
+ // Not cast unknown spell
+ // sLog.outError("Unit::HandleProcTriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",auraSpellInfo->Id,triggeredByAura->GetEffIndex());
+ return false;
+ }
+
+ // not allow proc extra attack spell at extra attack
+ if( m_extraAttacks && IsSpellHaveEffect(triggerEntry, SPELL_EFFECT_ADD_EXTRA_ATTACKS) )
+ return false;
+
+ // Costum requirements (not listed in procEx) Warning! damage dealing after this
+ // Custom triggered spells
+ switch (auraSpellInfo->Id)
+ {
+ // Persistent Shield (Scarab Brooch trinket)
+ // This spell originally trigger 13567 - Dummy Trigger (vs dummy efect)
+ case 26467:
+ {
+ basepoints0 = damage * 15 / 100;
+ target = pVictim;
+ trigger_spell_id = 26470;
+ break;
+ }
+ // Cheat Death
+ case 28845:
+ {
+ // When your health drops below 20% ....
+ if (GetHealth() - damage > GetMaxHealth() / 5 || GetHealth() < GetMaxHealth() / 5)
+ return false;
+ break;
+ }
+ // Deadly Swiftness (Rank 1)
+ case 31255:
+ {
+ // whenever you deal damage to a target who is below 20% health.
+ if (pVictim->GetHealth() > pVictim->GetMaxHealth() / 5)
+ return false;
+
+ target = this;
+ trigger_spell_id = 22588;
+ }
+ // Greater Heal Refund (Avatar Raiment set)
+ case 37594:
+ {
+ // Not give if target alredy have full health
+ if (pVictim->GetHealth() == pVictim->GetMaxHealth())
+ return false;
+ // If your Greater Heal brings the target to full health, you gain $37595s1 mana.
+ if (pVictim->GetHealth() + damage < pVictim->GetMaxHealth())
+ return false;
+ break;
+ }
+ // Bonus Healing (Crystal Spire of Karabor mace)
+ case 40971:
+ {
+ // If your target is below $s1% health
+ if (pVictim->GetHealth() > pVictim->GetMaxHealth() * triggerAmount / 100)
+ return false;
+ break;
+ }
+ // Evasive Maneuvers (Commendation of Kael`thas trinket)
+ case 45057:
+ {
+ // reduce you below $s1% health
+ if (GetHealth() - damage > GetMaxHealth() * triggerAmount / 100)
+ return false;
+ break;
+ }
+ }
+
+ // Costum basepoints/target for exist spell
+ // dummy basepoints or other customs
+ switch(trigger_spell_id)
+ {
+ // Cast positive spell on enemy target
+ case 7099: // Curse of Mending
+ case 39647: // Curse of Mending
+ case 29494: // Temptation
+ case 20233: // Improved Lay on Hands (cast on target)
+ {
+ target = pVictim;
+ break;
+ }
+ // Combo points add triggers (need add combopoint only for main tatget, and after possible combopoints reset)
+ case 15250: // Rogue Setup
+ {
+ if(!pVictim || pVictim != getVictim()) // applied only for main target
+ return false;
+ break; // continue normal case
+ }
+ // Finish movies that add combo
+ case 14189: // Seal Fate (Netherblade set)
+ case 14157: // Ruthlessness
+ {
+ // Need add combopoint AFTER finish movie (or they dropped in finish phase)
+ break;
+ }
+ // Shamanistic Rage triggered spell
+ case 30824:
+ {
+ basepoints0 = int32(GetTotalAttackPowerValue(BASE_ATTACK) * triggerAmount / 100);
+ trigger_spell_id = 30824;
+ break;
+ }
+ // Enlightenment (trigger only from mana cost spells)
+ case 35095:
+ {
+ if(!procSpell || procSpell->powerType!=POWER_MANA || procSpell->manaCost==0 && procSpell->ManaCostPercentage==0 && procSpell->manaCostPerlevel==0)
+ return false;
+ break;
+ }
+ }
+
+ if( cooldown && GetTypeId()==TYPEID_PLAYER && ((Player*)this)->HasSpellCooldown(trigger_spell_id))
+ return false;
+
+ // try detect target manually if not set
+ if ( target == NULL )
+ target = !(procFlags & PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL) && IsPositiveSpell(trigger_spell_id) ? this : pVictim;
+
+ // default case
+ if(!target || target!=this && !target->isAlive())
+ return false;
+
+ if(basepoints0)
+ CastCustomSpell(target,trigger_spell_id,&basepoints0,NULL,NULL,true,castItem,triggeredByAura);
+ else
+ CastSpell(target,trigger_spell_id,true,castItem,triggeredByAura);
+
+ if( cooldown && GetTypeId()==TYPEID_PLAYER )
+ ((Player*)this)->AddSpellCooldown(trigger_spell_id,0,time(NULL) + cooldown);
+
+ return true;
+}
bool Unit::HandleOverrideClassScriptAuraProc(Unit *pVictim, Aura *triggeredByAura, SpellEntry const *procSpell, uint32 cooldown)
{
@@ -6971,7 +8247,7 @@ bool Unit::Attack(Unit *victim, bool meleeAttack)
data << uint32(AI_REACTION_AGGRO); // Aggro sound
((WorldObject*)this)->SendMessageToSet(&data, true);
- ((Creature*)this)->CallAssistence();
+ ((Creature*)this)->CallAssistance();
((Creature*)this)->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
}
@@ -7005,7 +8281,7 @@ bool Unit::AttackStop()
if( GetTypeId()==TYPEID_UNIT )
{
// reset call assistance
- ((Creature*)this)->SetNoCallAssistence(false);
+ ((Creature*)this)->SetNoCallAssistance(false);
}
SendAttackStop(victim);
@@ -7364,7 +8640,7 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
(*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 )
// 0 == any inventory type (not wand then)
{
- DoneTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
+ DoneTotalMod *= ((*i)->GetModifierValue() +100.0f)/100.0f;
}
}
@@ -7372,13 +8648,13 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
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;
+ DoneTotalMod *= ((*i)->GetModifierValue() +100.0f)/100.0f;
// ..taken
AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
if( (*i)->GetModifier()->m_miscvalue & GetSpellSchoolMask(spellProto) )
- TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
+ TakenTotalMod *= ((*i)->GetModifierValue() +100.0f)/100.0f;
// .. taken pct: scripted (increases damage of * against targets *)
AuraList const& mOverrideClassScript = GetAurasByType(SPELL_AURA_OVERRIDE_CLASS_SCRIPTS);
@@ -7559,7 +8835,7 @@ uint32 Unit::SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint3
// Seal of Vengeance - 17% per Fully Stacked Tick - 5 Applications
else if ((spellProto->SpellFamilyFlags & 0x80000000000LL) && spellProto->SpellIconID == 2292)
{
- DotFactor = 0.17f;
+ DotFactor = 0.85f;
CastingTime = 3500;
}
// Holy shield - 5% of Holy Damage
@@ -7691,7 +8967,7 @@ int32 Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask)
// -1 == any item class (not wand then)
(*i)->GetSpellProto()->EquippedItemInventoryTypeMask == 0 )
// 0 == any inventory type (not wand then)
- DoneAdvertisedBenefit += (*i)->GetModifier()->m_amount;
+ DoneAdvertisedBenefit += (*i)->GetModifierValue();
if (GetTypeId() == TYPEID_PLAYER)
{
@@ -7709,14 +8985,14 @@ int32 Unit::SpellBaseDamageBonus(SpellSchoolMask schoolMask)
if(eff < 2 && iSpellProto->EffectApplyAuraName[eff+1]==SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT)
usedStat = Stats(iSpellProto->EffectMiscValue[eff+1]);
- DoneAdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifier()->m_amount / 100.0f);
+ DoneAdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifierValue() / 100.0f);
}
}
// ... and attack power
AuraList const& mDamageDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER);
for(AuraList::const_iterator i =mDamageDonebyAP.begin();i != mDamageDonebyAP.end(); ++i)
if ((*i)->GetModifier()->m_miscvalue & schoolMask)
- DoneAdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifier()->m_amount / 100.0f);
+ DoneAdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifierValue() / 100.0f);
}
return DoneAdvertisedBenefit;
@@ -7731,13 +9007,13 @@ int32 Unit::SpellBaseDamageBonusForVictim(SpellSchoolMask schoolMask, Unit *pVic
AuraList const& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount;
+ TakenAdvertisedBenefit += (*i)->GetModifierValue();
// ..taken
AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0)
- TakenAdvertisedBenefit += (*i)->GetModifier()->m_amount;
+ TakenAdvertisedBenefit += (*i)->GetModifierValue();
return TakenAdvertisedBenefit;
}
@@ -8005,7 +9281,7 @@ uint32 Unit::SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount,
// Healing done percent
AuraList const& mHealingDonePct = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE_PERCENT);
for(AuraList::const_iterator i = mHealingDonePct.begin();i != mHealingDonePct.end(); ++i)
- heal *= (100.0f + (*i)->GetModifier()->m_amount) / 100.0f;
+ heal *= (100.0f + (*i)->GetModifierValue()) / 100.0f;
// apply spellmod to Done amount
if(Player* modOwner = GetSpellModOwner())
@@ -8046,7 +9322,7 @@ int32 Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask)
AuraList const& mHealingDone = GetAurasByType(SPELL_AURA_MOD_HEALING_DONE);
for(AuraList::const_iterator i = mHealingDone.begin();i != mHealingDone.end(); ++i)
if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0)
- AdvertisedBenefit += (*i)->GetModifier()->m_amount;
+ AdvertisedBenefit += (*i)->GetModifierValue();
// Healing bonus of spirit, intellect and strength
if (GetTypeId() == TYPEID_PLAYER)
@@ -8057,14 +9333,14 @@ int32 Unit::SpellBaseHealingBonus(SpellSchoolMask schoolMask)
{
// stat used dependent from misc value (stat index)
Stats usedStat = Stats((*i)->GetSpellProto()->EffectMiscValue[(*i)->GetEffIndex()]);
- AdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifier()->m_amount / 100.0f);
+ AdvertisedBenefit += int32(GetStat(usedStat) * (*i)->GetModifierValue() / 100.0f);
}
// ... and attack power
AuraList const& mHealingDonebyAP = GetAurasByType(SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER);
for(AuraList::const_iterator i = mHealingDonebyAP.begin();i != mHealingDonebyAP.end(); ++i)
if ((*i)->GetModifier()->m_miscvalue & schoolMask)
- AdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifier()->m_amount / 100.0f);
+ AdvertisedBenefit += int32(GetTotalAttackPowerValue(BASE_ATTACK) * (*i)->GetModifierValue() / 100.0f);
}
return AdvertisedBenefit;
}
@@ -8075,44 +9351,23 @@ int32 Unit::SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask, Unit *pVi
AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_HEALING);
for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
if(((*i)->GetModifier()->m_miscvalue & schoolMask) != 0)
- AdvertisedBenefit += (*i)->GetModifier()->m_amount;
+ AdvertisedBenefit += (*i)->GetModifierValue();
return AdvertisedBenefit;
}
bool Unit::IsImmunedToDamage(SpellSchoolMask shoolMask, bool useCharges)
{
- // no charges dependent checks
+ //If m_immuneToSchool type contain this school type, IMMUNE damage.
SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for (SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
if(itr->type & shoolMask)
return true;
- // charges dependent checks
+ //If m_immuneToDamage type contain magic, IMMUNE damage.
SpellImmuneList const& damageList = m_spellImmune[IMMUNITY_DAMAGE];
for (SpellImmuneList::const_iterator itr = damageList.begin(); itr != damageList.end(); ++itr)
- {
if(itr->type & shoolMask)
- {
- if(useCharges)
- {
- AuraList const& auraDamageImmunity = GetAurasByType(SPELL_AURA_DAMAGE_IMMUNITY);
- for(AuraList::const_iterator auraItr = auraDamageImmunity.begin(); auraItr != auraDamageImmunity.end(); ++auraItr)
- {
- if((*auraItr)->GetId()==itr->spellId)
- {
- if((*auraItr)->m_procCharges > 0)
- {
- --(*auraItr)->m_procCharges;
- if((*auraItr)->m_procCharges==0)
- RemoveAurasDueToSpell(itr->spellId);
- }
- break;
- }
- }
- }
return true;
- }
- }
return false;
}
@@ -8122,8 +9377,6 @@ bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges)
if (!spellInfo)
return false;
- // no charges first
-
//FIX ME this hack: don't get feared if stunned
if (spellInfo->Mechanic == MECHANIC_FEAR )
{
@@ -8131,7 +9384,6 @@ bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges)
return true;
}
- // not have spells with charges currently
SpellImmuneList const& dispelList = m_spellImmune[IMMUNITY_DISPEL];
for(SpellImmuneList::const_iterator itr = dispelList.begin(); itr != dispelList.end(); ++itr)
if(itr->type == spellInfo->Dispel)
@@ -8139,7 +9391,6 @@ bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges)
if( !(spellInfo->AttributesEx & SPELL_ATTR_EX_UNAFFECTED_BY_SCHOOL_IMMUNE) && (spellInfo->Id != 42292)) // unaffected by school immunity
{
- // not have spells with charges currently
SpellImmuneList const& schoolList = m_spellImmune[IMMUNITY_SCHOOL];
for(SpellImmuneList::const_iterator itr = schoolList.begin(); itr != schoolList.end(); ++itr)
if( !(IsPositiveSpell(itr->spellId) && IsPositiveSpell(spellInfo->Id)) &&
@@ -8147,30 +9398,11 @@ bool Unit::IsImmunedToSpell(SpellEntry const* spellInfo, bool useCharges)
return true;
}
- // charges dependent checks
-
SpellImmuneList const& mechanicList = m_spellImmune[IMMUNITY_MECHANIC];
for(SpellImmuneList::const_iterator itr = mechanicList.begin(); itr != mechanicList.end(); ++itr)
{
if(itr->type == spellInfo->Mechanic)
{
- if(useCharges)
- {
- AuraList const& auraMechImmunity = GetAurasByType(SPELL_AURA_MECHANIC_IMMUNITY);
- for(AuraList::const_iterator auraItr = auraMechImmunity.begin(); auraItr != auraMechImmunity.end(); ++auraItr)
- {
- if((*auraItr)->GetId()==itr->spellId)
- {
- if((*auraItr)->m_procCharges > 0)
- {
- --(*auraItr)->m_procCharges;
- if((*auraItr)->m_procCharges==0)
- RemoveAurasDueToSpell(itr->spellId);
- }
- break;
- }
- }
- }
return true;
}
}
@@ -8228,7 +9460,7 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
AuraList const& mDamageDoneCreature = GetAurasByType(SPELL_AURA_MOD_DAMAGE_DONE_CREATURE);
for(AuraList::const_iterator i = mDamageDoneCreature.begin();i != mDamageDoneCreature.end(); ++i)
if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- DoneFlatBenefit += (*i)->GetModifier()->m_amount;
+ DoneFlatBenefit += (*i)->GetModifierValue();
// ..done
// SPELL_AURA_MOD_DAMAGE_DONE included in weapon damage
@@ -8243,7 +9475,7 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
AuraList const& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS);
for(AuraList::const_iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i)
if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- APbonus += (*i)->GetModifier()->m_amount;
+ APbonus += (*i)->GetModifierValue();
}
else
{
@@ -8253,7 +9485,7 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
AuraList const& mCreatureAttackPower = GetAurasByType(SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS);
for(AuraList::const_iterator i = mCreatureAttackPower.begin();i != mCreatureAttackPower.end(); ++i)
if(creatureTypeMask & uint32((*i)->GetModifier()->m_miscvalue))
- APbonus += (*i)->GetModifier()->m_amount;
+ APbonus += (*i)->GetModifierValue();
}
if (APbonus!=0) // Can be negative
@@ -8278,7 +9510,7 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
AuraList const& mDamageTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_TAKEN);
for(AuraList::const_iterator i = mDamageTaken.begin();i != mDamageTaken.end(); ++i)
if((*i)->GetModifier()->m_miscvalue & GetMeleeDamageSchoolMask())
- TakenFlatBenefit += (*i)->GetModifier()->m_amount;
+ TakenFlatBenefit += (*i)->GetModifierValue();
if(attType!=RANGED_ATTACK)
TakenFlatBenefit += pVictim->GetTotalAuraModifier(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN);
@@ -8296,13 +9528,13 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
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;
+ DoneTotalMod *= ((*i)->GetModifierValue()+100.0f)/100.0f;
// ..taken
AuraList const& mModDamagePercentTaken = pVictim->GetAurasByType(SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN);
for(AuraList::const_iterator i = mModDamagePercentTaken.begin(); i != mModDamagePercentTaken.end(); ++i)
if((*i)->GetModifier()->m_miscvalue & GetMeleeDamageSchoolMask())
- TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
+ TakenTotalMod *= ((*i)->GetModifierValue()+100.0f)/100.0f;
// .. taken pct: dummy auras
AuraList const& mDummyAuras = pVictim->GetAurasByType(SPELL_AURA_DUMMY);
@@ -8360,13 +9592,13 @@ void Unit::MeleeDamageBonus(Unit *pVictim, uint32 *pdamage,WeaponAttackType attT
{
AuraList const& mModMeleeDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT);
for(AuraList::const_iterator i = mModMeleeDamageTakenPercent.begin(); i != mModMeleeDamageTakenPercent.end(); ++i)
- TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
+ TakenTotalMod *= ((*i)->GetModifierValue()+100.0f)/100.0f;
}
else
{
AuraList const& mModRangedDamageTakenPercent = pVictim->GetAurasByType(SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT);
for(AuraList::const_iterator i = mModRangedDamageTakenPercent.begin(); i != mModRangedDamageTakenPercent.end(); ++i)
- TakenTotalMod *= ((*i)->GetModifier()->m_amount+100.0f)/100.0f;
+ TakenTotalMod *= ((*i)->GetModifierValue()+100.0f)/100.0f;
}
float tmpDamage = float(int32(*pdamage) + DoneFlatBenefit) * DoneTotalMod;
@@ -8523,17 +9755,21 @@ void Unit::CombatStart(Unit* target)
if(!target->IsStandState() && !target->hasUnitState(UNIT_STAT_STUNNED))
target->SetStandState(PLAYER_STATE_NONE);
- if(!target->isInCombat() && target->GetTypeId() != TYPEID_PLAYER && ((Creature*)target)->AI())
+ if(!target->isInCombat() && target->GetTypeId() != TYPEID_PLAYER
+ && ((Creature*)target)->isAggressive() && ((Creature*)target)->AI())
+ {
+ SetInCombatWith(target);
+ target->SetInCombatWith(this);
((Creature*)target)->AI()->AttackStart(this);
-
- SetInCombatWith(target);
- target->SetInCombatWith(this);
+ }
+ else
+ {
+ SetInCombatWith(target);
+ target->SetInCombatWith(this);
+ }
if(Player* attackedPlayer = target->GetCharmerOrOwnerPlayerOrPlayerItself())
SetContestedPvP(attackedPlayer);
-
- if(!isInCombat()) // remove this?
- RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ATTACK);
}
void Unit::SetInCombatState(bool PvP)
@@ -8544,10 +9780,24 @@ void Unit::SetInCombatState(bool PvP)
if(PvP)
m_CombatTimer = 5000;
+
+ if(isInCombat())
+ return;
+
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
- if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet()))
+ if(isCharmed() || GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet())
SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
+
+ if(GetTypeId() == TYPEID_PLAYER && GetPetGUID())
+ {
+ if(Pet *pet = GetPet())
+ {
+ pet->UpdateSpeed(MOVE_RUN, true);
+ pet->UpdateSpeed(MOVE_SWIM, true);
+ pet->UpdateSpeed(MOVE_FLY, true);
+ }
+ }
}
void Unit::ClearInCombat()
@@ -8555,12 +9805,19 @@ void Unit::ClearInCombat()
m_CombatTimer = 0;
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT);
- if(isCharmed() || (GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet()))
+ if(isCharmed() || GetTypeId()!=TYPEID_PLAYER && ((Creature*)this)->isPet())
RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PET_IN_COMBAT);
// Player's state will be cleared in Player::UpdateContestedPvP
if(GetTypeId()!=TYPEID_PLAYER)
clearUnitState(UNIT_STAT_ATTACK_PLAYER);
+
+ if(GetTypeId() == TYPEID_PLAYER && GetPetGUID())
+ {
+ if(Pet *pet = GetPet())
+ for(int i = 0; i < MAX_MOVE_TYPE; ++i)
+ pet->SetSpeed(UnitMoveType(i), m_speed_rate[i], true);
+ }
}
//TODO: remove this function
@@ -8569,10 +9826,18 @@ bool Unit::isTargetableForAttack() const
return isAttackableByAOE() && !hasUnitState(UNIT_STAT_DIED);
}
-bool Unit::canAttack(Unit const* target) const
+bool Unit::canAttack(Unit const* target, bool force) const
{
assert(target);
+ if(force)
+ {
+ if(IsFriendlyTo(target))
+ return false;
+ }
+ else if(!IsHostileTo(target))
+ return false;
+
if(!target->isAttackableByAOE() || target->hasUnitState(UNIT_STAT_DIED))
return false;
@@ -8590,7 +9855,8 @@ bool Unit::isAttackableByAOE() const
if(!isAlive())
return false;
- if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE))
+ if(HasFlag(UNIT_FIELD_FLAGS,
+ UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NOT_ATTACKABLE_2))
return false;
if(GetTypeId()==TYPEID_PLAYER && ((Player *)this)->isGameMaster())
@@ -8951,8 +10217,9 @@ void Unit::SetSpeed(UnitMoveType mtype, float rate, bool forced)
data << float(GetSpeed(mtype));
SendMessageToSet( &data, true );
}
- if(Pet* pet = GetPet())
- pet->SetSpeed(MOVE_RUN, m_speed_rate[mtype],forced);
+ if(GetPetGUID() && !isInCombat())
+ if(Pet* pet = GetPet())
+ pet->SetSpeed(mtype, m_speed_rate[mtype], forced);
}
void Unit::SetHover(bool on)
@@ -9130,6 +10397,8 @@ bool Unit::SelectHostilTarget()
{
target = m_ThreatManager.getHostilTarget();
}
+ else
+ target = getVictim();
}
if(target)
@@ -9141,7 +10410,7 @@ bool Unit::SelectHostilTarget()
}
// no target but something prevent go to evade mode
- if( !isInCombat() || HasAuraType(SPELL_AURA_MOD_TAUNT) )
+ if( !isInCombat() /*|| HasAuraType(SPELL_AURA_MOD_TAUNT)*/ )
return false;
// last case when creature don't must go to evade mode:
@@ -9157,6 +10426,25 @@ bool Unit::SelectHostilTarget()
}
}
+ // search nearby enemy before enter evade mode
+ if(Unit *target = ((Creature*)this)->SelectNearestTarget())
+ {
+ ((Creature*)this)->AI()->AttackStart(target);
+ return true;
+ }
+
+ if(m_invisibilityMask)
+ {
+ Unit::AuraList const& iAuras = GetAurasByType(SPELL_AURA_MOD_INVISIBILITY);
+ for(Unit::AuraList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr)
+ if((*itr)->IsPermanent())
+ {
+ ((Creature*)this)->AI()->EnterEvadeMode();
+ break;
+ }
+ return false;
+ }
+
// enter in evade mode in other case
((Creature*)this)->AI()->EnterEvadeMode();
@@ -9649,6 +10937,9 @@ void Unit::SetMaxHealth(uint32 val)
void Unit::SetPower(Powers power, uint32 val)
{
+ if(GetPower(power) == val)
+ return;
+
uint32 maxPower = GetMaxPower(power);
if(maxPower < val)
val = maxPower;
@@ -9818,7 +11109,7 @@ CharmInfo* Unit::InitCharmInfo(Unit *charm)
}
CharmInfo::CharmInfo(Unit* unit)
-: m_unit(unit), m_CommandState(COMMAND_FOLLOW), m_reactState(REACT_PASSIVE), m_petnumber(0)
+: m_unit(unit), m_CommandState(COMMAND_FOLLOW), m_reactState(REACT_PASSIVE), m_petnumber(0), m_barInit(false)
{
for(int i =0; i<4; ++i)
{
@@ -9829,6 +11120,9 @@ CharmInfo::CharmInfo(Unit* unit)
void CharmInfo::InitPetActionBar()
{
+ if (m_barInit)
+ return;
+
// the first 3 SpellOrActions are attack, follow and stay
for(uint32 i = 0; i < 3; i++)
{
@@ -9843,17 +11137,25 @@ void CharmInfo::InitPetActionBar()
PetActionBar[i + 3].Type = ACT_DISABLED;
PetActionBar[i + 3].SpellOrAction = 0;
}
+ m_barInit = true;
}
-void CharmInfo::InitEmptyActionBar()
+void CharmInfo::InitEmptyActionBar(bool withAttack)
{
- for(uint32 x = 1; x < 10; ++x)
+ if (m_barInit)
+ return;
+
+ for(uint32 x = 0; x < 10; ++x)
{
PetActionBar[x].Type = ACT_CAST;
PetActionBar[x].SpellOrAction = 0;
}
- PetActionBar[0].Type = ACT_COMMAND;
- PetActionBar[0].SpellOrAction = COMMAND_ATTACK;
+ if (withAttack)
+ {
+ PetActionBar[0].Type = ACT_COMMAND;
+ PetActionBar[0].SpellOrAction = COMMAND_ATTACK;
+ }
+ m_barInit = true;
}
void CharmInfo::InitPossessCreateSpells()
@@ -9971,6 +11273,7 @@ bool Unit::isFrozen() const
return false;
}
+/*
struct ProcTriggeredData
{
ProcTriggeredData(Aura* _triggeredByAura, uint32 _cooldown)
@@ -10144,6 +11447,371 @@ void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag
}
}
}
+*/
+struct ProcTriggeredData
+{
+ ProcTriggeredData(SpellProcEventEntry const * _spellProcEvent, Aura* _triggeredByAura)
+ : spellProcEvent(_spellProcEvent), triggeredByAura(_triggeredByAura),
+ triggeredByAura_SpellPair(Unit::spellEffectPair(triggeredByAura->GetId(),triggeredByAura->GetEffIndex()))
+ {}
+ SpellProcEventEntry const *spellProcEvent;
+ Aura* triggeredByAura;
+ Unit::spellEffectPair triggeredByAura_SpellPair;
+};
+
+typedef std::list< ProcTriggeredData > ProcTriggeredList;
+typedef std::list< uint32> RemoveSpellList;
+
+// List of auras that CAN be trigger but may not exist in spell_proc_event
+// in most case need for drop charges
+// in some types of aura need do additional check
+// for example SPELL_AURA_MECHANIC_IMMUNITY - need check for mechanic
+static bool isTriggerAura[TOTAL_AURAS];
+static bool isNonTriggerAura[TOTAL_AURAS];
+void InitTriggerAuraData()
+{
+ for (int i=0;i<TOTAL_AURAS;i++)
+ {
+ isTriggerAura[i]=false;
+ isNonTriggerAura[i] = false;
+ }
+ isTriggerAura[SPELL_AURA_DUMMY] = true;
+ isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true;
+ isTriggerAura[SPELL_AURA_MOD_THREAT] = true;
+ isTriggerAura[SPELL_AURA_MOD_STUN] = true; // Aura not have charges but need remove him on trigger
+ isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true;
+ isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true;
+ isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true;
+ isTriggerAura[SPELL_AURA_MOD_ROOT] = true;
+ isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true;
+ isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true;
+ isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true;
+ isTriggerAura[SPELL_AURA_PROC_TRIGGER_DAMAGE] = true;
+ isTriggerAura[SPELL_AURA_MOD_CASTING_SPEED] = true;
+ isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT] = true;
+ isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL] = true;
+ isTriggerAura[SPELL_AURA_REFLECT_SPELLS_SCHOOL] = true;
+ isTriggerAura[SPELL_AURA_MECHANIC_IMMUNITY] = true;
+ isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN] = true;
+ isTriggerAura[SPELL_AURA_SPELL_MAGNET] = true;
+ isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER] = true;
+ isTriggerAura[SPELL_AURA_ADD_CASTER_HIT_TRIGGER] = true;
+ isTriggerAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
+ isTriggerAura[SPELL_AURA_MOD_MECHANIC_RESISTANCE] = true;
+ isTriggerAura[SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS] = true;
+ isTriggerAura[SPELL_AURA_MOD_HASTE] = true;
+ isTriggerAura[SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE]=true;
+ isTriggerAura[SPELL_AURA_PRAYER_OF_MENDING] = true;
+
+ isNonTriggerAura[SPELL_AURA_MOD_POWER_REGEN]=true;
+ isNonTriggerAura[SPELL_AURA_RESIST_PUSHBACK]=true;
+}
+
+uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition)
+{
+ uint32 procEx = PROC_EX_NONE;
+ // Check victim state
+ if (missCondition!=SPELL_MISS_NONE)
+ switch (missCondition)
+ {
+ case SPELL_MISS_MISS: procEx|=PROC_EX_MISS; break;
+ case SPELL_MISS_RESIST: procEx|=PROC_EX_RESIST; break;
+ case SPELL_MISS_DODGE: procEx|=PROC_EX_DODGE; break;
+ case SPELL_MISS_PARRY: procEx|=PROC_EX_PARRY; break;
+ case SPELL_MISS_BLOCK: procEx|=PROC_EX_BLOCK; break;
+ case SPELL_MISS_EVADE: procEx|=PROC_EX_EVADE; break;
+ case SPELL_MISS_IMMUNE: procEx|=PROC_EX_IMMUNE; break;
+ case SPELL_MISS_IMMUNE2: procEx|=PROC_EX_IMMUNE; break;
+ case SPELL_MISS_DEFLECT: procEx|=PROC_EX_DEFLECT;break;
+ case SPELL_MISS_ABSORB: procEx|=PROC_EX_ABSORB; break;
+ case SPELL_MISS_REFLECT: procEx|=PROC_EX_REFLECT;break;
+ default:
+ break;
+ }
+ else
+ {
+ // On block
+ if (damageInfo->blocked)
+ procEx|=PROC_EX_BLOCK;
+ // On absorb
+ if (damageInfo->absorb)
+ procEx|=PROC_EX_ABSORB;
+ // On crit
+ if (damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT)
+ procEx|=PROC_EX_CRITICAL_HIT;
+ else
+ procEx|=PROC_EX_NORMAL_HIT;
+ }
+ return procEx;
+}
+
+static int deep = 0;
+void Unit::ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage )
+{
+ deep ++;
+ if (deep > 5)
+ {
+ sLog.outError("Prevent possible stack owerflow in Unit::ProcDamageAndSpellFor");
+ if (procSpell)
+ sLog.outError(" Spell %u", procSpell->Id);
+ deep--;
+ return;
+ }
+ // For melee/ranged based attack need update skills and set some Aura states
+ if (procFlag & MELEE_BASED_TRIGGER_MASK)
+ {
+ // Update skills here for players
+ if (GetTypeId() == TYPEID_PLAYER)
+ {
+ // On melee based hit/miss/resist need update skill (for victim and attacker)
+ if (procExtra&(PROC_EX_NORMAL_HIT|PROC_EX_MISS|PROC_EX_RESIST))
+ {
+ if (pTarget->GetTypeId() != TYPEID_PLAYER && pTarget->GetCreatureType() != CREATURE_TYPE_CRITTER)
+ ((Player*)this)->UpdateCombatSkills(pTarget, attType, MELEE_HIT_MISS, isVictim);
+ }
+ // Update defence if player is victim and parry/dodge/block
+ if (isVictim && procExtra&(PROC_EX_DODGE|PROC_EX_PARRY|PROC_EX_BLOCK))
+ ((Player*)this)->UpdateDefense();
+ }
+ // If exist crit/parry/dodge/block need update aura state (for victim and attacker)
+ if (procExtra & (PROC_EX_CRITICAL_HIT|PROC_EX_PARRY|PROC_EX_DODGE|PROC_EX_BLOCK))
+ {
+ // for victim
+ if (isVictim)
+ {
+ // if victim and dodge attack
+ if (procExtra&PROC_EX_DODGE)
+ {
+ //Update AURA_STATE on dodge
+ if (getClass() != CLASS_ROGUE) // skip Rogue Riposte
+ {
+ ModifyAuraState(AURA_STATE_DEFENSE, true);
+ StartReactiveTimer( REACTIVE_DEFENSE );
+ }
+ }
+ // if victim and parry attack
+ if (procExtra & PROC_EX_PARRY)
+ {
+ // For Hunters only Counterattack (skip Mongoose bite)
+ if (getClass() == CLASS_HUNTER)
+ {
+ ModifyAuraState(AURA_STATE_HUNTER_PARRY, true);
+ StartReactiveTimer( REACTIVE_HUNTER_PARRY );
+ }
+ else
+ {
+ ModifyAuraState(AURA_STATE_DEFENSE, true);
+ StartReactiveTimer( REACTIVE_DEFENSE );
+ }
+ }
+ // if and victim block attack
+ if (procExtra & PROC_EX_BLOCK)
+ {
+ ModifyAuraState(AURA_STATE_DEFENSE,true);
+ StartReactiveTimer( REACTIVE_DEFENSE );
+ }
+ }
+ else //For attacker
+ {
+ // Overpower on victim dodge
+ if (procExtra&PROC_EX_DODGE && GetTypeId() == TYPEID_PLAYER && getClass() == CLASS_WARRIOR)
+ {
+ ((Player*)this)->AddComboPoints(pTarget, 1);
+ StartReactiveTimer( REACTIVE_OVERPOWER );
+ }
+ // Enable AURA_STATE_CRIT on crit
+ if (procExtra & PROC_EX_CRITICAL_HIT)
+ {
+ ModifyAuraState(AURA_STATE_CRIT, true);
+ StartReactiveTimer( REACTIVE_CRIT );
+ if(getClass()==CLASS_HUNTER)
+ {
+ ModifyAuraState(AURA_STATE_HUNTER_CRIT_STRIKE, true);
+ StartReactiveTimer( REACTIVE_HUNTER_CRIT );
+ }
+ }
+ }
+ }
+ }
+
+ RemoveSpellList removedSpells;
+ ProcTriggeredList procTriggered;
+ // Fill procTriggered list
+ for(AuraMap::const_iterator itr = GetAuras().begin(); itr!= GetAuras().end(); ++itr)
+ {
+ SpellProcEventEntry const* spellProcEvent = NULL;
+ if(!IsTriggeredAtSpellProcEvent(itr->second, procSpell, procFlag, procExtra, attType, isVictim, (damage > 0), spellProcEvent))
+ continue;
+
+ procTriggered.push_back( ProcTriggeredData(spellProcEvent, itr->second) );
+ }
+ // Handle effects proceed this time
+ for(ProcTriggeredList::iterator i = procTriggered.begin(); i != procTriggered.end(); ++i)
+ {
+ // Some auras can be deleted in function called in this loop (except first, ofc)
+ // Until storing auars in std::multimap to hard check deleting by another way
+ if(i != procTriggered.begin())
+ {
+ bool found = false;
+ AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair);
+ AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair);
+ for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr)
+ {
+ if(itr->second==i->triggeredByAura)
+ {
+ found = true;
+ break;
+ }
+ }
+ if(!found)
+ {
+// sLog.outDebug("Spell aura %u (id:%u effect:%u) has been deleted before call spell proc event handler", i->triggeredByAura->GetModifier()->m_auraname, i->triggeredByAura_SpellPair.first, i->triggeredByAura_SpellPair.second);
+// sLog.outDebug("It can be deleted one from early proccesed auras:");
+// for(ProcTriggeredList::iterator i2 = procTriggered.begin(); i != i2; ++i2)
+// sLog.outDebug(" Spell aura %u (id:%u effect:%u)", i->triggeredByAura->GetModifier()->m_auraname,i2->triggeredByAura_SpellPair.first,i2->triggeredByAura_SpellPair.second);
+// sLog.outDebug(" <end of list>");
+ continue;
+ }
+ }
+
+ SpellProcEventEntry const *spellProcEvent = i->spellProcEvent;
+ Aura *triggeredByAura = i->triggeredByAura;
+ Modifier *auraModifier = triggeredByAura->GetModifier();
+ SpellEntry const *spellInfo = triggeredByAura->GetSpellProto();
+ uint32 effIndex = triggeredByAura->GetEffIndex();
+ bool useCharges = triggeredByAura->m_procCharges > 0;
+ // For players set spell cooldown if need
+ uint32 cooldown = 0;
+ if (GetTypeId() == TYPEID_PLAYER && spellProcEvent && spellProcEvent->cooldown)
+ cooldown = spellProcEvent->cooldown;
+
+ switch(auraModifier->m_auraname)
+ {
+ case SPELL_AURA_PROC_TRIGGER_SPELL:
+ {
+ sLog.outDebug("ProcDamageAndSpell: casting spell %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
+ // Don`t drop charge or add cooldown for not started trigger
+ if (!HandleProcTriggerSpell(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ continue;
+ break;
+ }
+ case SPELL_AURA_PROC_TRIGGER_DAMAGE:
+ {
+ sLog.outDebug("ProcDamageAndSpell: doing %u damage from spell id %u (triggered by %s aura of spell %u)", auraModifier->m_amount, spellInfo->Id, (isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
+ SpellNonMeleeDamage damageInfo(this, pTarget, spellInfo->Id, spellInfo->SchoolMask);
+ CalculateSpellDamage(&damageInfo, auraModifier->m_amount, spellInfo);
+ SendSpellNonMeleeDamageLog(&damageInfo);
+ DealSpellDamage(&damageInfo, true);
+ break;
+ }
+ case SPELL_AURA_MANA_SHIELD:
+ case SPELL_AURA_DUMMY:
+ {
+ sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s dummy aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
+ if (!HandleDummyAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ continue;
+ break;
+ }
+ case SPELL_AURA_MOD_HASTE:
+ {
+ sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s haste aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
+ if (!HandleHasteAuraProc(pTarget, damage, triggeredByAura, procSpell, procFlag, procExtra, cooldown))
+ continue;
+ break;
+ }
+ case SPELL_AURA_OVERRIDE_CLASS_SCRIPTS:
+ {
+ sLog.outDebug("ProcDamageAndSpell: casting spell id %u (triggered by %s aura of spell %u)", spellInfo->Id,(isVictim?"a victim's":"an attacker's"), triggeredByAura->GetId());
+ if (!HandleOverrideClassScriptAuraProc(pTarget, triggeredByAura, procSpell, cooldown))
+ continue;
+ break;
+ }
+ case SPELL_AURA_PRAYER_OF_MENDING:
+ {
+ sLog.outDebug("ProcDamageAndSpell: casting mending (triggered by %s dummy aura of spell %u)",
+ (isVictim?"a victim's":"an attacker's"),triggeredByAura->GetId());
+
+ HandleMeandingAuraProc(triggeredByAura);
+ break;
+ }
+ case SPELL_AURA_MOD_STUN:
+ // Remove by default, but if charge exist drop it
+ if (triggeredByAura->m_procCharges == 0)
+ removedSpells.push_back(triggeredByAura->GetId());
+ break;
+ case SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS:
+ case SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS:
+ // Hunter's Mark (1-4 Rangs)
+ if (spellInfo->SpellFamilyName == SPELLFAMILY_HUNTER && (spellInfo->SpellFamilyFlags&0x0000000000000400LL))
+ {
+ uint32 basevalue = triggeredByAura->GetBasePoints();
+ auraModifier->m_amount += basevalue/10;
+ if (auraModifier->m_amount > basevalue*4)
+ auraModifier->m_amount = basevalue*4;
+ }
+ break;
+ case SPELL_AURA_MOD_CASTING_SPEED:
+ // Skip melee hits or instant cast spells
+ if (procSpell == NULL || GetSpellCastTime(procSpell) == 0)
+ continue;
+ break;
+ case SPELL_AURA_REFLECT_SPELLS_SCHOOL:
+ // Skip Melee hits and spells ws wrong school
+ if (procSpell == NULL || (auraModifier->m_miscvalue & procSpell->SchoolMask) == 0)
+ continue;
+ break;
+ case SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT:
+ case SPELL_AURA_MOD_POWER_COST_SCHOOL:
+ // Skip melee hits and spells ws wrong school or zero cost
+ if (procSpell == NULL ||
+ (procSpell->manaCost == 0 && procSpell->ManaCostPercentage == 0) || // Cost check
+ (auraModifier->m_miscvalue & procSpell->SchoolMask) == 0) // School check
+ continue;
+ break;
+ case SPELL_AURA_MECHANIC_IMMUNITY:
+ // Compare mechanic
+ if (procSpell==NULL || procSpell->Mechanic != auraModifier->m_miscvalue)
+ continue;
+ break;
+ case SPELL_AURA_MOD_MECHANIC_RESISTANCE:
+ // Compare mechanic
+ if (procSpell==NULL || procSpell->Mechanic != auraModifier->m_miscvalue)
+ continue;
+ break;
+ default:
+ // nothing do, just charges counter
+ break;
+ }
+ // Remove charge (aura can be removed by triggers)
+ if(useCharges)
+ {
+ // need found aura on drop (can be dropped by triggers)
+ AuraMap::const_iterator lower = GetAuras().lower_bound(i->triggeredByAura_SpellPair);
+ AuraMap::const_iterator upper = GetAuras().upper_bound(i->triggeredByAura_SpellPair);
+ for(AuraMap::const_iterator itr = lower; itr!= upper; ++itr)
+ {
+ if(itr->second == i->triggeredByAura)
+ {
+ triggeredByAura->m_procCharges -=1;
+ triggeredByAura->UpdateAuraCharges();
+ if (triggeredByAura->m_procCharges <= 0)
+ removedSpells.push_back(triggeredByAura->GetId());
+ break;
+ }
+ }
+ }
+ }
+ if (removedSpells.size())
+ {
+ // Sort spells and remove dublicates
+ removedSpells.sort();
+ removedSpells.unique();
+ // Remove auras from removedAuras
+ for(RemoveSpellList::const_iterator i = removedSpells.begin(); i != removedSpells.end();i++)
+ RemoveAurasDueToSpell(*i);
+ }
+ deep--;
+}
SpellSchoolMask Unit::GetMeleeDamageSchoolMask() const
{
@@ -10455,7 +12123,7 @@ void Unit::UpdateReactives( uint32 p_time )
}
}
-Unit* Unit::SelectNearbyTarget() const
+Unit* Unit::SelectNearbyTarget(float dist) const
{
CellPair p(Trinity::ComputeCellPair(GetPositionX(), GetPositionY()));
Cell cell(p);
@@ -10465,7 +12133,7 @@ Unit* Unit::SelectNearbyTarget() const
std::list<Unit *> targets;
{
- Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, this, ATTACK_DISTANCE);
+ Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(this, this, dist);
Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(targets, u_check);
TypeContainerVisitor<Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck>, WorldTypeMapContainer > world_unit_searcher(searcher);
@@ -10695,7 +12363,7 @@ void Unit::SetContestedPvP(Player *attackedPlayer)
player->addUnitState(UNIT_STAT_ATTACK_PLAYER);
player->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP);
// call MoveInLineOfSight for nearby contested guards
- SetVisibility(GetVisibility());
+ player->SetVisibility(GetVisibility());
}
if(!hasUnitState(UNIT_STAT_ATTACK_PLAYER))
{
@@ -10750,60 +12418,83 @@ Pet* Unit::CreateTamedPetFrom(Creature* creatureTarget,uint32 spell_id)
return pet;
}
-bool Unit::IsTriggeredAtSpellProcEvent(SpellEntry const* spellProto, SpellEntry const* procSpell, uint32 procFlag, WeaponAttackType attType, bool isVictim, uint32& cooldown )
+bool Unit::IsTriggeredAtSpellProcEvent(Aura* aura, SpellEntry const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent )
{
- SpellProcEventEntry const * spellProcEvent = spellmgr.GetSpellProcEvent(spellProto->Id);
+ SpellEntry const* spellProto = aura->GetSpellProto ();
- if(!spellProcEvent)
- {
- // used to prevent spam in log about same non-handled spells
- static std::set<uint32> nonHandledSpellProcSet;
+ // Get proc Event Entry
+ spellProcEvent = spellmgr.GetSpellProcEvent(spellProto->Id);
- if(spellProto->procFlags != 0 && nonHandledSpellProcSet.find(spellProto->Id)==nonHandledSpellProcSet.end())
- {
- sLog.outError("ProcDamageAndSpell: spell %u (%s aura source) not have record in `spell_proc_event`)",spellProto->Id,(isVictim?"a victim's":"an attacker's"));
- nonHandledSpellProcSet.insert(spellProto->Id);
- }
+ // Aura info stored here
+ Modifier *mod = aura->GetModifier();
+ // Skip this auras
+ if (isNonTriggerAura[mod->m_auraname])
+ return false;
+ // If not trigger by default and spellProcEvent==NULL - skip
+ if (!isTriggerAura[mod->m_auraname] && spellProcEvent==NULL)
+ return false;
- // spell.dbc use totally different flags, that only can create problems if used.
+ // Get EventProcFlag
+ uint32 EventProcFlag;
+ if (spellProcEvent && spellProcEvent->procFlags) // if exist get custom spellProcEvent->procFlags
+ EventProcFlag = spellProcEvent->procFlags;
+ else
+ EventProcFlag = spellProto->procFlags; // else get from spell proto
+ // Continue if no trigger exist
+ if (!EventProcFlag)
return false;
- }
// Check spellProcEvent data requirements
- if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent, procSpell,procFlag))
+ if(!SpellMgr::IsSpellProcEventCanTriggeredBy(spellProcEvent, EventProcFlag, procSpell, procFlag, procExtra, active))
+ return false;
+
+ // Aura added by spell can`t trogger from self (prevent drop cahres/do triggers)
+ // But except periodic triggers (can triggered from self)
+ if(procSpell && procSpell->Id == spellProto->Id && !(spellProto->procFlags&PROC_FLAG_ON_TAKE_PERIODIC))
return false;
// Check if current equipment allows aura to proc
- if(!isVictim && GetTypeId() == TYPEID_PLAYER )
+ if(!isVictim && GetTypeId() == TYPEID_PLAYER)
{
if(spellProto->EquippedItemClass == ITEM_CLASS_WEAPON)
{
- Item *item = ((Player*)this)->GetWeaponForAttack(attType,true);
+ Item *item = NULL;
+ if(attType == BASE_ATTACK)
+ item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND);
+ else if (attType == OFF_ATTACK)
+ item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
+ else
+ item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED);
- if(!item || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
+ if (!((Player*)this)->IsUseEquipedWeapon(attType==BASE_ATTACK))
+ return false;
+
+ if(!item || item->IsBroken() || item->GetProto()->Class != ITEM_CLASS_WEAPON || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
return false;
}
else if(spellProto->EquippedItemClass == ITEM_CLASS_ARMOR)
{
// Check if player is wearing shield
- Item *item = ((Player*)this)->GetShield(true);
- if(!item || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
+ Item *item = ((Player*)this)->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND);
+ if(!item || item->IsBroken() || item->GetProto()->Class != ITEM_CLASS_ARMOR || !((1<<item->GetProto()->SubClass) & spellProto->EquippedItemSubClassMask))
return false;
}
}
-
+ // Get chance from spell
float chance = (float)spellProto->procChance;
-
- if(Player* modOwner = GetSpellModOwner())
- modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance);
-
+ // If in spellProcEvent exist custom chance, chance = spellProcEvent->customChance;
+ if(spellProcEvent && spellProcEvent->customChance)
+ chance = spellProcEvent->customChance;
+ // If PPM exist calculate chance from PPM
if(!isVictim && spellProcEvent && spellProcEvent->ppmRate != 0)
{
uint32 WeaponSpeed = GetAttackTime(attType);
chance = GetPPMProcChance(WeaponSpeed, spellProcEvent->ppmRate);
}
+ // Apply chance modifer aura
+ if(Player* modOwner = GetSpellModOwner())
+ modOwner->ApplySpellMod(spellProto->Id,SPELLMOD_CHANCE_OF_SUCCESS,chance);
- cooldown = spellProcEvent ? spellProcEvent->cooldown : 0;
return roll_chance_f(chance);
}
@@ -10878,3 +12569,11 @@ void Unit::RemoveAurasAtChanneledTarget(SpellEntry const* spellInfo)
++iter;
}
}
+
+/*-----------------------TRINITY-----------------------------*/
+
+void Unit::SetToNotify()
+{
+ if(Map *map = GetMap())
+ map->AddUnitToNotify(this);
+} \ No newline at end of file
diff --git a/src/game/Unit.h b/src/game/Unit.h
index 4a5dc7e4bb9..3b2656b539a 100644
--- a/src/game/Unit.h
+++ b/src/game/Unit.h
@@ -453,7 +453,7 @@ enum UnitFlags
UNIT_FLAG_PREPARATION = 0x00000020, // don't take reagents for spells with SPELL_ATTR_EX5_NO_REAGENT_WHILE_PREP
UNIT_FLAG_UNKNOWN9 = 0x00000040,
UNIT_FLAG_NOT_ATTACKABLE_1 = 0x00000080, // ?? (UNIT_FLAG_PVP_ATTACKABLE | UNIT_FLAG_NOT_ATTACKABLE_1) is NON_PVP_ATTACKABLE
- UNIT_FLAG_UNKNOWN2 = 0x00000100, // 2.0.8
+ UNIT_FLAG_NOT_ATTACKABLE_2 = 0x00000100, // 2.0.8
UNIT_FLAG_UNKNOWN11 = 0x00000200,
UNIT_FLAG_LOOTING = 0x00000400, // loot animation
UNIT_FLAG_PET_IN_COMBAT = 0x00000800, // in combat?, 2.0.8
@@ -583,6 +583,50 @@ struct CleanDamage
MeleeHitOutcome hitOutCome;
};
+// Struct for use in Unit::CalculateMeleeDamage
+// Need create structure like in SMSG_ATTACKERSTATEUPDATE opcode
+struct CalcDamageInfo
+{
+ Unit *attacker; // Attacker
+ Unit *target; // Target for damage
+ uint32 damageSchoolMask;
+ uint32 damage;
+ uint32 absorb;
+ uint32 resist;
+ uint32 blocked_amount;
+ uint32 HitInfo;
+ uint32 TargetState;
+// Helper
+ WeaponAttackType attackType; //
+ uint32 procAttacker;
+ uint32 procVictim;
+ uint32 procEx;
+ uint32 cleanDamage; // Used only fo rage calcultion
+ MeleeHitOutcome hitOutCome; // TODO: remove this field (need use TargetState)
+};
+
+// Spell damage info structure based on structure sending in SMSG_SPELLNONMELEEDAMAGELOG opcode
+struct SpellNonMeleeDamage{
+ SpellNonMeleeDamage(Unit *_attacker, Unit *_target, uint32 _SpellID, uint32 _schoolMask) :
+ attacker(_attacker), target(_target), SpellID(_SpellID), damage(0), schoolMask(_schoolMask),
+ absorb(0), resist(0), phusicalLog(false), unused(false), blocked(0), HitInfo(0), cleanDamage(0) {}
+ Unit *target;
+ Unit *attacker;
+ uint32 SpellID;
+ uint32 damage;
+ uint32 schoolMask;
+ uint32 absorb;
+ uint32 resist;
+ bool phusicalLog;
+ bool unused;
+ uint32 blocked;
+ uint32 HitInfo;
+ // Used for help
+ uint32 cleanDamage;
+};
+
+uint32 createProcExtendMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition);
+
struct UnitActionBarEntry
{
uint32 Type;
@@ -640,7 +684,7 @@ struct CharmSpellEntry
typedef std::list<Player*> SharedVisionList;
-struct CharmInfo
+struct TRINITY_DLL_SPEC CharmInfo
{
public:
explicit CharmInfo(Unit* unit);
@@ -657,7 +701,7 @@ struct CharmInfo
void InitPossessCreateSpells();
void InitCharmCreateSpells();
void InitPetActionBar();
- void InitEmptyActionBar();
+ void InitEmptyActionBar(bool withAttack = true);
//return true if successful
bool AddSpellToAB(uint32 oldid, uint32 newid, ActiveStates newstate = ACT_DECIDE);
void ToggleCreatureAutocast(uint32 spellid, bool apply);
@@ -671,6 +715,7 @@ struct CharmInfo
CommandStates m_CommandState;
ReactStates m_reactState;
uint32 m_petnumber;
+ bool m_barInit;
};
// for clearing special attacks
@@ -691,6 +736,8 @@ enum ReactiveType
// delay time next attack to prevent client attack animation problems
#define ATTACK_DISPLAY_DELAY 200
+struct SpellProcEventEntry; // used only privately
+
class TRINITY_DLL_SPEC Unit : public WorldObject
{
public:
@@ -762,7 +809,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
Unit* getVictim() const { return m_attacking; }
void CombatStop(bool cast = false);
void CombatStopWithPets(bool cast = false);
- Unit* SelectNearbyTarget() const;
+ Unit* SelectNearbyTarget(float dist = ATTACK_DISTANCE) const;
void addUnitState(uint32 f) { m_state |= f; }
bool hasUnitState(const uint32 f) const { return (m_state & f); }
@@ -848,15 +895,23 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
uint16 GetMaxSkillValueForLevel(Unit const* target = NULL) const { return (target ? getLevelForTarget(target) : getLevel()) * 5; }
void RemoveSpellbyDamageTaken(uint32 damage, uint32 spell);
uint32 DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDamage, DamageEffectType damagetype, SpellSchoolMask damageSchoolMask, SpellEntry const *spellProto, bool durabilityLoss);
- void DealFlatDamage(Unit *pVictim, SpellEntry const *spellInfo, uint32 *damage, CleanDamage *cleanDamage, bool *crit = false, bool isTriggeredSpell = false);
- void DoAttackDamage(Unit *pVictim, uint32 *damage, CleanDamage *cleanDamage, uint32 *blocked_amount, SpellSchoolMask damageSchoolMask, uint32 *hitInfo, VictimState *victimState, uint32 *absorbDamage, uint32 *resistDamage, WeaponAttackType attType, SpellEntry const *spellCasted = NULL, bool isTriggeredSpell = false);
- void CastMeleeProcDamageAndSpell(Unit* pVictim, uint32 damage, SpellSchoolMask damageSchoolMask, WeaponAttackType attType, MeleeHitOutcome outcome, SpellEntry const *spellCasted = NULL, bool isTriggeredSpell = false);
- void ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 damage = 0, SpellSchoolMask damageSchoolMask = SPELL_SCHOOL_MASK_NONE, SpellEntry const *procSpell = NULL, bool isTriggeredSpell = false, WeaponAttackType attType = BASE_ATTACK);
+ void ProcDamageAndSpell(Unit *pVictim, uint32 procAttacker, uint32 procVictim, uint32 procEx, uint32 amount, WeaponAttackType attType = BASE_ATTACK, SpellEntry const *procSpell = NULL);
+ void ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage );
+
void HandleEmoteCommand(uint32 anim_id);
void AttackerStateUpdate (Unit *pVictim, WeaponAttackType attType = BASE_ATTACK, bool extra = false );
float MeleeMissChanceCalc(const Unit *pVictim, WeaponAttackType attType) const;
+
+ void CalculateMeleeDamage(Unit *pVictim, uint32 damage, CalcDamageInfo *damageInfo, WeaponAttackType attackType = BASE_ATTACK);
+ void DealMeleeDamage(CalcDamageInfo *damageInfo, bool durabilityLoss);
+
+ void CalculateSpellDamage(SpellNonMeleeDamage *damageInfo, int32 damage, SpellEntry const *spellInfo, WeaponAttackType attackType = BASE_ATTACK);
+ void DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss);
+
+ float MeleeSpellMissChance(Unit *pVictim, WeaponAttackType attType, int32 skillDiff, SpellEntry const *spell);
+ SpellMissInfo MeleeSpellHitResult(Unit *pVictim, SpellEntry const *spell);
SpellMissInfo MagicSpellHitResult(Unit *pVictim, SpellEntry const *spell);
SpellMissInfo SpellHitResult(Unit *pVictim, SpellEntry const *spell, bool canReflect = false);
@@ -871,7 +926,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
uint32 GetWeaponSkillValue(WeaponAttackType attType, Unit const* target = NULL) const;
float GetWeaponProcChance() const;
float GetPPMProcChance(uint32 WeaponSpeed, float PPM) const;
- MeleeHitOutcome RollPhysicalOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, SpellEntry const *spellInfo);
+
MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType) const;
MeleeHitOutcome RollMeleeOutcomeAgainst (const Unit *pVictim, WeaponAttackType attType, int32 crit_chance, int32 miss_chance, int32 dodge_chance, int32 parry_chance, int32 block_chance, bool SpellCasted ) const;
@@ -927,7 +982,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
bool isTargetableForAttack() const;
bool isAttackableByAOE() const;
- bool canAttack(Unit const* target) const;
+ bool canAttack(Unit const* target, bool force = true) const;
virtual bool IsInWater() const;
virtual bool IsUnderWater() const;
bool isInAccessiblePlaceFor(Creature const* c) const;
@@ -947,7 +1002,9 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void DeMorph();
void SendAttackStart(Unit* pVictim);
+ void SendAttackStateUpdate(CalcDamageInfo *damageInfo);
void SendAttackStateUpdate(uint32 HitInfo, Unit *target, uint8 SwingType, SpellSchoolMask damageSchoolMask, uint32 Damage, uint32 AbsorbDamage, uint32 Resist, VictimState TargetState, uint32 BlockedAmount);
+ void SendSpellNonMeleeDamageLog(SpellNonMeleeDamage *log);
void SendSpellNonMeleeDamageLog(Unit *target,uint32 SpellID,uint32 Damage, SpellSchoolMask damageSchoolMask,uint32 AbsorbedDamage, uint32 Resist,bool PhysicalDamage, uint32 Blocked, bool CriticalHit = false);
void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo);
@@ -1033,7 +1090,8 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode = AURA_REMOVE_BY_DEFAULT);
void RemoveAura(uint32 spellId, uint32 effindex, Aura* except = NULL);
- void RemoveSingleAuraFromStack(uint32 spellId, uint32 effindex);
+ void RemoveSingleAuraFromStackByDispel(uint32 spellId);
+ void RemoveSingleAuraFromStack(uint32 spellId, uint32 effindex);
void RemoveAurasDueToSpell(uint32 spellId, Aura* except = NULL);
void RemoveAurasDueToItemSpell(Item* castItem,uint32 spellId);
void RemoveAurasDueToSpellByDispel(uint32 spellId, uint64 casterGUID, Unit *dispeler);
@@ -1045,7 +1103,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void RemoveSpellsCausingAura(AuraType auraType);
void RemoveRankAurasDueToSpell(uint32 spellId);
bool RemoveNoStackAurasDueToAura(Aura *Aur);
- void RemoveAurasWithInterruptFlags(uint32 flags);
+ void RemoveAurasWithInterruptFlags(uint32 flags, uint32 except = 0);
void RemoveAurasWithDispelType( DispelType type );
void RemoveAllAuras();
@@ -1227,7 +1285,8 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
int32 SpellBaseHealingBonusForVictim(SpellSchoolMask schoolMask, Unit *pVictim);
uint32 SpellDamageBonus(Unit *pVictim, SpellEntry const *spellProto, uint32 damage, DamageEffectType damagetype);
uint32 SpellHealingBonus(SpellEntry const *spellProto, uint32 healamount, DamageEffectType damagetype, Unit *pVictim);
- bool isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType);
+ bool isSpellBlocked(Unit *pVictim, SpellEntry const *spellProto, WeaponAttackType attackType = BASE_ATTACK);
+ bool isSpellCrit(Unit *pVictim, SpellEntry const *spellProto, SpellSchoolMask schoolMask, WeaponAttackType attackType = BASE_ATTACK);
uint32 SpellCriticalBonus(SpellEntry const *spellProto, uint32 damage, Unit *pVictim);
void SetLastManaUse(uint32 spellCastTime) { m_lastManaUse = spellCastTime; }
@@ -1315,6 +1374,8 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void AddPetAura(PetAura const* petSpell);
void RemovePetAura(PetAura const* petSpell);
+ void SetToNotify();
+ bool m_Notified, m_IsInNotifyList;
protected:
explicit Unit ();
@@ -1370,12 +1431,11 @@ class TRINITY_DLL_SPEC Unit : public WorldObject
void SendAttackStop(Unit* victim); // only from AttackStop(Unit*)
//void SendAttackStart(Unit* pVictim); // only from Unit::AttackStart(Unit*)
- void ProcDamageAndSpellFor( bool isVictim, Unit * pTarget, uint32 procFlag, AuraTypeSet const& procAuraTypes, WeaponAttackType attType, SpellEntry const * procSpell, uint32 damage, SpellSchoolMask damageSchoolMask );
- bool IsTriggeredAtSpellProcEvent( SpellEntry const* spellProto, SpellEntry const* procSpell, uint32 procFlag, WeaponAttackType attType, bool isVictim, uint32& cooldown );
- bool HandleDummyAuraProc( Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const* procSpell, uint32 procFlag, uint32 cooldown);
- bool HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const* procSpell, uint32 procFlag, WeaponAttackType attType, uint32 cooldown);
- bool HandleHasteAuraProc( Unit *pVictim, uint32 damage, Aura* triggeredByAura, SpellEntry const* procSpell, uint32 procFlag, uint32 cooldown);
- bool HandleOverrideClassScriptAuraProc(Unit *pVictim, Aura* triggeredByAura, SpellEntry const *procSpell, uint32 cooldown);
+ bool IsTriggeredAtSpellProcEvent( Aura* aura, SpellEntry const* procSpell, uint32 procFlag, uint32 procExtra, WeaponAttackType attType, bool isVictim, bool active, SpellProcEventEntry const*& spellProcEvent );
+ bool HandleDummyAuraProc( Unit *pVictim, uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
+ bool HandleHasteAuraProc( Unit *pVictim, uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
+ bool HandleProcTriggerSpell(Unit *pVictim, uint32 damage, Aura* triggredByAura, SpellEntry const *procSpell, uint32 procFlag, uint32 procEx, uint32 cooldown);
+ bool HandleOverrideClassScriptAuraProc(Unit *pVictim, Aura* triggredByAura, SpellEntry const *procSpell, uint32 cooldown);
bool HandleMeandingAuraProc(Aura* triggeredByAura);
uint32 m_state; // Even derived shouldn't modify
diff --git a/src/game/WaypointManager.cpp b/src/game/WaypointManager.cpp
index 57c1734359b..831f616060b 100644
--- a/src/game/WaypointManager.cpp
+++ b/src/game/WaypointManager.cpp
@@ -1,310 +1,342 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
- *
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
- *
- * 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
- */
-
-#include "Database/DatabaseEnv.h"
-#include "GridDefines.h"
-#include "Policies/SingletonImp.h"
-#include "WaypointManager.h"
-#include "ProgressBar.h"
-#include "MapManager.h"
-#include "ObjectMgr.h"
-
-INSTANTIATE_SINGLETON_1(WaypointManager);
-
-bool WaypointBehavior::isEmpty()
-{
- if (emote || spell || model1 || model2)
- return false;
-
- for(int i = 0; i < MAX_WAYPOINT_TEXT; ++i)
- if(textid[i])
- return false;
-
- return true;
-}
-
-WaypointBehavior::WaypointBehavior(const WaypointBehavior &b)
-{
- emote = b.emote;
- spell = b.spell;
- model1 = b.model1;
- model2 = b.model2;
- for(int i=0; i < MAX_WAYPOINT_TEXT; ++i)
- textid[i] = b.textid[i];
-}
-
-void WaypointManager::Load()
-{
- Cleanup();
-
- uint32 total_paths = 0;
- uint32 total_nodes = 0;
- uint32 total_behaviors = 0;
-
- QueryResult *result = WorldDatabase.Query("SELECT id, COUNT(point) FROM creature_movement GROUP BY id");
- if(result)
- {
- total_paths = result->GetRowCount();
- barGoLink bar( total_paths );
- do
- {
- Field *fields = result->Fetch();
- uint32 id = fields[0].GetUInt32();
- uint32 count = fields[1].GetUInt32();
- m_pathMap[id].resize(count);
-
- total_nodes += count;
- bar.step();
- } while( result->NextRow() );
- delete result;
- }
-
- result = WorldDatabase.Query("SELECT position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5, id, point FROM creature_movement");
- if(result)
- {
- barGoLink bar( result->GetRowCount() );
- do
- {
- Field *fields = result->Fetch();
- uint32 point = fields[15].GetUInt32();
- uint32 id = fields[14].GetUInt32();
-
- WaypointPath &path = m_pathMap[id];
- // the cleanup queries make sure the following is true
- assert(point >= 1 && point <= path.size());
- WaypointNode &node = path[point-1];
-
- node.x = fields[0].GetFloat();
- node.y = fields[1].GetFloat();
- node.z = fields[2].GetFloat();
- node.orientation = fields[3].GetFloat();
- node.delay = fields[6].GetUInt16();
-
- // prevent using invalid coordinates
- if(!Trinity::IsValidMapCoord(node.x, node.y, node.z, node.orientation))
- {
- QueryResult *result1 = WorldDatabase.PQuery("SELECT id, map FROM creature WHERE guid = '%u'", id);
- if(result1)
- sLog.outErrorDb("ERROR: Creature (guidlow %d, entry %d) have invalid coordinates in his waypoint %d (X: %f, Y: %f).",
- id, result1->Fetch()[0].GetUInt32(), point, node.x, node.y);
- else
- sLog.outErrorDb("ERROR: Waypoint path %d, have invalid coordinates in his waypoint %d (X: %f, Y: %f).",
- id, point, node.x, node.y);
-
- Trinity::NormalizeMapCoord(node.x);
- Trinity::NormalizeMapCoord(node.y);
- if(result1)
- {
- node.z = MapManager::Instance ().GetBaseMap(result1->Fetch()[1].GetUInt32())->GetHeight(node.x, node.y, node.z);
- delete result1;
- }
- WorldDatabase.PExecute("UPDATE creature_movement SET position_x = '%f', position_y = '%f', position_z = '%f' WHERE id = '%u' AND point = '%u'", node.x, node.y, node.z, id, point);
- }
-
- WaypointBehavior be;
- be.model1 = fields[4].GetUInt32();
- be.model2 = fields[5].GetUInt32();
- be.emote = fields[7].GetUInt32();
- be.spell = fields[8].GetUInt32();
-
- // load and store without holes in array
- int j = 0;
- for(int i = 0; i < MAX_WAYPOINT_TEXT; ++i)
- {
- be.textid[j] = fields[9+i].GetUInt32();
- if(be.textid[j])
- {
- if (be.textid[j] < MIN_DB_SCRIPT_STRING_ID || be.textid[j] >= MAX_DB_SCRIPT_STRING_ID)
- {
- sLog.outErrorDb( "Table `db_script_string` not have string id %u", be.textid[j]);
- continue;
- }
-
- if (!objmgr.GetTrinityStringLocale (be.textid[j]))
- {
- sLog.outErrorDb("ERROR: Waypoint path %d (point %d), have invalid text id (%i) in `textid%d, ignored.",
- id, point, be.textid[j], i+1);
- continue;
- }
-
- ++j; // to next internal field
- }
- }
- // fill array tail
- for(; j < MAX_WAYPOINT_TEXT; ++j)
- be.textid[j] = 0;
-
- // save memory by not storing empty behaviors
- if(!be.isEmpty())
- {
- node.behavior = new WaypointBehavior(be);
- ++total_behaviors;
- }
- else
- node.behavior = NULL;
- bar.step();
- } while( result->NextRow() );
- delete result;
- }
- sLog.outString( ">> Loaded %u paths, %u nodes and %u behaviors", total_paths, total_nodes, total_behaviors);
-}
-
-void WaypointManager::Cleanup()
-{
- // check if points need to be renumbered and do it
- if(QueryResult *result = WorldDatabase.Query("SELECT 1 from creature_movement As T WHERE point <> (SELECT COUNT(*) FROM creature_movement WHERE id = T.id AND point <= T.point) LIMIT 1"))
- {
- delete result;
- WorldDatabase.DirectExecute("CREATE TEMPORARY TABLE temp LIKE creature_movement");
- WorldDatabase.DirectExecute("INSERT INTO temp SELECT * FROM creature_movement");
- WorldDatabase.DirectExecute("ALTER TABLE creature_movement DROP PRIMARY KEY");
- WorldDatabase.DirectExecute("UPDATE creature_movement AS T SET point = (SELECT COUNT(*) FROM temp WHERE id = T.id AND point <= T.point)");
- WorldDatabase.DirectExecute("ALTER TABLE creature_movement ADD PRIMARY KEY (id, point)");
- WorldDatabase.DirectExecute("DROP TABLE temp");
- assert(!(result = WorldDatabase.Query("SELECT 1 from creature_movement As T WHERE point <> (SELECT COUNT(*) FROM creature_movement WHERE id = T.id AND point <= T.point) LIMIT 1")));
- }
-}
-
-void WaypointManager::Unload()
-{
- for(WaypointPathMap::iterator itr = m_pathMap.begin(); itr != m_pathMap.end(); ++itr)
- _clearPath(itr->second);
- m_pathMap.clear();
-}
-
-void WaypointManager::_clearPath(WaypointPath &path)
-{
- for(WaypointPath::iterator itr = path.begin(); itr != path.end(); ++itr)
- if(itr->behavior)
- delete itr->behavior;
- path.clear();
-}
-
-/// - Insert after the last point
-void WaypointManager::AddLastNode(uint32 id, float x, float y, float z, float o, uint32 delay, uint32 wpGuid)
-{
- _addNode(id, GetLastPoint(id, 0) + 1, x, y, z, o, delay, wpGuid);
-}
-
-/// - Insert after a certain point
-void WaypointManager::AddAfterNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid)
-{
- for(uint32 i = GetLastPoint(id, 0); i > point; i--)
- WorldDatabase.PExecuteLog("UPDATE creature_movement SET point=point+1 WHERE id='%u' AND point='%u'", id, i);
-
- _addNode(id, point + 1, x, y, z, o, delay, wpGuid);
-}
-
-/// - Insert without checking for collision
-void WaypointManager::_addNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid)
-{
- if(point == 0) return; // counted from 1 in the DB
- WorldDatabase.PExecuteLog("INSERT INTO creature_movement (id,point,position_x,position_y,position_z,orientation,wpguid,waittime) VALUES ('%u','%u','%f', '%f', '%f', '%f', '%d', '%d')", id, point, x, y, z, o, wpGuid, delay);
- WaypointPathMap::iterator itr = m_pathMap.find(id);
- if(itr == m_pathMap.end())
- itr = m_pathMap.insert(WaypointPathMap::value_type(id, WaypointPath())).first;
- itr->second.insert(itr->second.begin() + (point - 1), WaypointNode(x, y, z, o, delay, NULL));
-}
-
-uint32 WaypointManager::GetLastPoint(uint32 id, uint32 default_notfound)
-{
- uint32 point = default_notfound;
- /*QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM creature_movement WHERE id = '%u'", id);
- if( result )
- {
- point = (*result)[0].GetUInt32()+1;
- delete result;
- }*/
- WaypointPathMap::iterator itr = m_pathMap.find(id);
- if(itr != m_pathMap.end() && itr->second.size() != 0)
- point = itr->second.size();
- return point;
-}
-
-void WaypointManager::DeleteNode(uint32 id, uint32 point)
-{
- if(point == 0) return; // counted from 1 in the DB
- WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id='%u' AND point='%u'", id, point);
- WorldDatabase.PExecuteLog("UPDATE creature_movement SET point=point-1 WHERE id='%u' AND point>'%u'", id, point);
- WaypointPathMap::iterator itr = m_pathMap.find(id);
- if(itr != m_pathMap.end() && point <= itr->second.size())
- itr->second.erase(itr->second.begin() + (point-1));
-}
-
-void WaypointManager::DeletePath(uint32 id)
-{
- WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id='%u'", id);
- WaypointPathMap::iterator itr = m_pathMap.find(id);
- if(itr != m_pathMap.end())
- _clearPath(itr->second);
- // the path is not removed from the map, just cleared
- // WMGs have pointers to the path, so deleting them would crash
- // this wastes some memory, but these functions are
- // only meant to be called by GM commands
-}
-
-void WaypointManager::SetNodePosition(uint32 id, uint32 point, float x, float y, float z)
-{
- if(point == 0) return; // counted from 1 in the DB
- WorldDatabase.PExecuteLog("UPDATE creature_movement SET position_x = '%f',position_y = '%f',position_z = '%f' where id = '%u' AND point='%u'", x, y, z, id, point);
- WaypointPathMap::iterator itr = m_pathMap.find(id);
- if(itr != m_pathMap.end() && point <= itr->second.size())
- {
- itr->second[point-1].x = x;
- itr->second[point-1].y = y;
- itr->second[point-1].z = z;
- }
-}
-
-void WaypointManager::SetNodeText(uint32 id, uint32 point, const char *text_field, const char *text)
-{
- if(point == 0) return; // counted from 1 in the DB
- if(!text_field) return;
- std::string field = text_field;
- WorldDatabase.escape_string(field);
-
- if(!text)
- {
- WorldDatabase.PExecuteLog("UPDATE creature_movement SET %s=NULL WHERE id='%u' AND point='%u'", field.c_str(), id, point);
- }
- else
- {
- std::string text2 = text;
- WorldDatabase.escape_string(text2);
- WorldDatabase.PExecuteLog("UPDATE creature_movement SET %s='%s' WHERE id='%u' AND point='%u'", field.c_str(), text2.c_str(), id, point);
- }
-
- WaypointPathMap::iterator itr = m_pathMap.find(id);
- if(itr != m_pathMap.end() && point <= itr->second.size())
- {
- WaypointNode &node = itr->second[point-1];
- if(!node.behavior) node.behavior = new WaypointBehavior();
-
-// if(field == "text1") node.behavior->text[0] = text ? text : "";
-// if(field == "text2") node.behavior->text[1] = text ? text : "";
-// if(field == "text3") node.behavior->text[2] = text ? text : "";
-// if(field == "text4") node.behavior->text[3] = text ? text : "";
-// if(field == "text5") node.behavior->text[4] = text ? text : "";
- if(field == "emote") node.behavior->emote = text ? atoi(text) : 0;
- if(field == "spell") node.behavior->spell = text ? atoi(text) : 0;
- if(field == "model1") node.behavior->model1 = text ? atoi(text) : 0;
- if(field == "model2") node.behavior->model2 = text ? atoi(text) : 0;
- }
-}
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ *
+ * 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
+ */
+
+#include "Database/DatabaseEnv.h"
+#include "GridDefines.h"
+#include "Policies/SingletonImp.h"
+#include "WaypointManager.h"
+#include "ProgressBar.h"
+#include "MapManager.h"
+#include "ObjectMgr.h"
+
+INSTANTIATE_SINGLETON_1(WaypointManager);
+
+bool WaypointBehavior::isEmpty()
+{
+ if (emote || spell || model1 || model2)
+ return false;
+
+ for(int i = 0; i < MAX_WAYPOINT_TEXT; ++i)
+ if(textid[i])
+ return false;
+
+ return true;
+}
+
+WaypointBehavior::WaypointBehavior(const WaypointBehavior &b)
+{
+ emote = b.emote;
+ spell = b.spell;
+ model1 = b.model1;
+ model2 = b.model2;
+ for(int i=0; i < MAX_WAYPOINT_TEXT; ++i)
+ textid[i] = b.textid[i];
+}
+
+void WaypointManager::Load()
+{
+ Cleanup();
+
+ uint32 total_paths = 0;
+ uint32 total_nodes = 0;
+ uint32 total_behaviors = 0;
+
+ QueryResult *result = WorldDatabase.Query("SELECT id, COUNT(point) FROM creature_movement GROUP BY id");
+ if(result)
+ {
+ total_paths = result->GetRowCount();
+ barGoLink bar( total_paths );
+ do
+ {
+ Field *fields = result->Fetch();
+ uint32 id = fields[0].GetUInt32();
+ uint32 count = fields[1].GetUInt32();
+ m_pathMap[id].resize(count);
+
+ total_nodes += count;
+ bar.step();
+ } while( result->NextRow() );
+ delete result;
+ }
+
+ result = WorldDatabase.Query("SELECT position_x, position_y, position_z, orientation, model1, model2, waittime, emote, spell, textid1, textid2, textid3, textid4, textid5, id, point FROM creature_movement");
+ if(result)
+ {
+ barGoLink bar( result->GetRowCount() );
+ do
+ {
+ Field *fields = result->Fetch();
+ uint32 point = fields[15].GetUInt32();
+ uint32 id = fields[14].GetUInt32();
+
+ WaypointPath &path = m_pathMap[id];
+ // the cleanup queries make sure the following is true
+ assert(point >= 1 && point <= path.size());
+ WaypointNode &node = path[point-1];
+
+ node.x = fields[0].GetFloat();
+ node.y = fields[1].GetFloat();
+ node.z = fields[2].GetFloat();
+ node.orientation = fields[3].GetFloat();
+ node.delay = fields[6].GetUInt16();
+
+ // prevent using invalid coordinates
+ if(!Trinity::IsValidMapCoord(node.x, node.y, node.z, node.orientation))
+ {
+ QueryResult *result1 = WorldDatabase.PQuery("SELECT id, map FROM creature WHERE guid = '%u'", id);
+ if(result1)
+ sLog.outErrorDb("ERROR: Creature (guidlow %d, entry %d) have invalid coordinates in his waypoint %d (X: %f, Y: %f).",
+ id, result1->Fetch()[0].GetUInt32(), point, node.x, node.y);
+ else
+ sLog.outErrorDb("ERROR: Waypoint path %d, have invalid coordinates in his waypoint %d (X: %f, Y: %f).",
+ id, point, node.x, node.y);
+
+ Trinity::NormalizeMapCoord(node.x);
+ Trinity::NormalizeMapCoord(node.y);
+ if(result1)
+ {
+ node.z = MapManager::Instance ().GetBaseMap(result1->Fetch()[1].GetUInt32())->GetHeight(node.x, node.y, node.z);
+ delete result1;
+ }
+ WorldDatabase.PExecute("UPDATE creature_movement SET position_x = '%f', position_y = '%f', position_z = '%f' WHERE id = '%u' AND point = '%u'", node.x, node.y, node.z, id, point);
+ }
+
+ WaypointBehavior be;
+ be.model1 = fields[4].GetUInt32();
+ be.model2 = fields[5].GetUInt32();
+ be.emote = fields[7].GetUInt32();
+ be.spell = fields[8].GetUInt32();
+
+ for(int i = 0; i < MAX_WAYPOINT_TEXT; ++i)
+ {
+ be.textid[i] = fields[9+i].GetUInt32();
+ if(be.textid[i])
+ {
+ if (be.textid[i] < MIN_DB_SCRIPT_STRING_ID || be.textid[i] >= MAX_DB_SCRIPT_STRING_ID)
+ {
+ sLog.outErrorDb( "Table `db_script_string` not have string id %u", be.textid[i]);
+ continue;
+ }
+ }
+ }
+
+ // save memory by not storing empty behaviors
+ if(!be.isEmpty())
+ {
+ node.behavior = new WaypointBehavior(be);
+ ++total_behaviors;
+ }
+ else
+ node.behavior = NULL;
+ bar.step();
+ } while( result->NextRow() );
+ delete result;
+ }
+ sLog.outString( ">> Loaded %u paths, %u nodes and %u behaviors", total_paths, total_nodes, total_behaviors);
+}
+
+void WaypointManager::Cleanup()
+{
+ // check if points need to be renumbered and do it
+ if(QueryResult *result = WorldDatabase.Query("SELECT 1 from creature_movement As T WHERE point <> (SELECT COUNT(*) FROM creature_movement WHERE id = T.id AND point <= T.point) LIMIT 1"))
+ {
+ delete result;
+ WorldDatabase.DirectExecute("CREATE TEMPORARY TABLE temp LIKE creature_movement");
+ WorldDatabase.DirectExecute("INSERT INTO temp SELECT * FROM creature_movement");
+ WorldDatabase.DirectExecute("ALTER TABLE creature_movement DROP PRIMARY KEY");
+ WorldDatabase.DirectExecute("UPDATE creature_movement AS T SET point = (SELECT COUNT(*) FROM temp WHERE id = T.id AND point <= T.point)");
+ WorldDatabase.DirectExecute("ALTER TABLE creature_movement ADD PRIMARY KEY (id, point)");
+ WorldDatabase.DirectExecute("DROP TABLE temp");
+ assert(!(result = WorldDatabase.Query("SELECT 1 from creature_movement As T WHERE point <> (SELECT COUNT(*) FROM creature_movement WHERE id = T.id AND point <= T.point) LIMIT 1")));
+ }
+}
+
+void WaypointManager::Unload()
+{
+ for(WaypointPathMap::iterator itr = m_pathMap.begin(); itr != m_pathMap.end(); ++itr)
+ _clearPath(itr->second);
+ m_pathMap.clear();
+}
+
+void WaypointManager::_clearPath(WaypointPath &path)
+{
+ for(WaypointPath::iterator itr = path.begin(); itr != path.end(); ++itr)
+ if(itr->behavior)
+ delete itr->behavior;
+ path.clear();
+}
+
+/// - Insert after the last point
+void WaypointManager::AddLastNode(uint32 id, float x, float y, float z, float o, uint32 delay, uint32 wpGuid)
+{
+ _addNode(id, GetLastPoint(id, 0) + 1, x, y, z, o, delay, wpGuid);
+}
+
+/// - Insert after a certain point
+void WaypointManager::AddAfterNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid)
+{
+ for(uint32 i = GetLastPoint(id, 0); i > point; i--)
+ WorldDatabase.PExecuteLog("UPDATE creature_movement SET point=point+1 WHERE id='%u' AND point='%u'", id, i);
+
+ _addNode(id, point + 1, x, y, z, o, delay, wpGuid);
+}
+
+/// - Insert without checking for collision
+void WaypointManager::_addNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid)
+{
+ if(point == 0) return; // counted from 1 in the DB
+ WorldDatabase.PExecuteLog("INSERT INTO creature_movement (id,point,position_x,position_y,position_z,orientation,wpguid,waittime) VALUES ('%u','%u','%f', '%f', '%f', '%f', '%d', '%d')", id, point, x, y, z, o, wpGuid, delay);
+ WaypointPathMap::iterator itr = m_pathMap.find(id);
+ if(itr == m_pathMap.end())
+ itr = m_pathMap.insert(WaypointPathMap::value_type(id, WaypointPath())).first;
+ itr->second.insert(itr->second.begin() + (point - 1), WaypointNode(x, y, z, o, delay, NULL));
+}
+
+uint32 WaypointManager::GetLastPoint(uint32 id, uint32 default_notfound)
+{
+ uint32 point = default_notfound;
+ /*QueryResult *result = WorldDatabase.PQuery( "SELECT MAX(point) FROM creature_movement WHERE id = '%u'", id);
+ if( result )
+ {
+ point = (*result)[0].GetUInt32()+1;
+ delete result;
+ }*/
+ WaypointPathMap::iterator itr = m_pathMap.find(id);
+ if(itr != m_pathMap.end() && itr->second.size() != 0)
+ point = itr->second.size();
+ return point;
+}
+
+void WaypointManager::DeleteNode(uint32 id, uint32 point)
+{
+ if(point == 0) return; // counted from 1 in the DB
+ WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id='%u' AND point='%u'", id, point);
+ WorldDatabase.PExecuteLog("UPDATE creature_movement SET point=point-1 WHERE id='%u' AND point>'%u'", id, point);
+ WaypointPathMap::iterator itr = m_pathMap.find(id);
+ if(itr != m_pathMap.end() && point <= itr->second.size())
+ itr->second.erase(itr->second.begin() + (point-1));
+}
+
+void WaypointManager::DeletePath(uint32 id)
+{
+ WorldDatabase.PExecuteLog("DELETE FROM creature_movement WHERE id='%u'", id);
+ WaypointPathMap::iterator itr = m_pathMap.find(id);
+ if(itr != m_pathMap.end())
+ _clearPath(itr->second);
+ // the path is not removed from the map, just cleared
+ // WMGs have pointers to the path, so deleting them would crash
+ // this wastes some memory, but these functions are
+ // only meant to be called by GM commands
+}
+
+void WaypointManager::SetNodePosition(uint32 id, uint32 point, float x, float y, float z)
+{
+ if(point == 0) return; // counted from 1 in the DB
+ WorldDatabase.PExecuteLog("UPDATE creature_movement SET position_x = '%f',position_y = '%f',position_z = '%f' where id = '%u' AND point='%u'", x, y, z, id, point);
+ WaypointPathMap::iterator itr = m_pathMap.find(id);
+ if(itr != m_pathMap.end() && point <= itr->second.size())
+ {
+ itr->second[point-1].x = x;
+ itr->second[point-1].y = y;
+ itr->second[point-1].z = z;
+ }
+}
+
+void WaypointManager::SetNodeText(uint32 id, uint32 point, const char *text_field, const char *text)
+{
+ if(point == 0) return; // counted from 1 in the DB
+ if(!text_field) return;
+ std::string field = text_field;
+ WorldDatabase.escape_string(field);
+
+ if(!text)
+ {
+ WorldDatabase.PExecuteLog("UPDATE creature_movement SET %s=NULL WHERE id='%u' AND point='%u'", field.c_str(), id, point);
+ }
+ else
+ {
+ std::string text2 = text;
+ WorldDatabase.escape_string(text2);
+ WorldDatabase.PExecuteLog("UPDATE creature_movement SET %s='%s' WHERE id='%u' AND point='%u'", field.c_str(), text2.c_str(), id, point);
+ }
+
+ WaypointPathMap::iterator itr = m_pathMap.find(id);
+ if(itr != m_pathMap.end() && point <= itr->second.size())
+ {
+ WaypointNode &node = itr->second[point-1];
+ if(!node.behavior) node.behavior = new WaypointBehavior();
+
+// if(field == "text1") node.behavior->text[0] = text ? text : "";
+// if(field == "text2") node.behavior->text[1] = text ? text : "";
+// if(field == "text3") node.behavior->text[2] = text ? text : "";
+// if(field == "text4") node.behavior->text[3] = text ? text : "";
+// if(field == "text5") node.behavior->text[4] = text ? text : "";
+ if(field == "emote") node.behavior->emote = text ? atoi(text) : 0;
+ if(field == "spell") node.behavior->spell = text ? atoi(text) : 0;
+ if(field == "model1") node.behavior->model1 = text ? atoi(text) : 0;
+ if(field == "model2") node.behavior->model2 = text ? atoi(text) : 0;
+ }
+}
+
+void WaypointManager::CheckTextsExistance(std::set<int32>& ids)
+{
+ WaypointPathMap::iterator pmItr = m_pathMap.begin();
+ for ( ; pmItr != m_pathMap.end(); ++pmItr)
+ {
+ for (int i = 0; i < pmItr->second.size(); ++i)
+ {
+ if (!pmItr->second[i].behavior)
+ continue;
+
+ // Now we check text existence and put all zero texts ids to the end of array
+
+ // Counting leading zeros for futher textid shift
+ int zeroCount = 0;
+ for (int j = 0; j < MAX_WAYPOINT_TEXT; ++j)
+ {
+ if (!pmItr->second[i].behavior->textid[j])
+ {
+ ++zeroCount;
+ continue;
+ }
+ else
+ {
+ if (!objmgr.GetTrinityStringLocale(pmItr->second[i].behavior->textid[j]))
+ {
+ sLog.outErrorDb("ERROR: Some waypoint has textid%u with not existing %u text.", j, pmItr->second[i].behavior->textid[j]);
+ pmItr->second[i].behavior->textid[j] = 0;
+ ++zeroCount;
+ continue;
+ }
+ else
+ ids.erase(pmItr->second[i].behavior->textid[j]);
+
+ // Shifting check
+ if (zeroCount)
+ {
+ // Correct textid but some zeros leading, so move it forward.
+ pmItr->second[i].behavior->textid[j-zeroCount] = pmItr->second[i].behavior->textid[j];
+ pmItr->second[i].behavior->textid[j] = 0;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/game/WaypointManager.h b/src/game/WaypointManager.h
index c7e8e0fb530..38cf5551d64 100644
--- a/src/game/WaypointManager.h
+++ b/src/game/WaypointManager.h
@@ -1,92 +1,93 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
- *
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
- *
- * 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
- */
-
-#ifndef TRINITY_WAYPOINTMANAGER_H
-#define TRINITY_WAYPOINTMANAGER_H
-
-#include <vector>
-#include <string>
-#include "Utilities/UnorderedMap.h"
-
-#define MAX_WAYPOINT_TEXT 5
-struct WaypointBehavior
-{
- uint32 emote;
- uint32 spell;
- int32 textid[MAX_WAYPOINT_TEXT];
- uint32 model1;
- uint32 model2;
-
- bool isEmpty();
- WaypointBehavior() {}
- WaypointBehavior(const WaypointBehavior &b);
-};
-
-struct WaypointNode
-{
- float x;
- float y;
- float z;
- float orientation;
- uint32 delay;
- WaypointBehavior * behavior;
- WaypointNode() {}
- WaypointNode(float _x, float _y, float _z, float _o, uint32 _delay, WaypointBehavior * _behavior)
- : x(_x), y(_y), z(_z), orientation(_o), delay(_delay), behavior(_behavior) {}
-};
-
-typedef std::vector<WaypointNode> WaypointPath;
-
-class WaypointManager
-{
- public:
- WaypointManager() {}
- ~WaypointManager() { Unload(); }
-
- void Load();
- void Unload();
-
- void Cleanup();
-
- WaypointPath *GetPath(uint32 id)
- {
- WaypointPathMap::iterator itr = m_pathMap.find(id);
- return itr != m_pathMap.end() ? &itr->second : NULL;
- }
-
- void AddLastNode(uint32 id, float x, float y, float z, float o, uint32 delay, uint32 wpGuid);
- void AddAfterNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid);
- uint32 GetLastPoint(uint32 id, uint32 default_notfound);
- void DeleteNode(uint32 id, uint32 point);
- void DeletePath(uint32 id);
- void SetNodePosition(uint32 id, uint32 point, float x, float y, float z);
- void SetNodeText(uint32 id, uint32 point, const char *text_field, const char *text);
-
- private:
- void _addNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid);
- void _clearPath(WaypointPath &path);
-
- typedef UNORDERED_MAP<uint32, WaypointPath> WaypointPathMap;
- WaypointPathMap m_pathMap;
-};
-
-#define WaypointMgr Trinity::Singleton<WaypointManager>::Instance()
-
-#endif
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ *
+ * 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
+ */
+
+#ifndef TRINITY_WAYPOINTMANAGER_H
+#define TRINITY_WAYPOINTMANAGER_H
+
+#include <vector>
+#include <string>
+#include "Utilities/UnorderedMap.h"
+
+#define MAX_WAYPOINT_TEXT 5
+struct WaypointBehavior
+{
+ uint32 emote;
+ uint32 spell;
+ int32 textid[MAX_WAYPOINT_TEXT];
+ uint32 model1;
+ uint32 model2;
+
+ bool isEmpty();
+ WaypointBehavior() {}
+ WaypointBehavior(const WaypointBehavior &b);
+};
+
+struct WaypointNode
+{
+ float x;
+ float y;
+ float z;
+ float orientation;
+ uint32 delay;
+ WaypointBehavior * behavior;
+ WaypointNode() {}
+ WaypointNode(float _x, float _y, float _z, float _o, uint32 _delay, WaypointBehavior * _behavior)
+ : x(_x), y(_y), z(_z), orientation(_o), delay(_delay), behavior(_behavior) {}
+};
+
+typedef std::vector<WaypointNode> WaypointPath;
+
+class WaypointManager
+{
+ public:
+ WaypointManager() {}
+ ~WaypointManager() { Unload(); }
+
+ void Load();
+ void Unload();
+
+ void Cleanup();
+
+ WaypointPath *GetPath(uint32 id)
+ {
+ WaypointPathMap::iterator itr = m_pathMap.find(id);
+ return itr != m_pathMap.end() ? &itr->second : NULL;
+ }
+
+ void AddLastNode(uint32 id, float x, float y, float z, float o, uint32 delay, uint32 wpGuid);
+ void AddAfterNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid);
+ uint32 GetLastPoint(uint32 id, uint32 default_notfound);
+ void DeleteNode(uint32 id, uint32 point);
+ void DeletePath(uint32 id);
+ void SetNodePosition(uint32 id, uint32 point, float x, float y, float z);
+ void SetNodeText(uint32 id, uint32 point, const char *text_field, const char *text);
+ void CheckTextsExistance(std::set<int32>& ids);
+
+ private:
+ void _addNode(uint32 id, uint32 point, float x, float y, float z, float o, uint32 delay, uint32 wpGuid);
+ void _clearPath(WaypointPath &path);
+
+ typedef UNORDERED_MAP<uint32, WaypointPath> WaypointPathMap;
+ WaypointPathMap m_pathMap;
+};
+
+#define WaypointMgr Trinity::Singleton<WaypointManager>::Instance()
+
+#endif
diff --git a/src/game/WaypointMovementGenerator.cpp b/src/game/WaypointMovementGenerator.cpp
index 4de150a4af5..3dc3ddebf42 100644
--- a/src/game/WaypointMovementGenerator.cpp
+++ b/src/game/WaypointMovementGenerator.cpp
@@ -1,652 +1,653 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
- *
- * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
- *
- * 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
- */
-
-/*
-creature_movement Table
-
-alter table creature_movement add `textid1` int(11) NOT NULL default '0';
-alter table creature_movement add `textid2` int(11) NOT NULL default '0';
-alter table creature_movement add `textid3` int(11) NOT NULL default '0';
-alter table creature_movement add `textid4` int(11) NOT NULL default '0';
-alter table creature_movement add `textid5` int(11) NOT NULL default '0';
-alter table creature_movement add `emote` int(10) unsigned default '0';
-alter table creature_movement add `spell` int(5) unsigned default '0';
-alter table creature_movement add `wpguid` int(11) default '0';
-
-*/
-
-#include <ctime>
-
-#include "WaypointMovementGenerator.h"
-#include "ObjectMgr.h"
-#include "Creature.h"
-#include "DestinationHolderImp.h"
-#include "CreatureAI.h"
-#include "WaypointManager.h"
-
-#include <cassert>
-
-//-----------------------------------------------//
-void
-WaypointMovementGenerator<Creature>::LoadPath(Creature &c)
-{
- sLog.outDetail("LoadPath: loading waypoint path for creature %d,%d", c.GetGUIDLow(), c.GetDBTableGUIDLow());
-
- i_path = WaypointMgr.GetPath(c.GetDBTableGUIDLow());
- if(!i_path)
- {
- sLog.outErrorDb("WaypointMovementGenerator::LoadPath: creature %s(%d) doesn't have waypoint path", c.GetName(), c.GetDBTableGUIDLow());
- return;
- }
-
- uint32 node_count = i_path->size();
- i_hasDone.resize(node_count);
- for(uint32 i = 0; i < node_count-1; i++)
- i_hasDone[i] = false;
-
- // to prevent a misbehaviour inside "update"
- // update is always called with the next wp - but the wpSys needs the current
- // so when the routine is called the first time, wpSys gets the last waypoint
- // and this prevents the system from performing text/emote, etc
- i_hasDone[node_count - 1] = true;
-}
-
-void
-WaypointMovementGenerator<Creature>::ClearWaypoints()
-{
- i_path = NULL;
-}
-
-void
-WaypointMovementGenerator<Creature>::Initialize()
-{
-}
-
-bool
-WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff)
-{
- if(!&creature)
- return true;
-
- // Waypoint movement can be switched on/off
- // This is quite handy for escort quests and other stuff
- if(creature.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
- return true;
-
- // prevent a crash at empty waypoint path.
- if(!i_path || i_path->empty())
- return true;
-
- // i_path was modified by chat commands for example
- if(i_path->size() != i_hasDone.size())
- i_hasDone.resize(i_path->size());
- if(i_currentNode >= i_path->size())
- i_currentNode = 0;
-
- CreatureTraveller traveller(creature);
-
- i_nextMoveTime.Update(diff);
- i_destinationHolder.UpdateTraveller(traveller, diff, false, true);
-
- // creature has been stoped in middle of the waypoint segment
- if (!i_destinationHolder.HasArrived() && creature.IsStopped())
- {
- if( i_nextMoveTime.Passed()) // Timer has elapsed, meaning this part controlled it
- {
- SetStopedByPlayer(false);
- // Now we re-set destination to same node and start travel
- creature.addUnitState(UNIT_STAT_ROAMING);
- if (creature.canFly())
- creature.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
- const WaypointNode &node = i_path->at(i_currentNode);
- i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
- i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
- }
- else // if( !i_nextMoveTime.Passed())
- { // unexpected end of timer && creature stopped && not at end of segment
- if (!IsStopedByPlayer())
- { // Put 30 seconds delay
- i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER);
- i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER);
- SetStopedByPlayer(true); // Mark we did it
- }
- }
- return true; // Abort here this update
- }
-
- if( creature.IsStopped())
- {
- uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1;
-
- if (!i_hasDone[idx])
- {
- if (i_path->at(idx).orientation !=100)
- creature.SetOrientation(i_path->at(idx).orientation);
-
- if(WaypointBehavior *behavior = i_path->at(idx).behavior)
- {
- if(behavior->emote != 0)
- creature.SetUInt32Value(UNIT_NPC_EMOTESTATE,behavior->emote);
- if(behavior->spell != 0)
- creature.CastSpell(&creature,behavior->spell, false);
- if(behavior->model1 != 0)
- creature.SetDisplayId(behavior->model1);
- if(behavior->textid[0])
- {
- // Not only one text is set
- if( behavior->textid[1] )
- {
- // Select one from max 5 texts (0 and 1 already checked)
- int i = 2;
- for( ; i < MAX_WAYPOINT_TEXT; ++i )
- if( !behavior->textid[i] )
- break;
-
- creature.Say(behavior->textid[rand() % i], 0, 0);
- }
- else
- creature.Say(behavior->textid[0], 0, 0);
- }
- } // wpBehaviour found
- i_hasDone[idx] = true;
- MovementInform(creature);
- } // HasDone == false
- } // i_creature.IsStopped()
-
- if( i_nextMoveTime.Passed() ) // This is at the end of waypoint segment or has been stopped by player
- {
- if( creature.IsStopped() ) // If stopped then begin a new move segment
- {
- creature.addUnitState(UNIT_STAT_ROAMING);
- if (creature.canFly())
- creature.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
- const WaypointNode &node = i_path->at(i_currentNode);
- i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
- i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
- uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1;
-
- if (i_path->at(idx).orientation !=100)
- creature.SetOrientation(i_path->at(idx).orientation);
-
- if(WaypointBehavior *behavior = i_path->at(idx).behavior )
- {
- i_hasDone[idx] = false;
- if(behavior->model2 != 0)
- creature.SetDisplayId(behavior->model2);
-
- creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
- }
- }
- else // If not stopped then stop it and set the reset of TimeTracker to waittime
- {
- creature.StopMoving();
- SetStopedByPlayer(false);
- i_nextMoveTime.Reset(i_path->at(i_currentNode).delay);
- ++i_currentNode;
- if( i_currentNode >= i_path->size() )
- i_currentNode = 0;
- }
- }
- return true;
-}
-
-void WaypointMovementGenerator<Creature>::MovementInform(Creature &unit)
-{
- if(unit.AI())
- unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
-}
-
-//----------------------------------------------------//
-void
-FlightPathMovementGenerator::LoadPath(Player &)
-{
- objmgr.GetTaxiPathNodes(i_pathId, i_path,i_mapIds);
-}
-
-uint32
-FlightPathMovementGenerator::GetPathAtMapEnd() const
-{
- if(i_currentNode >= i_mapIds.size())
- return i_mapIds.size();
-
- uint32 curMapId = i_mapIds[i_currentNode];
- for(uint32 i = i_currentNode; i < i_mapIds.size(); ++i)
- {
- if(i_mapIds[i] != curMapId)
- return i;
- }
-
- return i_mapIds.size();
-}
-
-void
-FlightPathMovementGenerator::Initialize(Player &player)
-{
- player.getHostilRefManager().setOnlineOfflineState(false);
- player.addUnitState(UNIT_STAT_IN_FLIGHT);
- player.SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
- LoadPath(player);
- Traveller<Player> traveller(player);
- // do not send movement, it was sent already
- i_destinationHolder.SetDestination(traveller, i_path[i_currentNode].x, i_path[i_currentNode].y, i_path[i_currentNode].z, false);
-
- player.SendMonsterMoveByPath(GetPath(),GetCurrentNode(),GetPathAtMapEnd(),MOVEMENTFLAG_WALK_MODE|MOVEMENTFLAG_ONTRANSPORT);
-}
-
-void FlightPathMovementGenerator::Finalize(Player & player)
-{
-
- float x, y, z;
- i_destinationHolder.GetLocationNow(player.GetMapId(), x, y, z);
- player.SetPosition(x, y, z, player.GetOrientation());
-
- player.clearUnitState(UNIT_STAT_IN_FLIGHT);
- player.Unmount();
- player.RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
-
- if(player.m_taxi.empty())
- {
- player.getHostilRefManager().setOnlineOfflineState(true);
- if(player.pvpInfo.inHostileArea)
- player.CastSpell(&player, 2479, true);
-
- player.SetUnitMovementFlags(MOVEMENTFLAG_WALK_MODE);
- player.StopMoving();
- }
-}
-
-bool
-FlightPathMovementGenerator::Update(Player &player, const uint32 &diff)
-{
- if( MovementInProgress() )
- {
- Traveller<Player> traveller(player);
- if( i_destinationHolder.UpdateTraveller(traveller, diff, false) )
- {
- i_destinationHolder.ResetUpdate(FLIGHT_TRAVEL_UPDATE);
- if( i_destinationHolder.HasArrived() )
- {
- uint32 curMap = i_mapIds[i_currentNode];
- ++i_currentNode;
- if( MovementInProgress() )
- {
- DEBUG_LOG("loading node %u for player %s", i_currentNode, player.GetName());
- if(i_mapIds[i_currentNode]==curMap)
- {
- // do not send movement, it was sent already
- i_destinationHolder.SetDestination(traveller, i_path[i_currentNode].x, i_path[i_currentNode].y, i_path[i_currentNode].z, false);
- }
- return true;
- }
- //else HasArrived()
- }
- else
- return true;
- }
- else
- return true;
- }
-
- // we have arrived at the end of the path
- return false;
-}
-
-void
-FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
-{
- if(i_mapIds.empty())
- return;
-
- uint32 map0 = i_mapIds[0];
- for(int i = 1; i < i_mapIds.size(); ++i)
- {
- if(i_mapIds[i]!=map0)
- {
- i_currentNode = i;
- return;
- }
- }
-}
-
-//
-// Unique1's ASTAR Pathfinding Code... For future use & reference...
-//
-
-#ifdef __PATHFINDING__
-
-int GetFCost(int to, int num, int parentNum, float *gcost); // Below...
-
-int ShortenASTARRoute(short int *pathlist, int number)
-{ // Wrote this to make the routes a little smarter (shorter)... No point looping back to the same places... Unique1
- short int temppathlist[MAX_PATHLIST_NODES];
- int count = 0;
- // int count2 = 0;
- int temp, temp2;
- int link;
- int upto = 0;
-
- for (temp = number; temp >= 0; temp--)
- {
- qboolean shortened = qfalse;
-
- for (temp2 = 0; temp2 < temp; temp2++)
- {
- for (link = 0; link < nodes[pathlist[temp]].enodenum; link++)
- {
- if (nodes[pathlist[temp]].links[link].flags & PATH_BLOCKED)
- continue;
-
- //if ((bot->client->ps.eFlags & EF_TANK) && nodes[bot->current_node].links[link].flags & PATH_NOTANKS) //if this path is blocked, skip it
- // continue;
-
- //if (nodes[nodes[pathlist[temp]].links[link].targetNode].origin[2] > nodes[pathlist[temp]].origin[2] + 32)
- // continue;
-
- if (nodes[pathlist[temp]].links[link].targetNode == pathlist[temp2])
- { // Found a shorter route...
- //if (OrgVisible(nodes[pathlist[temp2]].origin, nodes[pathlist[temp]].origin, -1))
- {
- temppathlist[count] = pathlist[temp2];
- temp = temp2;
- ++count;
- shortened = qtrue;
- }
- }
- }
- }
-
- if (!shortened)
- {
- temppathlist[count] = pathlist[temp];
- ++count;
- }
- }
-
- upto = count;
-
- for (temp = 0; temp < count; temp++)
- {
- pathlist[temp] = temppathlist[upto];
- --upto;
- }
-
- G_Printf("ShortenASTARRoute: Path size reduced from %i to %i nodes...n", number, count);
- return count;
-}
-
-/*
-===========================================================================
-CreatePathAStar
-This function uses the A* pathfinding algorithm to determine the
-shortest path between any two nodes.
-It's fairly complex, so I'm not really going to explain it much.
-Look up A* and binary heaps for more info.
-pathlist stores the ideal path between the nodes, in reverse order,
-and the return value is the number of nodes in that path
-===========================================================================
-*/
-int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist)
-{
- //all the data we have to hold...since we can't do dynamic allocation, has to be MAX_NODES
- //we can probably lower this later - eg, the open list should never have more than at most a few dozen items on it
- short int openlist[MAX_NODES+1]; //add 1 because it's a binary heap, and they don't use 0 - 1 is the first used index
- float gcost[MAX_NODES];
- int fcost[MAX_NODES];
- char list[MAX_NODES]; //0 is neither, 1 is open, 2 is closed - char because it's the smallest data type
- short int parent[MAX_NODES];
-
- short int numOpen = 0;
- short int atNode, temp, newnode=-1;
- qboolean found = qfalse;
- int count = -1;
- float gc;
- int i, u, v, m;
- vec3_t vec;
-
- //clear out all the arrays
- memset(openlist, 0, sizeof(short int)*(MAX_NODES+1));
- memset(fcost, 0, sizeof(int)*MAX_NODES);
- memset(list, 0, sizeof(char)*MAX_NODES);
- memset(parent, 0, sizeof(short int)*MAX_NODES);
- memset(gcost, -1, sizeof(float)*MAX_NODES);
-
- //make sure we have valid data before calculating everything
- if ((from == NODE_INVALID) || (to == NODE_INVALID) || (from >= MAX_NODES) || (to >= MAX_NODES) || (from == to))
- return -1;
-
- openlist[1] = from; //add the starting node to the open list
- ++numOpen;
- gcost[from] = 0; //its f and g costs are obviously 0
- fcost[from] = 0;
-
- while (1)
- {
- if (numOpen != 0) //if there are still items in the open list
- {
- //pop the top item off of the list
- atNode = openlist[1];
- list[atNode] = 2; //put the node on the closed list so we don't check it again
- --numOpen;
-
- openlist[1] = openlist[numOpen+1]; //move the last item in the list to the top position
- v = 1;
-
- //this while loop reorders the list so that the new lowest fcost is at the top again
- while (1)
- {
- u = v;
- if ((2*u+1) < numOpen) //if both children exist
- {
- if (fcost[openlist[u]] >= fcost[openlist[2*u]])
- v = 2*u;
- if (fcost[openlist[v]] >= fcost[openlist[2*u+1]])
- v = 2*u+1;
- }
- else
- {
- if ((2*u) < numOpen) //if only one child exists
- {
- if (fcost[openlist[u]] >= fcost[openlist[2*u]])
- v = 2*u;
- }
- }
-
- if (u != v) //if they're out of order, swap this item with its parent
- {
- temp = openlist[u];
- openlist[u] = openlist[v];
- openlist[v] = temp;
- }
- else
- break;
- }
-
- for (i = 0; i < nodes[atNode].enodenum; i++) //loop through all the links for this node
- {
- newnode = nodes[atNode].links[i].targetNode;
-
- //if this path is blocked, skip it
- if (nodes[atNode].links[i].flags & PATH_BLOCKED)
- continue;
- //if this path is blocked, skip it
- if (bot->client && (bot->client->ps.eFlags & EF_TANK) && nodes[atNode].links[i].flags & PATH_NOTANKS)
- continue;
- //skip any unreachable nodes
- if (bot->client && (nodes[newnode].type & NODE_ALLY_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_ALLIES))
- continue;
- if (bot->client && (nodes[newnode].type & NODE_AXIS_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_AXIS))
- continue;
-
- if (list[newnode] == 2) //if this node is on the closed list, skip it
- continue;
-
- if (list[newnode] != 1) //if this node is not already on the open list
- {
- openlist[++numOpen] = newnode; //add the new node to the open list
- list[newnode] = 1;
- parent[newnode] = atNode; //record the node's parent
-
- if (newnode == to) //if we've found the goal, don't keep computing paths!
- break; //this will break the 'for' and go all the way to 'if (list[to] == 1)'
-
- //store it's f cost value
- fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost);
-
- //this loop re-orders the heap so that the lowest fcost is at the top
- m = numOpen;
- while (m != 1) //while this item isn't at the top of the heap already
- {
- //if it has a lower fcost than its parent
- if (fcost[openlist[m]] <= fcost[openlist[m/2]])
- {
- temp = openlist[m/2];
- openlist[m/2] = openlist[m];
- openlist[m] = temp; //swap them
- m /= 2;
- }
- else
- break;
- }
- }
- else //if this node is already on the open list
- {
- gc = gcost[atNode];
- VectorSubtract(nodes[newnode].origin, nodes[atNode].origin, vec);
- gc += VectorLength(vec); //calculate what the gcost would be if we reached this node along the current path
-
- if (gc < gcost[newnode]) //if the new gcost is less (ie, this path is shorter than what we had before)
- {
- parent[newnode] = atNode; //set the new parent for this node
- gcost[newnode] = gc; //and the new g cost
-
- for (i = 1; i < numOpen; i++) //loop through all the items on the open list
- {
- if (openlist[i] == newnode) //find this node in the list
- {
- //calculate the new fcost and store it
- fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost);
-
- //reorder the list again, with the lowest fcost item on top
- m = i;
- while (m != 1)
- {
- //if the item has a lower fcost than it's parent
- if (fcost[openlist[m]] < fcost[openlist[m/2]])
- {
- temp = openlist[m/2];
- openlist[m/2] = openlist[m];
- openlist[m] = temp; //swap them
- m /= 2;
- }
- else
- break;
- }
- break; //exit the 'for' loop because we already changed this node
- } //if
- } //for
- } //if (gc < gcost[newnode])
- } //if (list[newnode] != 1) --> else
- } //for (loop through links)
- } //if (numOpen != 0)
- else
- {
- found = qfalse; //there is no path between these nodes
- break;
- }
-
- if (list[to] == 1) //if the destination node is on the open list, we're done
- {
- found = qtrue;
- break;
- }
- } //while (1)
-
- if (found == qtrue) //if we found a path
- {
- //G_Printf("%s - path found!n", bot->client->pers.netname);
- count = 0;
-
- temp = to; //start at the end point
- while (temp != from) //travel along the path (backwards) until we reach the starting point
- {
- pathlist[count++] = temp; //add the node to the pathlist and increment the count
- temp = parent[temp]; //move to the parent of this node to continue the path
- }
-
- pathlist[count++] = from; //add the beginning node to the end of the pathlist
-
- #ifdef __BOT_SHORTEN_ROUTING__
- count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1
- #endif //__BOT_SHORTEN_ROUTING__
- }
- else
- {
- //G_Printf("^1*** ^4BOT DEBUG^5: (CreatePathAStar) There is no route between node ^7%i^5 and node ^7%i^5.n", from, to);
- count = CreateDumbRoute(from, to, pathlist);
-
- if (count > 0)
- {
- #ifdef __BOT_SHORTEN_ROUTING__
- count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1
- #endif //__BOT_SHORTEN_ROUTING__
- return count;
- }
- }
-
- return count; //return the number of nodes in the path, -1 if not found
-}
-
-/*
-===========================================================================
-GetFCost
-Utility function used by A* pathfinding to calculate the
-cost to move between nodes towards a goal. Using the A*
-algorithm F = G + H, G here is the distance along the node
-paths the bot must travel, and H is the straight-line distance
-to the goal node.
-Returned as an int because more precision is unnecessary and it
-will slightly speed up heap access
-===========================================================================
-*/
-int GetFCost(int to, int num, int parentNum, float *gcost)
-{
- float gc = 0;
- float hc = 0;
- vec3_t v;
-
- if (gcost[num] == -1)
- {
- if (parentNum != -1)
- {
- gc = gcost[parentNum];
- VectorSubtract(nodes[num].origin, nodes[parentNum].origin, v);
- gc += VectorLength(v);
- }
- gcost[num] = gc;
- }
- else
- gc = gcost[num];
-
- VectorSubtract(nodes[to].origin, nodes[num].origin, v);
- hc = VectorLength(v);
-
- return (int)(gc + hc);
-}
-#endif //__PATHFINDING__
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
+ *
+ * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
+ *
+ * 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
+ */
+
+/*
+creature_movement Table
+
+alter table creature_movement add `textid1` int(11) NOT NULL default '0';
+alter table creature_movement add `textid2` int(11) NOT NULL default '0';
+alter table creature_movement add `textid3` int(11) NOT NULL default '0';
+alter table creature_movement add `textid4` int(11) NOT NULL default '0';
+alter table creature_movement add `textid5` int(11) NOT NULL default '0';
+alter table creature_movement add `emote` int(10) unsigned default '0';
+alter table creature_movement add `spell` int(5) unsigned default '0';
+alter table creature_movement add `wpguid` int(11) default '0';
+
+*/
+
+#include <ctime>
+
+#include "WaypointMovementGenerator.h"
+#include "ObjectMgr.h"
+#include "Creature.h"
+#include "DestinationHolderImp.h"
+#include "CreatureAI.h"
+#include "WaypointManager.h"
+
+#include <cassert>
+
+//-----------------------------------------------//
+void
+WaypointMovementGenerator<Creature>::LoadPath(Creature &c)
+{
+ sLog.outDetail("LoadPath: loading waypoint path for creature %d,%d", c.GetGUIDLow(), c.GetDBTableGUIDLow());
+
+ i_path = WaypointMgr.GetPath(c.GetDBTableGUIDLow());
+ if(!i_path)
+ {
+ sLog.outErrorDb("WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %d) doesn't have waypoint path",
+ c.GetName(), c.GetEntry(), c.GetDBTableGUIDLow());
+ return;
+ }
+
+ uint32 node_count = i_path->size();
+ i_hasDone.resize(node_count);
+ for(uint32 i = 0; i < node_count-1; i++)
+ i_hasDone[i] = false;
+
+ // to prevent a misbehaviour inside "update"
+ // update is always called with the next wp - but the wpSys needs the current
+ // so when the routine is called the first time, wpSys gets the last waypoint
+ // and this prevents the system from performing text/emote, etc
+ i_hasDone[node_count - 1] = true;
+}
+
+void
+WaypointMovementGenerator<Creature>::ClearWaypoints()
+{
+ i_path = NULL;
+}
+
+void
+WaypointMovementGenerator<Creature>::Initialize()
+{
+}
+
+bool
+WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff)
+{
+ if(!&creature)
+ return true;
+
+ // Waypoint movement can be switched on/off
+ // This is quite handy for escort quests and other stuff
+ if(creature.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
+ return true;
+
+ // prevent a crash at empty waypoint path.
+ if(!i_path || i_path->empty())
+ return true;
+
+ // i_path was modified by chat commands for example
+ if(i_path->size() != i_hasDone.size())
+ i_hasDone.resize(i_path->size());
+ if(i_currentNode >= i_path->size())
+ i_currentNode = 0;
+
+ CreatureTraveller traveller(creature);
+
+ i_nextMoveTime.Update(diff);
+ i_destinationHolder.UpdateTraveller(traveller, diff, false, true);
+
+ // creature has been stoped in middle of the waypoint segment
+ if (!i_destinationHolder.HasArrived() && creature.IsStopped())
+ {
+ if( i_nextMoveTime.Passed()) // Timer has elapsed, meaning this part controlled it
+ {
+ SetStopedByPlayer(false);
+ // Now we re-set destination to same node and start travel
+ creature.addUnitState(UNIT_STAT_ROAMING);
+ if (creature.canFly())
+ creature.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
+ const WaypointNode &node = i_path->at(i_currentNode);
+ i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
+ i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
+ }
+ else // if( !i_nextMoveTime.Passed())
+ { // unexpected end of timer && creature stopped && not at end of segment
+ if (!IsStopedByPlayer())
+ { // Put 30 seconds delay
+ i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER);
+ i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER);
+ SetStopedByPlayer(true); // Mark we did it
+ }
+ }
+ return true; // Abort here this update
+ }
+
+ if( creature.IsStopped())
+ {
+ uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1;
+
+ if (!i_hasDone[idx])
+ {
+ if (i_path->at(idx).orientation !=100)
+ creature.SetOrientation(i_path->at(idx).orientation);
+
+ if(WaypointBehavior *behavior = i_path->at(idx).behavior)
+ {
+ if(behavior->emote != 0)
+ creature.SetUInt32Value(UNIT_NPC_EMOTESTATE,behavior->emote);
+ if(behavior->spell != 0)
+ creature.CastSpell(&creature,behavior->spell, false);
+ if(behavior->model1 != 0)
+ creature.SetDisplayId(behavior->model1);
+ if(behavior->textid[0])
+ {
+ // Not only one text is set
+ if( behavior->textid[1] )
+ {
+ // Select one from max 5 texts (0 and 1 already checked)
+ int i = 2;
+ for( ; i < MAX_WAYPOINT_TEXT; ++i )
+ if( !behavior->textid[i] )
+ break;
+
+ creature.Say(behavior->textid[rand() % i], 0, 0);
+ }
+ else
+ creature.Say(behavior->textid[0], 0, 0);
+ }
+ } // wpBehaviour found
+ i_hasDone[idx] = true;
+ MovementInform(creature);
+ } // HasDone == false
+ } // i_creature.IsStopped()
+
+ if( i_nextMoveTime.Passed() ) // This is at the end of waypoint segment or has been stopped by player
+ {
+ if( creature.IsStopped() ) // If stopped then begin a new move segment
+ {
+ creature.addUnitState(UNIT_STAT_ROAMING);
+ if (creature.canFly())
+ creature.AddUnitMovementFlag(MOVEMENTFLAG_FLYING2);
+ const WaypointNode &node = i_path->at(i_currentNode);
+ i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z);
+ i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime());
+ uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1;
+
+ if (i_path->at(idx).orientation !=100)
+ creature.SetOrientation(i_path->at(idx).orientation);
+
+ if(WaypointBehavior *behavior = i_path->at(idx).behavior )
+ {
+ i_hasDone[idx] = false;
+ if(behavior->model2 != 0)
+ creature.SetDisplayId(behavior->model2);
+
+ creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0);
+ }
+ }
+ else // If not stopped then stop it and set the reset of TimeTracker to waittime
+ {
+ creature.StopMoving();
+ SetStopedByPlayer(false);
+ i_nextMoveTime.Reset(i_path->at(i_currentNode).delay);
+ ++i_currentNode;
+ if( i_currentNode >= i_path->size() )
+ i_currentNode = 0;
+ }
+ }
+ return true;
+}
+
+void WaypointMovementGenerator<Creature>::MovementInform(Creature &unit)
+{
+ if(unit.AI())
+ unit.AI()->MovementInform(WAYPOINT_MOTION_TYPE, i_currentNode);
+}
+
+//----------------------------------------------------//
+void
+FlightPathMovementGenerator::LoadPath(Player &)
+{
+ objmgr.GetTaxiPathNodes(i_pathId, i_path,i_mapIds);
+}
+
+uint32
+FlightPathMovementGenerator::GetPathAtMapEnd() const
+{
+ if(i_currentNode >= i_mapIds.size())
+ return i_mapIds.size();
+
+ uint32 curMapId = i_mapIds[i_currentNode];
+ for(uint32 i = i_currentNode; i < i_mapIds.size(); ++i)
+ {
+ if(i_mapIds[i] != curMapId)
+ return i;
+ }
+
+ return i_mapIds.size();
+}
+
+void
+FlightPathMovementGenerator::Initialize(Player &player)
+{
+ player.getHostilRefManager().setOnlineOfflineState(false);
+ player.addUnitState(UNIT_STAT_IN_FLIGHT);
+ player.SetFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
+ LoadPath(player);
+ Traveller<Player> traveller(player);
+ // do not send movement, it was sent already
+ i_destinationHolder.SetDestination(traveller, i_path[i_currentNode].x, i_path[i_currentNode].y, i_path[i_currentNode].z, false);
+
+ player.SendMonsterMoveByPath(GetPath(),GetCurrentNode(),GetPathAtMapEnd(),MOVEMENTFLAG_WALK_MODE|MOVEMENTFLAG_ONTRANSPORT);
+}
+
+void FlightPathMovementGenerator::Finalize(Player & player)
+{
+
+ float x, y, z;
+ i_destinationHolder.GetLocationNow(player.GetMapId(), x, y, z);
+ player.SetPosition(x, y, z, player.GetOrientation());
+
+ player.clearUnitState(UNIT_STAT_IN_FLIGHT);
+ player.Unmount();
+ player.RemoveFlag(UNIT_FIELD_FLAGS,UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_TAXI_FLIGHT);
+
+ if(player.m_taxi.empty())
+ {
+ player.getHostilRefManager().setOnlineOfflineState(true);
+ if(player.pvpInfo.inHostileArea)
+ player.CastSpell(&player, 2479, true);
+
+ player.SetUnitMovementFlags(MOVEMENTFLAG_WALK_MODE);
+ player.StopMoving();
+ }
+}
+
+bool
+FlightPathMovementGenerator::Update(Player &player, const uint32 &diff)
+{
+ if( MovementInProgress() )
+ {
+ Traveller<Player> traveller(player);
+ if( i_destinationHolder.UpdateTraveller(traveller, diff, false) )
+ {
+ i_destinationHolder.ResetUpdate(FLIGHT_TRAVEL_UPDATE);
+ if( i_destinationHolder.HasArrived() )
+ {
+ uint32 curMap = i_mapIds[i_currentNode];
+ ++i_currentNode;
+ if( MovementInProgress() )
+ {
+ DEBUG_LOG("loading node %u for player %s", i_currentNode, player.GetName());
+ if(i_mapIds[i_currentNode]==curMap)
+ {
+ // do not send movement, it was sent already
+ i_destinationHolder.SetDestination(traveller, i_path[i_currentNode].x, i_path[i_currentNode].y, i_path[i_currentNode].z, false);
+ }
+ return true;
+ }
+ //else HasArrived()
+ }
+ else
+ return true;
+ }
+ else
+ return true;
+ }
+
+ // we have arrived at the end of the path
+ return false;
+}
+
+void
+FlightPathMovementGenerator::SetCurrentNodeAfterTeleport()
+{
+ if(i_mapIds.empty())
+ return;
+
+ uint32 map0 = i_mapIds[0];
+ for(int i = 1; i < i_mapIds.size(); ++i)
+ {
+ if(i_mapIds[i]!=map0)
+ {
+ i_currentNode = i;
+ return;
+ }
+ }
+}
+
+//
+// Unique1's ASTAR Pathfinding Code... For future use & reference...
+//
+
+#ifdef __PATHFINDING__
+
+int GetFCost(int to, int num, int parentNum, float *gcost); // Below...
+
+int ShortenASTARRoute(short int *pathlist, int number)
+{ // Wrote this to make the routes a little smarter (shorter)... No point looping back to the same places... Unique1
+ short int temppathlist[MAX_PATHLIST_NODES];
+ int count = 0;
+ // int count2 = 0;
+ int temp, temp2;
+ int link;
+ int upto = 0;
+
+ for (temp = number; temp >= 0; temp--)
+ {
+ qboolean shortened = qfalse;
+
+ for (temp2 = 0; temp2 < temp; temp2++)
+ {
+ for (link = 0; link < nodes[pathlist[temp]].enodenum; link++)
+ {
+ if (nodes[pathlist[temp]].links[link].flags & PATH_BLOCKED)
+ continue;
+
+ //if ((bot->client->ps.eFlags & EF_TANK) && nodes[bot->current_node].links[link].flags & PATH_NOTANKS) //if this path is blocked, skip it
+ // continue;
+
+ //if (nodes[nodes[pathlist[temp]].links[link].targetNode].origin[2] > nodes[pathlist[temp]].origin[2] + 32)
+ // continue;
+
+ if (nodes[pathlist[temp]].links[link].targetNode == pathlist[temp2])
+ { // Found a shorter route...
+ //if (OrgVisible(nodes[pathlist[temp2]].origin, nodes[pathlist[temp]].origin, -1))
+ {
+ temppathlist[count] = pathlist[temp2];
+ temp = temp2;
+ ++count;
+ shortened = qtrue;
+ }
+ }
+ }
+ }
+
+ if (!shortened)
+ {
+ temppathlist[count] = pathlist[temp];
+ ++count;
+ }
+ }
+
+ upto = count;
+
+ for (temp = 0; temp < count; temp++)
+ {
+ pathlist[temp] = temppathlist[upto];
+ --upto;
+ }
+
+ G_Printf("ShortenASTARRoute: Path size reduced from %i to %i nodes...n", number, count);
+ return count;
+}
+
+/*
+===========================================================================
+CreatePathAStar
+This function uses the A* pathfinding algorithm to determine the
+shortest path between any two nodes.
+It's fairly complex, so I'm not really going to explain it much.
+Look up A* and binary heaps for more info.
+pathlist stores the ideal path between the nodes, in reverse order,
+and the return value is the number of nodes in that path
+===========================================================================
+*/
+int CreatePathAStar(gentity_t *bot, int from, int to, short int *pathlist)
+{
+ //all the data we have to hold...since we can't do dynamic allocation, has to be MAX_NODES
+ //we can probably lower this later - eg, the open list should never have more than at most a few dozen items on it
+ short int openlist[MAX_NODES+1]; //add 1 because it's a binary heap, and they don't use 0 - 1 is the first used index
+ float gcost[MAX_NODES];
+ int fcost[MAX_NODES];
+ char list[MAX_NODES]; //0 is neither, 1 is open, 2 is closed - char because it's the smallest data type
+ short int parent[MAX_NODES];
+
+ short int numOpen = 0;
+ short int atNode, temp, newnode=-1;
+ qboolean found = qfalse;
+ int count = -1;
+ float gc;
+ int i, u, v, m;
+ vec3_t vec;
+
+ //clear out all the arrays
+ memset(openlist, 0, sizeof(short int)*(MAX_NODES+1));
+ memset(fcost, 0, sizeof(int)*MAX_NODES);
+ memset(list, 0, sizeof(char)*MAX_NODES);
+ memset(parent, 0, sizeof(short int)*MAX_NODES);
+ memset(gcost, -1, sizeof(float)*MAX_NODES);
+
+ //make sure we have valid data before calculating everything
+ if ((from == NODE_INVALID) || (to == NODE_INVALID) || (from >= MAX_NODES) || (to >= MAX_NODES) || (from == to))
+ return -1;
+
+ openlist[1] = from; //add the starting node to the open list
+ ++numOpen;
+ gcost[from] = 0; //its f and g costs are obviously 0
+ fcost[from] = 0;
+
+ while (1)
+ {
+ if (numOpen != 0) //if there are still items in the open list
+ {
+ //pop the top item off of the list
+ atNode = openlist[1];
+ list[atNode] = 2; //put the node on the closed list so we don't check it again
+ --numOpen;
+
+ openlist[1] = openlist[numOpen+1]; //move the last item in the list to the top position
+ v = 1;
+
+ //this while loop reorders the list so that the new lowest fcost is at the top again
+ while (1)
+ {
+ u = v;
+ if ((2*u+1) < numOpen) //if both children exist
+ {
+ if (fcost[openlist[u]] >= fcost[openlist[2*u]])
+ v = 2*u;
+ if (fcost[openlist[v]] >= fcost[openlist[2*u+1]])
+ v = 2*u+1;
+ }
+ else
+ {
+ if ((2*u) < numOpen) //if only one child exists
+ {
+ if (fcost[openlist[u]] >= fcost[openlist[2*u]])
+ v = 2*u;
+ }
+ }
+
+ if (u != v) //if they're out of order, swap this item with its parent
+ {
+ temp = openlist[u];
+ openlist[u] = openlist[v];
+ openlist[v] = temp;
+ }
+ else
+ break;
+ }
+
+ for (i = 0; i < nodes[atNode].enodenum; i++) //loop through all the links for this node
+ {
+ newnode = nodes[atNode].links[i].targetNode;
+
+ //if this path is blocked, skip it
+ if (nodes[atNode].links[i].flags & PATH_BLOCKED)
+ continue;
+ //if this path is blocked, skip it
+ if (bot->client && (bot->client->ps.eFlags & EF_TANK) && nodes[atNode].links[i].flags & PATH_NOTANKS)
+ continue;
+ //skip any unreachable nodes
+ if (bot->client && (nodes[newnode].type & NODE_ALLY_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_ALLIES))
+ continue;
+ if (bot->client && (nodes[newnode].type & NODE_AXIS_UNREACHABLE) && (bot->client->sess.sessionTeam == TEAM_AXIS))
+ continue;
+
+ if (list[newnode] == 2) //if this node is on the closed list, skip it
+ continue;
+
+ if (list[newnode] != 1) //if this node is not already on the open list
+ {
+ openlist[++numOpen] = newnode; //add the new node to the open list
+ list[newnode] = 1;
+ parent[newnode] = atNode; //record the node's parent
+
+ if (newnode == to) //if we've found the goal, don't keep computing paths!
+ break; //this will break the 'for' and go all the way to 'if (list[to] == 1)'
+
+ //store it's f cost value
+ fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost);
+
+ //this loop re-orders the heap so that the lowest fcost is at the top
+ m = numOpen;
+ while (m != 1) //while this item isn't at the top of the heap already
+ {
+ //if it has a lower fcost than its parent
+ if (fcost[openlist[m]] <= fcost[openlist[m/2]])
+ {
+ temp = openlist[m/2];
+ openlist[m/2] = openlist[m];
+ openlist[m] = temp; //swap them
+ m /= 2;
+ }
+ else
+ break;
+ }
+ }
+ else //if this node is already on the open list
+ {
+ gc = gcost[atNode];
+ VectorSubtract(nodes[newnode].origin, nodes[atNode].origin, vec);
+ gc += VectorLength(vec); //calculate what the gcost would be if we reached this node along the current path
+
+ if (gc < gcost[newnode]) //if the new gcost is less (ie, this path is shorter than what we had before)
+ {
+ parent[newnode] = atNode; //set the new parent for this node
+ gcost[newnode] = gc; //and the new g cost
+
+ for (i = 1; i < numOpen; i++) //loop through all the items on the open list
+ {
+ if (openlist[i] == newnode) //find this node in the list
+ {
+ //calculate the new fcost and store it
+ fcost[newnode] = GetFCost(to, newnode, parent[newnode], gcost);
+
+ //reorder the list again, with the lowest fcost item on top
+ m = i;
+ while (m != 1)
+ {
+ //if the item has a lower fcost than it's parent
+ if (fcost[openlist[m]] < fcost[openlist[m/2]])
+ {
+ temp = openlist[m/2];
+ openlist[m/2] = openlist[m];
+ openlist[m] = temp; //swap them
+ m /= 2;
+ }
+ else
+ break;
+ }
+ break; //exit the 'for' loop because we already changed this node
+ } //if
+ } //for
+ } //if (gc < gcost[newnode])
+ } //if (list[newnode] != 1) --> else
+ } //for (loop through links)
+ } //if (numOpen != 0)
+ else
+ {
+ found = qfalse; //there is no path between these nodes
+ break;
+ }
+
+ if (list[to] == 1) //if the destination node is on the open list, we're done
+ {
+ found = qtrue;
+ break;
+ }
+ } //while (1)
+
+ if (found == qtrue) //if we found a path
+ {
+ //G_Printf("%s - path found!n", bot->client->pers.netname);
+ count = 0;
+
+ temp = to; //start at the end point
+ while (temp != from) //travel along the path (backwards) until we reach the starting point
+ {
+ pathlist[count++] = temp; //add the node to the pathlist and increment the count
+ temp = parent[temp]; //move to the parent of this node to continue the path
+ }
+
+ pathlist[count++] = from; //add the beginning node to the end of the pathlist
+
+ #ifdef __BOT_SHORTEN_ROUTING__
+ count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1
+ #endif //__BOT_SHORTEN_ROUTING__
+ }
+ else
+ {
+ //G_Printf("^1*** ^4BOT DEBUG^5: (CreatePathAStar) There is no route between node ^7%i^5 and node ^7%i^5.n", from, to);
+ count = CreateDumbRoute(from, to, pathlist);
+
+ if (count > 0)
+ {
+ #ifdef __BOT_SHORTEN_ROUTING__
+ count = ShortenASTARRoute(pathlist, count); // This isn't working... Dunno why.. Unique1
+ #endif //__BOT_SHORTEN_ROUTING__
+ return count;
+ }
+ }
+
+ return count; //return the number of nodes in the path, -1 if not found
+}
+
+/*
+===========================================================================
+GetFCost
+Utility function used by A* pathfinding to calculate the
+cost to move between nodes towards a goal. Using the A*
+algorithm F = G + H, G here is the distance along the node
+paths the bot must travel, and H is the straight-line distance
+to the goal node.
+Returned as an int because more precision is unnecessary and it
+will slightly speed up heap access
+===========================================================================
+*/
+int GetFCost(int to, int num, int parentNum, float *gcost)
+{
+ float gc = 0;
+ float hc = 0;
+ vec3_t v;
+
+ if (gcost[num] == -1)
+ {
+ if (parentNum != -1)
+ {
+ gc = gcost[parentNum];
+ VectorSubtract(nodes[num].origin, nodes[parentNum].origin, v);
+ gc += VectorLength(v);
+ }
+ gcost[num] = gc;
+ }
+ else
+ gc = gcost[num];
+
+ VectorSubtract(nodes[to].origin, nodes[num].origin, v);
+ hc = VectorLength(v);
+
+ return (int)(gc + hc);
+}
+#endif //__PATHFINDING__
diff --git a/src/game/World.cpp b/src/game/World.cpp
index 64c2bd49099..a7cff4cb686 100644
--- a/src/game/World.cpp
+++ b/src/game/World.cpp
@@ -116,10 +116,12 @@ World::World()
World::~World()
{
///- Empty the kicked session set
- for (std::set<WorldSession*>::iterator itr = m_kicked_sessions.begin(); itr != m_kicked_sessions.end(); ++itr)
- delete *itr;
-
- m_kicked_sessions.clear();
+ while (!m_sessions.empty())
+ {
+ // not remove from queue, prevent loading new sessions
+ delete m_sessions.begin()->second;
+ m_sessions.erase(m_sessions.begin());
+ }
///- Empty the WeatherMap
for (WeatherMap::iterator itr = m_weathers.begin(); itr != m_weathers.end(); ++itr)
@@ -199,17 +201,26 @@ World::AddSession_ (WorldSession* s)
if (!RemoveSession (s->GetAccountId ()))
{
s->KickPlayer ();
- m_kicked_sessions.insert (s);
+ delete s; // session not added yet in session list, so not listed in queue
return;
}
+ // decrease session counts only at not reconnection case
+ bool decrease_session = true;
+
// if session already exist, prepare to it deleting at next world update
// NOTE - KickPlayer() should be called on "old" in RemoveSession()
{
- SessionMap::const_iterator old = m_sessions.find(s->GetAccountId ());
+ SessionMap::const_iterator old = m_sessions.find(s->GetAccountId ());
- if(old != m_sessions.end())
- m_kicked_sessions.insert (old->second);
+ if(old != m_sessions.end())
+ {
+ // prevent decrease sessions count if session queued
+ if(RemoveQueuedPlayer(old->second))
+ decrease_session = false;
+ // not remove replaced session form queue if listed
+ delete old->second;
+ }
}
m_sessions[s->GetAccountId ()] = s;
@@ -217,10 +228,11 @@ World::AddSession_ (WorldSession* s)
uint32 Sessions = GetActiveAndQueuedSessionCount ();
uint32 pLimit = GetPlayerAmountLimit ();
uint32 QueueSize = GetQueueSize (); //number of players in the queue
- bool inQueue = false;
+
//so we don't count the user trying to
//login as a session and queue the socket that we are using
- --Sessions;
+ if(decrease_session)
+ --Sessions;
if (pLimit > 0 && Sessions >= pLimit && s->GetSecurity () == SEC_PLAYER )
{
@@ -264,6 +276,7 @@ int32 World::GetQueuePos(WorldSession* sess)
void World::AddQueuedPlayer(WorldSession* sess)
{
+ sess->SetInQueue(true);
m_QueuedPlayer.push_back (sess);
// The 1st SMSG_AUTH_RESPONSE needs to contain other info too.
@@ -279,7 +292,7 @@ void World::AddQueuedPlayer(WorldSession* sess)
//sess->SendAuthWaitQue (GetQueuePos (sess));
}
-void World::RemoveQueuedPlayer(WorldSession* sess)
+bool World::RemoveQueuedPlayer(WorldSession* sess)
{
// sessions count including queued to remove (if removed_session set)
uint32 sessions = GetActiveSessionCount();
@@ -287,16 +300,16 @@ void World::RemoveQueuedPlayer(WorldSession* sess)
uint32 position = 1;
Queue::iterator iter = m_QueuedPlayer.begin();
- // if session not queued then we need decrease sessions count (Remove socked callet before session removing from session list)
- bool decrease_session = true;
-
// search to remove and count skipped positions
+ bool found = false;
+
for(;iter != m_QueuedPlayer.end(); ++iter, ++position)
{
if(*iter==sess)
{
+ sess->SetInQueue(false);
iter = m_QueuedPlayer.erase(iter);
- decrease_session = false; // removing queued session
+ found = true; // removing queued session
break;
}
}
@@ -304,15 +317,16 @@ void World::RemoveQueuedPlayer(WorldSession* sess)
// iter point to next socked after removed or end()
// position store position of removed socket and then new position next socket after removed
- // decrease for case session queued for removing
- if(decrease_session && sessions)
+ // if session not queued then we need decrease sessions count
+ if(!found && sessions)
--sessions;
// accept first in queue
if( (!m_playerLimit || sessions < m_playerLimit) && !m_QueuedPlayer.empty() )
{
- WorldSession * socket = m_QueuedPlayer.front();
- socket->SendAuthWaitQue(0);
+ WorldSession* pop_sess = m_QueuedPlayer.front();
+ pop_sess->SetInQueue(false);
+ pop_sess->SendAuthWaitQue(0);
m_QueuedPlayer.pop_front();
// update iter to point first queued socket or end() if queue is empty now
@@ -324,6 +338,8 @@ void World::RemoveQueuedPlayer(WorldSession* sess)
// iter point to first not updated socket, position store new position
for(; iter != m_QueuedPlayer.end(); ++iter, ++position)
(*iter)->SendAuthWaitQue(position);
+
+ return found;
}
/// Find a Weather object by the given zoneid
@@ -581,8 +597,6 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_CHARACTERS_CREATING_DISABLED] = sConfig.GetIntDefault("CharactersCreatingDisabled", 0);
- m_configs[CONFIG_MAX_WHO] = sConfig.GetIntDefault("MaxWhoListReturns", 49);
-
m_configs[CONFIG_CHARACTERS_PER_REALM] = sConfig.GetIntDefault("CharactersPerRealm", 10);
if(m_configs[CONFIG_CHARACTERS_PER_REALM] < 1 || m_configs[CONFIG_CHARACTERS_PER_REALM] > 10)
{
@@ -630,13 +644,70 @@ void World::LoadConfigSettings(bool reload)
sLog.outError("StartPlayerLevel (%i) must be in range 1..MaxPlayerLevel(%u). Set to %u.",m_configs[CONFIG_START_PLAYER_LEVEL],m_configs[CONFIG_MAX_PLAYER_LEVEL],m_configs[CONFIG_MAX_PLAYER_LEVEL]);
m_configs[CONFIG_START_PLAYER_LEVEL] = m_configs[CONFIG_MAX_PLAYER_LEVEL];
}
+
+ m_configs[CONFIG_START_PLAYER_MONEY] = sConfig.GetIntDefault("StartPlayerMoney", 0);
+ if(m_configs[CONFIG_START_PLAYER_MONEY] < 0)
+ {
+ sLog.outError("StartPlayerMoney (%i) must be in range 0..%u. Set to %u.",m_configs[CONFIG_START_PLAYER_MONEY],MAX_MONEY_AMOUNT,0);
+ m_configs[CONFIG_START_PLAYER_MONEY] = 0;
+ }
+ else if(m_configs[CONFIG_START_PLAYER_MONEY] > MAX_MONEY_AMOUNT)
+ {
+ sLog.outError("StartPlayerMoney (%i) must be in range 0..%u. Set to %u.",
+ m_configs[CONFIG_START_PLAYER_MONEY],MAX_MONEY_AMOUNT,MAX_MONEY_AMOUNT);
+ m_configs[CONFIG_START_PLAYER_MONEY] = MAX_MONEY_AMOUNT;
+ }
+
m_configs[CONFIG_MAX_HONOR_POINTS] = sConfig.GetIntDefault("MaxHonorPoints", 75000);
+ if(m_configs[CONFIG_MAX_HONOR_POINTS] < 0)
+ {
+ sLog.outError("MaxHonorPoints (%i) can't be negative. Set to 0.",m_configs[CONFIG_MAX_HONOR_POINTS]);
+ m_configs[CONFIG_MAX_HONOR_POINTS] = 0;
+ }
+
+ m_configs[CONFIG_START_HONOR_POINTS] = sConfig.GetIntDefault("StartHonorPoints", 0);
+ if(m_configs[CONFIG_START_HONOR_POINTS] < 0)
+ {
+ sLog.outError("StartHonorPoints (%i) must be in range 0..MaxHonorPoints(%u). Set to %u.",
+ m_configs[CONFIG_START_HONOR_POINTS],m_configs[CONFIG_MAX_HONOR_POINTS],0);
+ m_configs[CONFIG_MAX_HONOR_POINTS] = 0;
+ }
+ else if(m_configs[CONFIG_START_HONOR_POINTS] > m_configs[CONFIG_MAX_HONOR_POINTS])
+ {
+ sLog.outError("StartHonorPoints (%i) must be in range 0..MaxHonorPoints(%u). Set to %u.",
+ m_configs[CONFIG_START_HONOR_POINTS],m_configs[CONFIG_MAX_HONOR_POINTS],m_configs[CONFIG_MAX_HONOR_POINTS]);
+ m_configs[CONFIG_START_HONOR_POINTS] = m_configs[CONFIG_MAX_HONOR_POINTS];
+ }
+
m_configs[CONFIG_MAX_ARENA_POINTS] = sConfig.GetIntDefault("MaxArenaPoints", 5000);
+ if(m_configs[CONFIG_MAX_ARENA_POINTS] < 0)
+ {
+ sLog.outError("MaxArenaPoints (%i) can't be negative. Set to 0.",m_configs[CONFIG_MAX_ARENA_POINTS]);
+ m_configs[CONFIG_MAX_ARENA_POINTS] = 0;
+ }
+
+ m_configs[CONFIG_START_ARENA_POINTS] = sConfig.GetIntDefault("StartArenaPoints", 0);
+ if(m_configs[CONFIG_START_ARENA_POINTS] < 0)
+ {
+ sLog.outError("StartArenaPoints (%i) must be in range 0..MaxArenaPoints(%u). Set to %u.",
+ m_configs[CONFIG_START_ARENA_POINTS],m_configs[CONFIG_MAX_ARENA_POINTS],0);
+ m_configs[CONFIG_MAX_ARENA_POINTS] = 0;
+ }
+ else if(m_configs[CONFIG_START_ARENA_POINTS] > m_configs[CONFIG_MAX_ARENA_POINTS])
+ {
+ sLog.outError("StartArenaPoints (%i) must be in range 0..MaxArenaPoints(%u). Set to %u.",
+ m_configs[CONFIG_START_ARENA_POINTS],m_configs[CONFIG_MAX_ARENA_POINTS],m_configs[CONFIG_MAX_ARENA_POINTS]);
+ m_configs[CONFIG_START_ARENA_POINTS] = m_configs[CONFIG_MAX_ARENA_POINTS];
+ }
+
+ m_configs[CONFIG_ALL_TAXI_PATHS] = sConfig.GetBoolDefault("AllFlightPaths", false);
m_configs[CONFIG_INSTANCE_IGNORE_LEVEL] = sConfig.GetBoolDefault("Instance.IgnoreLevel", false);
m_configs[CONFIG_INSTANCE_IGNORE_RAID] = sConfig.GetBoolDefault("Instance.IgnoreRaid", false);
m_configs[CONFIG_BATTLEGROUND_CAST_DESERTER] = sConfig.GetBoolDefault("Battleground.CastDeserter", true);
+ m_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE] = sConfig.GetBoolDefault("Battleground.QueueAnnouncer.Enable", true);
+ m_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY] = sConfig.GetBoolDefault("Battleground.QueueAnnouncer.PlayerOnly", false);
m_configs[CONFIG_CAST_UNSTUCK] = sConfig.GetBoolDefault("CastUnstuck", true);
m_configs[CONFIG_INSTANCE_RESET_TIME_HOUR] = sConfig.GetIntDefault("Instance.ResetTimeHour", 4);
@@ -659,6 +730,19 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_GM_IN_WHO_LIST] = sConfig.GetBoolDefault("GM.InWhoList",false);
m_configs[CONFIG_GM_LOG_TRADE] = sConfig.GetBoolDefault("GM.LogTrade", false);
+ m_configs[CONFIG_START_GM_LEVEL] = sConfig.GetIntDefault("GM.StartLevel", 1);
+ if(m_configs[CONFIG_START_GM_LEVEL] < m_configs[CONFIG_START_PLAYER_LEVEL])
+ {
+ sLog.outError("GM.StartLevel (%i) must be in range StartPlayerLevel(%u)..255. Set to %u.",
+ m_configs[CONFIG_START_GM_LEVEL],m_configs[CONFIG_START_PLAYER_LEVEL],m_configs[CONFIG_START_PLAYER_LEVEL]);
+ m_configs[CONFIG_START_GM_LEVEL] = m_configs[CONFIG_START_PLAYER_LEVEL];
+ }
+ else if(m_configs[CONFIG_START_GM_LEVEL] > 255)
+ {
+ sLog.outError("GM.StartLevel (%i) must be in range 1..255. Set to %u.",m_configs[CONFIG_START_GM_LEVEL],255);
+ m_configs[CONFIG_START_GM_LEVEL] = 255;
+ }
+
m_configs[CONFIG_GROUP_VISIBILITY] = sConfig.GetIntDefault("Visibility.GroupMode",0);
m_configs[CONFIG_MAIL_DELIVERY_DELAY] = sConfig.GetIntDefault("MailDeliveryDelay",HOUR);
@@ -723,6 +807,10 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY] = sConfig.GetBoolDefault("SaveRespawnTimeImmediately",true);
m_configs[CONFIG_WEATHER] = sConfig.GetBoolDefault("ActivateWeather",true);
+ m_configs[CONFIG_DISABLE_BREATHING] = sConfig.GetIntDefault("DisableWaterBreath", SEC_CONSOLE);
+
+ m_configs[CONFIG_ALWAYS_MAX_SKILL_FOR_LEVEL] = sConfig.GetBoolDefault("AlwaysMaxSkillForLevel", false);
+
if(reload)
{
uint32 val = sConfig.GetIntDefault("Expansion",1);
@@ -738,7 +826,8 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_EVENT_ANNOUNCE] = sConfig.GetIntDefault("Event.Announce",0);
- m_configs[CONFIG_CREATURE_FAMILY_ASSISTEMCE_RADIUS] = sConfig.GetIntDefault("CreatureFamilyAssistenceRadius",10);
+ m_configs[CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS] = sConfig.GetIntDefault("CreatureFamilyAssistanceRadius",10);
+ m_configs[CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY] = sConfig.GetIntDefault("CreatureFamilyAssistanceDelay",1500);
m_configs[CONFIG_WORLD_BOSS_LEVEL_DIFF] = sConfig.GetIntDefault("WorldBossLevelDiff",3);
@@ -750,6 +839,8 @@ void World::LoadConfigSettings(bool reload)
if(m_configs[CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF] > 255)
m_configs[CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF] = 255;
+ m_configs[CONFIG_DETECT_POS_COLLISION] = sConfig.GetBoolDefault("DetectPosCollision", true);
+
m_configs[CONFIG_RESTRICTED_LFG_CHANNEL] = sConfig.GetBoolDefault("Channel.RestrictedLfg", true);
m_configs[CONFIG_SILENTLY_GM_JOIN_TO_CHANNEL] = sConfig.GetBoolDefault("Channel.SilentlyGMJoin", false);
@@ -776,48 +867,7 @@ void World::LoadConfigSettings(bool reload)
m_configs[CONFIG_LISTEN_RANGE_TEXTEMOTE] = sConfig.GetIntDefault("ListenRange.TextEmote", 25);
m_configs[CONFIG_LISTEN_RANGE_YELL] = sConfig.GetIntDefault("ListenRange.Yell", 300);
- m_configs[CONFIG_PLAYER_START_GOLD] = (uint32)(sConfig.GetFloatDefault("PlayerStart.Gold", 0.0f) * 10000.0f);
-
- if(m_configs[CONFIG_PLAYER_START_GOLD] > MAX_MONEY_AMOUNT)
- m_configs[CONFIG_PLAYER_START_GOLD] = MAX_MONEY_AMOUNT;
-
- m_configs[CONFIG_PLAYER_START_HONOR] = sConfig.GetIntDefault("PlayerStart.HonorPoints", 0);
- if(m_configs[CONFIG_PLAYER_START_HONOR] < 0)
- m_configs[CONFIG_PLAYER_START_HONOR] = 0;
-
- m_configs[CONFIG_PLAYER_START_ARENAPTS] = sConfig.GetIntDefault("PlayerStart.ArenaPoints", 0);
- if(m_configs[CONFIG_PLAYER_START_ARENAPTS] < 0)
- m_configs[CONFIG_PLAYER_START_ARENAPTS] = 0;
-
- m_configs[CONFIG_GM_START_LEVEL] = sConfig.GetIntDefault("GamemasterStartLevel", 1);
- if(m_configs[CONFIG_GM_START_LEVEL] < 1)
- m_configs[CONFIG_GM_START_LEVEL] = 1;
-
- m_configs[CONFIG_INSTANT_LOGOUT] = sConfig.GetBoolDefault("PlayerInstantLogout", false);
- m_configs[CONFIG_BG_START_MUSIC] = sConfig.GetBoolDefault("MusicInBattleground", false);
- m_configs[CONFIG_START_ALL_SPELLS] = sConfig.GetBoolDefault("PlayerStart.AllSpells", false);
- m_configs[CONFIG_HONOR_AFTER_DUEL] = sConfig.GetIntDefault("HonorPointsAfterDuel", 0);
- if(m_configs[CONFIG_HONOR_AFTER_DUEL] < 0)
- m_configs[CONFIG_HONOR_AFTER_DUEL]= 0;
- m_configs[CONFIG_START_ALL_EXPLORED] = sConfig.GetBoolDefault("PlayerStart.MapsExplored", false);
- m_configs[CONFIG_DISABLE_BREATHING] = sConfig.GetBoolDefault("DisableWaterBreath", false);
- m_configs[CONFIG_START_ALL_REP] = sConfig.GetBoolDefault("PlayerStart.AllReputation", false);
- m_configs[CONFIG_ALWAYS_MAXSKILL] = sConfig.GetBoolDefault("AlwaysMaxWeaponSkill", false);
- m_configs[CONFIG_START_ALL_TAXI] = sConfig.GetBoolDefault("PlayerStart.AllFlightPaths", false);
- m_configs[CONFIG_PVP_TOKEN_ENABLE] = sConfig.GetBoolDefault("PvPToken.Enable", false);
- m_configs[CONFIG_PVP_TOKEN_MAP_TYPE] = sConfig.GetIntDefault("PvPToken.MapAllowType", 4);
- m_configs[CONFIG_PVP_TOKEN_ID] = sConfig.GetIntDefault("PvPToken.ItemID", 29434);
- m_configs[CONFIG_PVP_TOKEN_COUNT] = sConfig.GetIntDefault("PvPToken.ItemCount", 1);
- if(m_configs[CONFIG_PVP_TOKEN_COUNT] < 1)
- m_configs[CONFIG_PVP_TOKEN_COUNT] = 1;
- m_configs[CONFIG_NO_RESET_TALENT_COST] = sConfig.GetBoolDefault("NoResetTalentsCost", false);
-
- m_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfig.GetIntDefault("Arena.MaxRatingDifference", 0);
- m_configs[CONFIG_ARENA_RATING_DISCARD_TIMER] = sConfig.GetIntDefault("Arena.RatingDiscardTimer",300000);
- m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS] = sConfig.GetBoolDefault("Arena.AutoDistributePoints", false);
- m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS] = sConfig.GetIntDefault("Arena.AutoDistributeInterval", 7);
-
- m_configs[CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER] = sConfig.GetIntDefault("BattleGround.PrematureFinishTimer", 0);
+ m_configs[CONFIG_INSTANT_LOGOUT] = sConfig.GetIntDefault("InstantLogout", SEC_MODERATOR);
m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1);
if(m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE)
@@ -888,6 +938,46 @@ void World::LoadConfigSettings(bool reload)
sLog.outString("Using DataDir %s",m_dataPath.c_str());
}
+ bool enableLOS = sConfig.GetBoolDefault("vmap.enableLOS", false);
+ bool enableHeight = sConfig.GetBoolDefault("vmap.enableHeight", false);
+ std::string ignoreMapIds = sConfig.GetStringDefault("vmap.ignoreMapIds", "");
+ std::string ignoreSpellIds = sConfig.GetStringDefault("vmap.ignoreSpellIds", "");
+ VMAP::VMapFactory::createOrGetVMapManager()->setEnableLineOfSightCalc(enableLOS);
+ VMAP::VMapFactory::createOrGetVMapManager()->setEnableHeightCalc(enableHeight);
+ VMAP::VMapFactory::createOrGetVMapManager()->preventMapsFromBeingUsed(ignoreMapIds.c_str());
+ VMAP::VMapFactory::preventSpellsFromBeingTestedForLoS(ignoreSpellIds.c_str());
+ sLog.outString( "WORLD: VMap support included. LineOfSight:%i, getHeight:%i",enableLOS, enableHeight);
+ sLog.outString( "WORLD: VMap data directory is: %svmaps",m_dataPath.c_str());
+ sLog.outString( "WORLD: VMap config keys are: vmap.enableLOS, vmap.enableHeight, vmap.ignoreMapIds, vmap.ignoreSpellIds");
+
+
+ m_configs[CONFIG_MAX_WHO] = sConfig.GetIntDefault("MaxWhoListReturns", 49);
+
+ m_configs[CONFIG_BG_START_MUSIC] = sConfig.GetBoolDefault("MusicInBattleground", false);
+ m_configs[CONFIG_START_ALL_SPELLS] = sConfig.GetBoolDefault("PlayerStart.AllSpells", false);
+ m_configs[CONFIG_HONOR_AFTER_DUEL] = sConfig.GetIntDefault("HonorPointsAfterDuel", 0);
+ if(m_configs[CONFIG_HONOR_AFTER_DUEL] < 0)
+ m_configs[CONFIG_HONOR_AFTER_DUEL]= 0;
+ m_configs[CONFIG_START_ALL_EXPLORED] = sConfig.GetBoolDefault("PlayerStart.MapsExplored", false);
+ m_configs[CONFIG_DISABLE_BREATHING] = sConfig.GetBoolDefault("DisableWaterBreath", false);
+ m_configs[CONFIG_START_ALL_REP] = sConfig.GetBoolDefault("PlayerStart.AllReputation", false);
+ m_configs[CONFIG_ALWAYS_MAXSKILL] = sConfig.GetBoolDefault("AlwaysMaxWeaponSkill", false);
+ m_configs[CONFIG_START_ALL_TAXI] = sConfig.GetBoolDefault("PlayerStart.AllFlightPaths", false);
+ m_configs[CONFIG_PVP_TOKEN_ENABLE] = sConfig.GetBoolDefault("PvPToken.Enable", false);
+ m_configs[CONFIG_PVP_TOKEN_MAP_TYPE] = sConfig.GetIntDefault("PvPToken.MapAllowType", 4);
+ m_configs[CONFIG_PVP_TOKEN_ID] = sConfig.GetIntDefault("PvPToken.ItemID", 29434);
+ m_configs[CONFIG_PVP_TOKEN_COUNT] = sConfig.GetIntDefault("PvPToken.ItemCount", 1);
+ if(m_configs[CONFIG_PVP_TOKEN_COUNT] < 1)
+ m_configs[CONFIG_PVP_TOKEN_COUNT] = 1;
+ m_configs[CONFIG_NO_RESET_TALENT_COST] = sConfig.GetBoolDefault("NoResetTalentsCost", false);
+
+ m_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfig.GetIntDefault("Arena.MaxRatingDifference", 0);
+ m_configs[CONFIG_ARENA_RATING_DISCARD_TIMER] = sConfig.GetIntDefault("Arena.RatingDiscardTimer",300000);
+ m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS] = sConfig.GetBoolDefault("Arena.AutoDistributePoints", false);
+ m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS] = sConfig.GetIntDefault("Arena.AutoDistributeInterval", 7);
+
+ m_configs[CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER] = sConfig.GetIntDefault("BattleGround.PrematureFinishTimer", 0);
+
std::string forbiddenmaps = sConfig.GetStringDefault("ForbiddenMaps", "");
char * forbiddenMaps = new char[forbiddenmaps.length() + 1];
forbiddenMaps[forbiddenmaps.length()] = 0;
@@ -901,18 +991,6 @@ void World::LoadConfigSettings(bool reload)
token = strtok(NULL,delim);
}
delete[] forbiddenMaps;
-
- bool enableLOS = sConfig.GetBoolDefault("vmap.enableLOS", false);
- bool enableHeight = sConfig.GetBoolDefault("vmap.enableHeight", false);
- std::string ignoreMapIds = sConfig.GetStringDefault("vmap.ignoreMapIds", "");
- std::string ignoreSpellIds = sConfig.GetStringDefault("vmap.ignoreSpellIds", "");
- VMAP::VMapFactory::createOrGetVMapManager()->setEnableLineOfSightCalc(enableLOS);
- VMAP::VMapFactory::createOrGetVMapManager()->setEnableHeightCalc(enableHeight);
- VMAP::VMapFactory::createOrGetVMapManager()->preventMapsFromBeingUsed(ignoreMapIds.c_str());
- VMAP::VMapFactory::preventSpellsFromBeingTestedForLoS(ignoreSpellIds.c_str());
- sLog.outString( "WORLD: VMap support included. LineOfSight:%i, getHeight:%i",enableLOS, enableHeight);
- sLog.outString( "WORLD: VMap data directory is: %svmaps",m_dataPath.c_str());
- sLog.outString( "WORLD: VMap config keys are: vmap.enableLOS, vmap.enableHeight, vmap.ignoreMapIds, vmap.ignoreSpellIds");
}
/// Initialize the World
@@ -2237,6 +2315,8 @@ void World::SendZoneText(uint32 zone, const char* text, WorldSession *self, uint
/// Kick (and save) all players
void World::KickAll()
{
+ m_QueuedPlayer.clear(); // prevent send queue update packet and login queued sessions
+
// session not removed at kick and will removed in next update tick
for (SessionMap::iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
itr->second->KickPlayer();
@@ -2251,18 +2331,6 @@ void World::KickAllLess(AccountTypes sec)
itr->second->KickPlayer();
}
-/// Kick all queued players
-void World::KickAllQueued()
-{
- // session not removed at kick and will removed in next update tick
- //TODO here
-// for (Queue::iterator itr = m_QueuedPlayer.begin(); itr != m_QueuedPlayer.end(); ++itr)
-// if(WorldSession* session = (*itr)->GetSession())
-// session->KickPlayer();
-
- m_QueuedPlayer.empty();
-}
-
/// Kick (and save) the designated player
bool World::KickPlayer(std::string playerName)
{
@@ -2493,19 +2561,12 @@ void World::SendServerMessage(uint32 type, const char *text, Player* player)
void World::UpdateSessions( time_t diff )
{
+ ///- Add new sessions
while(!addSessQueue.empty())
{
- WorldSession* sess = addSessQueue.next ();
- AddSession_ (sess);
- }
-
- ///- Delete kicked sessions at add new session
- for (std::set<WorldSession*>::iterator itr = m_kicked_sessions.begin(); itr != m_kicked_sessions.end(); ++itr)
- {
- RemoveQueuedPlayer (*itr);
- delete *itr;
+ WorldSession* sess = addSessQueue.next ();
+ AddSession_ (sess);
}
- m_kicked_sessions.clear();
///- Then send an update signal to remaining ones
for (SessionMap::iterator itr = m_sessions.begin(), next; itr != m_sessions.end(); itr = next)
diff --git a/src/game/World.h b/src/game/World.h
index 50065b360dd..73266c1b090 100644
--- a/src/game/World.h
+++ b/src/game/World.h
@@ -100,14 +100,16 @@ enum WorldConfigs
CONFIG_STRICT_CHARTER_NAMES,
CONFIG_STRICT_PET_NAMES,
CONFIG_CHARACTERS_CREATING_DISABLED,
- CONFIG_MAX_WHO,
CONFIG_CHARACTERS_PER_ACCOUNT,
CONFIG_CHARACTERS_PER_REALM,
CONFIG_SKIP_CINEMATICS,
CONFIG_MAX_PLAYER_LEVEL,
CONFIG_START_PLAYER_LEVEL,
+ CONFIG_START_PLAYER_MONEY,
CONFIG_MAX_HONOR_POINTS,
+ CONFIG_START_HONOR_POINTS,
CONFIG_MAX_ARENA_POINTS,
+ CONFIG_START_ARENA_POINTS,
CONFIG_INSTANCE_IGNORE_LEVEL,
CONFIG_INSTANCE_IGNORE_RAID,
CONFIG_BATTLEGROUND_CAST_DESERTER,
@@ -125,6 +127,7 @@ enum WorldConfigs
CONFIG_GM_IN_GM_LIST,
CONFIG_GM_IN_WHO_LIST,
CONFIG_GM_LOG_TRADE,
+ CONFIG_START_GM_LEVEL,
CONFIG_GROUP_VISIBILITY,
CONFIG_MAIL_DELIVERY_DELAY,
CONFIG_UPTIME_UPDATE,
@@ -141,13 +144,15 @@ enum WorldConfigs
CONFIG_SKILL_GAIN_WEAPON,
CONFIG_MAX_OVERSPEED_PINGS,
CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY,
+ CONFIG_ALWAYS_MAX_SKILL_FOR_LEVEL,
CONFIG_WEATHER,
CONFIG_EXPANSION,
CONFIG_CHATFLOOD_MESSAGE_COUNT,
CONFIG_CHATFLOOD_MESSAGE_DELAY,
CONFIG_CHATFLOOD_MUTE_TIME,
CONFIG_EVENT_ANNOUNCE,
- CONFIG_CREATURE_FAMILY_ASSISTEMCE_RADIUS,
+ CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS,
+ CONFIG_CREATURE_FAMILY_ASSISTANCE_DELAY,
CONFIG_WORLD_BOSS_LEVEL_DIFF,
CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF,
CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF,
@@ -165,17 +170,22 @@ enum WorldConfigs
CONFIG_DEATH_SICKNESS_LEVEL,
CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP,
CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE,
-
- CONFIG_PLAYER_START_GOLD,
- CONFIG_PLAYER_START_HONOR,
- CONFIG_PLAYER_START_ARENAPTS,
- CONFIG_GM_START_LEVEL,
+ CONFIG_THREAT_RADIUS,
CONFIG_INSTANT_LOGOUT,
+ CONFIG_DISABLE_BREATHING,
+ CONFIG_ALL_TAXI_PATHS,
+ CONFIG_DECLINED_NAMES_USED,
+ CONFIG_LISTEN_RANGE_SAY,
+ CONFIG_LISTEN_RANGE_TEXTEMOTE,
+ CONFIG_LISTEN_RANGE_YELL,
+
+ CONFIG_MAX_WHO,
+
CONFIG_BG_START_MUSIC,
CONFIG_START_ALL_SPELLS,
CONFIG_HONOR_AFTER_DUEL,
CONFIG_START_ALL_EXPLORED,
- CONFIG_DISABLE_BREATHING,
+
CONFIG_START_ALL_REP,
CONFIG_ALWAYS_MAXSKILL,
CONFIG_START_ALL_TAXI,
@@ -185,17 +195,13 @@ enum WorldConfigs
CONFIG_PVP_TOKEN_COUNT,
CONFIG_NO_RESET_TALENT_COST,
- CONFIG_THREAT_RADIUS,
- CONFIG_DECLINED_NAMES_USED,
- CONFIG_LISTEN_RANGE_SAY,
- CONFIG_LISTEN_RANGE_TEXTEMOTE,
- CONFIG_LISTEN_RANGE_YELL,
CONFIG_ARENA_MAX_RATING_DIFFERENCE,
CONFIG_ARENA_RATING_DISCARD_TIMER,
CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS,
CONFIG_ARENA_AUTO_DISTRIBUTE_INTERVAL_DAYS,
CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER,
- CONFIG_VALUE_COUNT
+
+ CONFIG_VALUE_COUNT,
};
/// Server rates
@@ -377,7 +383,7 @@ class World
//player Queue
typedef std::list<WorldSession*> Queue;
void AddQueuedPlayer(WorldSession*);
- void RemoveQueuedPlayer(WorldSession*);
+ bool RemoveQueuedPlayer(WorldSession* session);
int32 GetQueuePos(WorldSession*);
uint32 GetQueueSize() const { return m_QueuedPlayer.size(); }
@@ -460,7 +466,6 @@ class World
bool KickPlayer(std::string playerName);
void KickAll();
void KickAllLess(AccountTypes sec);
- void KickAllQueued();
BanReturn BanAccount(BanMode mode, std::string nameOrIP, std::string duration, std::string reason, std::string author);
bool RemoveBanAccount(BanMode mode, std::string nameOrIP);
@@ -522,7 +527,6 @@ class World
WeatherMap m_weathers;
typedef UNORDERED_MAP<uint32, WorldSession*> SessionMap;
SessionMap m_sessions;
- std::set<WorldSession*> m_kicked_sessions;
uint32 m_maxActiveSessionCount;
uint32 m_maxQueuedSessionCount;
diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp
index 69f1598d743..eeb7d41efb6 100644
--- a/src/game/WorldSession.cpp
+++ b/src/game/WorldSession.cpp
@@ -48,7 +48,7 @@ WorldSession::WorldSession(uint32 id, WorldSocket *sock, uint32 sec, uint8 expan
LookingForGroup_auto_join(false), LookingForGroup_auto_add(false), m_muteTime(mute_time),
_player(NULL), m_Socket(sock),_security(sec), _accountId(id), m_expansion(expansion),
m_sessionDbcLocale(sWorld.GetAvailableDbcLocale(locale)), m_sessionDbLocaleIndex(objmgr.GetIndexForLocale(locale)),
-_logoutTime(0), m_playerLoading(false), m_playerLogout(false), m_playerRecentlyLogout(false), m_latency(0)
+_logoutTime(0), m_inQueue(false), m_playerLoading(false), m_playerLogout(false), m_playerRecentlyLogout(false), m_latency(0)
{
if (sock)
{
@@ -208,6 +208,13 @@ bool WorldSession::Update(uint32 /*diff*/)
(this->*opHandle.handler)(*packet);
break;
case STATUS_AUTHED:
+ // prevent cheating with skip queue wait
+ if(m_inQueue)
+ {
+ logUnexpectedOpcode(packet, "the player not pass queue yet");
+ break;
+ }
+
m_playerRecentlyLogout = false;
(this->*opHandle.handler)(*packet);
break;
diff --git a/src/game/WorldSession.h b/src/game/WorldSession.h
index 27391ae9618..c9f98765092 100644
--- a/src/game/WorldSession.h
+++ b/src/game/WorldSession.h
@@ -98,6 +98,9 @@ class TRINITY_DLL_SPEC WorldSession
void SetPlayer(Player *plr) { _player = plr; }
uint8 Expansion() const { return m_expansion; }
+ /// Session in auth.queue currently
+ void SetInQueue(bool state) { m_inQueue = state; }
+
/// Is the user engaged in a log out process?
bool isLogingOut() const { return _logoutTime || m_playerLogout; }
@@ -639,6 +642,7 @@ class TRINITY_DLL_SPEC WorldSession
uint8 m_expansion;
time_t _logoutTime;
+ bool m_inQueue; // session wait in auth.queue
bool m_playerLoading; // code processed in LoginPlayer
bool m_playerLogout; // code processed in LogoutPlayer
bool m_playerRecentlyLogout;
diff --git a/src/shared/Database/DBCEnums.h b/src/shared/Database/DBCEnums.h
index 9050aae8daa..6ad7fdb127a 100644
--- a/src/shared/Database/DBCEnums.h
+++ b/src/shared/Database/DBCEnums.h
@@ -1,104 +1,104 @@
-/*
-* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
-*
-* This program is free software; you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation; either version 2 of the License, or
-* (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program; if not, write to the Free Software
-* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef DBCENUMS_H
-#define DBCENUMS_H
-
-enum AreaTeams
-{
- AREATEAM_NONE = 0,
- AREATEAM_ALLY = 2,
- AREATEAM_HORDE = 4
-};
-
-enum AreaFlags
-{
- AREA_FLAG_SNOW = 0x00000001, // snow (only Dun Morogh, Naxxramas, Razorfen Downs and Winterspring)
- AREA_FLAG_UNK1 = 0x00000002, // unknown, (only Naxxramas and Razorfen Downs)
- AREA_FLAG_UNK2 = 0x00000004, // Only used on development map
- AREA_FLAG_SLAVE_CAPITAL = 0x00000008, // slave capital city flag?
- AREA_FLAG_UNK3 = 0x00000010, // unknown
- AREA_FLAG_SLAVE_CAPITAL2 = 0x00000020, // slave capital city flag?
- AREA_FLAG_UNK4 = 0x00000040, // many zones have this flag
- AREA_FLAG_ARENA = 0x00000080, // arena, both instanced and world arenas
- AREA_FLAG_CAPITAL = 0x00000100, // main capital city flag
- AREA_FLAG_CITY = 0x00000200, // only for one zone named "City" (where it located?)
- AREA_FLAG_OUTLAND = 0x00000400, // outland zones? (only Eye of the Storm not have this flag, but have 0x00004000 flag)
- AREA_FLAG_SANCTUARY = 0x00000800, // sanctuary area (PvP disabled)
- AREA_FLAG_NEED_FLY = 0x00001000, // only Netherwing Ledge, Socrethar's Seat, Tempest Keep, The Arcatraz, The Botanica, The Mechanar, Sorrow Wing Point, Dragonspine Ridge, Netherwing Mines, Dragonmaw Base Camp, Dragonmaw Skyway
- AREA_FLAG_UNUSED1 = 0x00002000, // not used now (no area/zones with this flag set in 2.4.2)
- AREA_FLAG_OUTLAND2 = 0x00004000, // outland zones? (only Circle of Blood Arena not have this flag, but have 0x00000400 flag)
- AREA_FLAG_PVP = 0x00008000, // pvp objective area? (Death's Door also has this flag although it's no pvp object area)
- AREA_FLAG_ARENA_INSTANCE = 0x00010000, // used by instanced arenas only
- AREA_FLAG_UNUSED2 = 0x00020000, // not used now (no area/zones with this flag set in 2.4.2)
- AREA_FLAG_UNK5 = 0x00040000, // just used for Amani Pass, Hatchet Hills
- AREA_FLAG_LOWLEVEL = 0x00100000 // used for some starting areas with area_level <=15
-};
-
-enum FactionTemplateFlags
-{
- FACTION_TEMPLATE_FLAG_CONTESTED_GUARD = 0x00001000, // faction will attack players that were involved in PvP combats
-};
-
-enum FactionMasks
-{
- FACTION_MASK_PLAYER = 1, // any player
- FACTION_MASK_ALLIANCE = 2, // player or creature from alliance team
- FACTION_MASK_HORDE = 4, // player or creature from horde team
- FACTION_MASK_MONSTER = 8 // aggressive creature from monster team
- // if none flags set then non-aggressive creature
-};
-
-enum MapTypes
-{
- MAP_COMMON = 0,
- MAP_INSTANCE = 1,
- MAP_RAID = 2,
- MAP_BATTLEGROUND = 3,
- MAP_ARENA = 4
-};
-
-enum AbilytyLearnType
-{
- ABILITY_LEARNED_ON_GET_PROFESSION_SKILL = 1,
- ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL = 2
-};
-
-enum ItemEnchantmentType
-{
- ITEM_ENCHANTMENT_TYPE_NONE = 0,
- ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL = 1,
- ITEM_ENCHANTMENT_TYPE_DAMAGE = 2,
- ITEM_ENCHANTMENT_TYPE_EQUIP_SPELL = 3,
- ITEM_ENCHANTMENT_TYPE_RESISTANCE = 4,
- ITEM_ENCHANTMENT_TYPE_STAT = 5,
- ITEM_ENCHANTMENT_TYPE_TOTEM = 6
-};
-
-enum TotemCategoryType
-{
- TOTEM_CATEGORY_TYPE_KNIFE = 1,
- TOTEM_CATEGORY_TYPE_TOTEM = 2,
- TOTEM_CATEGORY_TYPE_ROD = 3,
- TOTEM_CATEGORY_TYPE_PICK = 21,
- TOTEM_CATEGORY_TYPE_STONE = 22,
- TOTEM_CATEGORY_TYPE_HAMMER = 23,
- TOTEM_CATEGORY_TYPE_SPANNER = 24
-};
-
-#endif
+/*
+* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation; either version 2 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef DBCENUMS_H
+#define DBCENUMS_H
+
+enum AreaTeams
+{
+ AREATEAM_NONE = 0,
+ AREATEAM_ALLY = 2,
+ AREATEAM_HORDE = 4
+};
+
+enum AreaFlags
+{
+ AREA_FLAG_SNOW = 0x00000001, // snow (only Dun Morogh, Naxxramas, Razorfen Downs and Winterspring)
+ AREA_FLAG_UNK1 = 0x00000002, // unknown, (only Naxxramas and Razorfen Downs)
+ AREA_FLAG_UNK2 = 0x00000004, // Only used on development map
+ AREA_FLAG_SLAVE_CAPITAL = 0x00000008, // slave capital city flag?
+ AREA_FLAG_UNK3 = 0x00000010, // unknown
+ AREA_FLAG_SLAVE_CAPITAL2 = 0x00000020, // slave capital city flag?
+ AREA_FLAG_UNK4 = 0x00000040, // many zones have this flag
+ AREA_FLAG_ARENA = 0x00000080, // arena, both instanced and world arenas
+ AREA_FLAG_CAPITAL = 0x00000100, // main capital city flag
+ AREA_FLAG_CITY = 0x00000200, // only for one zone named "City" (where it located?)
+ AREA_FLAG_OUTLAND = 0x00000400, // outland zones? (only Eye of the Storm not have this flag, but have 0x00004000 flag)
+ AREA_FLAG_SANCTUARY = 0x00000800, // sanctuary area (PvP disabled)
+ AREA_FLAG_NEED_FLY = 0x00001000, // only Netherwing Ledge, Socrethar's Seat, Tempest Keep, The Arcatraz, The Botanica, The Mechanar, Sorrow Wing Point, Dragonspine Ridge, Netherwing Mines, Dragonmaw Base Camp, Dragonmaw Skyway
+ AREA_FLAG_UNUSED1 = 0x00002000, // not used now (no area/zones with this flag set in 2.4.2)
+ AREA_FLAG_OUTLAND2 = 0x00004000, // outland zones? (only Circle of Blood Arena not have this flag, but have 0x00000400 flag)
+ AREA_FLAG_PVP = 0x00008000, // pvp objective area? (Death's Door also has this flag although it's no pvp object area)
+ AREA_FLAG_ARENA_INSTANCE = 0x00010000, // used by instanced arenas only
+ AREA_FLAG_UNUSED2 = 0x00020000, // not used now (no area/zones with this flag set in 2.4.2)
+ AREA_FLAG_UNK5 = 0x00040000, // just used for Amani Pass, Hatchet Hills
+ AREA_FLAG_LOWLEVEL = 0x00100000 // used for some starting areas with area_level <=15
+};
+
+enum FactionTemplateFlags
+{
+ FACTION_TEMPLATE_FLAG_CONTESTED_GUARD = 0x00001000, // faction will attack players that were involved in PvP combats
+};
+
+enum FactionMasks
+{
+ FACTION_MASK_PLAYER = 1, // any player
+ FACTION_MASK_ALLIANCE = 2, // player or creature from alliance team
+ FACTION_MASK_HORDE = 4, // player or creature from horde team
+ FACTION_MASK_MONSTER = 8 // aggressive creature from monster team
+ // if none flags set then non-aggressive creature
+};
+
+enum MapTypes
+{
+ MAP_COMMON = 0,
+ MAP_INSTANCE = 1,
+ MAP_RAID = 2,
+ MAP_BATTLEGROUND = 3,
+ MAP_ARENA = 4
+};
+
+enum AbilytyLearnType
+{
+ ABILITY_LEARNED_ON_GET_PROFESSION_SKILL = 1,
+ ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL = 2
+};
+
+enum ItemEnchantmentType
+{
+ ITEM_ENCHANTMENT_TYPE_NONE = 0,
+ ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL = 1,
+ ITEM_ENCHANTMENT_TYPE_DAMAGE = 2,
+ ITEM_ENCHANTMENT_TYPE_EQUIP_SPELL = 3,
+ ITEM_ENCHANTMENT_TYPE_RESISTANCE = 4,
+ ITEM_ENCHANTMENT_TYPE_STAT = 5,
+ ITEM_ENCHANTMENT_TYPE_TOTEM = 6
+};
+
+enum TotemCategoryType
+{
+ TOTEM_CATEGORY_TYPE_KNIFE = 1,
+ TOTEM_CATEGORY_TYPE_TOTEM = 2,
+ TOTEM_CATEGORY_TYPE_ROD = 3,
+ TOTEM_CATEGORY_TYPE_PICK = 21,
+ TOTEM_CATEGORY_TYPE_STONE = 22,
+ TOTEM_CATEGORY_TYPE_HAMMER = 23,
+ TOTEM_CATEGORY_TYPE_SPANNER = 24
+};
+
+#endif
diff --git a/src/shared/Database/DBCStores.cpp b/src/shared/Database/DBCStores.cpp
index 71e3483a1ab..03536daf738 100644
--- a/src/shared/Database/DBCStores.cpp
+++ b/src/shared/Database/DBCStores.cpp
@@ -38,6 +38,7 @@ static AreaFlagByMapID sAreaFlagByMapID; // for instances wit
DBCStorage <AreaTriggerEntry> sAreaTriggerStore(AreaTriggerEntryfmt);
DBCStorage <BankBagSlotPricesEntry> sBankBagSlotPricesStore(BankBagSlotPricesEntryfmt);
DBCStorage <BattlemasterListEntry> sBattlemasterListStore(BattlemasterListEntryfmt);
+DBCStorage <CharStartOutfitEntry> sCharStartOutfitStore(CharStartOutfitEntryfmt);
DBCStorage <CharTitlesEntry> sCharTitlesStore(CharTitlesEntryfmt);
DBCStorage <ChatChannelsEntry> sChatChannelsStore(ChatChannelsEntryfmt);
DBCStorage <ChrClassesEntry> sChrClassesStore(ChrClassesEntryfmt);
@@ -203,6 +204,8 @@ void LoadDBCStores(std::string dataPath)
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sAreaTriggerStore, dbcPath,"AreaTrigger.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sBankBagSlotPricesStore, dbcPath,"BankBagSlotPrices.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sBattlemasterListStore, dbcPath,"BattlemasterList.dbc");
+ LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCharStartOutfitStore, dbcPath,"CharStartOutfit.dbc");
+
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sCharTitlesStore, dbcPath,"CharTitles.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChatChannelsStore, dbcPath,"ChatChannels.dbc");
LoadDBC(availableDbcLocales,bar,bad_dbc_files,sChrClassesStore, dbcPath,"ChrClasses.dbc");
@@ -494,13 +497,22 @@ uint32 GetTalentSpellCost(uint32 spellId)
return 0;
}
-AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id)
+int32 GetAreaFlagByAreaID(uint32 area_id)
{
AreaFlagByAreaID::iterator i = sAreaFlagByAreaID.find(area_id);
if(i == sAreaFlagByAreaID.end())
+ return -1;
+
+ return i->second;
+}
+
+AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id)
+{
+ int32 areaflag = GetAreaFlagByAreaID(area_id);
+ if(areaflag < 0)
return NULL;
- return sAreaStore.LookupEntry(i->second);
+ return sAreaStore.LookupEntry(areaflag );
}
AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag,uint32 map_id)
diff --git a/src/shared/Database/DBCStores.h b/src/shared/Database/DBCStores.h
index 0375f20c7eb..399b94213fe 100644
--- a/src/shared/Database/DBCStores.h
+++ b/src/shared/Database/DBCStores.h
@@ -35,6 +35,7 @@ char* GetPetName(uint32 petfamily, uint32 dbclang);
uint32 GetTalentSpellCost(uint32 spellId);
TalentSpellPos const* GetTalentSpellPos(uint32 spellId);
+int32 GetAreaFlagByAreaID(uint32 area_id); // -1 if not found
AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id);
AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag,uint32 map_id);
uint32 GetAreaFlagByMapId(uint32 mapid);
@@ -136,6 +137,7 @@ extern DBCStorage <AreaTriggerEntry> sAreaTriggerStore;
extern DBCStorage <BankBagSlotPricesEntry> sBankBagSlotPricesStore;
extern DBCStorage <BattlemasterListEntry> sBattlemasterListStore;
//extern DBCStorage <ChatChannelsEntry> sChatChannelsStore; -- accessed using function, no usable index
+extern DBCStorage <CharStartOutfitEntry> sCharStartOutfitStore;
extern DBCStorage <CharTitlesEntry> sCharTitlesStore;
extern DBCStorage <ChrClassesEntry> sChrClassesStore;
extern DBCStorage <ChrRacesEntry> sChrRacesStore;
diff --git a/src/shared/Database/DBCStructure.h b/src/shared/Database/DBCStructure.h
index a71f80ac8c7..a84b119664d 100644
--- a/src/shared/Database/DBCStructure.h
+++ b/src/shared/Database/DBCStructure.h
@@ -86,6 +86,21 @@ struct BattlemasterListEntry
// 32 unused
};
+#define MAX_OUTFIT_ITEMS 12
+// #define MAX_OUTFIT_ITEMS 24 // 12->24 in 3.0.x
+
+struct CharStartOutfitEntry
+{
+ //uint32 Id; // 0
+ uint32 RaceClassGender; // 1 (UNIT_FIELD_BYTES_0 & 0x00FFFFFF) comparable (0 byte = race, 1 byte = class, 2 byte = gender)
+ int32 ItemId[MAX_OUTFIT_ITEMS]; // 2-13
+ //int32 ItemDisplayId[MAX_OUTFIT_ITEMS]; // 14-25 not required at server side
+ //int32 ItemInventorySlot[MAX_OUTFIT_ITEMS]; // 26-37 not required at server side
+ //uint32 Unknown1; // 38, unique values (index-like with gaps ordered in other way as ids)
+ //uint32 Unknown2; // 39
+ //uint32 Unknown3; // 40
+};
+
struct CharTitlesEntry
{
uint32 ID; // 0, title ids, for example in Quest::GetCharTitleId()
@@ -229,6 +244,8 @@ struct FactionTemplateEntry
// helpers
bool IsFriendlyTo(FactionTemplateEntry const& entry) const
{
+ if(ID == entry.ID)
+ return true;
if(enemyFaction1 == entry.faction || enemyFaction2 == entry.faction || enemyFaction3 == entry.faction || enemyFaction4 == entry.faction )
return false;
if(friendFaction1 == entry.faction || friendFaction2 == entry.faction || friendFaction3 == entry.faction || friendFaction4 == entry.faction )
@@ -237,6 +254,8 @@ struct FactionTemplateEntry
}
bool IsHostileTo(FactionTemplateEntry const& entry) const
{
+ if(ID == entry.ID)
+ return false;
if(enemyFaction1 == entry.faction || enemyFaction2 == entry.faction || enemyFaction3 == entry.faction || enemyFaction4 == entry.faction )
return true;
if(friendFaction1 == entry.faction || friendFaction2 == entry.faction || friendFaction3 == entry.faction || friendFaction4 == entry.faction )
@@ -667,6 +686,7 @@ struct SpellRangeEntry
uint32 ID;
float minRange;
float maxRange;
+ uint32 flags;
};
struct SpellShapeshiftEntry
diff --git a/src/shared/Database/DBCfmt.cpp b/src/shared/Database/DBCfmt.cpp
index 64163664b49..57a81921d62 100644
--- a/src/shared/Database/DBCfmt.cpp
+++ b/src/shared/Database/DBCfmt.cpp
@@ -22,6 +22,9 @@ const char AreaTableEntryfmt[]="iiinixxxxxissssssssssssssssxixxxxxx";
const char AreaTriggerEntryfmt[]="niffffffff";
const char BankBagSlotPricesEntryfmt[]="ni";
const char BattlemasterListEntryfmt[]="niiixxxxxiiiixxssssssssssssssssxx";
+const char CharStartOutfitEntryfmt[]="diiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxx";
+// 3*12 new item fields in 3.0.x
+//const char CharStartOutfitEntryfmt[]="diiiiiiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const char CharTitlesEntryfmt[]="nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi";
const char ChatChannelsEntryfmt[]="iixssssssssssssssssxxxxxxxxxxxxxxxxxx";
// ChatChannelsEntryfmt, index not used (more compact store)
@@ -68,7 +71,7 @@ const char SpellFocusObjectfmt[]="nxxxxxxxxxxxxxxxxx";
const char SpellItemEnchantmentfmt[]="niiiiiixxxiiissssssssssssssssxiiii";
const char SpellItemEnchantmentConditionfmt[]="nbbbbbxxxxxbbbbbbbbbbiiiiiXXXXX";
const char SpellRadiusfmt[]="nfxf";
-const char SpellRangefmt[]="nffxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
+const char SpellRangefmt[]="nffixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
const char SpellShapeshiftfmt[]="nxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxx";
const char StableSlotPricesfmt[] = "ni";
const char TalentEntryfmt[]="niiiiiiiixxxxixxixxxi";
diff --git a/src/shared/Database/SQLStorageImpl.h b/src/shared/Database/SQLStorageImpl.h
index 2ccd5724a07..4f10c6eee05 100644
--- a/src/shared/Database/SQLStorageImpl.h
+++ b/src/shared/Database/SQLStorageImpl.h
@@ -1,214 +1,214 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "ProgressBar.h"
-#include "Log.h"
-#include "dbcfile.h"
-
-template<class T>
-template<class S, class D>
-void SQLStorageLoaderBase<T>::convert(uint32 field_pos, S src, D &dst)
-{
- dst = D(src);
-}
-
-template<class T>
-void SQLStorageLoaderBase<T>::convert_str_to_str(uint32 field_pos, char *src, char *&dst)
-{
- if(!src)
- {
- dst = new char[1];
- *dst = 0;
- }
- else
- {
- uint32 l = strlen(src) + 1;
- dst = new char[l];
- memcpy(dst, src, l);
- }
-}
-
-template<class T>
-template<class S>
-void SQLStorageLoaderBase<T>::convert_to_str(uint32 field_pos, S src, char * & dst)
-{
- dst = new char[1];
- *dst = 0;
-}
-
-template<class T>
-template<class D>
-void SQLStorageLoaderBase<T>::convert_from_str(uint32 field_pos, char * src, D& dst)
-{
- dst = 0;
-}
-
-template<class T>
-template<class V>
-void SQLStorageLoaderBase<T>::storeValue(V value, SQLStorage &store, char *p, int x, uint32 &offset)
-{
- T * subclass = (static_cast<T*>(this));
- switch(store.dst_format[x])
- {
- case FT_LOGIC:
- subclass->convert(x, value, *((bool*)(&p[offset])) );
- offset+=sizeof(bool);
- break;
- case FT_BYTE:
- subclass->convert(x, value, *((char*)(&p[offset])) );
- offset+=sizeof(char);
- break;
- case FT_INT:
- subclass->convert(x, value, *((uint32*)(&p[offset])) );
- offset+=sizeof(uint32);
- break;
- case FT_FLOAT:
- subclass->convert(x, value, *((float*)(&p[offset])) );
- offset+=sizeof(float);
- break;
- case FT_STRING:
- subclass->convert_to_str(x, value, *((char**)(&p[offset])) );
- offset+=sizeof(char*);
- break;
- }
-}
-
-template<class T>
-void SQLStorageLoaderBase<T>::storeValue(char * value, SQLStorage &store, char *p, int x, uint32 &offset)
-{
- T * subclass = (static_cast<T*>(this));
- switch(store.dst_format[x])
- {
- case FT_LOGIC:
- subclass->convert_from_str(x, value, *((bool*)(&p[offset])) );
- offset+=sizeof(bool);
- break;
- case FT_BYTE:
- subclass->convert_from_str(x, value, *((char*)(&p[offset])) );
- offset+=sizeof(char);
- break;
- case FT_INT:
- subclass->convert_from_str(x, value, *((uint32*)(&p[offset])) );
- offset+=sizeof(uint32);
- break;
- case FT_FLOAT:
- subclass->convert_from_str(x, value, *((float*)(&p[offset])) );
- offset+=sizeof(float);
- break;
- case FT_STRING:
- subclass->convert_str_to_str(x, value, *((char**)(&p[offset])) );
- offset+=sizeof(char*);
- break;
- }
-}
-
-template<class T>
-void SQLStorageLoaderBase<T>::Load(SQLStorage &store)
-{
- uint32 maxi;
- Field *fields;
- QueryResult *result = WorldDatabase.PQuery("SELECT MAX(%s) FROM %s", store.entry_field, store.table);
- if(!result)
- {
- sLog.outError("Error loading %s table (not exist?)\n", store.table);
- exit(1); // Stop server at loading non exited table or not accessable table
- }
-
- maxi = (*result)[0].GetUInt32()+1;
- delete result;
-
- result = WorldDatabase.PQuery("SELECT COUNT(*) FROM %s", store.table);
- if(result)
- {
- fields = result->Fetch();
- store.RecordCount = fields[0].GetUInt32();
- delete result;
- }
- else
- store.RecordCount = 0;
-
- result = WorldDatabase.PQuery("SELECT * FROM %s", store.table);
-
- if(!result)
- {
- sLog.outError("%s table is empty!\n", store.table);
- store.RecordCount = 0;
- return;
- }
-
- uint32 recordsize = 0;
- uint32 offset = 0;
-
- if(store.iNumFields != result->GetFieldCount())
- {
- store.RecordCount = 0;
- sLog.outError("Error in %s table, probably sql file format was updated (there should be %d fields in sql).\n", store.table, store.iNumFields);
- delete result;
- exit(1); // Stop server at loading broken or non-compatible table.
- }
-
- //get struct size
- uint32 sc=0;
- uint32 bo=0;
- uint32 bb=0;
- for(uint32 x=0; x< store.iNumFields; x++)
- if(store.dst_format[x]==FT_STRING)
- ++sc;
- else if (store.dst_format[x]==FT_LOGIC)
- ++bo;
- else if (store.dst_format[x]==FT_BYTE)
- ++bb;
- recordsize=(store.iNumFields-sc-bo-bb)*4+sc*sizeof(char*)+bo*sizeof(bool)+bb*sizeof(char);
-
- char** newIndex=new char*[maxi];
- memset(newIndex,0,maxi*sizeof(char*));
-
- char * _data= new char[store.RecordCount *recordsize];
- uint32 count=0;
- barGoLink bar( store.RecordCount );
- do
- {
- fields = result->Fetch();
- bar.step();
- char *p=(char*)&_data[recordsize*count];
- newIndex[fields[0].GetUInt32()]=p;
-
- offset=0;
- for(uint32 x = 0; x < store.iNumFields; x++)
- switch(store.src_format[x])
- {
- case FT_LOGIC:
- storeValue((bool)(fields[x].GetUInt32() > 0), store, p, x, offset); break;
- case FT_BYTE:
- storeValue((char)fields[x].GetUInt8(), store, p, x, offset); break;
- case FT_INT:
- storeValue((uint32)fields[x].GetUInt32(), store, p, x, offset); break;
- case FT_FLOAT:
- storeValue((float)fields[x].GetFloat(), store, p, x, offset); break;
- case FT_STRING:
- storeValue((char*)fields[x].GetString(), store, p, x, offset); break;
- }
- ++count;
- }while( result->NextRow() );
-
- delete result;
-
- store.pIndex = newIndex;
- store.MaxEntry = maxi;
- store.data = _data;
-}
+/*
+ * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "ProgressBar.h"
+#include "Log.h"
+#include "dbcfile.h"
+
+template<class T>
+template<class S, class D>
+void SQLStorageLoaderBase<T>::convert(uint32 field_pos, S src, D &dst)
+{
+ dst = D(src);
+}
+
+template<class T>
+void SQLStorageLoaderBase<T>::convert_str_to_str(uint32 field_pos, char *src, char *&dst)
+{
+ if(!src)
+ {
+ dst = new char[1];
+ *dst = 0;
+ }
+ else
+ {
+ uint32 l = strlen(src) + 1;
+ dst = new char[l];
+ memcpy(dst, src, l);
+ }
+}
+
+template<class T>
+template<class S>
+void SQLStorageLoaderBase<T>::convert_to_str(uint32 field_pos, S src, char * & dst)
+{
+ dst = new char[1];
+ *dst = 0;
+}
+
+template<class T>
+template<class D>
+void SQLStorageLoaderBase<T>::convert_from_str(uint32 field_pos, char * src, D& dst)
+{
+ dst = 0;
+}
+
+template<class T>
+template<class V>
+void SQLStorageLoaderBase<T>::storeValue(V value, SQLStorage &store, char *p, int x, uint32 &offset)
+{
+ T * subclass = (static_cast<T*>(this));
+ switch(store.dst_format[x])
+ {
+ case FT_LOGIC:
+ subclass->convert(x, value, *((bool*)(&p[offset])) );
+ offset+=sizeof(bool);
+ break;
+ case FT_BYTE:
+ subclass->convert(x, value, *((char*)(&p[offset])) );
+ offset+=sizeof(char);
+ break;
+ case FT_INT:
+ subclass->convert(x, value, *((uint32*)(&p[offset])) );
+ offset+=sizeof(uint32);
+ break;
+ case FT_FLOAT:
+ subclass->convert(x, value, *((float*)(&p[offset])) );
+ offset+=sizeof(float);
+ break;
+ case FT_STRING:
+ subclass->convert_to_str(x, value, *((char**)(&p[offset])) );
+ offset+=sizeof(char*);
+ break;
+ }
+}
+
+template<class T>
+void SQLStorageLoaderBase<T>::storeValue(char * value, SQLStorage &store, char *p, int x, uint32 &offset)
+{
+ T * subclass = (static_cast<T*>(this));
+ switch(store.dst_format[x])
+ {
+ case FT_LOGIC:
+ subclass->convert_from_str(x, value, *((bool*)(&p[offset])) );
+ offset+=sizeof(bool);
+ break;
+ case FT_BYTE:
+ subclass->convert_from_str(x, value, *((char*)(&p[offset])) );
+ offset+=sizeof(char);
+ break;
+ case FT_INT:
+ subclass->convert_from_str(x, value, *((uint32*)(&p[offset])) );
+ offset+=sizeof(uint32);
+ break;
+ case FT_FLOAT:
+ subclass->convert_from_str(x, value, *((float*)(&p[offset])) );
+ offset+=sizeof(float);
+ break;
+ case FT_STRING:
+ subclass->convert_str_to_str(x, value, *((char**)(&p[offset])) );
+ offset+=sizeof(char*);
+ break;
+ }
+}
+
+template<class T>
+void SQLStorageLoaderBase<T>::Load(SQLStorage &store)
+{
+ uint32 maxi;
+ Field *fields;
+ QueryResult *result = WorldDatabase.PQuery("SELECT MAX(%s) FROM %s", store.entry_field, store.table);
+ if(!result)
+ {
+ sLog.outError("Error loading %s table (not exist?)\n", store.table);
+ exit(1); // Stop server at loading non exited table or not accessable table
+ }
+
+ maxi = (*result)[0].GetUInt32()+1;
+ delete result;
+
+ result = WorldDatabase.PQuery("SELECT COUNT(*) FROM %s", store.table);
+ if(result)
+ {
+ fields = result->Fetch();
+ store.RecordCount = fields[0].GetUInt32();
+ delete result;
+ }
+ else
+ store.RecordCount = 0;
+
+ result = WorldDatabase.PQuery("SELECT * FROM %s", store.table);
+
+ if(!result)
+ {
+ sLog.outError("%s table is empty!\n", store.table);
+ store.RecordCount = 0;
+ return;
+ }
+
+ uint32 recordsize = 0;
+ uint32 offset = 0;
+
+ if(store.iNumFields != result->GetFieldCount())
+ {
+ store.RecordCount = 0;
+ sLog.outError("Error in %s table, probably sql file format was updated (there should be %d fields in sql).\n", store.table, store.iNumFields);
+ delete result;
+ exit(1); // Stop server at loading broken or non-compatible table.
+ }
+
+ //get struct size
+ uint32 sc=0;
+ uint32 bo=0;
+ uint32 bb=0;
+ for(uint32 x=0; x< store.iNumFields; x++)
+ if(store.dst_format[x]==FT_STRING)
+ ++sc;
+ else if (store.dst_format[x]==FT_LOGIC)
+ ++bo;
+ else if (store.dst_format[x]==FT_BYTE)
+ ++bb;
+ recordsize=(store.iNumFields-sc-bo-bb)*4+sc*sizeof(char*)+bo*sizeof(bool)+bb*sizeof(char);
+
+ char** newIndex=new char*[maxi];
+ memset(newIndex,0,maxi*sizeof(char*));
+
+ char * _data= new char[store.RecordCount *recordsize];
+ uint32 count=0;
+ barGoLink bar( store.RecordCount );
+ do
+ {
+ fields = result->Fetch();
+ bar.step();
+ char *p=(char*)&_data[recordsize*count];
+ newIndex[fields[0].GetUInt32()]=p;
+
+ offset=0;
+ for(uint32 x = 0; x < store.iNumFields; x++)
+ switch(store.src_format[x])
+ {
+ case FT_LOGIC:
+ storeValue((bool)(fields[x].GetUInt32() > 0), store, p, x, offset); break;
+ case FT_BYTE:
+ storeValue((char)fields[x].GetUInt8(), store, p, x, offset); break;
+ case FT_INT:
+ storeValue((uint32)fields[x].GetUInt32(), store, p, x, offset); break;
+ case FT_FLOAT:
+ storeValue((float)fields[x].GetFloat(), store, p, x, offset); break;
+ case FT_STRING:
+ storeValue((char*)fields[x].GetString(), store, p, x, offset); break;
+ }
+ ++count;
+ }while( result->NextRow() );
+
+ delete result;
+
+ store.pIndex = newIndex;
+ store.MaxEntry = maxi;
+ store.data = _data;
+}
diff --git a/src/shared/Log.cpp b/src/shared/Log.cpp
index e30ecc56f25..705b34d3cc7 100644
--- a/src/shared/Log.cpp
+++ b/src/shared/Log.cpp
@@ -38,6 +38,13 @@ enum LogType
const int LogType_count = int(LogError) +1;
+Log::Log() :
+ raLogfile(NULL), logfile(NULL), gmLogfile(NULL), charLogfile(NULL),
+ dberLogfile(NULL), m_colored(false), m_includeTime(false), m_gmlog_per_account(false)
+{
+ Initialize();
+}
+
void Log::InitColors(std::string str)
{
if(str.empty())
@@ -175,73 +182,56 @@ void Log::SetLogFileLevel(char *Level)
void Log::Initialize()
{
- std::string logsDir = sConfig.GetStringDefault("LogsDir","");
-
- if(!logsDir.empty())
+ /// Common log files data
+ m_logsDir = sConfig.GetStringDefault("LogsDir","");
+ if(!m_logsDir.empty())
{
- if((logsDir.at(logsDir.length()-1)!='/') && (logsDir.at(logsDir.length()-1)!='\\'))
- logsDir.append("/");
+ if((m_logsDir.at(m_logsDir.length()-1)!='/') && (m_logsDir.at(m_logsDir.length()-1)!='\\'))
+ m_logsDir.append("/");
}
- std::string logfn=sConfig.GetStringDefault("LogFile", "");
- if(!logfn.empty())
- {
- if(sConfig.GetBoolDefault("LogTimestamp",false))
- {
- std::string logTimestamp = GetTimestampStr();
- logTimestamp.insert(0,"_");
- size_t dot_pos = logfn.find_last_of(".");
- if(dot_pos!=logfn.npos)
- logfn.insert(dot_pos,logTimestamp);
- else
- logfn += logTimestamp;
- }
+ m_logsTimestamp = "_" + GetTimestampStr();
- logfile = fopen((logsDir+logfn).c_str(), "w");
- }
+ /// Open specific log files
+ logfile = openLogFile("LogFile","LogTimestamp","w");
- std::string gmlogname = sConfig.GetStringDefault("GMLogFile", "");
- if(!gmlogname.empty())
+ m_gmlog_per_account = sConfig.GetBoolDefault("GmLogPerAccount",false);
+ if(!m_gmlog_per_account)
+ gmLogfile = openLogFile("GMLogFile","GmLogTimestamp","a");
+ else
{
- if(sConfig.GetBoolDefault("GmLogTimestamp",false))
+ // GM log settings for per account case
+ m_gmlog_filename_format = sConfig.GetStringDefault("GMLogFile", "");
+ if(!m_gmlog_filename_format.empty())
{
- std::string gmLogTimestamp = GetTimestampStr();
- gmLogTimestamp.insert(0,"_");
- size_t dot_pos = gmlogname.find_last_of(".");
- if(dot_pos!=gmlogname.npos)
- gmlogname.insert(dot_pos,gmLogTimestamp);
- else
- gmlogname += gmLogTimestamp;
- }
- gmLogfile = fopen((logsDir+gmlogname).c_str(), "a");
- }
+ bool m_gmlog_timestamp = sConfig.GetBoolDefault("GmLogTimestamp",false);
- std::string charlogname = sConfig.GetStringDefault("CharLogFile", "");
- if(!charlogname.empty())
- {
- if(sConfig.GetBoolDefault("CharLogTimestamp",false))
- {
- std::string charLogTimestamp = GetTimestampStr();
- charLogTimestamp.insert(0,"_");
- size_t dot_pos = charlogname.find_last_of(".");
- if(dot_pos!=charlogname.npos)
- charlogname.insert(dot_pos,charLogTimestamp);
+ size_t dot_pos = m_gmlog_filename_format.find_last_of(".");
+ if(dot_pos!=m_gmlog_filename_format.npos)
+ {
+ if(m_gmlog_timestamp)
+ m_gmlog_filename_format.insert(dot_pos,m_logsTimestamp);
+
+ m_gmlog_filename_format.insert(dot_pos,"_#%u");
+ }
else
- charlogname += charLogTimestamp;
+ {
+ m_gmlog_filename_format += "_#%u";
+
+ if(m_gmlog_timestamp)
+ m_gmlog_filename_format += m_logsTimestamp;
+ }
+
+ m_gmlog_filename_format = m_logsDir + m_gmlog_filename_format;
}
- charLogfile = fopen((logsDir+charlogname).c_str(), "a");
}
- std::string dberlogname = sConfig.GetStringDefault("DBErrorLogFile", "");
- if(!dberlogname.empty())
- {
- dberLogfile = fopen((logsDir+dberlogname).c_str(), "a");
- }
- std::string ralogname = sConfig.GetStringDefault("RaLogFile", "");
- if(!ralogname.empty())
- {
- raLogfile = fopen((logsDir+ralogname).c_str(), "a");
- }
+ charLogfile = openLogFile("CharLogFile","CharLogTimestamp","a");
+
+ dberLogfile = openLogFile("DBErrorLogFile",NULL,"a");
+ raLogfile = openLogFile("RaLogFile",NULL,"a");
+
+ // Main log file settings
m_includeTime = sConfig.GetBoolDefault("LogTime", false);
m_logLevel = sConfig.GetIntDefault("LogLevel", 0);
m_logFileLevel = sConfig.GetIntDefault("LogFileLevel", 0);
@@ -256,9 +246,38 @@ void Log::Initialize()
if(sConfig.GetBoolDefault("LogFilter_VisibilityChanges", true))
m_logFilter |= LOG_FILTER_VISIBILITY_CHANGES;
+ // Char log settings
m_charLog_Dump = sConfig.GetBoolDefault("CharLogDump", false);
}
+FILE* Log::openLogFile(char const* configFileName,char const* configTimeStampFlag, char const* mode)
+{
+ std::string logfn=sConfig.GetStringDefault(configFileName, "");
+ if(logfn.empty())
+ return NULL;
+
+ if(configTimeStampFlag && sConfig.GetBoolDefault(configTimeStampFlag,false))
+ {
+ size_t dot_pos = logfn.find_last_of(".");
+ if(dot_pos!=logfn.npos)
+ logfn.insert(dot_pos,m_logsTimestamp);
+ else
+ logfn += m_logsTimestamp;
+ }
+
+ return fopen((m_logsDir+logfn).c_str(), mode);
+}
+
+FILE* Log::openGmlogPerAccount(uint32 account)
+{
+ if(m_gmlog_filename_format.empty())
+ return NULL;
+
+ char namebuf[TRINITY_PATH_MAX];
+ snprintf(namebuf,TRINITY_PATH_MAX,m_gmlog_filename_format.c_str(),account);
+ return fopen(namebuf, "a");
+}
+
void Log::outTimestamp(FILE* file)
{
time_t t = time(NULL);
@@ -577,7 +596,7 @@ void Log::outDebug( const char * str, ... )
fflush(stdout);
}
-void Log::outCommand( const char * str, ... )
+void Log::outCommand( uint32 account, const char * str, ... )
{
if( !str )
return;
@@ -607,7 +626,21 @@ void Log::outCommand( const char * str, ... )
va_end(ap);
fflush(logfile);
}
- if(gmLogfile)
+
+ if (m_gmlog_per_account)
+ {
+ if (FILE* per_file = openGmlogPerAccount (account))
+ {
+ va_list ap;
+ outTimestamp(per_file);
+ va_start(ap, str);
+ vfprintf(per_file, str, ap);
+ fprintf(per_file, "\n" );
+ va_end(ap);
+ fclose(per_file);
+ }
+ }
+ else if (gmLogfile)
{
va_list ap;
outTimestamp(gmLogfile);
@@ -617,6 +650,7 @@ void Log::outCommand( const char * str, ... )
va_end(ap);
fflush(gmLogfile);
}
+
fflush(stdout);
}
diff --git a/src/shared/Log.h b/src/shared/Log.h
index c22c9e6778b..02f996d26c5 100644
--- a/src/shared/Log.h
+++ b/src/shared/Log.h
@@ -58,7 +58,8 @@ const int Color_count = int(WHITE)+1;
class Log : public Trinity::Singleton<Log, Trinity::ClassLevelLockable<Log, ZThread::FastMutex> >
{
friend class Trinity::OperatorNew<Log>;
- Log() : raLogfile(NULL), logfile(NULL), gmLogfile(NULL), charLogfile(NULL), dberLogfile(NULL), m_colored(false) { Initialize(); }
+ Log();
+
~Log()
{
if( logfile != NULL )
@@ -85,7 +86,7 @@ class Log : public Trinity::Singleton<Log, Trinity::ClassLevelLockable<Log, ZThr
void Initialize();
void InitColors(std::string init_str);
void outTitle( const char * str);
- void outCommand( const char * str, ...) ATTR_PRINTF(2,3);
+ void outCommand( uint32 account, const char * str, ...) ATTR_PRINTF(3,4);
void outString(); // any log level
// any log level
void outString( const char * str, ... ) ATTR_PRINTF(2,3);
@@ -120,6 +121,9 @@ class Log : public Trinity::Singleton<Log, Trinity::ClassLevelLockable<Log, ZThr
bool IsOutCharDump() const { return m_charLog_Dump; }
bool IsIncludeTime() const { return m_includeTime; }
private:
+ FILE* openLogFile(char const* configFileName,char const* configTimeStampFlag, char const* mode);
+ FILE* openGmlogPerAccount(uint32 account);
+
FILE* raLogfile;
FILE* logfile;
FILE* gmLogfile;
@@ -134,9 +138,16 @@ class Log : public Trinity::Singleton<Log, Trinity::ClassLevelLockable<Log, ZThr
Color m_colors[4];
uint32 m_logFilter;
+ // cache values for after initilization use (like gm log per account case)
+ std::string m_logsDir;
+ std::string m_logsTimestamp;
+
// char log control
bool m_charLog_Dump;
+ // gm log control
+ bool m_gmlog_per_account;
+ std::string m_gmlog_filename_format;
};
#define sLog Trinity::Singleton<Log>::Instance()
diff --git a/src/shared/Util.h b/src/shared/Util.h
index 690f1ec0ac0..44c0dda8370 100644
--- a/src/shared/Util.h
+++ b/src/shared/Util.h
@@ -172,9 +172,19 @@ inline bool isEastAsianCharacter(wchar_t wchar)
return false;
}
+inline bool isNumeric(wchar_t wchar)
+{
+ return (wchar >= L'0' && wchar <=L'9');
+}
+
+inline bool isNumeric(char c)
+{
+ return (c >= '0' && c <='9');
+}
+
inline bool isNumericOrSpace(wchar_t wchar)
{
- return (wchar >= L'0' && wchar <=L'9') || wchar == L' ';
+ return isNumeric(wchar) || wchar == L' ';
}
inline bool isBasicLatinString(std::wstring wstr, bool numericOrSpace)
diff --git a/src/trinitycore/CliRunnable.cpp b/src/trinitycore/CliRunnable.cpp
index 0af892819b6..7fe2ab784a6 100644
--- a/src/trinitycore/CliRunnable.cpp
+++ b/src/trinitycore/CliRunnable.cpp
@@ -29,7 +29,6 @@
#include "ScriptCalls.h"
#include "ObjectMgr.h"
#include "WorldSession.h"
-#include "SystemConfig.h"
#include "Config/ConfigEnv.h"
#include "Util.h"
#include "AccountMgr.h"
@@ -41,8 +40,7 @@
void utf8print(const char* str)
{
#if PLATFORM == PLATFORM_WINDOWS
-#define UTF8ZPRINTF utf8printf
- wchar_t wtemp_buf[6000];
+ wchar_t wtemp_buf[6000];
size_t wtemp_len = 6000-1;
if(!Utf8toWStr(str,strlen(str),wtemp_buf,wtemp_len))
return;
diff --git a/src/trinitycore/WorldRunnable.cpp b/src/trinitycore/WorldRunnable.cpp
index 5592b1d2064..b57dbc6bce2 100644
--- a/src/trinitycore/WorldRunnable.cpp
+++ b/src/trinitycore/WorldRunnable.cpp
@@ -74,7 +74,6 @@ void WorldRunnable::run()
prevSleepTime = 0;
}
- sWorld.KickAllQueued(); // kick all queued players (and prevent its login at kick in game players)
sWorld.KickAll(); // save and kick all players
sWorld.UpdateSessions( 1 ); // real players unload required UpdateSessions call
diff --git a/src/trinitycore/trinitycore.conf.dist b/src/trinitycore/trinitycore.conf.dist
index ad4ea6618e0..0f0c42eae13 100644
--- a/src/trinitycore/trinitycore.conf.dist
+++ b/src/trinitycore/trinitycore.conf.dist
@@ -17,7 +17,7 @@ ConfVersion=2008080101
# LogsDir
# Logs directory setting.
# Important: Logs dir must exists, or all logs need to be disabled
-# Default: "" - no log directory prefix, if used log names isn't absolute path
+# Default: "" - no log directory prefix, if used log names isn't absolute path
# then logs will be stored in current directory for run program.
#
#
@@ -82,7 +82,7 @@ EAIErrorLevel = 2
#
# Compression
# Compression level for update packages sent to client (1..9)
-# Default: 1 (speed)
+# Default: 1 (speed)
# 9 (best compression)
#
# PlayerLimit
@@ -143,15 +143,20 @@ EAIErrorLevel = 2
# These spells are ignored for LoS calculation
# List of ids with delimiter ','
#
+# DetectPosCollision
+# Check final move position, summon position, etc for visible collision with other objects or
+# wall (wall only if vmaps are enabled)
+# Default: 1 (enable, required more CPU power usage)
+# 0 (disable, less nice position selection but will less CPU power usage)
#
# TargetPosRecalculateRange
-# Max distance from movement target point (+moving unit size) and targeted object (+size)
+# Max distance from movement target point (+moving unit size) and targeted object (+size)
# after that new target movmeent point calculated. Max: melee attack range (5), min: contact range (0.5)
# More distance let have better performence, less distance let have more sensitive reaction at target move.
# Default: 1.5
#
# UpdateUptimeInterval
-# Update realm uptime period in minutes (for save data in 'uptime' table). Must be > 0
+# Update realm uptime period in minutes (for save data in 'uptime' table). Must be > 0
# Default: 10 (minutes)
#
# MaxCoreStuckTime
@@ -183,6 +188,7 @@ vmap.enableLOS = 0
vmap.enableHeight = 0
vmap.ignoreMapIds = "369"
vmap.ignoreSpellIds = "7720"
+DetectPosCollision = 1
TargetPosRecalculateRange = 1.5
UpdateUptimeInterval = 10
MaxCoreStuckTime = 0
@@ -215,7 +221,7 @@ AddonChannel = 1
#
# LogFile
# Logfile name
-# Default: "server.log"
+# Default: "Server.log"
# "" - Empty name disable creating log file
#
# LogTimestamp
@@ -237,15 +243,15 @@ AddonChannel = 1
#
# WorldLogFile
# Packet logging file for the worldserver
-# Default: ""
+# Default: "world.log"
#
# DBErrorLogFile
# Log file of DB errors detected at server run
-# Default: "db_errors.log"
+# Default: "DBErrors.log"
#
# CharLogFile
# Character operations logfile name
-# Default: "characters.log"
+# Default: "Char.log"
# "" - Empty name disable creating log file
#
# CharLogTimestamp
@@ -255,10 +261,10 @@ AddonChannel = 1
#
# CharLogDump
# Write character dump before deleting in Char.log
-# For restoration, cut character data from log starting from
+# For restoration, cut character data from log starting from
# line == START DUMP == to line == END DUMP == (without its) in file and load it using loadpdump command
# Default: 0 - don't include dumping chars to log
-# 1 - include dumping chars to log
+# 1 - include dumping chars to log
#
# GmLogFile
# Log file of gm commands
@@ -266,18 +272,25 @@ AddonChannel = 1
# "" - Empty name for disable
#
# GmLogTimestamp
-# Logfile with timestamp of server start in name
+# GM Logfile with timestamp of server start in name
# Default: 0 - no timestamp in name
# 1 - add timestamp in name in form Logname_YYYY-MM-DD_HH-MM-SS.Ext for Logname.Ext
#
+# GmLogPerAccount
+# GM Logfiles with GM account id (Note: logs not created if GmLogFile not set)
+# Default: 0 - add gm log data to single log file
+# 1 - add gm log data to account specific log files with name
+# in form Logname_#ID_YYYY-MM-DD_HH-MM-SS.Ext
+# or form Logname_#ID.Ext
+#
# RaLogFile
# Log file of RA commands
-# Default: "ra_commands.log"
+# Default: "Ra.log"
# "" - Empty name for disable
#
# LogColors
-# Color for messages (format "normal_color details_color debug_color error_color)
-# Colors: 0 - BLACK, 1 - RED, 2 - GREEN, 3 - BROWN, 4 - BLUE, 5 - MAGENTA, 6 - CYAN, 7 - GREY,
+# Color for messages (format "normal_color details_color debug_color error_color")
+# Colors: 0 - BLACK, 1 - RED, 2 - GREEN, 3 - BROWN, 4 - BLUE, 5 - MAGENTA, 6 - CYAN, 7 - GREY,
# 8 - YELLOW, 9 - LRED, 10 - LGREEN, 11 - LBLUE, 12 - LMAGENTA, 13 - LCYAN, 14 - WHITE
# Default: "" - none colors
# Example: "13 7 11 9"
@@ -288,7 +301,7 @@ LogSQL = 1
PidFile = ""
LogLevel = 1
LogTime = 0
-LogFile = "server.log"
+LogFile = "Server.log"
LogTimestamp = 0
LogFileLevel = 0
LogFilter_TransportMoves = 1
@@ -301,6 +314,7 @@ CharLogTimestamp = 0
CharLogDump = 0
GmLogFile = "gm_commands.log"
GmLogTimestamp = 0
+GmLogPerAccount = 0
RaLogFile = "ra_commands.log"
LogColors = ""
@@ -310,47 +324,47 @@ LogColors = ""
# GameType
# Server realm style
# 0 = NORMAL;1 = PVP; 4 = NORMAL; 6 = RP; 8 = RPPVP
-# also custom type: 16 FFA_PVP (free for all pvp mode like arena PvP in all zones except rest
+# also custom type: 16 FFA_PVP (free for all pvp mode like arena PvP in all zones except rest
# activated places and sanctuaries)
#
# RealmZone
# Server realm zone (set allowed alphabet in character names/etc). See also Strict*Names options.
#
-# 1 Development - any language (Default)
-# 2 United States - extended-Latin
-# 3 Oceanic - extended-Latin
-# 4 Latin America - extended-Latin
-# 5 Tournament - basic-Latin at create, any at login
-# 6 Korea - East-Asian
-# 7 Tournament - basic-Latin at create, any at login
-# 8 English - extended-Latin
-# 9 German - extended-Latin
-# 10 French - extended-Latin
-# 11 Spanish - extended-Latin
-# 12 Russian - Cyrillic
-# 13 Tournament - basic-Latin at create, any at login
-# 14 Taiwan - East-Asian
-# 15 Tournament - basic-Latin at create, any at login
-# 16 China - East-Asian
-# 17 CN1 - basic-Latin at create, any at login
-# 18 CN2 - basic-Latin at create, any at login
-# 19 CN3 - basic-Latin at create, any at login
-# 20 CN4 - basic-Latin at create, any at login
-# 21 CN5 - basic-Latin at create, any at login
-# 22 CN6 - basic-Latin at create, any at login
-# 23 CN7 - basic-Latin at create, any at login
-# 24 CN8 - basic-Latin at create, any at login
-# 25 Tournament - basic-Latin at create, any at login
-# 26 Test Server - any language
-# 27 Tournament - basic-Latin at create, any at login
-# 28 QA Server - any language
-# 29 CN9 - basic-Latin at create, any at login
+# 1 Development - any language (Default)
+# 2 United States - extended-Latin
+# 3 Oceanic - extended-Latin
+# 4 Latin America - extended-Latin
+# 5 Tournament - basic-Latin at create, any at login
+# 6 Korea - East-Asian
+# 7 Tournament - basic-Latin at create, any at login
+# 8 English - extended-Latin
+# 9 German - extended-Latin
+# 10 French - extended-Latin
+# 11 Spanish - extended-Latin
+# 12 Russian - Cyrillic
+# 13 Tournament - basic-Latin at create, any at login
+# 14 Taiwan - East-Asian
+# 15 Tournament - basic-Latin at create, any at login
+# 16 China - East-Asian
+# 17 CN1 - basic-Latin at create, any at login
+# 18 CN2 - basic-Latin at create, any at login
+# 19 CN3 - basic-Latin at create, any at login
+# 20 CN4 - basic-Latin at create, any at login
+# 21 CN5 - basic-Latin at create, any at login
+# 22 CN6 - basic-Latin at create, any at login
+# 23 CN7 - basic-Latin at create, any at login
+# 24 CN8 - basic-Latin at create, any at login
+# 25 Tournament - basic-Latin at create, any at login
+# 26 Test Server - any language
+# 27 Tournament - basic-Latin at create, any at login
+# 28 QA Server - any language
+# 29 CN9 - basic-Latin at create, any at login
#
# Expansion
-# Allow server use content from expansion
-# 2 - check expansion 2 maps existence, and if client support expansion 2 and account have
+# Allow server use content from expansion
+# 2 - check expansion 2 maps existence, and if client support expansion 2 and account have
# expansion 2 setting then allow visit expansion 2 maps, allow create new class character)
-# Default: 1 - check expansion 1 maps existence, and if client support expansion 1 and account have
+# Default: 1 - check expansion 1 maps existence, and if client support expansion 1 and account have
# expansion 1 setting then allow visit expansion 1 maps, allow create new races character)
# 0 - not check expansion maps existence, not allow wisit its, not allow create new race or new class
# characters, ignore account expansion setting)
@@ -361,16 +375,16 @@ LogColors = ""
# 8 = Russian; 255 = Auto Detect (Default)
#
# DeclinedNames
-# Allow russian clients to set and use declined names
-# Default: 0 - do not use declined names, except when the Russian RealmZone is set
-# 1 - use declined names
+# Allow russian clients to set and use declined names
+# Default: 0 - do not use declined names, except when the Russian RealmZone is set
+# 1 - use declined names
#
# StrictPlayerNames
# Limit player name to language specific symbols set, not allow create characters, and set rename request and disconnect at not allowed symbols name
# Default: 0 disable (but limited server timezone dependent client check)
# 1 basic latin characters (strict)
-# 2 realm zone specific (strict). See RealmZone setting.
-# Note: In any case if you want correctly see character name at client this client must have apporopriate fonts
+# 2 realm zone specific (strict). See RealmZone setting.
+# Note: In any case if you want correctly see character name at client this client must have apporopriate fonts
# (included in client by default, with active official localization or custom localization fonts in clientdir/Fonts).
# 3 basic latin characters + server timezone specific
#
@@ -378,8 +392,8 @@ LogColors = ""
# Limit guild/arena team charter names to language specific symbols set, not allow create charters with allowed symbols in name
# Default: 0 disable
# 1 basic latin characters (strict)
-# 2 realm zone specific (strict). See RealmZone setting.
-# Note: In any case if you want correctly see character name at client this client must have apporopriate fonts
+# 2 realm zone specific (strict). See RealmZone setting.
+# Note: In any case if you want correctly see character name at client this client must have apporopriate fonts
# (included in client by default, with active official localization or custom localization fonts in clientdir/Fonts).
# 3 basic latin characters + server timezone specific
#
@@ -387,8 +401,8 @@ LogColors = ""
# Limit pet names to language specific symbols set
# Default: 0 disable
# 1 basic latin characters (strict)
-# 2 realm zone specific (strict). See RealmZone setting.
-# Note: In any case if you want correctly see character name at client this client must have apporopriate fonts
+# 2 realm zone specific (strict). See RealmZone setting.
+# Note: In any case if you want correctly see character name at client this client must have apporopriate fonts
# (included in client by default, with active official localization or custom localization fonts in clientdir/Fonts).
# 3 basic latin characters + server timezone specific
#
@@ -406,7 +420,7 @@ LogColors = ""
# CharactersPerAccount
# Limit numbers of characters per account (at all realms).
# Note: this setting limit character creating at _current_ realm base at characters amount at all realms
-# Default: 50
+# Default: 50
# The number must be >= CharactersPerRealm
#
# CharactersPerRealm
@@ -425,17 +439,48 @@ LogColors = ""
# Change not recommended
# Default: 70
#
+# StartPlayerLevel
+# Staring level that have character at creating (in range 1 to MaxPlayerLevel)
+# Default: 1
+#
+# StartPlayerMoney
+# Amount of money that new players will start with.
+# If you want to start with silver, use for example 100 (100 copper = 1 silver)
+# Default: 0
+#
# MaxHonorPoints
# Max honor points that player can have.
# Default: 75000
#
+# StartHonorPoints
+# Amount of honor that new players will start with
+# Default: 0
+#
# MaxArenaPoints
# Max arena points that player can have.
# Default: 5000
#
-# StartPlayerLevel
-# Staring level that have character at creating (in range 1 to MaxPlayerLevel)
-# Default: 1
+# StartArenaPoints
+# Amount of arena points that new players will start with
+# Default: 0
+#
+# InstantLogout
+# Enable or disable instant logout for security level (0..4) or high (NOT in combat/while dueling/while falling)
+# Default: 1 (Mods/GMs/Admins)
+#
+# DisableWaterBreath
+# Disable/enable waterbreathing for security level (0..4) or high
+# Default: 4 (None)
+#
+# AllFlightPaths
+# Players will start with all flight paths (Note: ALL flight paths, not only player's team)
+# Default: 0 (true)
+# 1 (false)
+#
+# AlwaysMaxSkillForLevel
+# Players will automatically gain max level dependent (weapon/defense) skill when logging in, leveling up etc.
+# Default: 0 (true)
+# 1 (false)
#
# ActivateWeather
# Activate weather system
@@ -447,6 +492,16 @@ LogColors = ""
# Default: 1 (true)
# 0 (false)
#
+# Battleground.QueueAnnouncer.Enable
+# Enable queue announcer posting to chat
+# Default: 1 (true)
+# 0 (false)
+#
+# Battleground.QueueAnnouncer.PlayerOnly
+# Enable queue announcer posting to chat
+# Default: 0 (false)
+# 1 (true)
+#
# CastUnstuck
# Allow cast or not Unstuck spell at .start or client Help option use
# Default: 1 (true)
@@ -472,16 +527,16 @@ LogColors = ""
# 0 (instance maps are kept in memory until they are reset)
#
# Quests.LowLevelHideDiff
-# Quest level difference to hide for player low level quests:
+# Quest level difference to hide for player low level quests:
# if player_level > quest_level + LowLevelQuestsHideDiff then quest "!" mark not show for quest giver
# Default: 4
-# -1 (show all available quests marks)
+# -1 (show all available quests marks)
#
# Quests.HighLevelHideDiff
-# Quest level difference to hide for player high level quests:
+# Quest level difference to hide for player high level quests:
# if player_level < quest_min_level - HighLevelQuestsHideDiff then quest "!" mark not show for quest giver
# Default: 7
-# -1 (show all available quests marks)
+# -1 (show all available quests marks)
#
# MaxPrimaryTradeSkill
# Max count that player can learn the primary trade skill.
@@ -533,11 +588,20 @@ CharactersPerAccount = 50
CharactersPerRealm = 10
SkipCinematics = 0
MaxPlayerLevel = 70
+StartPlayerLevel = 1
+StartPlayerMoney = 0
MaxHonorPoints = 75000
+StartHonorPoints = 0
MaxArenaPoints = 5000
-StartPlayerLevel = 1
+StartArenaPoints = 0
+InstantLogout = 1
+DisableWaterBreath = 4
+AllFlightPaths = 0
+AlwaysMaxSkillForLevel = 0
ActivateWeather = 1
Battleground.CastDeserter = 1
+Battleground.QueueAnnouncer.Enable = 1
+Battleground.QueueAnnouncer.PlayerOnly = 0
CastUnstuck = 1
Instance.IgnoreLevel = 0
Instance.IgnoreRaid = 0
@@ -568,7 +632,7 @@ Motd = "Welcome to a Trinity Core server."
# AllowTwoSide.Interaction.Guild
# AllowTwoSide.Interaction.Auction
# AllowTwoSide.Interaction.Mail
-# Allow or not common :chat(say,yell);channel(chat)group(join)guild(join);merge all auction houses for players from
+# Allow or not common :chat(say,yell);channel(chat)group(join)guild(join);merge all auction houses for players from
# different teams, send mail to different team.
# Default: 0 (Not allowed)
# 1 (Allowed)
@@ -584,7 +648,7 @@ Motd = "Welcome to a Trinity Core server."
# 1 (Allowed)
#
# TalentsInspecting
-# Allow other players see character talents in inspect dialog (Characters in Gamemaster mode can
+# Allow other players see character talents in inspect dialog (Characters in Gamemaster mode can
# inspect talents always)
# Default: 1 (allow)
# 0 (not allow)
@@ -616,11 +680,15 @@ TalentsInspecting = 1
# 1.5 - 150%
# 0 - off (0%)
#
-# CreatureFamilyAssistenceRadius
-# Creature family assistence radius
+# CreatureFamilyAssistanceRadius
+# Creature family assistance radius
# Default: 10
# 0 - off
#
+# CreatureFamilyAssistanceDelay
+# Reaction time for creature assistance call
+# Default: 1500 (1.5s)
+#
# WorldBossLevelDiff
# Difference for boss dynamic level with target
# Default: 3
@@ -661,11 +729,24 @@ TalentsInspecting = 1
# Creature Health Ammount Modifier.
# Examples: 2 - creatures have 2x health, 1.7 - 1.7x.
#
+# ListenRange.Say
+# Distance from player to listen text that creature (or other world object) say
+# Default: 25
+#
+# ListenRange.TextEmote
+# Distance from player to listen textemote that creature (or other world object) say
+# Default: 25
+#
+# ListenRange.Yell
+# Distance from player to listen text that creature (or other world object) yell
+# Default: 300
+#
###################################################################################################################
ThreatRadius = 100
Rate.Creature.Aggro = 1
-CreatureFamilyAssistenceRadius = 10
+CreatureFamilyAssistanceRadius = 10
+CreatureFamilyAssistanceDelay = 1500
WorldBossLevelDiff = 3
Corpse.Decay.NORMAL = 60
Corpse.Decay.RARE = 300
@@ -688,13 +769,16 @@ Rate.Creature.Elite.Elite.HP = 1
Rate.Creature.Elite.RAREELITE.HP = 1
Rate.Creature.Elite.WORLDBOSS.HP = 1
Rate.Creature.Elite.RARE.HP = 1
+ListenRange.Say = 40
+ListenRange.TextEmote = 40
+ListenRange.Yell = 300
###################################################################################################################
# CHAT SETTINGS
#
# ChatFakeMessagePreventing
# Chat protection from creating fake messages using a lot spaces (other invisible symbols),
-# not applied to addon language messages, but can prevent working old addons
+# not applied to addon language messages, but can prevent working old addons
# that use normal languages for sending data to another clients.
# Default: 0 (disible fake messages preventing)
# 1 (enabled fake messages preventing)
@@ -734,10 +818,29 @@ Channel.SilentlyGMJoin = 0
###################################################################################################################
# GAME MASTER SETTINGS
#
+# GM.LoginState
+# GM mode at login
+# Default: 2 (last save state)
+# 0 (disable)
+# 1 (enable)
+#
+# GM.AcceptTickets
+# Is GM accepting tickets from player by default or not.
+# Default: 2 (last save state)
+# 0 (disable)
+# 1 (enable)
+#
+# GM.Chat
+# GM chat mode at login
+# Default: 2 (last save state)
+# 0 (disable)
+# 1 (enable)
+#
# GM.WhisperingTo
# Is GM accepting whispers from player by default or not.
-# Default: 0 (false)
-# 1 (true)
+# Default: 2 (last save state)
+# 0 (disable)
+# 1 (enable)
#
# GM.InGMList
# Is GM showed in GM list (if visible) in non-GM state (.gmoff)
@@ -749,24 +852,25 @@ Channel.SilentlyGMJoin = 0
# Default: 0 (false)
# 1 (true)
#
-# GM.LoginState
-# GM mode at login
-# Default: 2 (last save state)
-# 0 (disable)
-# 1 (enable)
-#
# GM.LogTrade
# Include GM trade and trade slot enchanting operations in GM log if it enable
# Default: 1 (include)
# 0 (not include)
#
+# GM.StartLevel
+# GM starting level (1-255)
+# Default: 1
+#
###################################################################################################################
-GM.WhisperingTo = 0
-GM.InGMList = 0
-GM.InWhoList = 0
-GM.LoginState = 2
-GM.LogTrade = 1
+GM.LoginState = 2
+GM.AcceptTickets = 2
+GM.Chat = 2
+GM.WhisperingTo = 2
+GM.InGMList = 0
+GM.InWhoList = 0
+GM.LogTrade = 1
+GM.StartLevel = 70
###################################################################################################################
# VISIBILITY AND RADIUSES
@@ -779,7 +883,7 @@ GM.LogTrade = 1
#
# Visibility.Distance.Creature
# Visibility.Distance.Player
-# Visibility distance for different in game object
+# Visibility distance for different in game object
# Max limited by active player zone: ~ 166
# Min limit dependent from objects
# Default: 66 (cell size)
@@ -796,7 +900,7 @@ GM.LogTrade = 1
# Visibility.Distance.Grey.Unit
# Visibility grey distance for creatures/players (fast changing objects)
# addition to appropriate object type Visibility.Distance.* use in case visibility removing to
-# object (except corpse around distences) If ? is distance and G is grey distance then object
+# object (except corpse around distences) If � is distance and G is grey distance then object
# make visible if distance to it <= D but make non visible if distance > D+G
# Default: 1 (yard)
#
@@ -819,7 +923,7 @@ Visibility.Distance.Grey.Object = 10
# SERVER RATES
#
# Rate.Health
-# Rate.Mana
+# Rate.Mana
# Rate.Rage.Income
# Rate.Rage.Loss
# Rate.Focus
@@ -875,7 +979,7 @@ Visibility.Distance.Grey.Object = 10
#
# Rate.Mining.Amount
# Rate.Mining.Next
-# Mining Rates (Mining.Amount changes minimum/maximum usetimes of a deposit,
+# Mining Rates (Mining.Amount changes minimum/maximum usetimes of a deposit,
# Mining.Next changes chance to have next use of a deposit)
#
# Rate.Talent
@@ -901,12 +1005,12 @@ Visibility.Distance.Grey.Object = 10
# SkillChance.Yellow
# SkillChance.Green
# SkillChance.Grey
-# Skill chance values (0..100)
+# Skill chance values (0..100)
# Default: 100-75-25-0
#
# SkillChance.MiningSteps
# SkillChance.SkinningSteps
-# For skinning and Mining chance decrease with skill level.
+# For skinning and Mining chance decrease with skill level.
# Default: 0 - no decrease
# 75 - in 2 times each 75 skill points
#
@@ -934,7 +1038,7 @@ Visibility.Distance.Grey.Object = 10
#
# Death.CorpseReclaimDelay.PvP
# Death.CorpseReclaimDelay.PvE
-# Enabled/disabled increase corpse reclaim delay at often PvP/PvE deaths
+# Enabled/disabled increase corpse reclaim delay at often PvP/PvE deaths
# Default: 1 (enabled)
# 0 (disabled)
#
@@ -992,6 +1096,34 @@ Death.CorpseReclaimDelay.PvP = 1
Death.CorpseReclaimDelay.PvE = 1
###################################################################################################################
+#
+# NETWORK CONFIG
+#
+# Network.Threads
+# Number of threads for network, recommend 1 thread per 1000 connections.
+# Default: 1
+#
+# Network.OutKBuff
+# The size of the output kernel buffer used ( SO_SNDBUF socket option, tcp manual ).
+# Default: -1 (Use system default setting)
+#
+# Network.OutUBuff
+# Userspace buffer for output. This is amount of memory reserved per each connection.
+# Default: 65536
+#
+# Network.TcpNoDelay:
+# TCP Nagle algorithm setting
+# Default: 0 (enable Nagle algorithm, less traffic, more latency)
+# 1 (TCP_NO_DELAY, disable Nagle algorithm, more traffic but less latency)
+#
+###################################################################################################################
+
+Network.Threads = 1
+Network.OutKBuff = -1
+Network.OutUBuff = 65536
+Network.TcpNodelay = 1
+
+###################################################################################################################
# CONSOLE AND REMOTE ACCESS
#
# Console.Enable
@@ -1066,46 +1198,8 @@ Arena.AutoDistributeInterval = 7
BattleGround.PrematureFinishTimer = 0
###################################################################################################################
-#
-# Network config
-#
-# Threads: number of threads for network ,recommend 1 thread per 1000 players.
-# Default: 1
-#
-# OutKBuff: the output kernel buffer used ( SO_SNDBUF socket option ) , -1 means use system default. Refer to tcp manual for explanation.
-# Default: -1
-#
-# OutUBuff: userspace buffer for output
-# Default: 65536
-#
-# TcpNodelay: enable ( 1 ) , disable ( 0 ) ,TCP_NODELAY socket option. Refer to tcp manual for explanation.
-# Default: 1
-#
-#
-#
-###################################################################################################################
-
-Network.Threads = 1
-Network.OutKBuff = -1
-Network.OutUBuff = 65536
-Network.TcpNodelay = 1
-
-###################################################################################################################
# CUSTOM SERVER OPTIONS
#
-# PlayerStart.Gold
-# Amount of gold that new players will start with.
-# If you want to start with silver, use for example 0.1 (for 10s)
-# Default: 0
-#
-# PlayerStart.HonorPoints
-# Amount of honor that new players will start with
-# Default: 0
-#
-# PlayerStart.ArenaPoints
-# Amount of arena points that new players will start with
-# Default: 0
-#
# PlayerStart.AllReputation
# Players will start with most of the high level reputations that are needed for items, mounts etc.
# If there are any reputation faction you want to be added, just tell me.
@@ -1122,10 +1216,6 @@ Network.TcpNodelay = 1
# PlayerStart.AllFlightPaths
# Players will start with all flight paths (Note: ALL flight paths, not only player's team)
#
-# GamemasterStartLevel
-# GM starting level
-# Default: 70 Min,max: 1 - 255
-#
# PlayerInstantLogout
# Enable or disable instant logout for all players (NOT in combat/while dueling/while falling)
# Default: 0 - off
@@ -1138,9 +1228,6 @@ Network.TcpNodelay = 1
# The amount of honor points the duel winner will get after a duel.
# Default: 0 - disable
#
-# DisableWaterBreath
-# Disable/enable waterbreathing for players
-#
# AlwaysMaxWeaponSkill
# Players will automatically gain max weapon/defense skill when logging in, leveling up etc.
#
@@ -1172,18 +1259,13 @@ Network.TcpNodelay = 1
#
###################################################################################################################
-PlayerStart.Gold = 0
-PlayerStart.HonorPoints = 0
-PlayerStart.ArenaPoints = 0
PlayerStart.AllReputation = 0
PlayerStart.AllSpells = 0
PlayerStart.MapsExplored = 0
PlayerStart.AllFlightPaths = 0
-GamemasterStartLevel = 70
PlayerInstantLogout = 0
MusicInBattleground = 0
HonorPointsAfterDuel = 0
-DisableWaterBreath = 0
AlwaysMaxWeaponSkill = 0
PvPToken.Enable = 0
PvPToken.MapAllowType = 4
diff --git a/win/VC80/framework.vcproj b/win/VC80/framework.vcproj
index 9b41a66926e..b9cda2773d9 100644
--- a/win/VC80/framework.vcproj
+++ b/win/VC80/framework.vcproj
@@ -422,7 +422,7 @@
>
</File>
<File
- RelativePath="..\..\src\game\LinkedList.h"
+ RelativePath="..\..\src\framework\Utilities\LinkedList.h"
>
</File>
<File
diff --git a/win/VC90/framework.vcproj b/win/VC90/framework.vcproj
index 71c5d1a2d37..4935e7e84d5 100644
--- a/win/VC90/framework.vcproj
+++ b/win/VC90/framework.vcproj
@@ -429,7 +429,7 @@
>
</File>
<File
- RelativePath="..\..\src\game\LinkedList.h"
+ RelativePath="..\..\src\framework\Utilities\LinkedList.h"
>
</File>
<File