diff --git a/6731-680 b/6743-685
similarity index 100%
rename from 6731-680
rename to 6743-685
diff --git a/dep/lib/win32_debug/dbghelp.dll b/dep/lib/win32_debug/dbghelp.dll
index 597188d77e9..6f646de49ae 100644
Binary files a/dep/lib/win32_debug/dbghelp.dll and b/dep/lib/win32_debug/dbghelp.dll differ
diff --git a/sql/characters.sql b/sql/characters.sql
index f42dfe764de..f695ac2fc55 100644
--- a/sql/characters.sql
+++ b/sql/characters.sql
@@ -1,1239 +1,1239 @@
--- MySQL dump 10.11
---
--- Host: localhost Database: characters
--- ------------------------------------------------------
--- Server version 5.0.45-Debian_1ubuntu3.1-log
-
-/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
-/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
-/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
-/*!40101 SET NAMES utf8 */;
-/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
-/*!40103 SET TIME_ZONE='+00:00' */;
-/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
-/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
-/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
-
---
--- Table structure for table `arena_team`
---
-
-DROP TABLE IF EXISTS `arena_team`;
-CREATE TABLE `arena_team` (
- `arenateamid` int(10) unsigned NOT NULL default '0',
- `name` char(255) NOT NULL,
- `captainguid` int(10) unsigned NOT NULL default '0',
- `type` tinyint(3) unsigned NOT NULL default '0',
- `BackgroundColor` int(10) unsigned NOT NULL default '0',
- `EmblemStyle` int(10) unsigned NOT NULL default '0',
- `EmblemColor` int(10) unsigned NOT NULL default '0',
- `BorderStyle` int(10) unsigned NOT NULL default '0',
- `BorderColor` int(10) unsigned NOT NULL default '0',
- PRIMARY KEY (`arenateamid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `arena_team`
---
-
-LOCK TABLES `arena_team` WRITE;
-/*!40000 ALTER TABLE `arena_team` DISABLE KEYS */;
-/*!40000 ALTER TABLE `arena_team` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `arena_team_member`
---
-
-DROP TABLE IF EXISTS `arena_team_member`;
-CREATE TABLE `arena_team_member` (
- `arenateamid` int(10) unsigned NOT NULL default '0',
- `guid` int(10) unsigned NOT NULL default '0',
- `played_week` int(10) unsigned NOT NULL default '0',
- `wons_week` int(10) unsigned NOT NULL default '0',
- `played_season` int(10) unsigned NOT NULL default '0',
- `wons_season` int(10) unsigned NOT NULL default '0',
- `points_to_add` int(10) unsigned NOT NULL default '0'
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `arena_team_member`
---
-
-LOCK TABLES `arena_team_member` WRITE;
-/*!40000 ALTER TABLE `arena_team_member` DISABLE KEYS */;
-/*!40000 ALTER TABLE `arena_team_member` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `arena_team_stats`
---
-
-DROP TABLE IF EXISTS `arena_team_stats`;
-CREATE TABLE `arena_team_stats` (
- `arenateamid` int(10) unsigned NOT NULL default '0',
- `rating` int(10) unsigned NOT NULL default '0',
- `games` int(10) unsigned NOT NULL default '0',
- `wins` int(10) unsigned NOT NULL default '0',
- `played` int(10) unsigned NOT NULL default '0',
- `wins2` int(10) unsigned NOT NULL default '0',
- `rank` int(10) unsigned NOT NULL default '0',
- PRIMARY KEY (`arenateamid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `arena_team_stats`
---
-
-LOCK TABLES `arena_team_stats` WRITE;
-/*!40000 ALTER TABLE `arena_team_stats` DISABLE KEYS */;
-/*!40000 ALTER TABLE `arena_team_stats` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `auctionhouse`
---
-
-DROP TABLE IF EXISTS `auctionhouse`;
-CREATE TABLE `auctionhouse` (
- `id` int(11) unsigned NOT NULL default '0',
- `auctioneerguid` int(11) unsigned NOT NULL default '0',
- `itemguid` int(11) unsigned NOT NULL default '0',
- `item_template` int(11) unsigned NOT NULL default '0' COMMENT 'Item Identifier',
- `itemowner` int(11) unsigned NOT NULL default '0',
- `buyoutprice` int(11) NOT NULL default '0',
- `time` bigint(40) NOT NULL default '0',
- `buyguid` int(11) unsigned NOT NULL default '0',
- `lastbid` int(11) NOT NULL default '0',
- `startbid` int(11) NOT NULL default '0',
- `deposit` int(11) NOT NULL default '0',
- `location` tinyint(3) unsigned NOT NULL default '3',
- PRIMARY KEY (`id`),
- UNIQUE KEY `item_guid` (`itemguid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `auctionhouse`
---
-
-LOCK TABLES `auctionhouse` WRITE;
-/*!40000 ALTER TABLE `auctionhouse` DISABLE KEYS */;
-/*!40000 ALTER TABLE `auctionhouse` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `bugreport`
---
-
-DROP TABLE IF EXISTS `bugreport`;
-CREATE TABLE `bugreport` (
- `id` int(11) NOT NULL auto_increment COMMENT 'Identifier',
- `type` varchar(255) NOT NULL default '',
- `content` varchar(255) NOT NULL default '',
- PRIMARY KEY (`id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Debug System';
-
---
--- Dumping data for table `bugreport`
---
-
-LOCK TABLES `bugreport` WRITE;
-/*!40000 ALTER TABLE `bugreport` DISABLE KEYS */;
-/*!40000 ALTER TABLE `bugreport` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `characters`
---
-
-DROP TABLE IF EXISTS `characters`;
-CREATE TABLE `characters` (
- `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
- `account` int(11) unsigned NOT NULL default '0' COMMENT 'Account Identifier',
- `data` longtext,
- `name` varchar(12) NOT NULL default '',
- `race` tinyint(3) unsigned NOT NULL default '0',
- `class` tinyint(3) unsigned NOT NULL default '0',
- `position_x` float NOT NULL default '0',
- `position_y` float NOT NULL default '0',
- `position_z` float NOT NULL default '0',
- `map` int(11) unsigned NOT NULL default '0' COMMENT 'Map Identifier',
- `dungeon_difficulty` tinyint(1) unsigned NOT NULL DEFAULT '0',
- `orientation` float NOT NULL default '0',
- `taximask` longtext,
- `online` tinyint(3) unsigned NOT NULL default '0',
- `cinematic` tinyint(3) unsigned NOT NULL default '0',
- `totaltime` int(11) unsigned NOT NULL default '0',
- `leveltime` int(11) unsigned NOT NULL default '0',
- `logout_time` bigint(20) unsigned NOT NULL default '0',
- `is_logout_resting` tinyint(3) unsigned NOT NULL default '0',
- `rest_bonus` float NOT NULL default '0',
- `resettalents_cost` int(11) unsigned NOT NULL default '0',
- `resettalents_time` bigint(20) unsigned NOT NULL default '0',
- `trans_x` float NOT NULL default '0',
- `trans_y` float NOT NULL default '0',
- `trans_z` float NOT NULL default '0',
- `trans_o` float NOT NULL default '0',
- `transguid` bigint(20) unsigned NOT NULL default '0',
- `gmstate` tinyint(3) unsigned NOT NULL default '0',
- `stable_slots` tinyint(1) unsigned NOT NULL default '0',
- `at_login` int(11) unsigned NOT NULL default '0',
- `zone` int(11) unsigned NOT NULL default '0',
- `death_expire_time` bigint(20) unsigned NOT NULL default '0',
- `taxi_path` text,
- PRIMARY KEY (`guid`),
- KEY `idx_account` (`account`),
- KEY `idx_online` (`online`),
- KEY `idx_name` (`name`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
-
---
--- Dumping data for table `characters`
---
-
-LOCK TABLES `characters` WRITE;
-/*!40000 ALTER TABLE `characters` DISABLE KEYS */;
-/*!40000 ALTER TABLE `characters` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `character_action`
---
-
-DROP TABLE IF EXISTS `character_action`;
-CREATE TABLE `character_action` (
- `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
- `button` tinyint(3) unsigned NOT NULL default '0',
- `action` smallint(5) unsigned NOT NULL default '0',
- `type` tinyint(3) unsigned NOT NULL default '0',
- `misc` tinyint(3) unsigned NOT NULL default '0',
- PRIMARY KEY (`guid`,`button`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
-
---
--- Dumping data for table `character_action`
---
-
-LOCK TABLES `character_action` WRITE;
-/*!40000 ALTER TABLE `character_action` DISABLE KEYS */;
-/*!40000 ALTER TABLE `character_action` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `character_aura`
---
-
-DROP TABLE IF EXISTS `character_aura`;
-CREATE TABLE `character_aura` (
- `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
- `caster_guid` bigint(20) unsigned NOT NULL default '0' COMMENT 'Full Global Unique Identifier',
- `spell` int(11) unsigned NOT NULL default '0',
- `effect_index` int(11) unsigned NOT NULL default '0',
- `amount` int(11) NOT NULL default '0',
- `maxduration` int(11) NOT NULL default '0',
- `remaintime` int(11) NOT NULL default '0',
- `remaincharges` int(11) NOT NULL default '0',
- PRIMARY KEY (`guid`,`spell`,`effect_index`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
-
---
--- Dumping data for table `character_aura`
---
-
-LOCK TABLES `character_aura` WRITE;
-/*!40000 ALTER TABLE `character_aura` DISABLE KEYS */;
-/*!40000 ALTER TABLE `character_aura` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `character_declinedname`
---
-
-DROP TABLE IF EXISTS `character_declinedname`;
-CREATE TABLE `character_declinedname` (
- `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
- `genitive` varchar(15) NOT NULL default '',
- `dative` varchar(15) NOT NULL default '',
- `accusative` varchar(15) NOT NULL default '',
- `instrumental` varchar(15) NOT NULL default '',
- `prepositional` varchar(15) NOT NULL default '',
- PRIMARY KEY (`guid`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
-
---
--- Dumping data for table `character_declinedname`
---
-
-LOCK TABLES `character_declinedname` WRITE;
-/*!40000 ALTER TABLE `character_declinedname` DISABLE KEYS */;
-/*!40000 ALTER TABLE `character_declinedname` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `character_gifts`
---
-
-DROP TABLE IF EXISTS `character_gifts`;
-CREATE TABLE `character_gifts` (
- `guid` int(20) unsigned NOT NULL default '0',
- `item_guid` int(11) unsigned NOT NULL default '0',
- `entry` int(20) unsigned NOT NULL default '0',
- `flags` int(20) unsigned NOT NULL default '0',
- PRIMARY KEY (`item_guid`),
- KEY `idx_guid` (`guid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `character_gifts`
---
-
-LOCK TABLES `character_gifts` WRITE;
-/*!40000 ALTER TABLE `character_gifts` DISABLE KEYS */;
-/*!40000 ALTER TABLE `character_gifts` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `character_homebind`
---
-
-DROP TABLE IF EXISTS `character_homebind`;
-CREATE TABLE `character_homebind` (
- `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
- `map` int(11) unsigned NOT NULL default '0' COMMENT 'Map Identifier',
- `zone` int(11) unsigned NOT NULL default '0' COMMENT 'Zone Identifier',
- `position_x` float NOT NULL default '0',
- `position_y` float NOT NULL default '0',
- `position_z` float NOT NULL default '0',
- PRIMARY KEY (`guid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
-
---
--- Dumping data for table `character_homebind`
---
-
-LOCK TABLES `character_homebind` WRITE;
-/*!40000 ALTER TABLE `character_homebind` DISABLE KEYS */;
-/*!40000 ALTER TABLE `character_homebind` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `character_instance`
---
-
-DROP TABLE IF EXISTS `character_instance`;
-CREATE TABLE `character_instance` (
- `guid` int(11) unsigned NOT NULL default '0',
- `instance` int(11) unsigned NOT NULL default '0',
- `permanent` tinyint(1) unsigned NOT NULL default '0',
- PRIMARY KEY (`guid`,`instance`),
- KEY `instance` (`instance`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `character_instance`
---
-
-LOCK TABLES `character_instance` WRITE;
-/*!40000 ALTER TABLE `character_instance` DISABLE KEYS */;
-/*!40000 ALTER TABLE `character_instance` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `character_inventory`
---
-
-DROP TABLE IF EXISTS `character_inventory`;
-CREATE TABLE `character_inventory` (
- `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
- `bag` int(11) unsigned NOT NULL default '0',
- `slot` tinyint(3) unsigned NOT NULL default '0',
- `item` int(11) unsigned NOT NULL default '0' COMMENT 'Item Global Unique Identifier',
- `item_template` int(11) unsigned NOT NULL default '0' COMMENT 'Item Identifier',
- PRIMARY KEY (`item`),
- KEY `idx_guid` (`guid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
-
---
--- Dumping data for table `character_inventory`
---
-
-LOCK TABLES `character_inventory` WRITE;
-/*!40000 ALTER TABLE `character_inventory` DISABLE KEYS */;
-/*!40000 ALTER TABLE `character_inventory` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `character_pet`
---
-
-DROP TABLE IF EXISTS `character_pet`;
-CREATE TABLE `character_pet` (
- `id` int(11) unsigned NOT NULL default '0',
- `entry` int(11) unsigned NOT NULL default '0',
- `owner` int(11) unsigned NOT NULL default '0',
- `modelid` int(11) unsigned default '0',
- `CreatedBySpell` int(11) unsigned NOT NULL default '0',
- `PetType` tinyint(3) unsigned NOT NULL default '0',
- `level` int(11) unsigned NOT NULL default '1',
- `exp` int(11) unsigned NOT NULL default '0',
- `Reactstate` tinyint(1) unsigned NOT NULL default '0',
- `loyaltypoints` int(11) NOT NULL default '0',
- `loyalty` int(11) unsigned NOT NULL default '0',
- `trainpoint` int(11) NOT NULL default '0',
- `name` varchar(100) default 'Pet',
- `renamed` tinyint(1) unsigned NOT NULL default '0',
- `slot` int(11) unsigned NOT NULL default '0',
- `curhealth` int(11) unsigned NOT NULL default '1',
- `curmana` int(11) unsigned NOT NULL default '0',
- `curhappiness` int(11) unsigned NOT NULL default '0',
- `savetime` bigint(20) unsigned NOT NULL default '0',
- `resettalents_cost` int(11) unsigned NOT NULL default '0',
- `resettalents_time` bigint(20) unsigned NOT NULL default '0',
- `abdata` longtext,
- `teachspelldata` longtext,
- PRIMARY KEY (`id`),
- KEY `owner` (`owner`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Pet System';
-
---
--- Dumping data for table `character_pet`
---
-
-LOCK TABLES `character_pet` WRITE;
-/*!40000 ALTER TABLE `character_pet` DISABLE KEYS */;
-/*!40000 ALTER TABLE `character_pet` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `character_pet_declinedname`
---
-
-DROP TABLE IF EXISTS `character_pet_declinedname`;
-CREATE TABLE `character_pet_declinedname` (
- `id` int(11) unsigned NOT NULL default '0',
- `owner` int(11) unsigned NOT NULL default '0',
- `genitive` varchar(12) NOT NULL default '',
- `dative` varchar(12) NOT NULL default '',
- `accusative` varchar(12) NOT NULL default '',
- `instrumental` varchar(12) NOT NULL default '',
- `prepositional` varchar(12) NOT NULL default '',
- PRIMARY KEY (`id`),
- KEY owner_key (`owner`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
-
---
--- Dumping data for table `character_pet_declinedname`
---
-
-LOCK TABLES `character_pet_declinedname` WRITE;
-/*!40000 ALTER TABLE `character_pet_declinedname` DISABLE KEYS */;
-/*!40000 ALTER TABLE `character_pet_declinedname` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `character_queststatus`
---
-
-DROP TABLE IF EXISTS `character_queststatus`;
-CREATE TABLE `character_queststatus` (
- `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
- `quest` int(11) unsigned NOT NULL default '0' COMMENT 'Quest Identifier',
- `status` int(11) unsigned NOT NULL default '0',
- `rewarded` tinyint(1) unsigned NOT NULL default '0',
- `explored` tinyint(1) unsigned NOT NULL default '0',
- `timer` bigint(20) unsigned NOT NULL default '0',
- `mobcount1` int(11) unsigned NOT NULL default '0',
- `mobcount2` int(11) unsigned NOT NULL default '0',
- `mobcount3` int(11) unsigned NOT NULL default '0',
- `mobcount4` int(11) unsigned NOT NULL default '0',
- `itemcount1` int(11) unsigned NOT NULL default '0',
- `itemcount2` int(11) unsigned NOT NULL default '0',
- `itemcount3` int(11) unsigned NOT NULL default '0',
- `itemcount4` int(11) unsigned NOT NULL default '0',
- PRIMARY KEY (`guid`,`quest`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
-
---
--- Dumping data for table `character_queststatus`
---
-
-LOCK TABLES `character_queststatus` WRITE;
-/*!40000 ALTER TABLE `character_queststatus` DISABLE KEYS */;
-/*!40000 ALTER TABLE `character_queststatus` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `character_queststatus_daily`
---
-
-DROP TABLE IF EXISTS `character_queststatus_daily`;
-CREATE TABLE `character_queststatus_daily` (
- `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
- `quest` int(11) unsigned NOT NULL default '0' COMMENT 'Quest Identifier',
- `time` bigint(20) unsigned NOT NULL default '0',
- PRIMARY KEY (`guid`,`quest`),
- KEY `idx_guid` (`guid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
-
---
--- Dumping data for table `character_queststatus_daily`
---
-
-LOCK TABLES `character_queststatus_daily` WRITE;
-/*!40000 ALTER TABLE `character_queststatus_daily` DISABLE KEYS */;
-/*!40000 ALTER TABLE `character_queststatus_daily` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `character_reputation`
---
-
-DROP TABLE IF EXISTS `character_reputation`;
-CREATE TABLE `character_reputation` (
- `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
- `faction` int(11) unsigned NOT NULL default '0',
- `standing` int(11) NOT NULL default '0',
- `flags` int(11) NOT NULL default '0',
- PRIMARY KEY (`guid`,`faction`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
-
---
--- Dumping data for table `character_reputation`
---
-
-LOCK TABLES `character_reputation` WRITE;
-/*!40000 ALTER TABLE `character_reputation` DISABLE KEYS */;
-/*!40000 ALTER TABLE `character_reputation` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `character_social`
---
-
-DROP TABLE IF EXISTS `character_social`;
-CREATE TABLE `character_social` (
- `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Character Global Unique Identifier',
- `friend` int(11) unsigned NOT NULL default '0' COMMENT 'Friend Global Unique Identifier',
- `flags` tinyint(1) unsigned NOT NULL default '0' COMMENT 'Friend Flags',
- `note` varchar(48) NOT NULL DEFAULT '' COMMENT 'Friend Note',
- PRIMARY KEY (`guid`,`friend`,`flags`),
- KEY `guid` (`guid`),
- KEY `friend` (`friend`),
- KEY `guid_flags` (`guid`,`flags`),
- KEY `friend_flags` (`friend`,`flags`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
-
---
--- Dumping data for table `character_social`
---
-
-LOCK TABLES `character_social` WRITE;
-/*!40000 ALTER TABLE `character_social` DISABLE KEYS */;
-/*!40000 ALTER TABLE `character_social` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `character_spell`
---
-
-DROP TABLE IF EXISTS `character_spell`;
-CREATE TABLE `character_spell` (
- `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
- `spell` int(11) unsigned NOT NULL default '0' COMMENT 'Spell Identifier',
- `slot` int(11) unsigned NOT NULL default '0',
- `active` tinyint(3) unsigned NOT NULL default '1',
- `disabled` tinyint(3) unsigned NOT NULL default '0',
- PRIMARY KEY (`guid`,`spell`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
-
---
--- Dumping data for table `character_spell`
---
-
-LOCK TABLES `character_spell` WRITE;
-/*!40000 ALTER TABLE `character_spell` DISABLE KEYS */;
-/*!40000 ALTER TABLE `character_spell` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `character_spell_cooldown`
---
-
-DROP TABLE IF EXISTS `character_spell_cooldown`;
-CREATE TABLE `character_spell_cooldown` (
- `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier, Low part',
- `spell` int(11) unsigned NOT NULL default '0' COMMENT 'Spell Identifier',
- `item` int(11) unsigned NOT NULL default '0' COMMENT 'Item Identifier',
- `time` bigint(20) unsigned NOT NULL default '0',
- PRIMARY KEY (`guid`,`spell`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `character_spell_cooldown`
---
-
-LOCK TABLES `character_spell_cooldown` WRITE;
-/*!40000 ALTER TABLE `character_spell_cooldown` DISABLE KEYS */;
-/*!40000 ALTER TABLE `character_spell_cooldown` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `character_ticket`
---
-
-DROP TABLE IF EXISTS `character_ticket`;
-CREATE TABLE `character_ticket` (
- `ticket_id` int(11) unsigned NOT NULL auto_increment,
- `guid` int(11) unsigned NOT NULL default '0',
- `ticket_text` text,
- `ticket_lastchange` TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
- PRIMARY KEY (`ticket_id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
-
---
--- Dumping data for table `character_ticket`
---
-
-LOCK TABLES `character_ticket` WRITE;
-/*!40000 ALTER TABLE `character_ticket` DISABLE KEYS */;
-/*!40000 ALTER TABLE `character_ticket` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `character_tutorial`
---
-
-DROP TABLE IF EXISTS `character_tutorial`;
-CREATE TABLE `character_tutorial` (
- `account` bigint(20) unsigned NOT NULL auto_increment COMMENT 'Account Identifier',
- `realmid` int(11) unsigned NOT NULL default '0' COMMENT 'Realm Identifier',
- `tut0` int(11) unsigned NOT NULL default '0',
- `tut1` int(11) unsigned NOT NULL default '0',
- `tut2` int(11) unsigned NOT NULL default '0',
- `tut3` int(11) unsigned NOT NULL default '0',
- `tut4` int(11) unsigned NOT NULL default '0',
- `tut5` int(11) unsigned NOT NULL default '0',
- `tut6` int(11) unsigned NOT NULL default '0',
- `tut7` int(11) unsigned NOT NULL default '0',
- PRIMARY KEY (`account`,`realmid`),
- KEY acc_key (`account`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
-
---
--- Dumping data for table `character_tutorial`
---
-
-LOCK TABLES `character_tutorial` WRITE;
-/*!40000 ALTER TABLE `character_tutorial` DISABLE KEYS */;
-/*!40000 ALTER TABLE `character_tutorial` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `corpse`
---
-
-DROP TABLE IF EXISTS `corpse`;
-CREATE TABLE `corpse` (
- `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
- `player` int(11) unsigned NOT NULL default '0' COMMENT 'Character Global Unique Identifier',
- `position_x` float NOT NULL default '0',
- `position_y` float NOT NULL default '0',
- `position_z` float NOT NULL default '0',
- `orientation` float NOT NULL default '0',
- `zone` int(11) unsigned NOT NULL default '38' COMMENT 'Zone Identifier',
- `map` int(11) unsigned NOT NULL default '0' COMMENT 'Map Identifier',
- `data` longtext,
- `time` bigint(20) unsigned NOT NULL default '0',
- `corpse_type` tinyint(3) unsigned NOT NULL default '0',
- `instance` int(11) unsigned NOT NULL default '0',
- PRIMARY KEY (`guid`),
- KEY `idx_type` (`corpse_type`),
- KEY `instance` (`instance`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Death System';
-
---
--- Dumping data for table `corpse`
---
-
-LOCK TABLES `corpse` WRITE;
-/*!40000 ALTER TABLE `corpse` DISABLE KEYS */;
-/*!40000 ALTER TABLE `corpse` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `groups`
---
-
-DROP TABLE IF EXISTS `groups`;
-CREATE TABLE `groups` (
- `leaderGuid` int(11) unsigned NOT NULL,
- `mainTank` int(11) unsigned NOT NULL,
- `mainAssistant` int(11) unsigned NOT NULL,
- `lootMethod` tinyint(4) unsigned NOT NULL,
- `looterGuid` int(11) unsigned NOT NULL,
- `lootThreshold` tinyint(4) unsigned NOT NULL,
- `icon1` int(11) unsigned NOT NULL,
- `icon2` int(11) unsigned NOT NULL,
- `icon3` int(11) unsigned NOT NULL,
- `icon4` int(11) unsigned NOT NULL,
- `icon5` int(11) unsigned NOT NULL,
- `icon6` int(11) unsigned NOT NULL,
- `icon7` int(11) unsigned NOT NULL,
- `icon8` int(11) unsigned NOT NULL,
- `isRaid` tinyint(1) unsigned NOT NULL,
- `difficulty` tinyint(3) unsigned NOT NULL default '0',
- PRIMARY KEY (`leaderGuid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Groups';
-
---
--- Dumping data for table `groups`
---
-
-LOCK TABLES `groups` WRITE;
-/*!40000 ALTER TABLE `groups` DISABLE KEYS */;
-/*!40000 ALTER TABLE `groups` ENABLE KEYS */;
-UNLOCK TABLES;
-
--- ----------------------------
--- Table structure for group_instance
--- ----------------------------
-DROP TABLE IF EXISTS `group_instance`;
-CREATE TABLE `group_instance` (
- `leaderGuid` int(11) unsigned NOT NULL default '0',
- `instance` int(11) unsigned NOT NULL default '0',
- `permanent` tinyint(1) unsigned NOT NULL default '0',
- PRIMARY KEY (`leaderGuid`,`instance`),
- KEY `instance` (`instance`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `group_instance`
---
-
-LOCK TABLES `group_instance` WRITE;
-/*!40000 ALTER TABLE `group_instance` DISABLE KEYS */;
-/*!40000 ALTER TABLE `group_instance` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `group_member`
---
-
-DROP TABLE IF EXISTS `group_member`;
-CREATE TABLE `group_member` (
- `leaderGuid` int(11) unsigned NOT NULL,
- `memberGuid` int(11) unsigned NOT NULL,
- `assistant` tinyint(1) unsigned NOT NULL,
- `subgroup` smallint(6) unsigned NOT NULL,
- PRIMARY KEY (`leaderGuid`,`memberGuid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Groups';
-
---
--- Dumping data for table `group_member`
---
-
-LOCK TABLES `group_member` WRITE;
-/*!40000 ALTER TABLE `group_member` DISABLE KEYS */;
-/*!40000 ALTER TABLE `group_member` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `guild`
---
-
-DROP TABLE IF EXISTS `guild`;
-CREATE TABLE `guild` (
- `guildid` int(6) unsigned NOT NULL default '0',
- `name` varchar(255) NOT NULL default '',
- `leaderguid` int(6) unsigned NOT NULL default '0',
- `EmblemStyle` int(5) NOT NULL default '0',
- `EmblemColor` int(5) NOT NULL default '0',
- `BorderStyle` int(5) NOT NULL default '0',
- `BorderColor` int(5) NOT NULL default '0',
- `BackgroundColor` int(5) NOT NULL default '0',
- `info` text NOT NULL,
- `motd` varchar(255) NOT NULL default '',
- `createdate` datetime default NULL,
- `BankMoney` bigint(20) NOT NULL default '0',
- PRIMARY KEY (`guildid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Guild System';
-
---
--- Dumping data for table `guild`
---
-
-LOCK TABLES `guild` WRITE;
-/*!40000 ALTER TABLE `guild` DISABLE KEYS */;
-/*!40000 ALTER TABLE `guild` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `guild_bank_eventlog`
---
-
-DROP TABLE IF EXISTS `guild_bank_eventlog`;
-CREATE TABLE `guild_bank_eventlog` (
- `guildid` int(11) unsigned NOT NULL default '0',
- `LogGuid` int(11) unsigned NOT NULL default '0',
- `LogEntry` tinyint(1) unsigned NOT NULL default '0',
- `TabId` tinyint(1) unsigned NOT NULL default '0',
- `PlayerGuid` int(11) unsigned NOT NULL default '0',
- `ItemOrMoney` int(11) unsigned NOT NULL default '0',
- `ItemStackCount` tinyint(3) unsigned NOT NULL default '0',
- `DestTabId` tinyint(1) unsigned NOT NULL default '0',
- `TimeStamp` bigint(20) unsigned NOT NULL default '0',
- PRIMARY KEY (`guildid`,`LogGuid`),
- KEY `guildid_key` (`guildid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `guild_bank_eventlog`
---
-
-LOCK TABLES `guild_bank_eventlog` WRITE;
-/*!40000 ALTER TABLE `guild_bank_eventlog` DISABLE KEYS */;
-/*!40000 ALTER TABLE `guild_bank_eventlog` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `guild_bank_item`
---
-
-DROP TABLE IF EXISTS `guild_bank_item`;
-CREATE TABLE `guild_bank_item` (
- `guildid` int(11) unsigned NOT NULL default '0',
- `TabId` tinyint(1) unsigned NOT NULL default '0',
- `SlotId` tinyint(3) unsigned NOT NULL default '0',
- `item_guid` int(11) unsigned NOT NULL default '0',
- `item_entry` int(11) unsigned NOT NULL default '0',
- PRIMARY KEY (`guildid`,`tabid`,`slotid`),
- KEY `guildid_key` (`guildid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `guild_bank_item`
---
-
-LOCK TABLES `guild_bank_item` WRITE;
-/*!40000 ALTER TABLE `guild_bank_item` DISABLE KEYS */;
-/*!40000 ALTER TABLE `guild_bank_item` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `guild_bank_right`
---
-
-DROP TABLE IF EXISTS `guild_bank_right`;
-CREATE TABLE `guild_bank_right` (
- `guildid` int(11) unsigned NOT NULL default '0',
- `TabId` tinyint(1) unsigned NOT NULL default '0',
- `rid` int(11) unsigned NOT NULL default '0',
- `gbright` tinyint(3) unsigned NOT NULL default '0',
- `SlotPerDay` int(11) unsigned NOT NULL default '0',
- PRIMARY KEY (`guildid`,`TabId`,`rid`),
- KEY `guildid_key` (`guildid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `guild_bank_right`
---
-
-LOCK TABLES `guild_bank_right` WRITE;
-/*!40000 ALTER TABLE `guild_bank_right` DISABLE KEYS */;
-/*!40000 ALTER TABLE `guild_bank_right` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `guild_bank_tab`
---
-
-DROP TABLE IF EXISTS `guild_bank_tab`;
-CREATE TABLE `guild_bank_tab` (
- `guildid` int(11) unsigned NOT NULL default '0',
- `TabId` tinyint(1) unsigned NOT NULL default '0',
- `TabName` varchar(100) NOT NULL default '',
- `TabIcon` varchar(100) NOT NULL default '',
- `TabText` varchar(500) NOT NULL default '',
- PRIMARY KEY (`guildid`,`TabId`),
- KEY `guildid_key` (`guildid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `guild_bank_tab`
---
-
-LOCK TABLES `guild_bank_tab` WRITE;
-/*!40000 ALTER TABLE `guild_bank_tab` DISABLE KEYS */;
-/*!40000 ALTER TABLE `guild_bank_tab` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `guild_eventlog`
---
-
-DROP TABLE IF EXISTS `guild_eventlog`;
-CREATE TABLE `guild_eventlog` (
- `guildid` int(11) NOT NULL COMMENT 'Guild Identificator',
- `LogGuid` int(11) NOT NULL COMMENT 'Log entry identificator',
- `EventType` tinyint(1) NOT NULL COMMENT 'Event type',
- `PlayerGuid1` int(11) NOT NULL COMMENT 'Player 1',
- `PlayerGuid2` int(11) NOT NULL COMMENT 'Player 2',
- `NewRank` tinyint(2) NOT NULL COMMENT 'New rank(in case promotion/demotion)',
- `TimeStamp` bigint(20) NOT NULL COMMENT 'Event UNIX time'
-) ENGINE = InnoDB DEFAULT CHARSET = latin1 COMMENT 'Guild Eventlog';
-
---
--- Dumping data for table `guild_eventlog`
---
-
-LOCK TABLES `guild_eventlog` WRITE;
-/*!40000 ALTER TABLE `guild_eventlog` DISABLE KEYS */;
-/*!40000 ALTER TABLE `guild_eventlog` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `guild_member`
---
-
-DROP TABLE IF EXISTS `guild_member`;
-CREATE TABLE `guild_member` (
- `guildid` int(6) unsigned NOT NULL default '0',
- `guid` int(11) unsigned NOT NULL default '0',
- `rank` tinyint(2) unsigned NOT NULL default '0',
- `pnote` varchar(255) NOT NULL default '',
- `offnote` varchar(255) NOT NULL default '',
- `BankResetTimeMoney` int(11) unsigned NOT NULL default '0',
- `BankRemMoney` int(11) unsigned NOT NULL default '0',
- `BankResetTimeTab0` int(11) unsigned NOT NULL default '0',
- `BankRemSlotsTab0` int(11) unsigned NOT NULL default '0',
- `BankResetTimeTab1` int(11) unsigned NOT NULL default '0',
- `BankRemSlotsTab1` int(11) unsigned NOT NULL default '0',
- `BankResetTimeTab2` int(11) unsigned NOT NULL default '0',
- `BankRemSlotsTab2` int(11) unsigned NOT NULL default '0',
- `BankResetTimeTab3` int(11) unsigned NOT NULL default '0',
- `BankRemSlotsTab3` int(11) unsigned NOT NULL default '0',
- `BankResetTimeTab4` int(11) unsigned NOT NULL default '0',
- `BankRemSlotsTab4` int(11) unsigned NOT NULL default '0',
- `BankResetTimeTab5` int(11) unsigned NOT NULL default '0',
- `BankRemSlotsTab5` int(11) unsigned NOT NULL default '0',
- KEY `guildid_key` (`guildid`),
- KEY `guildid_rank_key` (`guildid`,`rank`),
- KEY `guid_key` (`guid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Guild System';
-
---
--- Dumping data for table `guild_member`
---
-
-LOCK TABLES `guild_member` WRITE;
-/*!40000 ALTER TABLE `guild_member` DISABLE KEYS */;
-/*!40000 ALTER TABLE `guild_member` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `guild_rank`
---
-
-DROP TABLE IF EXISTS `guild_rank`;
-CREATE TABLE `guild_rank` (
- `guildid` int(6) unsigned NOT NULL default '0',
- `rid` int(11) unsigned NOT NULL,
- `rname` varchar(255) NOT NULL default '',
- `rights` int(3) unsigned NOT NULL default '0',
- `BankMoneyPerDay` int(11) unsigned NOT NULL default '0',
- PRIMARY KEY (`guildid`,`rid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Guild System';
-
---
--- Dumping data for table `guild_rank`
---
-
-LOCK TABLES `guild_rank` WRITE;
-/*!40000 ALTER TABLE `guild_rank` DISABLE KEYS */;
-/*!40000 ALTER TABLE `guild_rank` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `instance`
---
-
-DROP TABLE IF EXISTS `instance`;
-CREATE TABLE `instance` (
- `id` int(11) unsigned NOT NULL default '0',
- `map` int(11) unsigned NOT NULL default '0',
- `resettime` bigint(40) NOT NULL default '0',
- `difficulty` tinyint(1) unsigned NOT NULL default '0',
- `data` longtext,
- PRIMARY KEY (`id`),
- KEY `map` (`map`),
- KEY `resettime` (`resettime`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `instance`
---
-
-LOCK TABLES `instance` WRITE;
-/*!40000 ALTER TABLE `instance` DISABLE KEYS */;
-/*!40000 ALTER TABLE `instance` ENABLE KEYS */;
-UNLOCK TABLES;
-
--- ----------------------------
--- Table structure for instance_reset
--- ----------------------------
-DROP TABLE IF EXISTS `instance_reset`;
-CREATE TABLE `instance_reset` (
- `mapid` int(11) unsigned NOT NULL default '0',
- `resettime` bigint(40) NOT NULL default '0',
- PRIMARY KEY (`mapid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `instance_reset`
---
-
-LOCK TABLES `instance_reset` WRITE;
-/*!40000 ALTER TABLE `instance_reset` DISABLE KEYS */;
-/*!40000 ALTER TABLE `instance_reset` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `item_instance`
---
-
-DROP TABLE IF EXISTS `item_instance`;
-CREATE TABLE `item_instance` (
- `guid` int(11) unsigned NOT NULL default '0',
- `owner_guid` int(11) unsigned NOT NULL default '0',
- `data` longtext,
- PRIMARY KEY (`guid`),
- KEY `idx_owner_guid` (`owner_guid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Item System';
-
---
--- Dumping data for table `item_instance`
---
-
-LOCK TABLES `item_instance` WRITE;
-/*!40000 ALTER TABLE `item_instance` DISABLE KEYS */;
-/*!40000 ALTER TABLE `item_instance` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `item_text`
---
-
-DROP TABLE IF EXISTS `item_text`;
-CREATE TABLE `item_text` (
- `id` int(11) unsigned NOT NULL default '0',
- `text` longtext,
- PRIMARY KEY (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Item System';
-
---
--- Dumping data for table `item_text`
---
-
-LOCK TABLES `item_text` WRITE;
-/*!40000 ALTER TABLE `item_text` DISABLE KEYS */;
-/*!40000 ALTER TABLE `item_text` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `mail`
---
-
-DROP TABLE IF EXISTS `mail`;
-CREATE TABLE `mail` (
- `id` int(11) unsigned NOT NULL default '0' COMMENT 'Identifier',
- `messageType` tinyint(3) unsigned NOT NULL default '0',
- `stationery` tinyint(3) NOT NULL default '41',
- `mailTemplateId` mediumint(8) unsigned NOT NULL default '0',
- `sender` int(11) unsigned NOT NULL default '0' COMMENT 'Character Global Unique Identifier',
- `receiver` int(11) unsigned NOT NULL default '0' COMMENT 'Character Global Unique Identifier',
- `subject` longtext,
- `itemTextId` int(11) unsigned NOT NULL default '0',
- `has_items` tinyint(3) unsigned NOT NULL default '0',
- `expire_time` bigint(40) NOT NULL default '0',
- `deliver_time` bigint(40) NOT NULL default '0',
- `money` int(11) unsigned NOT NULL default '0',
- `cod` int(11) unsigned NOT NULL default '0',
- `checked` tinyint(3) unsigned NOT NULL default '0',
- PRIMARY KEY (`id`),
- KEY `idx_receiver` (`receiver`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Mail System';
-
---
--- Dumping data for table `mail`
---
-
-LOCK TABLES `mail` WRITE;
-/*!40000 ALTER TABLE `mail` DISABLE KEYS */;
-/*!40000 ALTER TABLE `mail` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `mail_items`
---
-
-DROP TABLE IF EXISTS `mail_items`;
-CREATE TABLE `mail_items` (
- `mail_id` int(11) NOT NULL default '0',
- `item_guid` int(11) NOT NULL default '0',
- `item_template` int(11) NOT NULL default '0',
- `receiver` int(11) unsigned NOT NULL default '0' COMMENT 'Character Global Unique Identifier',
- PRIMARY KEY (`mail_id`,`item_guid`),
- KEY `idx_receiver` (`receiver`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
-
---
--- Dumping data for table `mail_items`
---
-
-LOCK TABLES `mail_items` WRITE;
-/*!40000 ALTER TABLE `mail_items` DISABLE KEYS */;
-/*!40000 ALTER TABLE `mail_items` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `pet_aura`
---
-
-DROP TABLE IF EXISTS `pet_aura`;
-CREATE TABLE `pet_aura` (
- `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
- `caster_guid` bigint(20) unsigned NOT NULL default '0' COMMENT 'Full Global Unique Identifier',
- `spell` int(11) unsigned NOT NULL default '0',
- `effect_index` int(11) unsigned NOT NULL default '0',
- `amount` int(11) NOT NULL default '0',
- `maxduration` int(11) NOT NULL default '0',
- `remaintime` int(11) NOT NULL default '0',
- `remaincharges` int(11) NOT NULL default '0',
- PRIMARY KEY (`guid`,`spell`,`effect_index`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Pet System';
-
---
--- Dumping data for table `pet_aura`
---
-
-LOCK TABLES `pet_aura` WRITE;
-/*!40000 ALTER TABLE `pet_aura` DISABLE KEYS */;
-/*!40000 ALTER TABLE `pet_aura` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `pet_spell`
---
-
-DROP TABLE IF EXISTS `pet_spell`;
-CREATE TABLE `pet_spell` (
- `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
- `spell` int(11) unsigned NOT NULL default '0' COMMENT 'Spell Identifier',
- `slot` int(11) unsigned NOT NULL default '0',
- `active` int(11) unsigned NOT NULL default '0',
- PRIMARY KEY (`guid`,`spell`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Pet System';
-
---
--- Dumping data for table `pet_spell`
---
-
-LOCK TABLES `pet_spell` WRITE;
-/*!40000 ALTER TABLE `pet_spell` DISABLE KEYS */;
-/*!40000 ALTER TABLE `pet_spell` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `pet_spell_cooldown`
---
-
-DROP TABLE IF EXISTS `pet_spell_cooldown`;
-CREATE TABLE `pet_spell_cooldown` (
- `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier, Low part',
- `spell` int(11) unsigned NOT NULL default '0' COMMENT 'Spell Identifier',
- `time` bigint(20) unsigned NOT NULL default '0',
- PRIMARY KEY (`guid`,`spell`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
---
--- Dumping data for table `pet_spell_cooldown`
---
-
-LOCK TABLES `pet_spell_cooldown` WRITE;
-/*!40000 ALTER TABLE `pet_spell_cooldown` DISABLE KEYS */;
-/*!40000 ALTER TABLE `pet_spell_cooldown` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `petition`
---
-
-DROP TABLE IF EXISTS `petition`;
-CREATE TABLE `petition` (
- `ownerguid` int(10) unsigned NOT NULL,
- `petitionguid` int(10) unsigned default '0',
- `name` varchar(255) NOT NULL default '',
- `type` int(10) unsigned NOT NULL default '0',
- PRIMARY KEY (`ownerguid`,`type`),
- UNIQUE KEY `index_ownerguid_petitionguid` (`ownerguid`,`petitionguid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Guild System';
-
---
--- Dumping data for table `petition`
---
-
-LOCK TABLES `petition` WRITE;
-/*!40000 ALTER TABLE `petition` DISABLE KEYS */;
-/*!40000 ALTER TABLE `petition` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `petition_sign`
---
-
-DROP TABLE IF EXISTS `petition_sign`;
-CREATE TABLE `petition_sign` (
- `ownerguid` int(10) unsigned NOT NULL,
- `petitionguid` int(11) unsigned NOT NULL default '0',
- `playerguid` int(11) unsigned NOT NULL default '0',
- `player_account` int(11) unsigned NOT NULL default '0',
- `type` int(10) unsigned NOT NULL default '0',
- PRIMARY KEY (`petitionguid`,`playerguid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Guild System';
---
--- Dumping data for table `petition_sign`
---
-
-LOCK TABLES `petition_sign` WRITE;
-/*!40000 ALTER TABLE `petition_sign` DISABLE KEYS */;
-/*!40000 ALTER TABLE `petition_sign` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Table structure for table `saved_variables`
---
-DROP TABLE IF EXISTS `saved_variables`;
-CREATE TABLE `saved_variables` (
- `NextArenaPointDistributionTime` timestamp NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Variable Saves';
-
---
--- Dumping data for table `saved_variables`
---
-
-LOCK TABLES `saved_variables` WRITE;
-/*!40000 ALTER TABLE `saved_variables` DISABLE KEYS */;
-/*!40000 ALTER TABLE `saved_variables` ENABLE KEYS */;
-UNLOCK TABLES;
-/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
-
-/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
-/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
-/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
-/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
-/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
-/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
-/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-
--- Dump completed on 2008-01-10 11:37:06
+-- MySQL dump 10.11
+--
+-- Host: localhost Database: characters
+-- ------------------------------------------------------
+-- Server version 5.0.45-Debian_1ubuntu3.1-log
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
+/*!40103 SET TIME_ZONE='+00:00' */;
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+
+--
+-- Table structure for table `arena_team`
+--
+
+DROP TABLE IF EXISTS `arena_team`;
+CREATE TABLE `arena_team` (
+ `arenateamid` int(10) unsigned NOT NULL default '0',
+ `name` char(255) NOT NULL,
+ `captainguid` int(10) unsigned NOT NULL default '0',
+ `type` tinyint(3) unsigned NOT NULL default '0',
+ `BackgroundColor` int(10) unsigned NOT NULL default '0',
+ `EmblemStyle` int(10) unsigned NOT NULL default '0',
+ `EmblemColor` int(10) unsigned NOT NULL default '0',
+ `BorderStyle` int(10) unsigned NOT NULL default '0',
+ `BorderColor` int(10) unsigned NOT NULL default '0',
+ PRIMARY KEY (`arenateamid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `arena_team`
+--
+
+LOCK TABLES `arena_team` WRITE;
+/*!40000 ALTER TABLE `arena_team` DISABLE KEYS */;
+/*!40000 ALTER TABLE `arena_team` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `arena_team_member`
+--
+
+DROP TABLE IF EXISTS `arena_team_member`;
+CREATE TABLE `arena_team_member` (
+ `arenateamid` int(10) unsigned NOT NULL default '0',
+ `guid` int(10) unsigned NOT NULL default '0',
+ `played_week` int(10) unsigned NOT NULL default '0',
+ `wons_week` int(10) unsigned NOT NULL default '0',
+ `played_season` int(10) unsigned NOT NULL default '0',
+ `wons_season` int(10) unsigned NOT NULL default '0',
+ `points_to_add` int(10) unsigned NOT NULL default '0'
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `arena_team_member`
+--
+
+LOCK TABLES `arena_team_member` WRITE;
+/*!40000 ALTER TABLE `arena_team_member` DISABLE KEYS */;
+/*!40000 ALTER TABLE `arena_team_member` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `arena_team_stats`
+--
+
+DROP TABLE IF EXISTS `arena_team_stats`;
+CREATE TABLE `arena_team_stats` (
+ `arenateamid` int(10) unsigned NOT NULL default '0',
+ `rating` int(10) unsigned NOT NULL default '0',
+ `games` int(10) unsigned NOT NULL default '0',
+ `wins` int(10) unsigned NOT NULL default '0',
+ `played` int(10) unsigned NOT NULL default '0',
+ `wins2` int(10) unsigned NOT NULL default '0',
+ `rank` int(10) unsigned NOT NULL default '0',
+ PRIMARY KEY (`arenateamid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `arena_team_stats`
+--
+
+LOCK TABLES `arena_team_stats` WRITE;
+/*!40000 ALTER TABLE `arena_team_stats` DISABLE KEYS */;
+/*!40000 ALTER TABLE `arena_team_stats` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `auctionhouse`
+--
+
+DROP TABLE IF EXISTS `auctionhouse`;
+CREATE TABLE `auctionhouse` (
+ `id` int(11) unsigned NOT NULL default '0',
+ `auctioneerguid` int(11) unsigned NOT NULL default '0',
+ `itemguid` int(11) unsigned NOT NULL default '0',
+ `item_template` int(11) unsigned NOT NULL default '0' COMMENT 'Item Identifier',
+ `itemowner` int(11) unsigned NOT NULL default '0',
+ `buyoutprice` int(11) NOT NULL default '0',
+ `time` bigint(40) NOT NULL default '0',
+ `buyguid` int(11) unsigned NOT NULL default '0',
+ `lastbid` int(11) NOT NULL default '0',
+ `startbid` int(11) NOT NULL default '0',
+ `deposit` int(11) NOT NULL default '0',
+ `location` tinyint(3) unsigned NOT NULL default '3',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `item_guid` (`itemguid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `auctionhouse`
+--
+
+LOCK TABLES `auctionhouse` WRITE;
+/*!40000 ALTER TABLE `auctionhouse` DISABLE KEYS */;
+/*!40000 ALTER TABLE `auctionhouse` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `bugreport`
+--
+
+DROP TABLE IF EXISTS `bugreport`;
+CREATE TABLE `bugreport` (
+ `id` int(11) NOT NULL auto_increment COMMENT 'Identifier',
+ `type` varchar(255) NOT NULL default '',
+ `content` varchar(255) NOT NULL default '',
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Debug System';
+
+--
+-- Dumping data for table `bugreport`
+--
+
+LOCK TABLES `bugreport` WRITE;
+/*!40000 ALTER TABLE `bugreport` DISABLE KEYS */;
+/*!40000 ALTER TABLE `bugreport` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `characters`
+--
+
+DROP TABLE IF EXISTS `characters`;
+CREATE TABLE `characters` (
+ `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
+ `account` int(11) unsigned NOT NULL default '0' COMMENT 'Account Identifier',
+ `data` longtext,
+ `name` varchar(12) NOT NULL default '',
+ `race` tinyint(3) unsigned NOT NULL default '0',
+ `class` tinyint(3) unsigned NOT NULL default '0',
+ `position_x` float NOT NULL default '0',
+ `position_y` float NOT NULL default '0',
+ `position_z` float NOT NULL default '0',
+ `map` int(11) unsigned NOT NULL default '0' COMMENT 'Map Identifier',
+ `dungeon_difficulty` tinyint(1) unsigned NOT NULL DEFAULT '0',
+ `orientation` float NOT NULL default '0',
+ `taximask` longtext,
+ `online` tinyint(3) unsigned NOT NULL default '0',
+ `cinematic` tinyint(3) unsigned NOT NULL default '0',
+ `totaltime` int(11) unsigned NOT NULL default '0',
+ `leveltime` int(11) unsigned NOT NULL default '0',
+ `logout_time` bigint(20) unsigned NOT NULL default '0',
+ `is_logout_resting` tinyint(3) unsigned NOT NULL default '0',
+ `rest_bonus` float NOT NULL default '0',
+ `resettalents_cost` int(11) unsigned NOT NULL default '0',
+ `resettalents_time` bigint(20) unsigned NOT NULL default '0',
+ `trans_x` float NOT NULL default '0',
+ `trans_y` float NOT NULL default '0',
+ `trans_z` float NOT NULL default '0',
+ `trans_o` float NOT NULL default '0',
+ `transguid` bigint(20) unsigned NOT NULL default '0',
+ `gmstate` int(11) unsigned NOT NULL default '0',
+ `stable_slots` tinyint(1) unsigned NOT NULL default '0',
+ `at_login` int(11) unsigned NOT NULL default '0',
+ `zone` int(11) unsigned NOT NULL default '0',
+ `death_expire_time` bigint(20) unsigned NOT NULL default '0',
+ `taxi_path` text,
+ PRIMARY KEY (`guid`),
+ KEY `idx_account` (`account`),
+ KEY `idx_online` (`online`),
+ KEY `idx_name` (`name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
+
+--
+-- Dumping data for table `characters`
+--
+
+LOCK TABLES `characters` WRITE;
+/*!40000 ALTER TABLE `characters` DISABLE KEYS */;
+/*!40000 ALTER TABLE `characters` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `character_action`
+--
+
+DROP TABLE IF EXISTS `character_action`;
+CREATE TABLE `character_action` (
+ `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
+ `button` tinyint(3) unsigned NOT NULL default '0',
+ `action` smallint(5) unsigned NOT NULL default '0',
+ `type` tinyint(3) unsigned NOT NULL default '0',
+ `misc` tinyint(3) unsigned NOT NULL default '0',
+ PRIMARY KEY (`guid`,`button`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
+
+--
+-- Dumping data for table `character_action`
+--
+
+LOCK TABLES `character_action` WRITE;
+/*!40000 ALTER TABLE `character_action` DISABLE KEYS */;
+/*!40000 ALTER TABLE `character_action` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `character_aura`
+--
+
+DROP TABLE IF EXISTS `character_aura`;
+CREATE TABLE `character_aura` (
+ `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
+ `caster_guid` bigint(20) unsigned NOT NULL default '0' COMMENT 'Full Global Unique Identifier',
+ `spell` int(11) unsigned NOT NULL default '0',
+ `effect_index` int(11) unsigned NOT NULL default '0',
+ `amount` int(11) NOT NULL default '0',
+ `maxduration` int(11) NOT NULL default '0',
+ `remaintime` int(11) NOT NULL default '0',
+ `remaincharges` int(11) NOT NULL default '0',
+ PRIMARY KEY (`guid`,`spell`,`effect_index`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
+
+--
+-- Dumping data for table `character_aura`
+--
+
+LOCK TABLES `character_aura` WRITE;
+/*!40000 ALTER TABLE `character_aura` DISABLE KEYS */;
+/*!40000 ALTER TABLE `character_aura` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `character_declinedname`
+--
+
+DROP TABLE IF EXISTS `character_declinedname`;
+CREATE TABLE `character_declinedname` (
+ `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
+ `genitive` varchar(15) NOT NULL default '',
+ `dative` varchar(15) NOT NULL default '',
+ `accusative` varchar(15) NOT NULL default '',
+ `instrumental` varchar(15) NOT NULL default '',
+ `prepositional` varchar(15) NOT NULL default '',
+ PRIMARY KEY (`guid`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
+
+--
+-- Dumping data for table `character_declinedname`
+--
+
+LOCK TABLES `character_declinedname` WRITE;
+/*!40000 ALTER TABLE `character_declinedname` DISABLE KEYS */;
+/*!40000 ALTER TABLE `character_declinedname` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `character_gifts`
+--
+
+DROP TABLE IF EXISTS `character_gifts`;
+CREATE TABLE `character_gifts` (
+ `guid` int(20) unsigned NOT NULL default '0',
+ `item_guid` int(11) unsigned NOT NULL default '0',
+ `entry` int(20) unsigned NOT NULL default '0',
+ `flags` int(20) unsigned NOT NULL default '0',
+ PRIMARY KEY (`item_guid`),
+ KEY `idx_guid` (`guid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `character_gifts`
+--
+
+LOCK TABLES `character_gifts` WRITE;
+/*!40000 ALTER TABLE `character_gifts` DISABLE KEYS */;
+/*!40000 ALTER TABLE `character_gifts` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `character_homebind`
+--
+
+DROP TABLE IF EXISTS `character_homebind`;
+CREATE TABLE `character_homebind` (
+ `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
+ `map` int(11) unsigned NOT NULL default '0' COMMENT 'Map Identifier',
+ `zone` int(11) unsigned NOT NULL default '0' COMMENT 'Zone Identifier',
+ `position_x` float NOT NULL default '0',
+ `position_y` float NOT NULL default '0',
+ `position_z` float NOT NULL default '0',
+ PRIMARY KEY (`guid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
+
+--
+-- Dumping data for table `character_homebind`
+--
+
+LOCK TABLES `character_homebind` WRITE;
+/*!40000 ALTER TABLE `character_homebind` DISABLE KEYS */;
+/*!40000 ALTER TABLE `character_homebind` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `character_instance`
+--
+
+DROP TABLE IF EXISTS `character_instance`;
+CREATE TABLE `character_instance` (
+ `guid` int(11) unsigned NOT NULL default '0',
+ `instance` int(11) unsigned NOT NULL default '0',
+ `permanent` tinyint(1) unsigned NOT NULL default '0',
+ PRIMARY KEY (`guid`,`instance`),
+ KEY `instance` (`instance`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `character_instance`
+--
+
+LOCK TABLES `character_instance` WRITE;
+/*!40000 ALTER TABLE `character_instance` DISABLE KEYS */;
+/*!40000 ALTER TABLE `character_instance` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `character_inventory`
+--
+
+DROP TABLE IF EXISTS `character_inventory`;
+CREATE TABLE `character_inventory` (
+ `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
+ `bag` int(11) unsigned NOT NULL default '0',
+ `slot` tinyint(3) unsigned NOT NULL default '0',
+ `item` int(11) unsigned NOT NULL default '0' COMMENT 'Item Global Unique Identifier',
+ `item_template` int(11) unsigned NOT NULL default '0' COMMENT 'Item Identifier',
+ PRIMARY KEY (`item`),
+ KEY `idx_guid` (`guid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
+
+--
+-- Dumping data for table `character_inventory`
+--
+
+LOCK TABLES `character_inventory` WRITE;
+/*!40000 ALTER TABLE `character_inventory` DISABLE KEYS */;
+/*!40000 ALTER TABLE `character_inventory` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `character_pet`
+--
+
+DROP TABLE IF EXISTS `character_pet`;
+CREATE TABLE `character_pet` (
+ `id` int(11) unsigned NOT NULL default '0',
+ `entry` int(11) unsigned NOT NULL default '0',
+ `owner` int(11) unsigned NOT NULL default '0',
+ `modelid` int(11) unsigned default '0',
+ `CreatedBySpell` int(11) unsigned NOT NULL default '0',
+ `PetType` tinyint(3) unsigned NOT NULL default '0',
+ `level` int(11) unsigned NOT NULL default '1',
+ `exp` int(11) unsigned NOT NULL default '0',
+ `Reactstate` tinyint(1) unsigned NOT NULL default '0',
+ `loyaltypoints` int(11) NOT NULL default '0',
+ `loyalty` int(11) unsigned NOT NULL default '0',
+ `trainpoint` int(11) NOT NULL default '0',
+ `name` varchar(100) default 'Pet',
+ `renamed` tinyint(1) unsigned NOT NULL default '0',
+ `slot` int(11) unsigned NOT NULL default '0',
+ `curhealth` int(11) unsigned NOT NULL default '1',
+ `curmana` int(11) unsigned NOT NULL default '0',
+ `curhappiness` int(11) unsigned NOT NULL default '0',
+ `savetime` bigint(20) unsigned NOT NULL default '0',
+ `resettalents_cost` int(11) unsigned NOT NULL default '0',
+ `resettalents_time` bigint(20) unsigned NOT NULL default '0',
+ `abdata` longtext,
+ `teachspelldata` longtext,
+ PRIMARY KEY (`id`),
+ KEY `owner` (`owner`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Pet System';
+
+--
+-- Dumping data for table `character_pet`
+--
+
+LOCK TABLES `character_pet` WRITE;
+/*!40000 ALTER TABLE `character_pet` DISABLE KEYS */;
+/*!40000 ALTER TABLE `character_pet` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `character_pet_declinedname`
+--
+
+DROP TABLE IF EXISTS `character_pet_declinedname`;
+CREATE TABLE `character_pet_declinedname` (
+ `id` int(11) unsigned NOT NULL default '0',
+ `owner` int(11) unsigned NOT NULL default '0',
+ `genitive` varchar(12) NOT NULL default '',
+ `dative` varchar(12) NOT NULL default '',
+ `accusative` varchar(12) NOT NULL default '',
+ `instrumental` varchar(12) NOT NULL default '',
+ `prepositional` varchar(12) NOT NULL default '',
+ PRIMARY KEY (`id`),
+ KEY owner_key (`owner`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
+
+--
+-- Dumping data for table `character_pet_declinedname`
+--
+
+LOCK TABLES `character_pet_declinedname` WRITE;
+/*!40000 ALTER TABLE `character_pet_declinedname` DISABLE KEYS */;
+/*!40000 ALTER TABLE `character_pet_declinedname` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `character_queststatus`
+--
+
+DROP TABLE IF EXISTS `character_queststatus`;
+CREATE TABLE `character_queststatus` (
+ `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
+ `quest` int(11) unsigned NOT NULL default '0' COMMENT 'Quest Identifier',
+ `status` int(11) unsigned NOT NULL default '0',
+ `rewarded` tinyint(1) unsigned NOT NULL default '0',
+ `explored` tinyint(1) unsigned NOT NULL default '0',
+ `timer` bigint(20) unsigned NOT NULL default '0',
+ `mobcount1` int(11) unsigned NOT NULL default '0',
+ `mobcount2` int(11) unsigned NOT NULL default '0',
+ `mobcount3` int(11) unsigned NOT NULL default '0',
+ `mobcount4` int(11) unsigned NOT NULL default '0',
+ `itemcount1` int(11) unsigned NOT NULL default '0',
+ `itemcount2` int(11) unsigned NOT NULL default '0',
+ `itemcount3` int(11) unsigned NOT NULL default '0',
+ `itemcount4` int(11) unsigned NOT NULL default '0',
+ PRIMARY KEY (`guid`,`quest`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
+
+--
+-- Dumping data for table `character_queststatus`
+--
+
+LOCK TABLES `character_queststatus` WRITE;
+/*!40000 ALTER TABLE `character_queststatus` DISABLE KEYS */;
+/*!40000 ALTER TABLE `character_queststatus` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `character_queststatus_daily`
+--
+
+DROP TABLE IF EXISTS `character_queststatus_daily`;
+CREATE TABLE `character_queststatus_daily` (
+ `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
+ `quest` int(11) unsigned NOT NULL default '0' COMMENT 'Quest Identifier',
+ `time` bigint(20) unsigned NOT NULL default '0',
+ PRIMARY KEY (`guid`,`quest`),
+ KEY `idx_guid` (`guid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
+
+--
+-- Dumping data for table `character_queststatus_daily`
+--
+
+LOCK TABLES `character_queststatus_daily` WRITE;
+/*!40000 ALTER TABLE `character_queststatus_daily` DISABLE KEYS */;
+/*!40000 ALTER TABLE `character_queststatus_daily` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `character_reputation`
+--
+
+DROP TABLE IF EXISTS `character_reputation`;
+CREATE TABLE `character_reputation` (
+ `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
+ `faction` int(11) unsigned NOT NULL default '0',
+ `standing` int(11) NOT NULL default '0',
+ `flags` int(11) NOT NULL default '0',
+ PRIMARY KEY (`guid`,`faction`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
+
+--
+-- Dumping data for table `character_reputation`
+--
+
+LOCK TABLES `character_reputation` WRITE;
+/*!40000 ALTER TABLE `character_reputation` DISABLE KEYS */;
+/*!40000 ALTER TABLE `character_reputation` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `character_social`
+--
+
+DROP TABLE IF EXISTS `character_social`;
+CREATE TABLE `character_social` (
+ `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Character Global Unique Identifier',
+ `friend` int(11) unsigned NOT NULL default '0' COMMENT 'Friend Global Unique Identifier',
+ `flags` tinyint(1) unsigned NOT NULL default '0' COMMENT 'Friend Flags',
+ `note` varchar(48) NOT NULL DEFAULT '' COMMENT 'Friend Note',
+ PRIMARY KEY (`guid`,`friend`,`flags`),
+ KEY `guid` (`guid`),
+ KEY `friend` (`friend`),
+ KEY `guid_flags` (`guid`,`flags`),
+ KEY `friend_flags` (`friend`,`flags`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
+
+--
+-- Dumping data for table `character_social`
+--
+
+LOCK TABLES `character_social` WRITE;
+/*!40000 ALTER TABLE `character_social` DISABLE KEYS */;
+/*!40000 ALTER TABLE `character_social` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `character_spell`
+--
+
+DROP TABLE IF EXISTS `character_spell`;
+CREATE TABLE `character_spell` (
+ `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
+ `spell` int(11) unsigned NOT NULL default '0' COMMENT 'Spell Identifier',
+ `slot` int(11) unsigned NOT NULL default '0',
+ `active` tinyint(3) unsigned NOT NULL default '1',
+ `disabled` tinyint(3) unsigned NOT NULL default '0',
+ PRIMARY KEY (`guid`,`spell`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
+
+--
+-- Dumping data for table `character_spell`
+--
+
+LOCK TABLES `character_spell` WRITE;
+/*!40000 ALTER TABLE `character_spell` DISABLE KEYS */;
+/*!40000 ALTER TABLE `character_spell` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `character_spell_cooldown`
+--
+
+DROP TABLE IF EXISTS `character_spell_cooldown`;
+CREATE TABLE `character_spell_cooldown` (
+ `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier, Low part',
+ `spell` int(11) unsigned NOT NULL default '0' COMMENT 'Spell Identifier',
+ `item` int(11) unsigned NOT NULL default '0' COMMENT 'Item Identifier',
+ `time` bigint(20) unsigned NOT NULL default '0',
+ PRIMARY KEY (`guid`,`spell`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `character_spell_cooldown`
+--
+
+LOCK TABLES `character_spell_cooldown` WRITE;
+/*!40000 ALTER TABLE `character_spell_cooldown` DISABLE KEYS */;
+/*!40000 ALTER TABLE `character_spell_cooldown` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `character_ticket`
+--
+
+DROP TABLE IF EXISTS `character_ticket`;
+CREATE TABLE `character_ticket` (
+ `ticket_id` int(11) unsigned NOT NULL auto_increment,
+ `guid` int(11) unsigned NOT NULL default '0',
+ `ticket_text` text,
+ `ticket_lastchange` TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY (`ticket_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
+
+--
+-- Dumping data for table `character_ticket`
+--
+
+LOCK TABLES `character_ticket` WRITE;
+/*!40000 ALTER TABLE `character_ticket` DISABLE KEYS */;
+/*!40000 ALTER TABLE `character_ticket` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `character_tutorial`
+--
+
+DROP TABLE IF EXISTS `character_tutorial`;
+CREATE TABLE `character_tutorial` (
+ `account` bigint(20) unsigned NOT NULL auto_increment COMMENT 'Account Identifier',
+ `realmid` int(11) unsigned NOT NULL default '0' COMMENT 'Realm Identifier',
+ `tut0` int(11) unsigned NOT NULL default '0',
+ `tut1` int(11) unsigned NOT NULL default '0',
+ `tut2` int(11) unsigned NOT NULL default '0',
+ `tut3` int(11) unsigned NOT NULL default '0',
+ `tut4` int(11) unsigned NOT NULL default '0',
+ `tut5` int(11) unsigned NOT NULL default '0',
+ `tut6` int(11) unsigned NOT NULL default '0',
+ `tut7` int(11) unsigned NOT NULL default '0',
+ PRIMARY KEY (`account`,`realmid`),
+ KEY acc_key (`account`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Player System';
+
+--
+-- Dumping data for table `character_tutorial`
+--
+
+LOCK TABLES `character_tutorial` WRITE;
+/*!40000 ALTER TABLE `character_tutorial` DISABLE KEYS */;
+/*!40000 ALTER TABLE `character_tutorial` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `corpse`
+--
+
+DROP TABLE IF EXISTS `corpse`;
+CREATE TABLE `corpse` (
+ `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
+ `player` int(11) unsigned NOT NULL default '0' COMMENT 'Character Global Unique Identifier',
+ `position_x` float NOT NULL default '0',
+ `position_y` float NOT NULL default '0',
+ `position_z` float NOT NULL default '0',
+ `orientation` float NOT NULL default '0',
+ `zone` int(11) unsigned NOT NULL default '38' COMMENT 'Zone Identifier',
+ `map` int(11) unsigned NOT NULL default '0' COMMENT 'Map Identifier',
+ `data` longtext,
+ `time` bigint(20) unsigned NOT NULL default '0',
+ `corpse_type` tinyint(3) unsigned NOT NULL default '0',
+ `instance` int(11) unsigned NOT NULL default '0',
+ PRIMARY KEY (`guid`),
+ KEY `idx_type` (`corpse_type`),
+ KEY `instance` (`instance`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Death System';
+
+--
+-- Dumping data for table `corpse`
+--
+
+LOCK TABLES `corpse` WRITE;
+/*!40000 ALTER TABLE `corpse` DISABLE KEYS */;
+/*!40000 ALTER TABLE `corpse` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `groups`
+--
+
+DROP TABLE IF EXISTS `groups`;
+CREATE TABLE `groups` (
+ `leaderGuid` int(11) unsigned NOT NULL,
+ `mainTank` int(11) unsigned NOT NULL,
+ `mainAssistant` int(11) unsigned NOT NULL,
+ `lootMethod` tinyint(4) unsigned NOT NULL,
+ `looterGuid` int(11) unsigned NOT NULL,
+ `lootThreshold` tinyint(4) unsigned NOT NULL,
+ `icon1` int(11) unsigned NOT NULL,
+ `icon2` int(11) unsigned NOT NULL,
+ `icon3` int(11) unsigned NOT NULL,
+ `icon4` int(11) unsigned NOT NULL,
+ `icon5` int(11) unsigned NOT NULL,
+ `icon6` int(11) unsigned NOT NULL,
+ `icon7` int(11) unsigned NOT NULL,
+ `icon8` int(11) unsigned NOT NULL,
+ `isRaid` tinyint(1) unsigned NOT NULL,
+ `difficulty` tinyint(3) unsigned NOT NULL default '0',
+ PRIMARY KEY (`leaderGuid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Groups';
+
+--
+-- Dumping data for table `groups`
+--
+
+LOCK TABLES `groups` WRITE;
+/*!40000 ALTER TABLE `groups` DISABLE KEYS */;
+/*!40000 ALTER TABLE `groups` ENABLE KEYS */;
+UNLOCK TABLES;
+
+-- ----------------------------
+-- Table structure for group_instance
+-- ----------------------------
+DROP TABLE IF EXISTS `group_instance`;
+CREATE TABLE `group_instance` (
+ `leaderGuid` int(11) unsigned NOT NULL default '0',
+ `instance` int(11) unsigned NOT NULL default '0',
+ `permanent` tinyint(1) unsigned NOT NULL default '0',
+ PRIMARY KEY (`leaderGuid`,`instance`),
+ KEY `instance` (`instance`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `group_instance`
+--
+
+LOCK TABLES `group_instance` WRITE;
+/*!40000 ALTER TABLE `group_instance` DISABLE KEYS */;
+/*!40000 ALTER TABLE `group_instance` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `group_member`
+--
+
+DROP TABLE IF EXISTS `group_member`;
+CREATE TABLE `group_member` (
+ `leaderGuid` int(11) unsigned NOT NULL,
+ `memberGuid` int(11) unsigned NOT NULL,
+ `assistant` tinyint(1) unsigned NOT NULL,
+ `subgroup` smallint(6) unsigned NOT NULL,
+ PRIMARY KEY (`leaderGuid`,`memberGuid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Groups';
+
+--
+-- Dumping data for table `group_member`
+--
+
+LOCK TABLES `group_member` WRITE;
+/*!40000 ALTER TABLE `group_member` DISABLE KEYS */;
+/*!40000 ALTER TABLE `group_member` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `guild`
+--
+
+DROP TABLE IF EXISTS `guild`;
+CREATE TABLE `guild` (
+ `guildid` int(6) unsigned NOT NULL default '0',
+ `name` varchar(255) NOT NULL default '',
+ `leaderguid` int(6) unsigned NOT NULL default '0',
+ `EmblemStyle` int(5) NOT NULL default '0',
+ `EmblemColor` int(5) NOT NULL default '0',
+ `BorderStyle` int(5) NOT NULL default '0',
+ `BorderColor` int(5) NOT NULL default '0',
+ `BackgroundColor` int(5) NOT NULL default '0',
+ `info` text NOT NULL,
+ `motd` varchar(255) NOT NULL default '',
+ `createdate` datetime default NULL,
+ `BankMoney` bigint(20) NOT NULL default '0',
+ PRIMARY KEY (`guildid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Guild System';
+
+--
+-- Dumping data for table `guild`
+--
+
+LOCK TABLES `guild` WRITE;
+/*!40000 ALTER TABLE `guild` DISABLE KEYS */;
+/*!40000 ALTER TABLE `guild` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `guild_bank_eventlog`
+--
+
+DROP TABLE IF EXISTS `guild_bank_eventlog`;
+CREATE TABLE `guild_bank_eventlog` (
+ `guildid` int(11) unsigned NOT NULL default '0',
+ `LogGuid` int(11) unsigned NOT NULL default '0',
+ `LogEntry` tinyint(1) unsigned NOT NULL default '0',
+ `TabId` tinyint(1) unsigned NOT NULL default '0',
+ `PlayerGuid` int(11) unsigned NOT NULL default '0',
+ `ItemOrMoney` int(11) unsigned NOT NULL default '0',
+ `ItemStackCount` tinyint(3) unsigned NOT NULL default '0',
+ `DestTabId` tinyint(1) unsigned NOT NULL default '0',
+ `TimeStamp` bigint(20) unsigned NOT NULL default '0',
+ PRIMARY KEY (`guildid`,`LogGuid`),
+ KEY `guildid_key` (`guildid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `guild_bank_eventlog`
+--
+
+LOCK TABLES `guild_bank_eventlog` WRITE;
+/*!40000 ALTER TABLE `guild_bank_eventlog` DISABLE KEYS */;
+/*!40000 ALTER TABLE `guild_bank_eventlog` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `guild_bank_item`
+--
+
+DROP TABLE IF EXISTS `guild_bank_item`;
+CREATE TABLE `guild_bank_item` (
+ `guildid` int(11) unsigned NOT NULL default '0',
+ `TabId` tinyint(1) unsigned NOT NULL default '0',
+ `SlotId` tinyint(3) unsigned NOT NULL default '0',
+ `item_guid` int(11) unsigned NOT NULL default '0',
+ `item_entry` int(11) unsigned NOT NULL default '0',
+ PRIMARY KEY (`guildid`,`tabid`,`slotid`),
+ KEY `guildid_key` (`guildid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `guild_bank_item`
+--
+
+LOCK TABLES `guild_bank_item` WRITE;
+/*!40000 ALTER TABLE `guild_bank_item` DISABLE KEYS */;
+/*!40000 ALTER TABLE `guild_bank_item` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `guild_bank_right`
+--
+
+DROP TABLE IF EXISTS `guild_bank_right`;
+CREATE TABLE `guild_bank_right` (
+ `guildid` int(11) unsigned NOT NULL default '0',
+ `TabId` tinyint(1) unsigned NOT NULL default '0',
+ `rid` int(11) unsigned NOT NULL default '0',
+ `gbright` tinyint(3) unsigned NOT NULL default '0',
+ `SlotPerDay` int(11) unsigned NOT NULL default '0',
+ PRIMARY KEY (`guildid`,`TabId`,`rid`),
+ KEY `guildid_key` (`guildid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `guild_bank_right`
+--
+
+LOCK TABLES `guild_bank_right` WRITE;
+/*!40000 ALTER TABLE `guild_bank_right` DISABLE KEYS */;
+/*!40000 ALTER TABLE `guild_bank_right` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `guild_bank_tab`
+--
+
+DROP TABLE IF EXISTS `guild_bank_tab`;
+CREATE TABLE `guild_bank_tab` (
+ `guildid` int(11) unsigned NOT NULL default '0',
+ `TabId` tinyint(1) unsigned NOT NULL default '0',
+ `TabName` varchar(100) NOT NULL default '',
+ `TabIcon` varchar(100) NOT NULL default '',
+ `TabText` varchar(500) NOT NULL default '',
+ PRIMARY KEY (`guildid`,`TabId`),
+ KEY `guildid_key` (`guildid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `guild_bank_tab`
+--
+
+LOCK TABLES `guild_bank_tab` WRITE;
+/*!40000 ALTER TABLE `guild_bank_tab` DISABLE KEYS */;
+/*!40000 ALTER TABLE `guild_bank_tab` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `guild_eventlog`
+--
+
+DROP TABLE IF EXISTS `guild_eventlog`;
+CREATE TABLE `guild_eventlog` (
+ `guildid` int(11) NOT NULL COMMENT 'Guild Identificator',
+ `LogGuid` int(11) NOT NULL COMMENT 'Log entry identificator',
+ `EventType` tinyint(1) NOT NULL COMMENT 'Event type',
+ `PlayerGuid1` int(11) NOT NULL COMMENT 'Player 1',
+ `PlayerGuid2` int(11) NOT NULL COMMENT 'Player 2',
+ `NewRank` tinyint(2) NOT NULL COMMENT 'New rank(in case promotion/demotion)',
+ `TimeStamp` bigint(20) NOT NULL COMMENT 'Event UNIX time'
+) ENGINE = InnoDB DEFAULT CHARSET = latin1 COMMENT 'Guild Eventlog';
+
+--
+-- Dumping data for table `guild_eventlog`
+--
+
+LOCK TABLES `guild_eventlog` WRITE;
+/*!40000 ALTER TABLE `guild_eventlog` DISABLE KEYS */;
+/*!40000 ALTER TABLE `guild_eventlog` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `guild_member`
+--
+
+DROP TABLE IF EXISTS `guild_member`;
+CREATE TABLE `guild_member` (
+ `guildid` int(6) unsigned NOT NULL default '0',
+ `guid` int(11) unsigned NOT NULL default '0',
+ `rank` tinyint(2) unsigned NOT NULL default '0',
+ `pnote` varchar(255) NOT NULL default '',
+ `offnote` varchar(255) NOT NULL default '',
+ `BankResetTimeMoney` int(11) unsigned NOT NULL default '0',
+ `BankRemMoney` int(11) unsigned NOT NULL default '0',
+ `BankResetTimeTab0` int(11) unsigned NOT NULL default '0',
+ `BankRemSlotsTab0` int(11) unsigned NOT NULL default '0',
+ `BankResetTimeTab1` int(11) unsigned NOT NULL default '0',
+ `BankRemSlotsTab1` int(11) unsigned NOT NULL default '0',
+ `BankResetTimeTab2` int(11) unsigned NOT NULL default '0',
+ `BankRemSlotsTab2` int(11) unsigned NOT NULL default '0',
+ `BankResetTimeTab3` int(11) unsigned NOT NULL default '0',
+ `BankRemSlotsTab3` int(11) unsigned NOT NULL default '0',
+ `BankResetTimeTab4` int(11) unsigned NOT NULL default '0',
+ `BankRemSlotsTab4` int(11) unsigned NOT NULL default '0',
+ `BankResetTimeTab5` int(11) unsigned NOT NULL default '0',
+ `BankRemSlotsTab5` int(11) unsigned NOT NULL default '0',
+ KEY `guildid_key` (`guildid`),
+ KEY `guildid_rank_key` (`guildid`,`rank`),
+ KEY `guid_key` (`guid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Guild System';
+
+--
+-- Dumping data for table `guild_member`
+--
+
+LOCK TABLES `guild_member` WRITE;
+/*!40000 ALTER TABLE `guild_member` DISABLE KEYS */;
+/*!40000 ALTER TABLE `guild_member` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `guild_rank`
+--
+
+DROP TABLE IF EXISTS `guild_rank`;
+CREATE TABLE `guild_rank` (
+ `guildid` int(6) unsigned NOT NULL default '0',
+ `rid` int(11) unsigned NOT NULL,
+ `rname` varchar(255) NOT NULL default '',
+ `rights` int(3) unsigned NOT NULL default '0',
+ `BankMoneyPerDay` int(11) unsigned NOT NULL default '0',
+ PRIMARY KEY (`guildid`,`rid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Guild System';
+
+--
+-- Dumping data for table `guild_rank`
+--
+
+LOCK TABLES `guild_rank` WRITE;
+/*!40000 ALTER TABLE `guild_rank` DISABLE KEYS */;
+/*!40000 ALTER TABLE `guild_rank` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `instance`
+--
+
+DROP TABLE IF EXISTS `instance`;
+CREATE TABLE `instance` (
+ `id` int(11) unsigned NOT NULL default '0',
+ `map` int(11) unsigned NOT NULL default '0',
+ `resettime` bigint(40) NOT NULL default '0',
+ `difficulty` tinyint(1) unsigned NOT NULL default '0',
+ `data` longtext,
+ PRIMARY KEY (`id`),
+ KEY `map` (`map`),
+ KEY `resettime` (`resettime`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `instance`
+--
+
+LOCK TABLES `instance` WRITE;
+/*!40000 ALTER TABLE `instance` DISABLE KEYS */;
+/*!40000 ALTER TABLE `instance` ENABLE KEYS */;
+UNLOCK TABLES;
+
+-- ----------------------------
+-- Table structure for instance_reset
+-- ----------------------------
+DROP TABLE IF EXISTS `instance_reset`;
+CREATE TABLE `instance_reset` (
+ `mapid` int(11) unsigned NOT NULL default '0',
+ `resettime` bigint(40) NOT NULL default '0',
+ PRIMARY KEY (`mapid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `instance_reset`
+--
+
+LOCK TABLES `instance_reset` WRITE;
+/*!40000 ALTER TABLE `instance_reset` DISABLE KEYS */;
+/*!40000 ALTER TABLE `instance_reset` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `item_instance`
+--
+
+DROP TABLE IF EXISTS `item_instance`;
+CREATE TABLE `item_instance` (
+ `guid` int(11) unsigned NOT NULL default '0',
+ `owner_guid` int(11) unsigned NOT NULL default '0',
+ `data` longtext,
+ PRIMARY KEY (`guid`),
+ KEY `idx_owner_guid` (`owner_guid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Item System';
+
+--
+-- Dumping data for table `item_instance`
+--
+
+LOCK TABLES `item_instance` WRITE;
+/*!40000 ALTER TABLE `item_instance` DISABLE KEYS */;
+/*!40000 ALTER TABLE `item_instance` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `item_text`
+--
+
+DROP TABLE IF EXISTS `item_text`;
+CREATE TABLE `item_text` (
+ `id` int(11) unsigned NOT NULL default '0',
+ `text` longtext,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Item System';
+
+--
+-- Dumping data for table `item_text`
+--
+
+LOCK TABLES `item_text` WRITE;
+/*!40000 ALTER TABLE `item_text` DISABLE KEYS */;
+/*!40000 ALTER TABLE `item_text` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `mail`
+--
+
+DROP TABLE IF EXISTS `mail`;
+CREATE TABLE `mail` (
+ `id` int(11) unsigned NOT NULL default '0' COMMENT 'Identifier',
+ `messageType` tinyint(3) unsigned NOT NULL default '0',
+ `stationery` tinyint(3) NOT NULL default '41',
+ `mailTemplateId` mediumint(8) unsigned NOT NULL default '0',
+ `sender` int(11) unsigned NOT NULL default '0' COMMENT 'Character Global Unique Identifier',
+ `receiver` int(11) unsigned NOT NULL default '0' COMMENT 'Character Global Unique Identifier',
+ `subject` longtext,
+ `itemTextId` int(11) unsigned NOT NULL default '0',
+ `has_items` tinyint(3) unsigned NOT NULL default '0',
+ `expire_time` bigint(40) NOT NULL default '0',
+ `deliver_time` bigint(40) NOT NULL default '0',
+ `money` int(11) unsigned NOT NULL default '0',
+ `cod` int(11) unsigned NOT NULL default '0',
+ `checked` tinyint(3) unsigned NOT NULL default '0',
+ PRIMARY KEY (`id`),
+ KEY `idx_receiver` (`receiver`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Mail System';
+
+--
+-- Dumping data for table `mail`
+--
+
+LOCK TABLES `mail` WRITE;
+/*!40000 ALTER TABLE `mail` DISABLE KEYS */;
+/*!40000 ALTER TABLE `mail` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `mail_items`
+--
+
+DROP TABLE IF EXISTS `mail_items`;
+CREATE TABLE `mail_items` (
+ `mail_id` int(11) NOT NULL default '0',
+ `item_guid` int(11) NOT NULL default '0',
+ `item_template` int(11) NOT NULL default '0',
+ `receiver` int(11) unsigned NOT NULL default '0' COMMENT 'Character Global Unique Identifier',
+ PRIMARY KEY (`mail_id`,`item_guid`),
+ KEY `idx_receiver` (`receiver`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
+
+--
+-- Dumping data for table `mail_items`
+--
+
+LOCK TABLES `mail_items` WRITE;
+/*!40000 ALTER TABLE `mail_items` DISABLE KEYS */;
+/*!40000 ALTER TABLE `mail_items` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `pet_aura`
+--
+
+DROP TABLE IF EXISTS `pet_aura`;
+CREATE TABLE `pet_aura` (
+ `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
+ `caster_guid` bigint(20) unsigned NOT NULL default '0' COMMENT 'Full Global Unique Identifier',
+ `spell` int(11) unsigned NOT NULL default '0',
+ `effect_index` int(11) unsigned NOT NULL default '0',
+ `amount` int(11) NOT NULL default '0',
+ `maxduration` int(11) NOT NULL default '0',
+ `remaintime` int(11) NOT NULL default '0',
+ `remaincharges` int(11) NOT NULL default '0',
+ PRIMARY KEY (`guid`,`spell`,`effect_index`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Pet System';
+
+--
+-- Dumping data for table `pet_aura`
+--
+
+LOCK TABLES `pet_aura` WRITE;
+/*!40000 ALTER TABLE `pet_aura` DISABLE KEYS */;
+/*!40000 ALTER TABLE `pet_aura` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `pet_spell`
+--
+
+DROP TABLE IF EXISTS `pet_spell`;
+CREATE TABLE `pet_spell` (
+ `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier',
+ `spell` int(11) unsigned NOT NULL default '0' COMMENT 'Spell Identifier',
+ `slot` int(11) unsigned NOT NULL default '0',
+ `active` int(11) unsigned NOT NULL default '0',
+ PRIMARY KEY (`guid`,`spell`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Pet System';
+
+--
+-- Dumping data for table `pet_spell`
+--
+
+LOCK TABLES `pet_spell` WRITE;
+/*!40000 ALTER TABLE `pet_spell` DISABLE KEYS */;
+/*!40000 ALTER TABLE `pet_spell` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `pet_spell_cooldown`
+--
+
+DROP TABLE IF EXISTS `pet_spell_cooldown`;
+CREATE TABLE `pet_spell_cooldown` (
+ `guid` int(11) unsigned NOT NULL default '0' COMMENT 'Global Unique Identifier, Low part',
+ `spell` int(11) unsigned NOT NULL default '0' COMMENT 'Spell Identifier',
+ `time` bigint(20) unsigned NOT NULL default '0',
+ PRIMARY KEY (`guid`,`spell`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Dumping data for table `pet_spell_cooldown`
+--
+
+LOCK TABLES `pet_spell_cooldown` WRITE;
+/*!40000 ALTER TABLE `pet_spell_cooldown` DISABLE KEYS */;
+/*!40000 ALTER TABLE `pet_spell_cooldown` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `petition`
+--
+
+DROP TABLE IF EXISTS `petition`;
+CREATE TABLE `petition` (
+ `ownerguid` int(10) unsigned NOT NULL,
+ `petitionguid` int(10) unsigned default '0',
+ `name` varchar(255) NOT NULL default '',
+ `type` int(10) unsigned NOT NULL default '0',
+ PRIMARY KEY (`ownerguid`,`type`),
+ UNIQUE KEY `index_ownerguid_petitionguid` (`ownerguid`,`petitionguid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Guild System';
+
+--
+-- Dumping data for table `petition`
+--
+
+LOCK TABLES `petition` WRITE;
+/*!40000 ALTER TABLE `petition` DISABLE KEYS */;
+/*!40000 ALTER TABLE `petition` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `petition_sign`
+--
+
+DROP TABLE IF EXISTS `petition_sign`;
+CREATE TABLE `petition_sign` (
+ `ownerguid` int(10) unsigned NOT NULL,
+ `petitionguid` int(11) unsigned NOT NULL default '0',
+ `playerguid` int(11) unsigned NOT NULL default '0',
+ `player_account` int(11) unsigned NOT NULL default '0',
+ `type` int(10) unsigned NOT NULL default '0',
+ PRIMARY KEY (`petitionguid`,`playerguid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='Guild System';
+--
+-- Dumping data for table `petition_sign`
+--
+
+LOCK TABLES `petition_sign` WRITE;
+/*!40000 ALTER TABLE `petition_sign` DISABLE KEYS */;
+/*!40000 ALTER TABLE `petition_sign` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `saved_variables`
+--
+DROP TABLE IF EXISTS `saved_variables`;
+CREATE TABLE `saved_variables` (
+ `NextArenaPointDistributionTime` timestamp NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Variable Saves';
+
+--
+-- Dumping data for table `saved_variables`
+--
+
+LOCK TABLES `saved_variables` WRITE;
+/*!40000 ALTER TABLE `saved_variables` DISABLE KEYS */;
+/*!40000 ALTER TABLE `saved_variables` ENABLE KEYS */;
+UNLOCK TABLES;
+/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+
+-- Dump completed on 2008-01-10 11:37:06
diff --git a/sql/mangos.sql b/sql/mangos.sql
index 14e084afd5b..7692f776c65 100644
--- a/sql/mangos.sql
+++ b/sql/mangos.sql
@@ -210,7 +210,8 @@ INSERT INTO `command` VALUES
('event stop',2,'Syntax: .event stop #event_id\r\nStop event #event_id. Set start time for event to time in past that make current moment is event stop time (change not saved in DB).'),
('explorecheat',3,'Syntax: .explorecheat #flag\r\n\r\nReveal or hide all maps for the selected player. If no player is selected, hide or reveal maps to you.\r\n\r\nUse a #flag of value 1 to reveal, use a #flag value of 0 to hide all maps.'),
('flusharenapoints',3,'Syntax: .flusharenapoints\r\n\r\nUse it to distribute arena points based on arena team ratings, and start a new week.'),
-('gm',1,'Syntax: .gm on/off\r\n\r\nEnable or Disable GM MODE'),
+('gm',1,'Syntax: .gm [on/off]\r\n\r\nEnable or Disable in game GM MODE or show current state of on/off not provided.'),
+('gm chat',1,'Syntax: .gm chat [on/off]\r\n\r\nEnable or disable chat GM MODE (show gm badge in messages) or show current state of on/off not provided.'),
('gm fly',3,'Syntax: .gm fly on/off\r\nEnable/disable gm fly mode.'),
('gm list',0,'Syntax: .gm list\r\n\r\nDisplay a list of available Game Masters.'),
('gm visible',1,'Syntax: .gm visible on/off\r\n\r\nOutput current visibility state or make GM visible(on) and invisible(off) for other players.'),
@@ -352,7 +353,7 @@ INSERT INTO `command` VALUES
('save',0,'Syntax: .save\r\n\r\nSaves your character.'),
('saveall',1,'Syntax: .saveall\r\n\r\nSave all characters in game.'),
('security',3,'Syntax: .security $name #level\r\n\r\nSet the security level of player $name to a level of #level.\r\n\r\n#level may range from 0 to 5.'),
-('sendmail',1,'Syntax: .sendmail #playername #subject #text\r\n\r\nSend a mail to a player. Note: subject may not contain spaces.'),
+('sendmail',1,'Syntax: .sendmail #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.'),
('server info',0,'Syntax: .server info\r\n\r\nDisplay server version and the number of connected players.'),
('server idleshutdown',3,'Syntax: .server idleshutdown #delay|cancel\r\n\r\nShut the server down after #delay seconds if no active connections are present (no players) or cancel the restart/shutdown if cancel value is used.'),
('server idlerestart',3,'Syntax: .server idlerestart #delay|cancel\r\n\r\nRestart the server after #delay seconds if no active connections are present (no players) or cancel the restart/shutdown if cancel value is used.'),
@@ -2137,6 +2138,8 @@ INSERT INTO `mangos_string` VALUES
(49,'You must be at least level %u to enter.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(50,'You must be at least level %u and have item %s to enter.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(51,'Hello! Ready for some training?',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(52,'Invaid item count (%u) for item %u',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(53,'Mail can\'t have more %u item stacks',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(100,'Global notify: ',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(101,'Map: %u (%s) Zone: %u (%s) Area: %u (%s)\nX: %f Y: %f Z: %f Orientation: %f\ngrid[%u,%u]cell[%u,%u] InstanceID: %u\n ZoneX: %f ZoneY: %f\nGroundZ: %f FloorZ: %f Have height data (Map: %u VMap: %u)',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(102,'%s is already being teleported.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
@@ -2339,6 +2342,10 @@ INSERT INTO `mangos_string` VALUES
(329,' %s (GUID %u)',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(330,'No players found!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(331,'Extended item cost %u not exist',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(332,'GM mode is ON',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(333,'GM mode is OFF',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(334,'GM Chat Badge is ON',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(335,'GM Chat Badge is OFF',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(400,'|cffff0000[System Message]:|rScripts reloaded',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(401,'You change security level of %s to %i.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(402,'%s changed your security level to %i.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
@@ -2578,22 +2585,37 @@ INSERT INTO `mangos_string` VALUES
(710,'Away from Keyboard',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(711,'Your group is too large for this battleground. Please regroup to join.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
(712,'Your group is too large for this arena. Please regroup to join.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
-(713,'Your group has members not in your arena team. Please regroup to join.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
-(714,'Your group does not have enough players to join this match.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
-(715,'The Gold Team wins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
-(716,'The Green Team wins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
-(717, '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),
-(718, 'Your group has an offline member. Please remove him before joining.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
-(719, '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),
-(720, 'Your group has players from different battleground brakets. You can\'t join as group.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
-(721, '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),
-(722, 'Someone in your party is Deserter. You can\'t join as group.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
-(723, 'Someone in your party is already in three battleground queues. You cannot join as group.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
-(724, 'You cannot teleport to a battleground or arena map.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
-(725, 'You cannot summon players to a battleground or arena map.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
-(726, 'You must be in GM mode to teleport to a player in a battleground.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
-(727, 'You cannot teleport to a battleground from another battleground. Please leave the current battleground first.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
-(728, 'Arena testing turned %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+(713,'You must be level %u to join an arena team!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(714,'%s is not high enough level to join your team',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(715,'You don\'t meet Battleground level requirements',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(716,'Your arena team is full, %s cannot join it.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(730,'Your group has members not in your arena team. Please regroup to join.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(731,'Your group does not have enough players to join this match.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(732,'The Gold Team wins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(733,'The Green Team wins!',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(734, '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),
+(735, 'Your group has an offline member. Please remove him before joining.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(736, '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),
+(737, 'Your group has players from different battleground brakets. You can\'t join as group.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(738, '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),
+(739, 'Someone in your party is Deserter. You can\'t join as group.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(740, 'Someone in your party is already in three battleground queues. You cannot join as group.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(741, 'You cannot teleport to a battleground or arena map.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(742, 'You cannot summon players to a battleground or arena map.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(743, 'You must be in GM mode to teleport to a player in a battleground.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(744, 'You cannot teleport to a battleground from another battleground. Please leave the current battleground first.',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(745, 'Arena testing turned %s',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(800,'Invalid name',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(801,'You do not have enough gold',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(802,'You do not have enough free slots',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(803,'Your partner does not have enough free bag slots',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(804,'You do not have permission to perform that function',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(805,'Unknown language',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(806,'You don\'t know that language',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(807,'Please provide character name',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(808,'Player %s not found or offline',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL),
+(809,'Account for character %s not found',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
+
/*!40000 ALTER TABLE `mangos_string` ENABLE KEYS */;
UNLOCK TABLES;
diff --git a/sql/updates/10_instantiated_battlegrounds.sql b/sql/updates/10_instantiated_battlegrounds.sql
index e32bc3f2824..c3234c3099e 100644
--- a/sql/updates/10_instantiated_battlegrounds.sql
+++ b/sql/updates/10_instantiated_battlegrounds.sql
@@ -15,24 +15,25 @@ INSERT INTO `command` (`name`, `security`, `help`) VALUES
('debug arena',3,'Syntax: .debug arena\r\n\r\n Toggles arena 1v1 or normal mode.');
-DELETE FROM mangos_string WHERE entry BETWEEN 711 AND 728;
+DELETE FROM mangos_string WHERE entry IN (711,712);
+DELETE FROM mangos_string WHERE entry BETWEEN 730 AND 745;
INSERT INTO mangos_string (entry, content_default) VALUES
(711,'Your group is too large for this battleground. Please regroup to join.'),
(712,'Your group is too large for this arena. Please regroup to join.'),
- (713,'Your group has members not in your arena team. Please regroup to join.'),
- (714,'Your group does not have enough players to join this match.'),
- (715,'The Gold Team wins!'),
- (716,'The Green Team wins!'),
- (717, 'There aren\'t enough players in this battleground. It will end soon unless some more players join to balance the fight.'),
- (718, 'Your group has an offline member. Please remove him before joining.'),
- (719, 'Your group has players from the opposing faction. You can\'t join the battleground as a group.'),
- (720, 'Your group has players from different battleground brakets. You can\'t join as group.'),
- (721, 'Someone in your party is already in this battleground queue. (S)he must leave it before joining as group.'),
- (722, 'Someone in your party is Deserter. You can\'t join as group.'),
- (723, 'Someone in your party is already in three battleground queues. You cannot join as group.'),
- (724, 'You cannot teleport to a battleground or arena map.'),
- (725, 'You cannot summon players to a battleground or arena map.'),
- (726, 'You must be in GM mode to teleport to a player in a battleground.'),
- (727, 'You cannot teleport to a battleground from another battleground. Please leave the current battleground first.'),
- (728, 'Arena testing turned %s');
+ (730,'Your group has members not in your arena team. Please regroup to join.'),
+ (731,'Your group does not have enough players to join this match.'),
+ (732,'The Gold Team wins!'),
+ (733,'The Green Team wins!'),
+ (734, 'There aren\'t enough players in this battleground. It will end soon unless some more players join to balance the fight.'),
+ (735, 'Your group has an offline member. Please remove him before joining.'),
+ (736, 'Your group has players from the opposing faction. You can\'t join the battleground as a group.'),
+ (737, 'Your group has players from different battleground brakets. You can\'t join as group.'),
+ (738, 'Someone in your party is already in this battleground queue. (S)he must leave it before joining as group.'),
+ (739, 'Someone in your party is Deserter. You can\'t join as group.'),
+ (740, 'Someone in your party is already in three battleground queues. You cannot join as group.'),
+ (741, 'You cannot teleport to a battleground or arena map.'),
+ (742, 'You cannot summon players to a battleground or arena map.'),
+ (743, 'You must be in GM mode to teleport to a player in a battleground.'),
+ (744, 'You cannot teleport to a battleground from another battleground. Please leave the current battleground first.'),
+ (745, 'Arena testing turned %s');
diff --git a/sql/updates/19_pack.sql b/sql/updates/19_pack.sql
deleted file mode 100644
index 3a43f43a955..00000000000
--- a/sql/updates/19_pack.sql
+++ /dev/null
@@ -1,4 +0,0 @@
-ALTER TABLE `quest_template` ADD COLUMN `Method` tinyint(3) unsigned NOT NULL default '2' AFTER `entry`;
-DELETE FROM mangos_string WHERE entry IN (331);
-INSERT INTO mangos_string VALUES
-(331,'Extended item cost %u not exist',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
diff --git a/src/bindings/scripts/ScriptMgr.cpp b/src/bindings/scripts/ScriptMgr.cpp
index e382b62e2e3..11d293ffe3d 100644
--- a/src/bindings/scripts/ScriptMgr.cpp
+++ b/src/bindings/scripts/ScriptMgr.cpp
@@ -1,2105 +1,2135 @@
-/* Copyright (C) 2006 - 2008 ScriptDev2
- * This program is free software licensed under GPL version 2
- * Please see the included DOCS/LICENSE.TXT for more information */
-
-#include "precompiled.h"
-#include "Config/Config.h"
-#include "ProgressBar.h"
-#include "Database/DBCStores.h"
-#include "Database/DatabaseMysql.h"
-#include "ObjectMgr.h"
-#include "scripts/creature/mob_event_ai.h"
-
-#define _FULLVERSION "TrinityScript"
-
-#ifndef _TSCRIPTCONFVERSION
-# define _TSCRIPTCONFVERSION 2008100201
-#endif //_TSCRIPTCONFVERSION
-
-#ifndef _TRINITY_SCRIPT_CONFIG
-# define _TRINITY_SCRIPT_CONFIG "trinityscript.conf"
-#endif //_TRINITY_SCRIPT_CONFIG
-
-//*** Global data ***
-int nrscripts;
-Script *m_scripts[MAX_SCRIPTS];
-
-// Text Map for Event AI
-HM_NAMESPACE::hash_map EventAI_Text_Map;
-
-// Script Text used as says / yells / text emotes / whispers in scripts.
-struct ScriptText
-{
- uint32 SoundId;
- uint8 Type;
- uint32 Language;
- std::string Text;
-};
-
-// Enums used by ScriptText::Type
-enum ChatType
-{
- CHAT_TYPE_SAY = 0,
- CHAT_TYPE_YELL = 1,
- CHAT_TYPE_TEXT_EMOTE = 2,
- CHAT_TYPE_BOSS_EMOTE = 3,
- CHAT_TYPE_WHISPER = 4,
- CHAT_TYPE_BOSS_WHISPER = 5,
-};
-
-HM_NAMESPACE::hash_map Script_TextMap;
-
-// Localized Text structure for storing locales (for EAI and SD2 scripts).
-struct Localized_Text
-{
- std::string locale_1;
- std::string locale_2;
- std::string locale_3;
- std::string locale_4;
- std::string locale_5;
- std::string locale_6;
- std::string locale_7;
- std::string locale_8;
-};
-HM_NAMESPACE::hash_map EventAI_LocalizedTextMap;
-HM_NAMESPACE::hash_map Script_LocalizedTextMap;
-
-//*** End Global data ***
-
-//*** EventAI data ***
-//Event AI structure. Used exclusivly by mob_event_ai.cpp (60 bytes each)
-std::list EventAI_Event_List;
-
-//Event AI summon structure. Used exclusivly by mob_event_ai.cpp.
-HM_NAMESPACE::hash_map EventAI_Summon_Map;
-
-//Event AI error prevention structure. Used at runtime to prevent error log spam of same creature id.
-//HM_NAMESPACE::hash_map EventAI_CreatureErrorPreventionList;
-
-uint32 EAI_ErrorLevel;
-
-//*** End EventAI data ***
-
-DatabaseMysql TScriptDB;
-Config TScriptConfig;
-uint32 Locale;
-
-void FillSpellSummary();
-
-// -- Scripts to be added --
-
-// -- Areatrigger --
-extern void AddSC_areatrigger_scripts();
-
-// -- Boss --
-extern void AddSC_boss_emeriss();
-extern void AddSC_boss_taerar();
-extern void AddSC_boss_ysondre();
-
-// -- Creature --
-extern void AddSC_mob_event();
-extern void AddSC_generic_creature();
-
-// -- Custom --
-extern void AddSC_custom_example();
-extern void AddSC_custom_gossip_codebox();
-extern void AddSC_test();
-
-// -- GO --
-extern void AddSC_go_scripts();
-
-// -- Guard --
-extern void AddSC_guards();
-
-// -- Honor --
-
-// -- Item --
-extern void AddSC_item_scripts();
-extern void AddSC_item_test();
-
-// -- NPC --
-extern void AddSC_npc_professions();
-extern void AddSC_npcs_special();
-
-// -- Servers --
-
-//--------------------
-//------ ZONE --------
-
-//Alterac Mountains
-extern void AddSC_alterac_mountains();
-
-//Arathi Highlands
-//Ashenvale Forest
-//Aunchindoun
-//--Auchenai Crypts
-extern void AddSC_boss_exarch_maladaar();
-//--Mana Tombs
-extern void AddSC_boss_nexusprince_shaffar();
-extern void AddSC_boss_pandemonius();
-
-//--Sekketh Halls
-extern void AddSC_boss_darkweaver_syth();
-extern void AddSC_boss_talon_king_ikiss();
-extern void AddSC_instance_sethekk_halls();
-
-//--Shadow Labyrinth
-extern void AddSC_boss_ambassador_hellmaw();
-extern void AddSC_boss_blackheart_the_inciter();
-extern void AddSC_boss_grandmaster_vorpil();
-extern void AddSC_boss_murmur();
-extern void AddSC_instance_shadow_labyrinth();
-
-//Azshara
-extern void AddSC_boss_azuregos();
-extern void AddSC_azshara();
-
-//Azuremyst Isle
-extern void AddSC_azuremyst_isle();
-
-//Badlands
-//Barrens
-extern void AddSC_the_barrens();
-
-//Black Temple
-extern void AddSC_black_temple();
-extern void AddSC_boss_illidan();
-extern void AddSC_boss_shade_of_akama();
-extern void AddSC_boss_supremus();
-extern void AddSC_boss_gurtogg_bloodboil();
-extern void AddSC_boss_mother_shahraz();
-extern void AddSC_boss_reliquary_of_souls();
-extern void AddSC_boss_teron_gorefiend();
-extern void AddSC_boss_najentus();
-extern void AddSC_boss_illidari_council();
-extern void AddSC_instance_black_temple();
-
-//Blackfathom Depths
-//Blackrock Depths
-extern void AddSC_blackrock_depths();
-extern void AddSC_boss_ambassador_flamelash();
-extern void AddSC_boss_angerrel();
-extern void AddSC_boss_anubshiah();
-extern void AddSC_boss_doomrel();
-extern void AddSC_boss_doperel();
-extern void AddSC_boss_draganthaurissan();
-extern void AddSC_boss_general_angerforge();
-extern void AddSC_boss_gloomrel();
-extern void AddSC_boss_gorosh_the_dervish();
-extern void AddSC_boss_grizzle();
-extern void AddSC_boss_haterel();
-extern void AddSC_boss_high_interrogator_gerstahn();
-extern void AddSC_boss_magmus();
-extern void AddSC_boss_moira_bronzebeard();
-extern void AddSC_boss_seethrel();
-extern void AddSC_boss_vilerel();
-
-//Blackrock Spire
-extern void AddSC_boss_drakkisath();
-extern void AddSC_boss_halycon();
-extern void AddSC_boss_highlordomokk();
-extern void AddSC_boss_mothersmolderweb();
-extern void AddSC_boss_overlordwyrmthalak();
-extern void AddSC_boss_shadowvosh();
-extern void AddSC_boss_thebeast();
-extern void AddSC_boss_warmastervoone();
-extern void AddSC_boss_quatermasterzigris();
-extern void AddSC_boss_pyroguard_emberseer();
-extern void AddSC_boss_gyth();
-extern void AddSC_boss_rend_blackhand();
-
-//Blackwing lair
-extern void AddSC_boss_razorgore();
-extern void AddSC_boss_vael();
-extern void AddSC_boss_broodlord();
-extern void AddSC_boss_firemaw();
-extern void AddSC_boss_ebonroc();
-extern void AddSC_boss_flamegor();
-extern void AddSC_boss_chromaggus();
-extern void AddSC_boss_nefarian();
-extern void AddSC_boss_victor_nefarius();
-
-//Blade's Edge Mountains
-extern void AddSC_blades_edge_mountains();
-
-//Blasted lands
-extern void AddSC_boss_kruul();
-extern void AddSC_blasted_lands();
-
-//Bloodmyst Isle
-extern void AddSC_bloodmyst_isle();
-
-//Burning steppes
-extern void AddSC_burning_steppes();
-
-//Caverns of Time
-//--Battle for Mt. Hyjal
-extern void AddSC_hyjal();
-extern void AddSC_boss_archimonde();
-extern void AddSC_instance_mount_hyjal();
-
-//--Old Hillsbrad
-extern void AddSC_boss_captain_skarloc();
-extern void AddSC_boss_epoch_hunter();
-extern void AddSC_boss_lieutenant_drake();
-extern void AddSC_instance_old_hillsbrad();
-extern void AddSC_old_hillsbrad();
-
-//--The Dark Portal
-extern void AddSC_boss_aeonus();
-extern void AddSC_boss_chrono_lord_deja();
-extern void AddSC_boss_temporus();
-
-//Coilfang Resevoir
-//--Serpent Shrine Cavern
-extern void AddSC_boss_fathomlord_karathress();
-extern void AddSC_boss_hydross_the_unstable();
-extern void AddSC_boss_lady_vashj();
-extern void AddSC_boss_leotheras_the_blind();
-extern void AddSC_boss_morogrim_tidewalker();
-extern void AddSC_instance_serpentshrine_cavern();
-
-//--Slave Pens
-
-//--Steam Vault
-extern void AddSC_boss_hydromancer_thespia();
-extern void AddSC_boss_mekgineer_steamrigger();
-extern void AddSC_boss_warlord_kalithresh();
-extern void AddSC_instance_steam_vault();
-
-//--Underbog
-extern void AddSC_boss_hungarfen();
-
-//Darkshore
-//Darnassus
-//Deadmines
-//Deadwind pass
-//Desolace
-//Dire Maul
-//Dun Morogh
-extern void AddSC_dun_morogh();
-
-//Durotar
-//Duskwood
-//Dustwallow marsh
-extern void AddSC_dustwallow_marsh();
-
-//Eversong Woods
-extern void AddSC_eversong_woods();
-
-//Exodar
-//Eastern Plaguelands
-extern void AddSC_eastern_plaguelands();
-
-//Elwynn Forest
-extern void AddSC_elwynn_forest();
-
-//Felwood
-extern void AddSC_felwood();
-
-//Feralas
-extern void AddSC_feralas();
-
-//Ghostlands
-extern void AddSC_ghostlands();
-
-//Gnomeregan
-//Gruul's Lair
-extern void AddSC_boss_gruul();
-extern void AddSC_boss_high_king_maulgar();
-extern void AddSC_instance_gruuls_lair();
-
-//Hellfire Citadel
-//--Blood Furnace
-extern void AddSC_boss_broggok();
-extern void AddSC_boss_kelidan_the_breaker();
-extern void AddSC_boss_the_maker();
-
-//--Magtheridon's Lair
-extern void AddSC_boss_magtheridon();
-extern void AddSC_instance_magtheridons_lair();
-
-//--Shattered Halls
-extern void AddSC_boss_grand_warlock_nethekurse();
-extern void AddSC_boss_warbringer_omrogg();
-extern void AddSC_instance_shattered_halls();
-
-//--Ramparts
-extern void AddSC_boss_watchkeeper_gargolmar();
-extern void AddSC_boss_omor_the_unscarred();
-
-//Hellfire Peninsula
-extern void AddSC_boss_doomlordkazzak();
-extern void AddSC_hellfire_peninsula();
-
-//Hillsbrad Foothills
-//Hinterlands
-//Ironforge
-extern void AddSC_ironforge();
-
-//Isle of Quel'Danas
-extern void AddSC_isle_of_queldanas();
-
-//Karazhan
-extern void AddSC_boss_attumen();
-extern void AddSC_boss_curator();
-extern void AddSC_boss_maiden_of_virtue();
-extern void AddSC_boss_shade_of_aran();
-extern void AddSC_boss_malchezaar();
-extern void AddSC_boss_terestian_illhoof();
-extern void AddSC_netherspite_infernal();
-extern void AddSC_boss_moroes();
-extern void AddSC_bosses_opera();
-extern void AddSC_instance_karazhan();
-extern void AddSC_karazhan();
-
-//Loch Modan
-extern void AddSC_loch_modan();
-
-//Lower Blackrock Spire
-
-// Magister's Terrace
-extern void AddSC_boss_felblood_kaelthas();
-extern void AddSC_boss_selin_fireheart();
-extern void AddSC_boss_vexallus();
-extern void AddSC_boss_priestess_delrissa();
-extern void AddSC_instance_magisters_terrace();
-
-//Maraudon
-extern void AddSC_boss_celebras_the_cursed();
-extern void AddSC_boss_landslide();
-extern void AddSC_boss_noxxion();
-extern void AddSC_boss_ptheradras();
-
-//Molten core
-extern void AddSC_boss_lucifron();
-extern void AddSC_boss_magmadar();
-extern void AddSC_boss_gehennas();
-extern void AddSC_boss_garr();
-extern void AddSC_boss_baron_geddon();
-extern void AddSC_boss_shazzrah();
-extern void AddSC_boss_golemagg();
-extern void AddSC_boss_sulfuron();
-extern void AddSC_boss_majordomo();
-extern void AddSC_boss_ragnaros();
-extern void AddSC_instance_molten_core();
-extern void AddSC_molten_core();
-
-//Moonglade
-extern void AddSC_moonglade();
-
-//Mulgore
-extern void AddSC_mulgore();
-
-//Nagrand
-extern void AddSC_nagrand();
-
-//Naxxramas
-extern void AddSC_boss_anubrekhan();
-extern void AddSC_boss_maexxna();
-extern void AddSC_boss_patchwerk();
-extern void AddSC_boss_razuvious();
-extern void AddSC_boss_highlord_mograine();
-extern void AddSC_boss_lady_blaumeux();
-extern void AddSC_boss_sir_zeliek();
-extern void AddSC_boss_thane_korthazz();
-extern void AddSC_boss_kelthuzad();
-extern void AddSC_boss_faerlina();
-extern void AddSC_boss_loatheb();
-extern void AddSC_boss_noth();
-extern void AddSC_boss_gluth();
-extern void AddSC_boss_sapphiron();
-
-//Netherstorm
-extern void AddSC_netherstorm();
-
-//Onyxia's Lair
-extern void AddSC_boss_onyxia();
-
-//Orgrimmar
-extern void AddSC_orgrimmar();
-
-//Ragefire Chasm
-//Razorfen Downs
-extern void AddSC_boss_amnennar_the_coldbringer();
-
-//Redridge Mountains
-//Ruins of Ahn'Qiraj
-//Scarlet Monastery
-extern void AddSC_boss_arcanist_doan();
-extern void AddSC_boss_azshir_the_sleepless();
-extern void AddSC_boss_bloodmage_thalnos();
-extern void AddSC_boss_herod();
-extern void AddSC_boss_high_inquisitor_fairbanks();
-extern void AddSC_boss_high_inquisitor_whitemane();
-extern void AddSC_boss_houndmaster_loksey();
-extern void AddSC_boss_interrogator_vishas();
-extern void AddSC_boss_scarlet_commander_mograine();
-extern void AddSC_boss_scorn();
-
-//Scholomance
-extern void AddSC_boss_darkmaster_gandling();
-extern void AddSC_boss_death_knight_darkreaver();
-extern void AddSC_boss_theolenkrastinov();
-extern void AddSC_boss_illuciabarov();
-extern void AddSC_boss_instructormalicia();
-extern void AddSC_boss_jandicebarov();
-extern void AddSC_boss_kormok();
-extern void AddSC_boss_lordalexeibarov();
-extern void AddSC_boss_lorekeeperpolkelt();
-extern void AddSC_boss_rasfrost();
-extern void AddSC_boss_theravenian();
-extern void AddSC_boss_vectus();
-extern void AddSC_instance_scholomance();
-
-//Searing gorge
-extern void AddSC_searing_gorge();
-
-//Shadowfang keep
-extern void AddSC_shadowfang_keep();
-extern void AddSC_instance_shadowfang_keep();
-
-//Shadowmoon Valley
-extern void AddSC_boss_doomwalker();
-extern void AddSC_shadowmoon_valley();
-
-//Shattrath
-extern void AddSC_shattrath_city();
-
-//Silithus
-extern void AddSC_silithus();
-
-//Silvermoon
-extern void AddSC_silvermoon_city();
-
-//Silverpine forest
-extern void AddSC_silverpine_forest();
-
-//Stockade
-//Stonetalon mountains
-extern void AddSC_stonetalon_mountains();
-
-//Stormwind City
-extern void AddSC_stormwind_city();
-
-//Stranglethorn Vale
-extern void AddSC_stranglethorn_vale();
-
-//Stratholme
-extern void AddSC_boss_magistrate_barthilas();
-extern void AddSC_boss_maleki_the_pallid();
-extern void AddSC_boss_nerubenkan();
-extern void AddSC_boss_cannon_master_willey();
-extern void AddSC_boss_baroness_anastari();
-extern void AddSC_boss_ramstein_the_gorger();
-extern void AddSC_boss_timmy_the_cruel();
-extern void AddSC_boss_postmaster_malown();
-extern void AddSC_boss_baron_rivendare();
-extern void AddSC_boss_dathrohan_balnazzar();
-extern void AddSC_boss_order_of_silver_hand();
-extern void AddSC_instance_stratholme();
-extern void AddSC_stratholme();
-
-//Sunken Temple
-//Tanaris
-extern void AddSC_tanaris();
-
-//Teldrassil
-//Tempest Keep
-//--Arcatraz
-extern void AddSC_arcatraz();
-extern void AddSC_boss_harbinger_skyriss();
-extern void AddSC_instance_arcatraz();
-
-//--Botanica
-extern void AddSC_boss_high_botanist_freywinn();
-extern void AddSC_boss_laj();
-extern void AddSC_boss_warp_splinter();
-
-//--The Eye
-extern void AddSC_boss_kaelthas();
-extern void AddSC_boss_void_reaver();
-extern void AddSC_boss_high_astromancer_solarian();
-extern void AddSC_instance_the_eye();
-extern void AddSC_the_eye();
-
-//--The Mechanar
-extern void AddSC_boss_gatewatcher_iron_hand();
-extern void AddSC_boss_nethermancer_sepethrea();
-
-//Temple of ahn'qiraj
-extern void AddSC_boss_cthun();
-extern void AddSC_boss_fankriss();
-extern void AddSC_boss_huhuran();
-extern void AddSC_bug_trio();
-extern void AddSC_boss_sartura();
-extern void AddSC_boss_skeram();
-extern void AddSC_boss_twinemperors();
-extern void AddSC_mob_anubisath_sentinel();
-extern void AddSC_instance_temple_of_ahnqiraj();
-
-//Terokkar Forest
-extern void AddSC_terokkar_forest();
-
-//Thousand Needles
-//Thunder Bluff
-extern void AddSC_thunder_bluff();
-
-//Tirisfal Glades
-extern void AddSC_tirisfal_glades();
-
-//Uldaman
-extern void AddSC_boss_ironaya();
-extern void AddSC_uldaman();
-
-//Undercity
-extern void AddSC_undercity();
-
-//Un'Goro Crater
-//Upper blackrock spire
-//Wailing caverns
-
-//Western plaguelands
-extern void AddSC_western_plaguelands();
-
-//Westfall
-//Wetlands
-//Winterspring
-extern void AddSC_winterspring();
-
-//Zangarmarsh
-extern void AddSC_zangarmarsh();
-
-//Zul'Farrak
-//Zul'Gurub
-extern void AddSC_boss_jeklik();
-extern void AddSC_boss_venoxis();
-extern void AddSC_boss_marli();
-extern void AddSC_boss_mandokir();
-extern void AddSC_boss_gahzranka();
-extern void AddSC_boss_thekal();
-extern void AddSC_boss_arlokk();
-extern void AddSC_boss_jindo();
-extern void AddSC_boss_hakkar();
-extern void AddSC_boss_grilek();
-extern void AddSC_boss_hazzarah();
-extern void AddSC_boss_renataki();
-extern void AddSC_boss_wushoolay();
-extern void AddSC_instance_zulgurub();
-//Zul'Aman
-extern void AddSC_boss_janalai();
-extern void AddSC_boss_nalorakk();
-extern void AddSC_instance_zulaman();
-extern void AddSC_zulaman();
-
-// -------------------
-void LoadDatabase()
-{
- //Get db string from file
- char const* dbstring = NULL;
- if(!TScriptConfig.GetString("TScriptDatabaseInfo", &dbstring))
- error_log("TSCR: Missing Trinity Script Database Info in configuration file");
-
- //Initilize connection to DB
- if(!dbstring || !TScriptDB.Initialize(dbstring))
- error_db_log("TSCR: Unable to connect to Database");
- else
- {
- //***Preform all DB queries here***
- QueryResult *result;
-
- //Get Version information
- result = TScriptDB.PQuery("SELECT `version`"
- "FROM `script_db_version`");
-
- if (result)
- {
- Field *fields = result->Fetch();
- outstring_log(" ");
- outstring_log("TSCR: Database version is: %s", fields[0].GetString());
- outstring_log(" ");
- delete result;
-
- }else error_db_log("TSCR: Missing script_db_version information.");
-
- // Drop existing Event AI Localized Text hash map
- EventAI_LocalizedTextMap.clear();
-
- // Gather EventAI Localized Texts
- result = TScriptDB.PQuery("SELECT `id`,`locale_1`,`locale_2`,`locale_3`,`locale_4`,`locale_5`,`locale_6`,`locale_7`,`locale_8`"
- "FROM `eventai_localized_texts`");
-
- if(result)
- {
- outstring_log("TSCR: Loading EAI Localized Texts....");
- barGoLink bar(result->GetRowCount());
- uint32 count = 0;
-
- do
- {
- Localized_Text temp;
- bar.step();
-
- Field *fields = result->Fetch();
-
- uint32 i = fields[0].GetInt32();
-
- temp.locale_1 = fields[1].GetString();
- temp.locale_2 = fields[2].GetString();
- temp.locale_3 = fields[3].GetString();
- temp.locale_4 = fields[4].GetString();
- temp.locale_5 = fields[5].GetString();
- temp.locale_6 = fields[6].GetString();
- temp.locale_7 = fields[7].GetString();
- temp.locale_8 = fields[8].GetString();
-
- EventAI_LocalizedTextMap[i] = temp;
- ++count;
-
- }while(result->NextRow());
-
- delete result;
-
- outstring_log("");
- outstring_log("TSCR: Loaded %u EventAI Localized Texts", count);
- }else outstring_log("TSCR: WARNING >> Loaded 0 EventAI Localized Texts. Database table `eventai_localized_texts` is empty");
-
- // Drop Existing Script Localized Text Hash Map
- Script_LocalizedTextMap.clear();
-
- // Gather Script Localized Texts
- result = TScriptDB.PQuery("SELECT `id`,`locale_1`,`locale_2`,`locale_3`,`locale_4`,`locale_5`,`locale_6`,`locale_7`,`locale_8`"
- "FROM `script_localized_texts`");
-
- if(result)
- {
- outstring_log("TSCR: Loading Script Localized Texts....");
- barGoLink bar(result->GetRowCount());
- uint32 count = 0;
-
- do
- {
- Localized_Text temp;
- bar.step();
-
- Field *fields = result->Fetch();
-
- uint32 i = fields[0].GetInt32();
-
- temp.locale_1 = fields[1].GetString();
- temp.locale_2 = fields[2].GetString();
- temp.locale_3 = fields[3].GetString();
- temp.locale_4 = fields[4].GetString();
- temp.locale_5 = fields[5].GetString();
- temp.locale_6 = fields[6].GetString();
- temp.locale_7 = fields[7].GetString();
- temp.locale_8 = fields[8].GetString();
-
- Script_LocalizedTextMap[i] = temp;
- ++count;
-
- }while(result->NextRow());
-
- delete result;
-
- outstring_log("");
- outstring_log("TSCR: Loaded %u Script Localized Texts", count);
- }else outstring_log("TSCR: WARNING >> Loaded 0 Script Localized Texts. Database table `script_localized_texts` is empty");
-
- //Drop existing EventAI Text hash map
- EventAI_Text_Map.clear();
-
- //Gather EventAI Text Entries
- result = TScriptDB.PQuery("SELECT `id`,`text` FROM `eventai_texts`");
-
- if (result)
- {
- outstring_log( "TSCR: Loading EventAI_Texts...");
- barGoLink bar(result->GetRowCount());
- uint32 Count = 0;
-
- do
- {
- bar.step();
- Field *fields = result->Fetch();
-
- uint32 i = fields[0].GetInt32();
-
- std::string text = fields[1].GetString();
-
- if (!strlen(text.c_str()))
- error_db_log("TSCR: EventAI text %u is empty", i);
-
- EventAI_Text_Map[i] = text;
- ++Count;
-
- }while (result->NextRow());
-
- delete result;
-
- outstring_log("");
- outstring_log("TSCR: >> Loaded %u EventAI_Texts", Count);
-
- }else outstring_log("TSCR: WARNING >> Loaded 0 EventAI_Texts. DB table `EventAI_Texts` is empty.");
-
- //Gather event data
- result = TScriptDB.PQuery("SELECT `id`,`position_x`,`position_y`,`position_z`,`orientation`,`spawntimesecs`"
- "FROM `eventai_summons`");
-
- //Drop Existing EventSummon Map
- EventAI_Summon_Map.clear();
-
- if (result)
- {
- outstring_log( "TSCR: Loading EventAI_Summons...");
- barGoLink bar(result->GetRowCount());
- uint32 Count = 0;
-
- do
- {
- bar.step();
- Field *fields = result->Fetch();
-
- EventAI_Summon temp;
-
- uint32 i = fields[0].GetUInt32();
- temp.position_x = fields[1].GetFloat();
- temp.position_y = fields[2].GetFloat();
- temp.position_z = fields[3].GetFloat();
- temp.orientation = fields[4].GetFloat();
- temp.SpawnTimeSecs = fields[5].GetUInt32();
-
- //Add to map
- EventAI_Summon_Map[i] = temp;
- ++Count;
-
- }while (result->NextRow());
-
- delete result;
- outstring_log("");
- outstring_log("TSCR: >> Loaded %u EventAI_Summons", Count);
-
- }else outstring_log("TSCR: WARNING >> Loaded 0 EventAI_Summons. DB table `EventAI_Summons` is empty.");
-
- //Gather event data
- result = TScriptDB.PQuery("SELECT `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`"
- "FROM `eventai_scripts`");
-
- //Drop Existing EventAI List
- EventAI_Event_List.clear();
-
- if (result)
- {
- outstring_log( "TSCR: Loading EventAI_Scripts...");
- barGoLink bar(result->GetRowCount());
- uint32 Count = 0;
-
- do
- {
- bar.step();
- Field *fields = result->Fetch();
-
- EventAI_Event temp;
-
- temp.event_id = fields[0].GetUInt32();
- uint32 i = temp.event_id;
- temp.creature_id = fields[1].GetUInt32();
- temp.event_type = fields[2].GetUInt16();
- temp.event_inverse_phase_mask = fields[3].GetUInt32();
- temp.event_chance = fields[4].GetUInt8();
- temp.event_flags = fields[5].GetUInt8();
- temp.event_param1 = fields[6].GetUInt32();
- temp.event_param2 = fields[7].GetUInt32();
- temp.event_param3 = fields[8].GetUInt32();
- temp.event_param4 = fields[9].GetUInt32();
-
- //Report any errors in event
- if (temp.event_type >= EVENT_T_END)
- error_db_log("TSCR: Event %u has incorrect event type. Maybe DB requires updated version of SD2.", i);
-
- //No chance of this event occuring
- if (temp.event_chance == 0)
- error_db_log("TSCR: Event %u has 0 percent chance. Event will never trigger!", i);
- //Chance above 100, force it to be 100
- if (temp.event_chance > 100)
- {
- error_db_log("TSCR: Creature %u are using event %u with more than 100 percent chance. Adjusting to 100 percent.", temp.creature_id, i);
- temp.event_chance = 100;
- }
-
- //Individual event checks
- switch (temp.event_type)
- {
- case EVENT_T_HP:
- case EVENT_T_MANA:
- case EVENT_T_TARGET_HP:
- {
- if (temp.event_param2 > 100)
- error_db_log("TSCR: Creature %u are using percentage event(%u) with param2 (MinPercent) > 100. Event will never trigger! ", temp.creature_id, i);
-
- if (temp.event_param1 <= temp.event_param2)
- error_db_log("TSCR: Creature %u are using percentage event(%u) with param1 <= param2 (MaxPercent <= MinPercent). Event will never trigger! ", temp.creature_id, i);
-
- if (temp.event_flags & EFLAG_REPEATABLE && !temp.event_param3 && !temp.event_param4)
- {
- error_db_log("TSCR: Creature %u has param3 and param4=0 (RepeatMin/RepeatMax) but cannot be repeatable without timers. Removing EFLAG_REPEATABLE for event %u.", temp.creature_id, i);
- temp.event_flags &= ~EFLAG_REPEATABLE;
- }
- }
- break;
-
- case EVENT_T_SPELLHIT:
- {
- if (temp.event_param1)
- {
- SpellEntry const* pSpell = GetSpellStore()->LookupEntry(temp.event_param1);
- if (!pSpell)
- {
- error_db_log("TSCR: Creature %u has non-existant SpellID(%u) defined in event %u.", temp.creature_id, temp.event_param1, i);
- continue;
- }
-
- if (temp.event_param2_s != -1 && temp.event_param2 != pSpell->SchoolMask)
- error_db_log("TSCR: Creature %u has param1(spellId %u) but param2 is not -1 and not equal to spell's school mask. Event %u can never trigger.", temp.creature_id, temp.event_param1, i);
- }
-
- //TODO: fix this system with SPELL_SCHOOL_MASK. Current complicate things, using int32(-1) instead of just 0
- //SPELL_SCHOOL_MASK_NONE = 0 and does not exist, thus it can not ever trigger or be used in SpellHit()
- if (temp.event_param2_s != -1 && temp.event_param2_s > SPELL_SCHOOL_MASK_ALL)
- error_db_log("TSCR: Creature %u is using invalid SpellSchoolMask(%u) defined in event %u.", temp.creature_id, temp.event_param2, i);
-
- if (temp.event_param4 < temp.event_param3)
- error_db_log("TSCR: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
- }
- break;
-
- case EVENT_T_RANGE:
- case EVENT_T_OOC_LOS:
- case EVENT_T_FRIENDLY_HP:
- case EVENT_T_FRIENDLY_IS_CC:
- case EVENT_T_FRIENDLY_MISSING_BUFF:
- {
- if (temp.event_param4 < temp.event_param3)
- error_db_log("TSCR: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
- }
- break;
-
- case EVENT_T_TIMER:
- case EVENT_T_TIMER_OOC:
- {
- if (temp.event_param2 < temp.event_param1)
- error_db_log("TSCR: Creature %u are using timed event(%u) with param2 < param1 (InitialMax < InitialMin). Event will never repeat.", temp.creature_id, i);
-
- if (temp.event_param4 < temp.event_param3)
- error_db_log("TSCR: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
- }
- break;
-
- case EVENT_T_KILL:
- case EVENT_T_TARGET_CASTING:
- {
- if (temp.event_param2 < temp.event_param1)
- error_db_log("TSCR: Creature %u are using event(%u) with param2 < param1 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
- }
- break;
-
- case EVENT_T_AGGRO:
- case EVENT_T_DEATH:
- case EVENT_T_EVADE:
- case EVENT_T_SPAWNED:
- {
- if (temp.event_flags & EFLAG_REPEATABLE)
- {
- error_db_log("TSCR: Creature %u has EFLAG_REPEATABLE set. Event can never be repeatable. Removing flag for event %u.", temp.creature_id, i);
- temp.event_flags &= ~EFLAG_REPEATABLE;
- }
- }
- break;
- };
-
- for (uint32 j = 0; j < MAX_ACTIONS; j++)
- {
- temp.action[j].type = fields[10+(j*4)].GetUInt16();
- temp.action[j].param1 = fields[11+(j*4)].GetUInt32();
- temp.action[j].param2 = fields[12+(j*4)].GetUInt32();
- temp.action[j].param3 = fields[13+(j*4)].GetUInt32();
-
- //Report any errors in actions
- switch (temp.action[j].type)
- {
- case ACTION_T_SAY:
- case ACTION_T_YELL:
- case ACTION_T_TEXTEMOTE:
- if (GetEventAIText(temp.action[j].param1) == DEFAULT_TEXT)
- error_db_log("TSCR: Event %u Action %u refrences missing Localized_Text entry", i, j+1);
- break;
-
- case ACTION_T_SOUND:
- if (!GetSoundEntriesStore()->LookupEntry(temp.action[j].param1))
- error_db_log("TSCR: Event %u Action %u uses non-existant SoundID %u.", i, j+1, temp.action[j].param1);
- break;
-
- case ACTION_T_RANDOM_SAY:
- case ACTION_T_RANDOM_YELL:
- case ACTION_T_RANDOM_TEXTEMOTE:
- if ((temp.action[j].param1 != 0xffffffff && GetEventAIText(temp.action[j].param1) == DEFAULT_TEXT) ||
- (temp.action[j].param2 != 0xffffffff && GetEventAIText(temp.action[j].param2) == DEFAULT_TEXT) ||
- (temp.action[j].param3 != 0xffffffff && GetEventAIText(temp.action[j].param3) == DEFAULT_TEXT))
- error_db_log("TSCR: Event %u Action %u refrences missing Localized_Text entry", i, j+1);
- break;
-
- case ACTION_T_CAST:
- {
- if (!GetSpellStore()->LookupEntry(temp.action[j].param1))
- error_db_log("TSCR: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param1);
-
- if (temp.action[j].param2 >= TARGET_T_END)
- error_db_log("TSCR: Event %u Action %u uses incorrect Target type", i, j+1);
- }
- break;
-
- case ACTION_T_REMOVEAURASFROMSPELL:
- {
- if (!GetSpellStore()->LookupEntry(temp.action[j].param2))
- error_db_log("TSCR: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param2);
-
- if (temp.action[j].param1 >= TARGET_T_END)
- error_db_log("TSCR: Event %u Action %u uses incorrect Target type", i, j+1);
- }
- break;
-
- case ACTION_T_CASTCREATUREGO:
- {
- if (!GetSpellStore()->LookupEntry(temp.action[j].param2))
- error_db_log("TSCR: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param2);
-
- if (temp.action[j].param3 >= TARGET_T_END)
- error_db_log("TSCR: Event %u Action %u uses incorrect Target type", i, j+1);
- }
- break;
-
- //2nd param target
- case ACTION_T_SUMMON_ID:
- {
- if (EventAI_Summon_Map.find(temp.action[j].param3) == EventAI_Summon_Map.end())
- error_db_log("TSCR: Event %u Action %u summons missing EventAI_Summon %u", i, j+1, temp.action[j].param3);
-
- if (temp.action[j].param2 >= TARGET_T_END)
- error_db_log("TSCR: Event %u Action %u uses incorrect Target type", i, j+1);
- }
- break;
-
- case ACTION_T_SUMMON:
- case ACTION_T_THREAT_SINGLE_PCT:
- case ACTION_T_QUEST_EVENT:
- case ACTION_T_SET_UNIT_FLAG:
- case ACTION_T_REMOVE_UNIT_FLAG:
- case ACTION_T_SET_INST_DATA64:
- if (temp.action[j].param2 >= TARGET_T_END)
- error_db_log("TSCR: Event %u Action %u uses incorrect Target type", i, j+1);
- break;
-
- //3rd param target
- case ACTION_T_SET_UNIT_FIELD:
- if (temp.action[j].param3 >= TARGET_T_END)
- error_db_log("TSCR: Event %u Action %u uses incorrect Target type", i, j+1);
- break;
-
- case ACTION_T_SET_PHASE:
- if (temp.action[j].param1 > 31)
- error_db_log("TSCR: Event %u Action %u attempts to set phase > 31. Phase mask cannot be used past phase 31.", i, j+1);
- break;
-
- case ACTION_T_INC_PHASE:
- if (!temp.action[j].param1)
- error_db_log("TSCR: Event %u Action %u is incrementing phase by 0. Was this intended?", i, j+1);
- break;
-
- case ACTION_T_KILLED_MONSTER:
- if (temp.event_type != EVENT_T_DEATH)
- outstring_log("TSCR WARNING: Event %u Action %u calling ACTION_T_KILLED_MONSTER outside of EVENT_T_DEATH", i, j+1);
- break;
-
- case ACTION_T_SET_INST_DATA:
- if (temp.action[j].param2 > 3)
- error_db_log("TSCR: Event %u Action %u attempts to set instance data above encounter state 3. Custom case?", i, j+1);
- break;
-
- default:
- break;
- }
-
- if (temp.action[j].type >= ACTION_T_END)
- error_db_log("TSCR: Event %u Action %u has incorrect action type. Maybe DB requires updated version of SD2.", i, j+1);
- }
-
- //Add to list
- EventAI_Event_List.push_back(temp);
- ++Count;
-
- }while (result->NextRow());
-
- delete result;
- outstring_log("");
- outstring_log("TSCR: >> Loaded %u EventAI_Events", Count);
-
- }else outstring_log("TSCR: WARNING >> Loaded 0 EventAI_Scripts. DB table `EventAI_Scripts` is empty.");
-
- // Gather Script Text
- result = TScriptDB.PQuery("SELECT `id`, `sound`, `type`, `language`, `text`"
- "FROM `script_texts`;");
-
- // Drop Existing Script Text Map
- Script_TextMap.clear();
-
- if(result)
- {
- outstring_log("TSCR: Loading Script Text...");
- barGoLink bar(result->GetRowCount());
- uint32 count = 0;
-
- do
- {
- bar.step();
- Field* fields = result->Fetch();
- ScriptText temp;
-
- uint32 i = fields[0].GetInt32();
- temp.SoundId = fields[1].GetInt32();
- temp.Type = fields[2].GetInt32();
- temp.Language = fields[3].GetInt32();
- temp.Text = fields[4].GetString();
-
- if (temp.SoundId)
- {
- if (!GetSoundEntriesStore()->LookupEntry(temp.SoundId))
- error_db_log("TSCR: Id %u in table script_texts has soundid %u but sound does not exist.",i,temp.SoundId);
- }
-
- if(!strlen(temp.Text.c_str()))
- error_db_log("TSCR: Id %u in table script_texts has no text.", i);
-
- Script_TextMap[i] = temp;
- ++count;
-
- }while(result->NextRow());
-
- delete result;
-
- outstring_log("");
- outstring_log("TSCR: Loaded %u Script Texts", count);
-
- }else outstring_log("TSCR WARNING >> Loaded 0 Script Texts. Database table `script_texts` is empty.");
-
- //Free database thread and resources
- TScriptDB.HaltDelayThread();
-
- //***End DB queries***
- }
-}
-
-struct TSpellSummary {
- uint8 Targets; // set of enum SelectTarget
- uint8 Effects; // set of enum SelectEffect
-}extern *SpellSummary;
-
-MANGOS_DLL_EXPORT
-void ScriptsFree()
-{
- // Free Spell Summary
- delete []SpellSummary;
-
- // Free resources before library unload
- for(int i=0;i 8)
- {
- Locale = 0;
- error_log("TSCR: Locale set to invalid language id. Defaulting to 0.");
- }
-
- outstring_log("TSCR: Using locale %u", Locale);
- outstring_log("");
-
- EAI_ErrorLevel = TScriptConfig.GetIntDefault("EAIErrorLevel", 1);
-
- switch (EAI_ErrorLevel)
- {
- case 0:
- outstring_log("TSCR: EventAI Error Reporting level set to 0 (Startup Errors only)");
- break;
-
- case 1:
- outstring_log("TSCR: EventAI Error Reporting level set to 1 (Startup errors and Runtime event errors)");
- break;
-
- case 2:
- outstring_log("TSCR: EventAI Error Reporting level set to 2 (Startup errors, Runtime event errors, and Creation errors)");
- break;
-
- default:
- outstring_log("TSCR: Unknown EventAI Error Reporting level. Defaulting to 1 (Startup errors and Runtime event errors)");
- EAI_ErrorLevel = 1;
- break;
- }
- outstring_log("");
-
- //Load database (must be called after TScriptConfig.SetSource)
- LoadDatabase();
-
- nrscripts = 0;
- for(int i=0;i::iterator i = EventAI_LocalizedTextMap.find(entry);
-
- if (i == EventAI_LocalizedTextMap.end())
- {
- error_log("TSCR: EventAI Localized Text %u not found", entry);
- return DEFAULT_TEXT;
- }
-
- switch (Locale)
- {
- case 1:
- temp = (*i).second.locale_1.c_str();
- break;
-
- case 2:
- temp = (*i).second.locale_2.c_str();
- break;
-
- case 3:
- temp = (*i).second.locale_3.c_str();
- break;
-
- case 4:
- temp = (*i).second.locale_4.c_str();
- break;
-
- case 5:
- temp = (*i).second.locale_5.c_str();
- break;
-
- case 6:
- temp = (*i).second.locale_6.c_str();
- break;
-
- case 7:
- temp = (*i).second.locale_7.c_str();
- break;
-
- case 8:
- temp = (*i).second.locale_8.c_str();
- break;
- };
-
- if (strlen(temp))
- return temp;
-
- return DEFAULT_TEXT;
-}
-
-const char* GetScriptLocalizedText(uint32 entry)
-{
- const char* temp = NULL;
-
- HM_NAMESPACE::hash_map::iterator i = Script_LocalizedTextMap.find(entry);
-
- if (i == Script_LocalizedTextMap.end())
- {
- error_log("TSCR: Script Localized Text %u not found", entry);
- return DEFAULT_TEXT;
- }
-
- switch (Locale)
- {
- case 1:
- temp = (*i).second.locale_1.c_str();
- break;
-
- case 2:
- temp = (*i).second.locale_2.c_str();
- break;
-
- case 3:
- temp = (*i).second.locale_3.c_str();
- break;
-
- case 4:
- temp = (*i).second.locale_4.c_str();
- break;
-
- case 5:
- temp = (*i).second.locale_5.c_str();
- break;
-
- case 6:
- temp = (*i).second.locale_6.c_str();
- break;
-
- case 7:
- temp = (*i).second.locale_7.c_str();
- break;
-
- case 8:
- temp = (*i).second.locale_8.c_str();
- break;
- };
-
- if (strlen(temp))
- return temp;
-
- return DEFAULT_TEXT;
-}
-
-const char* GetEventAIText(uint32 entry)
-{
- if(entry == 0xffffffff)
- error_log("TSCR: Entry = -1, GetEventAIText should not be called in this case.");
-
- const char* str = NULL;
-
- HM_NAMESPACE::hash_map::iterator itr = EventAI_Text_Map.find(entry);
- if(itr == EventAI_Text_Map.end())
- {
- error_log("TSCR: Unable to find EventAI Text %u", entry);
- return DEFAULT_TEXT;
- }
-
- str = (*itr).second.c_str();
-
- if(strlen(str))
- return str;
-
- if(strlen((*itr).second.c_str()))
- return (*itr).second.c_str();
-
- return DEFAULT_TEXT;
-}
-
-void ProcessScriptText(uint32 id, WorldObject* pSource, Unit* target)
-{
- if (!pSource)
- {
- error_log("TSCR: ProcessScriptText invalid Source pointer.");
- return;
- }
-
- HM_NAMESPACE::hash_map::iterator i = Script_TextMap.find(id);
-
- if (i == Script_TextMap.end())
- {
- error_log("TSCR: ProcessScriptText could not find id %u.",id);
- return;
- }
-
- if((*i).second.SoundId)
- {
- if(GetSoundEntriesStore()->LookupEntry((*i).second.SoundId))
- {
- pSource->SendPlaySound((*i).second.SoundId, false);
- }
- else
- error_log("TSCR: ProcessScriptText id %u tried to process invalid soundid %u.",id,(*i).second.SoundId);
- }
-
- switch((*i).second.Type)
- {
- case CHAT_TYPE_SAY:
- pSource->MonsterSay((*i).second.Text.c_str(), (*i).second.Language, target ? target->GetGUID() : 0);
- break;
-
- case CHAT_TYPE_YELL:
- pSource->MonsterYell((*i).second.Text.c_str(), (*i).second.Language, target ? target->GetGUID() : 0);
- break;
-
- case CHAT_TYPE_TEXT_EMOTE:
- pSource->MonsterTextEmote((*i).second.Text.c_str(), target ? target->GetGUID() : 0);
- break;
-
- case CHAT_TYPE_BOSS_EMOTE:
- pSource->MonsterTextEmote((*i).second.Text.c_str(), target ? target->GetGUID() : 0, true);
- break;
-
- case CHAT_TYPE_WHISPER:
- {
- if (target && target->GetTypeId() == TYPEID_PLAYER)
- pSource->MonsterWhisper((*i).second.Text.c_str(), target->GetGUID());
- else error_log("TSCR: ProcessScriptText id %u cannot whisper without target unit (TYPEID_PLAYER).", id);
- }break;
-
- case CHAT_TYPE_BOSS_WHISPER:
- {
- if (target && target->GetTypeId() == TYPEID_PLAYER)
- pSource->MonsterWhisper((*i).second.Text.c_str(), target->GetGUID(), true);
- else error_log("TSCR: ProcessScriptText id %u cannot whisper without target unit (TYPEID_PLAYER).", id);
- }break;
- }
-}
-
-Script* GetScriptByName(std::string Name)
-{
- if(Name.empty())
- return NULL;
-
- for(int i=0;iName == Name )
- return m_scripts[i];
- }
- return NULL;
-}
-
-//********************************
-//*** Functions to be Exported ***
-
-MANGOS_DLL_EXPORT
-bool GossipHello ( Player * player, Creature *_Creature )
-{
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
- if(!tmpscript || !tmpscript->pGossipHello) return false;
-
- player->PlayerTalkClass->ClearMenus();
- return tmpscript->pGossipHello(player,_Creature);
-}
-
-MANGOS_DLL_EXPORT
-bool GossipSelect( Player *player, Creature *_Creature, uint32 sender, uint32 action )
-{
- debug_log("TSCR: Gossip selection, sender: %d, action: %d",sender, action);
-
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
- if(!tmpscript || !tmpscript->pGossipSelect) return false;
-
- player->PlayerTalkClass->ClearMenus();
- return tmpscript->pGossipSelect(player,_Creature,sender,action);
-}
-
-MANGOS_DLL_EXPORT
-bool GossipSelectWithCode( Player *player, Creature *_Creature, uint32 sender, uint32 action, const char* sCode )
-{
- debug_log("TSCR: Gossip selection with code, sender: %d, action: %d",sender, action);
-
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
- if(!tmpscript || !tmpscript->pGossipSelectWithCode) return false;
-
- player->PlayerTalkClass->ClearMenus();
- return tmpscript->pGossipSelectWithCode(player,_Creature,sender,action,sCode);
-}
-
-MANGOS_DLL_EXPORT
-bool QuestAccept( Player *player, Creature *_Creature, Quest const *_Quest )
-{
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
- if(!tmpscript || !tmpscript->pQuestAccept) return false;
-
- player->PlayerTalkClass->ClearMenus();
- return tmpscript->pQuestAccept(player,_Creature,_Quest);
-}
-
-MANGOS_DLL_EXPORT
-bool QuestSelect( Player *player, Creature *_Creature, Quest const *_Quest )
-{
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
- if(!tmpscript || !tmpscript->pQuestSelect) return false;
-
- player->PlayerTalkClass->ClearMenus();
- return tmpscript->pQuestSelect(player,_Creature,_Quest);
-}
-
-MANGOS_DLL_EXPORT
-bool QuestComplete( Player *player, Creature *_Creature, Quest const *_Quest )
-{
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
- if(!tmpscript || !tmpscript->pQuestComplete) return false;
-
- player->PlayerTalkClass->ClearMenus();
- return tmpscript->pQuestComplete(player,_Creature,_Quest);
-}
-
-MANGOS_DLL_EXPORT
-bool ChooseReward( Player *player, Creature *_Creature, Quest const *_Quest, uint32 opt )
-{
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
- if(!tmpscript || !tmpscript->pChooseReward) return false;
-
- player->PlayerTalkClass->ClearMenus();
- return tmpscript->pChooseReward(player,_Creature,_Quest,opt);
-}
-
-MANGOS_DLL_EXPORT
-uint32 NPCDialogStatus( Player *player, Creature *_Creature )
-{
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
- if(!tmpscript || !tmpscript->pNPCDialogStatus) return 100;
-
- player->PlayerTalkClass->ClearMenus();
- return tmpscript->pNPCDialogStatus(player,_Creature);
-}
-
-MANGOS_DLL_EXPORT
-uint32 GODialogStatus( Player *player, GameObject *_GO )
-{
- Script *tmpscript = GetScriptByName(_GO->GetGOInfo()->ScriptName);
- if(!tmpscript || !tmpscript->pGODialogStatus) return 100;
-
- player->PlayerTalkClass->ClearMenus();
- return tmpscript->pGODialogStatus(player,_GO);
-}
-
-MANGOS_DLL_EXPORT
-bool ItemHello( Player *player, Item *_Item, Quest const *_Quest )
-{
- Script *tmpscript = GetScriptByName(_Item->GetProto()->ScriptName);
- if(!tmpscript || !tmpscript->pItemHello) return false;
-
- player->PlayerTalkClass->ClearMenus();
- return tmpscript->pItemHello(player,_Item,_Quest);
-}
-
-MANGOS_DLL_EXPORT
-bool ItemQuestAccept( Player *player, Item *_Item, Quest const *_Quest )
-{
- Script *tmpscript = GetScriptByName(_Item->GetProto()->ScriptName);
- if(!tmpscript || !tmpscript->pItemQuestAccept) return false;
-
- player->PlayerTalkClass->ClearMenus();
- return tmpscript->pItemQuestAccept(player,_Item,_Quest);
-}
-
-MANGOS_DLL_EXPORT
-bool GOHello( Player *player, GameObject *_GO )
-{
- Script *tmpscript = GetScriptByName(_GO->GetGOInfo()->ScriptName);
- if(!tmpscript || !tmpscript->pGOHello) return false;
-
- player->PlayerTalkClass->ClearMenus();
- return tmpscript->pGOHello(player,_GO);
-}
-
-MANGOS_DLL_EXPORT
-bool GOQuestAccept( Player *player, GameObject *_GO, Quest const *_Quest )
-{
- Script *tmpscript = GetScriptByName(_GO->GetGOInfo()->ScriptName);
- if(!tmpscript || !tmpscript->pGOQuestAccept) return false;
-
- player->PlayerTalkClass->ClearMenus();
- return tmpscript->pGOQuestAccept(player,_GO,_Quest);
-}
-
-MANGOS_DLL_EXPORT
-bool GOChooseReward( Player *player, GameObject *_GO, Quest const *_Quest, uint32 opt )
-{
- Script *tmpscript = GetScriptByName(_GO->GetGOInfo()->ScriptName);
- if(!tmpscript || !tmpscript->pGOChooseReward) return false;
-
- player->PlayerTalkClass->ClearMenus();
- return tmpscript->pGOChooseReward(player,_GO,_Quest,opt);
-}
-
-MANGOS_DLL_EXPORT
-bool AreaTrigger( Player *player, AreaTriggerEntry * atEntry)
-{
- Script *tmpscript = NULL;
-
- tmpscript = GetScriptByName(GetAreaTriggerScriptNameById(atEntry->id));
- if(!tmpscript || !tmpscript->pAreaTrigger) return false;
-
- return tmpscript->pAreaTrigger(player, atEntry);
-}
-
-MANGOS_DLL_EXPORT
-CreatureAI* GetAI(Creature *_Creature)
-{
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
-
- if(!tmpscript || !tmpscript->GetAI) return NULL;
- return tmpscript->GetAI(_Creature);
-}
-
-MANGOS_DLL_EXPORT
-bool ItemUse( Player *player, Item* _Item, SpellCastTargets const& targets)
-{
- Script *tmpscript = GetScriptByName(_Item->GetProto()->ScriptName);
- if(!tmpscript || !tmpscript->pItemUse) return false;
-
- return tmpscript->pItemUse(player,_Item,targets);
-}
-
-MANGOS_DLL_EXPORT
-bool ReceiveEmote( Player *player, Creature *_Creature, uint32 emote )
-{
- Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
- if(!tmpscript || !tmpscript->pReceiveEmote) return false;
-
- return tmpscript->pReceiveEmote(player, _Creature, emote);
-}
-
-MANGOS_DLL_EXPORT
-InstanceData* CreateInstanceData(Map *map)
-{
- Script *tmpscript = NULL;
-
- if(!map->IsDungeon()) return false;
-
- tmpscript = GetScriptByName(((InstanceMap*)map)->GetScript());
- if(!tmpscript || !tmpscript->GetInstanceData) return false;
-
- return tmpscript->GetInstanceData(map);
-}
+/* Copyright (C) 2006 - 2008 TrinityScript
+ * This program is free software licensed under GPL version 2
+ * Please see the included DOCS/LICENSE.TXT for more information */
+
+#include "precompiled.h"
+#include "Config/Config.h"
+#include "Database/DatabaseEnv.h"
+#include "Database/DBCStores.h"
+#include "ObjectMgr.h"
+#include "ProgressBar.h"
+#include "scripts/creature/mob_event_ai.h"
+
+#define _FULLVERSION "TrinityScript"
+
+#ifndef _TSCRIPTCONFVERSION
+# define _TSCRIPTCONFVERSION 2008100201
+#endif //_TSCRIPTCONFVERSION
+
+#ifndef _TRINITY_SCRIPT_CONFIG
+# define _TRINITY_SCRIPT_CONFIG "trinityscript.conf"
+#endif //_TRINITY_SCRIPT_CONFIG
+
+//*** Global data ***
+int nrscripts;
+Script *m_scripts[MAX_SCRIPTS];
+
+DatabaseType TScriptDB;
+Config TScriptConfig;
+uint32 Locale;
+
+// String text additional data, used in TextMap
+struct StringTextData
+{
+ uint32 SoundId;
+ uint8 Type;
+ uint32 Language;
+};
+
+// Enums used by StringTextData::Type
+enum ChatType
+{
+ CHAT_TYPE_SAY = 0,
+ CHAT_TYPE_YELL = 1,
+ CHAT_TYPE_TEXT_EMOTE = 2,
+ CHAT_TYPE_BOSS_EMOTE = 3,
+ CHAT_TYPE_WHISPER = 4,
+ CHAT_TYPE_BOSS_WHISPER = 5,
+};
+
+#define TEXT_SOURCE_RANGE -100000 //the amount of entries each text source has available
+
+// Text Maps
+HM_NAMESPACE::hash_map EventAI_Text_Map;
+HM_NAMESPACE::hash_map TextMap;
+
+// Localized Text structure for storing locales (for EAI and SD2 scripts).
+struct Localized_Text
+{
+ std::string locale_1;
+ std::string locale_2;
+ std::string locale_3;
+ std::string locale_4;
+ std::string locale_5;
+ std::string locale_6;
+ std::string locale_7;
+ std::string locale_8;
+};
+//*** End Global data ***
+
+//*** EventAI data ***
+HM_NAMESPACE::hash_map EventAI_LocalizedTextMap;
+
+//Event AI structure. Used exclusivly by mob_event_ai.cpp (60 bytes each)
+std::list EventAI_Event_List;
+
+//Event AI summon structure. Used exclusivly by mob_event_ai.cpp.
+HM_NAMESPACE::hash_map EventAI_Summon_Map;
+
+//Event AI error prevention structure. Used at runtime to prevent error log spam of same creature id.
+//HM_NAMESPACE::hash_map EventAI_CreatureErrorPreventionList;
+
+uint32 EAI_ErrorLevel;
+//*** End EventAI data ***
+
+void FillSpellSummary();
+
+// -- Scripts to be added --
+
+// -- Areatrigger --
+extern void AddSC_areatrigger_scripts();
+
+// -- Boss --
+extern void AddSC_boss_emeriss();
+extern void AddSC_boss_taerar();
+extern void AddSC_boss_ysondre();
+
+// -- Creature --
+extern void AddSC_mob_event();
+extern void AddSC_generic_creature();
+
+// -- Custom --
+extern void AddSC_custom_example();
+extern void AddSC_custom_gossip_codebox();
+extern void AddSC_test();
+
+// -- GO --
+extern void AddSC_go_scripts();
+
+// -- Guard --
+extern void AddSC_guards();
+
+// -- Honor --
+
+// -- Item --
+extern void AddSC_item_scripts();
+extern void AddSC_item_test();
+
+// -- NPC --
+extern void AddSC_npc_professions();
+extern void AddSC_npcs_special();
+
+// -- Servers --
+
+//--------------------
+//------ ZONE --------
+
+//Alterac Mountains
+extern void AddSC_alterac_mountains();
+
+//Arathi Highlands
+//Ashenvale Forest
+//Aunchindoun
+//--Auchenai Crypts
+extern void AddSC_boss_exarch_maladaar();
+//--Mana Tombs
+extern void AddSC_boss_nexusprince_shaffar();
+extern void AddSC_boss_pandemonius();
+
+//--Sekketh Halls
+extern void AddSC_boss_darkweaver_syth();
+extern void AddSC_boss_talon_king_ikiss();
+extern void AddSC_instance_sethekk_halls();
+
+//--Shadow Labyrinth
+extern void AddSC_boss_ambassador_hellmaw();
+extern void AddSC_boss_blackheart_the_inciter();
+extern void AddSC_boss_grandmaster_vorpil();
+extern void AddSC_boss_murmur();
+extern void AddSC_instance_shadow_labyrinth();
+
+//Azshara
+extern void AddSC_boss_azuregos();
+extern void AddSC_azshara();
+
+//Azuremyst Isle
+extern void AddSC_azuremyst_isle();
+
+//Badlands
+//Barrens
+extern void AddSC_the_barrens();
+
+//Black Temple
+extern void AddSC_black_temple();
+extern void AddSC_boss_illidan();
+extern void AddSC_boss_shade_of_akama();
+extern void AddSC_boss_supremus();
+extern void AddSC_boss_gurtogg_bloodboil();
+extern void AddSC_boss_mother_shahraz();
+extern void AddSC_boss_reliquary_of_souls();
+extern void AddSC_boss_teron_gorefiend();
+extern void AddSC_boss_najentus();
+extern void AddSC_boss_illidari_council();
+extern void AddSC_instance_black_temple();
+
+//Blackfathom Depths
+//Blackrock Depths
+extern void AddSC_blackrock_depths();
+extern void AddSC_boss_ambassador_flamelash();
+extern void AddSC_boss_angerrel();
+extern void AddSC_boss_anubshiah();
+extern void AddSC_boss_doomrel();
+extern void AddSC_boss_doperel();
+extern void AddSC_boss_draganthaurissan();
+extern void AddSC_boss_general_angerforge();
+extern void AddSC_boss_gloomrel();
+extern void AddSC_boss_gorosh_the_dervish();
+extern void AddSC_boss_grizzle();
+extern void AddSC_boss_haterel();
+extern void AddSC_boss_high_interrogator_gerstahn();
+extern void AddSC_boss_magmus();
+extern void AddSC_boss_moira_bronzebeard();
+extern void AddSC_boss_seethrel();
+extern void AddSC_boss_vilerel();
+
+//Blackrock Spire
+extern void AddSC_boss_drakkisath();
+extern void AddSC_boss_halycon();
+extern void AddSC_boss_highlordomokk();
+extern void AddSC_boss_mothersmolderweb();
+extern void AddSC_boss_overlordwyrmthalak();
+extern void AddSC_boss_shadowvosh();
+extern void AddSC_boss_thebeast();
+extern void AddSC_boss_warmastervoone();
+extern void AddSC_boss_quatermasterzigris();
+extern void AddSC_boss_pyroguard_emberseer();
+extern void AddSC_boss_gyth();
+extern void AddSC_boss_rend_blackhand();
+
+//Blackwing lair
+extern void AddSC_boss_razorgore();
+extern void AddSC_boss_vael();
+extern void AddSC_boss_broodlord();
+extern void AddSC_boss_firemaw();
+extern void AddSC_boss_ebonroc();
+extern void AddSC_boss_flamegor();
+extern void AddSC_boss_chromaggus();
+extern void AddSC_boss_nefarian();
+extern void AddSC_boss_victor_nefarius();
+
+//Blade's Edge Mountains
+extern void AddSC_blades_edge_mountains();
+
+//Blasted lands
+extern void AddSC_boss_kruul();
+extern void AddSC_blasted_lands();
+
+//Bloodmyst Isle
+extern void AddSC_bloodmyst_isle();
+
+//Burning steppes
+extern void AddSC_burning_steppes();
+
+//Caverns of Time
+//--Battle for Mt. Hyjal
+extern void AddSC_hyjal();
+extern void AddSC_boss_archimonde();
+extern void AddSC_instance_mount_hyjal();
+
+//--Old Hillsbrad
+extern void AddSC_boss_captain_skarloc();
+extern void AddSC_boss_epoch_hunter();
+extern void AddSC_boss_lieutenant_drake();
+extern void AddSC_instance_old_hillsbrad();
+extern void AddSC_old_hillsbrad();
+
+//--The Dark Portal
+extern void AddSC_boss_aeonus();
+extern void AddSC_boss_chrono_lord_deja();
+extern void AddSC_boss_temporus();
+
+//Coilfang Resevoir
+//--Serpent Shrine Cavern
+extern void AddSC_boss_fathomlord_karathress();
+extern void AddSC_boss_hydross_the_unstable();
+extern void AddSC_boss_lady_vashj();
+extern void AddSC_boss_leotheras_the_blind();
+extern void AddSC_boss_morogrim_tidewalker();
+extern void AddSC_instance_serpentshrine_cavern();
+
+//--Slave Pens
+
+//--Steam Vault
+extern void AddSC_boss_hydromancer_thespia();
+extern void AddSC_boss_mekgineer_steamrigger();
+extern void AddSC_boss_warlord_kalithresh();
+extern void AddSC_instance_steam_vault();
+
+//--Underbog
+extern void AddSC_boss_hungarfen();
+
+//Darkshore
+//Darnassus
+//Deadmines
+//Deadwind pass
+//Desolace
+//Dire Maul
+//Dun Morogh
+extern void AddSC_dun_morogh();
+
+//Durotar
+//Duskwood
+//Dustwallow marsh
+extern void AddSC_dustwallow_marsh();
+
+//Eversong Woods
+extern void AddSC_eversong_woods();
+
+//Exodar
+//Eastern Plaguelands
+extern void AddSC_eastern_plaguelands();
+
+//Elwynn Forest
+extern void AddSC_elwynn_forest();
+
+//Felwood
+extern void AddSC_felwood();
+
+//Feralas
+extern void AddSC_feralas();
+
+//Ghostlands
+extern void AddSC_ghostlands();
+
+//Gnomeregan
+//Gruul's Lair
+extern void AddSC_boss_gruul();
+extern void AddSC_boss_high_king_maulgar();
+extern void AddSC_instance_gruuls_lair();
+
+//Hellfire Citadel
+//--Blood Furnace
+extern void AddSC_boss_broggok();
+extern void AddSC_boss_kelidan_the_breaker();
+extern void AddSC_boss_the_maker();
+
+//--Magtheridon's Lair
+extern void AddSC_boss_magtheridon();
+extern void AddSC_instance_magtheridons_lair();
+
+//--Shattered Halls
+extern void AddSC_boss_grand_warlock_nethekurse();
+extern void AddSC_boss_warbringer_omrogg();
+extern void AddSC_instance_shattered_halls();
+
+//--Ramparts
+extern void AddSC_boss_watchkeeper_gargolmar();
+extern void AddSC_boss_omor_the_unscarred();
+
+//Hellfire Peninsula
+extern void AddSC_boss_doomlordkazzak();
+extern void AddSC_hellfire_peninsula();
+
+//Hillsbrad Foothills
+//Hinterlands
+//Ironforge
+extern void AddSC_ironforge();
+
+//Isle of Quel'Danas
+extern void AddSC_isle_of_queldanas();
+
+//Karazhan
+extern void AddSC_boss_attumen();
+extern void AddSC_boss_curator();
+extern void AddSC_boss_maiden_of_virtue();
+extern void AddSC_boss_shade_of_aran();
+extern void AddSC_boss_malchezaar();
+extern void AddSC_boss_terestian_illhoof();
+extern void AddSC_netherspite_infernal();
+extern void AddSC_boss_moroes();
+extern void AddSC_bosses_opera();
+extern void AddSC_instance_karazhan();
+extern void AddSC_karazhan();
+
+//Loch Modan
+extern void AddSC_loch_modan();
+
+//Lower Blackrock Spire
+
+// Magister's Terrace
+extern void AddSC_boss_felblood_kaelthas();
+extern void AddSC_boss_selin_fireheart();
+extern void AddSC_boss_vexallus();
+extern void AddSC_boss_priestess_delrissa();
+extern void AddSC_instance_magisters_terrace();
+
+//Maraudon
+extern void AddSC_boss_celebras_the_cursed();
+extern void AddSC_boss_landslide();
+extern void AddSC_boss_noxxion();
+extern void AddSC_boss_ptheradras();
+
+//Molten core
+extern void AddSC_boss_lucifron();
+extern void AddSC_boss_magmadar();
+extern void AddSC_boss_gehennas();
+extern void AddSC_boss_garr();
+extern void AddSC_boss_baron_geddon();
+extern void AddSC_boss_shazzrah();
+extern void AddSC_boss_golemagg();
+extern void AddSC_boss_sulfuron();
+extern void AddSC_boss_majordomo();
+extern void AddSC_boss_ragnaros();
+extern void AddSC_instance_molten_core();
+extern void AddSC_molten_core();
+
+//Moonglade
+extern void AddSC_moonglade();
+
+//Mulgore
+extern void AddSC_mulgore();
+
+//Nagrand
+extern void AddSC_nagrand();
+
+//Naxxramas
+extern void AddSC_boss_anubrekhan();
+extern void AddSC_boss_maexxna();
+extern void AddSC_boss_patchwerk();
+extern void AddSC_boss_razuvious();
+extern void AddSC_boss_highlord_mograine();
+extern void AddSC_boss_lady_blaumeux();
+extern void AddSC_boss_sir_zeliek();
+extern void AddSC_boss_thane_korthazz();
+extern void AddSC_boss_kelthuzad();
+extern void AddSC_boss_faerlina();
+extern void AddSC_boss_loatheb();
+extern void AddSC_boss_noth();
+extern void AddSC_boss_gluth();
+extern void AddSC_boss_sapphiron();
+
+//Netherstorm
+extern void AddSC_netherstorm();
+
+//Onyxia's Lair
+extern void AddSC_boss_onyxia();
+
+//Orgrimmar
+extern void AddSC_orgrimmar();
+
+//Ragefire Chasm
+//Razorfen Downs
+extern void AddSC_boss_amnennar_the_coldbringer();
+
+//Redridge Mountains
+//Ruins of Ahn'Qiraj
+//Scarlet Monastery
+extern void AddSC_boss_arcanist_doan();
+extern void AddSC_boss_azshir_the_sleepless();
+extern void AddSC_boss_bloodmage_thalnos();
+extern void AddSC_boss_herod();
+extern void AddSC_boss_high_inquisitor_fairbanks();
+extern void AddSC_boss_high_inquisitor_whitemane();
+extern void AddSC_boss_houndmaster_loksey();
+extern void AddSC_boss_interrogator_vishas();
+extern void AddSC_boss_scarlet_commander_mograine();
+extern void AddSC_boss_scorn();
+
+//Scholomance
+extern void AddSC_boss_darkmaster_gandling();
+extern void AddSC_boss_death_knight_darkreaver();
+extern void AddSC_boss_theolenkrastinov();
+extern void AddSC_boss_illuciabarov();
+extern void AddSC_boss_instructormalicia();
+extern void AddSC_boss_jandicebarov();
+extern void AddSC_boss_kormok();
+extern void AddSC_boss_lordalexeibarov();
+extern void AddSC_boss_lorekeeperpolkelt();
+extern void AddSC_boss_rasfrost();
+extern void AddSC_boss_theravenian();
+extern void AddSC_boss_vectus();
+extern void AddSC_instance_scholomance();
+
+//Searing gorge
+extern void AddSC_searing_gorge();
+
+//Shadowfang keep
+extern void AddSC_shadowfang_keep();
+extern void AddSC_instance_shadowfang_keep();
+
+//Shadowmoon Valley
+extern void AddSC_boss_doomwalker();
+extern void AddSC_shadowmoon_valley();
+
+//Shattrath
+extern void AddSC_shattrath_city();
+
+//Silithus
+extern void AddSC_silithus();
+
+//Silvermoon
+extern void AddSC_silvermoon_city();
+
+//Silverpine forest
+extern void AddSC_silverpine_forest();
+
+//Stockade
+//Stonetalon mountains
+extern void AddSC_stonetalon_mountains();
+
+//Stormwind City
+extern void AddSC_stormwind_city();
+
+//Stranglethorn Vale
+extern void AddSC_stranglethorn_vale();
+
+//Stratholme
+extern void AddSC_boss_magistrate_barthilas();
+extern void AddSC_boss_maleki_the_pallid();
+extern void AddSC_boss_nerubenkan();
+extern void AddSC_boss_cannon_master_willey();
+extern void AddSC_boss_baroness_anastari();
+extern void AddSC_boss_ramstein_the_gorger();
+extern void AddSC_boss_timmy_the_cruel();
+extern void AddSC_boss_postmaster_malown();
+extern void AddSC_boss_baron_rivendare();
+extern void AddSC_boss_dathrohan_balnazzar();
+extern void AddSC_boss_order_of_silver_hand();
+extern void AddSC_instance_stratholme();
+extern void AddSC_stratholme();
+
+//Sunken Temple
+//Tanaris
+extern void AddSC_tanaris();
+
+//Teldrassil
+//Tempest Keep
+//--Arcatraz
+extern void AddSC_arcatraz();
+extern void AddSC_boss_harbinger_skyriss();
+extern void AddSC_instance_arcatraz();
+
+//--Botanica
+extern void AddSC_boss_high_botanist_freywinn();
+extern void AddSC_boss_laj();
+extern void AddSC_boss_warp_splinter();
+
+//--The Eye
+extern void AddSC_boss_kaelthas();
+extern void AddSC_boss_void_reaver();
+extern void AddSC_boss_high_astromancer_solarian();
+extern void AddSC_instance_the_eye();
+extern void AddSC_the_eye();
+
+//--The Mechanar
+extern void AddSC_boss_gatewatcher_iron_hand();
+extern void AddSC_boss_nethermancer_sepethrea();
+
+//Temple of ahn'qiraj
+extern void AddSC_boss_cthun();
+extern void AddSC_boss_fankriss();
+extern void AddSC_boss_huhuran();
+extern void AddSC_bug_trio();
+extern void AddSC_boss_sartura();
+extern void AddSC_boss_skeram();
+extern void AddSC_boss_twinemperors();
+extern void AddSC_mob_anubisath_sentinel();
+extern void AddSC_instance_temple_of_ahnqiraj();
+
+//Terokkar Forest
+extern void AddSC_terokkar_forest();
+
+//Thousand Needles
+//Thunder Bluff
+extern void AddSC_thunder_bluff();
+
+//Tirisfal Glades
+extern void AddSC_tirisfal_glades();
+
+//Uldaman
+extern void AddSC_boss_ironaya();
+extern void AddSC_uldaman();
+
+//Undercity
+extern void AddSC_undercity();
+
+//Un'Goro Crater
+//Upper blackrock spire
+//Wailing caverns
+
+//Western plaguelands
+extern void AddSC_western_plaguelands();
+
+//Westfall
+//Wetlands
+//Winterspring
+extern void AddSC_winterspring();
+
+//Zangarmarsh
+extern void AddSC_zangarmarsh();
+
+//Zul'Farrak
+//Zul'Gurub
+extern void AddSC_boss_jeklik();
+extern void AddSC_boss_venoxis();
+extern void AddSC_boss_marli();
+extern void AddSC_boss_mandokir();
+extern void AddSC_boss_gahzranka();
+extern void AddSC_boss_thekal();
+extern void AddSC_boss_arlokk();
+extern void AddSC_boss_jindo();
+extern void AddSC_boss_hakkar();
+extern void AddSC_boss_grilek();
+extern void AddSC_boss_hazzarah();
+extern void AddSC_boss_renataki();
+extern void AddSC_boss_wushoolay();
+extern void AddSC_instance_zulgurub();
+//Zul'Aman
+extern void AddSC_boss_janalai();
+extern void AddSC_boss_nalorakk();
+extern void AddSC_instance_zulaman();
+extern void AddSC_zulaman();
+
+// -------------------
+void LoadDatabase()
+{
+ //Get db string from file
+ char const* dbstring = NULL;
+
+ if( !TScriptConfig.GetString("TScriptDatabaseInfo", &dbstring) )
+ {
+ error_log("TSCR: Missing Trinity Script database info from configuration file. Load database aborted.");
+ return;
+ }
+
+ //Initialize connection to DB
+ if( dbstring && TScriptDB.Initialize(dbstring) )
+ outstring_log("TSCR: TrinityScript database: %s",dbstring);
+ else
+ {
+ error_log("TSCR: Unable to connect to Database. Load database aborted.");
+ return;
+ }
+
+ //***Preform all DB queries here***
+ QueryResult *result;
+
+ //Get Version information
+ result = TScriptDB.PQuery("SELECT version FROM script_db_version");
+
+ if (result)
+ {
+ Field *fields = result->Fetch();
+ outstring_log("TSCR: Database version is: %s", fields[0].GetString());
+ outstring_log("");
+ delete result;
+
+ }else
+ {
+ error_log("TSCR: Missing `script_db_version` information.");
+ outstring_log("");
+ }
+
+ // Drop Existing Text Map, only done once and we are ready to add data from multiple sources.
+ TextMap.clear();
+
+ //TODO: Add load from eventai_texts here
+
+ // Load Script Text
+ outstring_log("TSCR: Loading Script Texts...");
+ LoadMangosStrings(TScriptDB,"script_texts",TEXT_SOURCE_RANGE,(TEXT_SOURCE_RANGE*2)+1);
+
+ // Gather Additional data from Script Texts
+ result = TScriptDB.PQuery("SELECT entry, sound, type, language FROM script_texts");
+
+ outstring_log("TSCR: Loading Script Texts additional data...");
+ if (result)
+ {
+ barGoLink bar(result->GetRowCount());
+ uint32 count = 0;
+
+ do
+ {
+ bar.step();
+ Field* fields = result->Fetch();
+ StringTextData temp;
+
+ int32 i = fields[0].GetInt32();
+ temp.SoundId = fields[1].GetInt32();
+ temp.Type = fields[2].GetInt32();
+ temp.Language = fields[3].GetInt32();
+
+ if (i >= 0)
+ {
+ error_db_log("TSCR: Entry %i in table `script_texts` is not a negative value.",i);
+ continue;
+ }
+
+ if (i > TEXT_SOURCE_RANGE || i <= TEXT_SOURCE_RANGE*2)
+ {
+ error_db_log("TSCR: Entry %i in table `script_texts` is out of accepted entry range for table.",i);
+ continue;
+ }
+
+ if (temp.SoundId)
+ {
+ if (!GetSoundEntriesStore()->LookupEntry(temp.SoundId))
+ error_db_log("TSCR: Entry %i in table `script_texts` has soundId %u but sound does not exist.",i,temp.SoundId);
+ }
+
+ if (!GetLanguageDescByID(temp.Language))
+ error_db_log("TSCR: Entry %i in table `script_texts` using Language %u but Language does not exist.",i,temp.Language);
+
+ if (temp.Type > CHAT_TYPE_BOSS_WHISPER)
+ error_db_log("TSCR: Entry %i in table `script_texts` has Type %u but this Chat Type does not exist.",i,temp.Type);
+
+ TextMap[i] = temp;
+ ++count;
+ } while (result->NextRow());
+
+ delete result;
+
+ outstring_log("");
+ outstring_log(">> TSCR: Loaded %u additional Script Texts data.", count);
+ }else
+ {
+ barGoLink bar(1);
+ bar.step();
+ outstring_log("");
+ outstring_log(">> Loaded 0 additional Script Texts data. DB table `script_texts` is empty.");
+ }
+
+ // Load Custom Text
+ outstring_log("TSCR: Loading Custom Texts...");
+ LoadMangosStrings(TScriptDB,"custom_texts",TEXT_SOURCE_RANGE*2,(TEXT_SOURCE_RANGE*3)+1);
+
+ // Gather Additional data from Custom Texts
+ result = TScriptDB.PQuery("SELECT entry, sound, type, language FROM custom_texts");
+
+ outstring_log("TSCR: Loading Custom Texts additional data...");
+ if (result)
+ {
+ barGoLink bar(result->GetRowCount());
+ uint32 count = 0;
+
+ do
+ {
+ bar.step();
+ Field* fields = result->Fetch();
+ StringTextData temp;
+
+ int32 i = fields[0].GetInt32();
+ temp.SoundId = fields[1].GetInt32();
+ temp.Type = fields[2].GetInt32();
+ temp.Language = fields[3].GetInt32();
+
+ if (i >= 0)
+ {
+ error_db_log("TSCR: Entry %i in table `custom_texts` is not a negative value.",i);
+ continue;
+ }
+
+ if (i > TEXT_SOURCE_RANGE*2 || i <= TEXT_SOURCE_RANGE*3)
+ {
+ error_db_log("TSCR: Entry %i in table `custom_texts` is out of accepted entry range for table.",i);
+ continue;
+ }
+
+ if (temp.SoundId)
+ {
+ if (!GetSoundEntriesStore()->LookupEntry(temp.SoundId))
+ error_db_log("TSCR: Entry %i in table `custom_texts` has soundId %u but sound does not exist.",i,temp.SoundId);
+ }
+
+ if (!GetLanguageDescByID(temp.Language))
+ error_db_log("TSCR: Entry %i in table `custom_texts` using Language %u but Language does not exist.",i,temp.Language);
+
+ if (temp.Type > CHAT_TYPE_BOSS_WHISPER)
+ error_db_log("TSCR: Entry %i in table `custom_texts` has Type %u but this Chat Type does not exist.",i,temp.Type);
+
+ TextMap[i] = temp;
+ ++count;
+ } while (result->NextRow());
+
+ delete result;
+
+ outstring_log("");
+ outstring_log(">> Loaded %u additional Custom Texts data.", count);
+ }else
+ {
+ barGoLink bar(1);
+ bar.step();
+ outstring_log("");
+ outstring_log(">> Loaded 0 additional Custom Texts data. DB table `custom_texts` is empty.");
+ }
+
+ // Drop existing Event AI Localized Text hash map
+ EventAI_LocalizedTextMap.clear();
+
+ // Gather EventAI Localized Texts
+ result = TScriptDB.PQuery("SELECT id, locale_1, locale_2, locale_3, locale_4, locale_5, locale_6, locale_7, locale_8 "
+ "FROM eventai_localized_texts");
+
+ outstring_log("TSCR: Loading EventAI Localized Texts...");
+ if(result)
+ {
+ barGoLink bar(result->GetRowCount());
+ uint32 count = 0;
+
+ do
+ {
+ Localized_Text temp;
+ bar.step();
+
+ Field *fields = result->Fetch();
+
+ uint32 i = fields[0].GetInt32();
+
+ temp.locale_1 = fields[1].GetString();
+ temp.locale_2 = fields[2].GetString();
+ temp.locale_3 = fields[3].GetString();
+ temp.locale_4 = fields[4].GetString();
+ temp.locale_5 = fields[5].GetString();
+ temp.locale_6 = fields[6].GetString();
+ temp.locale_7 = fields[7].GetString();
+ temp.locale_8 = fields[8].GetString();
+
+ EventAI_LocalizedTextMap[i] = temp;
+ ++count;
+
+ }while(result->NextRow());
+
+ delete result;
+
+ outstring_log("");
+ outstring_log(">> Loaded %u EventAI Localized Texts", count);
+ }else
+ {
+ barGoLink bar(1);
+ bar.step();
+ outstring_log("");
+ outstring_log(">> Loaded 0 EventAI Localized Texts. DB table `eventai_localized_texts` is empty");
+ }
+
+ //Drop existing EventAI Text hash map
+ EventAI_Text_Map.clear();
+
+ //Gather EventAI Text Entries
+ result = TScriptDB.PQuery("SELECT id, text FROM eventai_texts");
+
+ outstring_log("TSCR: Loading EventAI_Texts...");
+ if (result)
+ {
+ barGoLink bar(result->GetRowCount());
+ uint32 Count = 0;
+
+ do
+ {
+ bar.step();
+ Field *fields = result->Fetch();
+
+ uint32 i = fields[0].GetInt32();
+
+ std::string text = fields[1].GetString();
+
+ if (!strlen(text.c_str()))
+ error_db_log("TSCR: EventAI text %u is empty", i);
+
+ EventAI_Text_Map[i] = text;
+ ++Count;
+
+ }while (result->NextRow());
+
+ delete result;
+
+ outstring_log("");
+ outstring_log(">> Loaded %u EventAI texts", Count);
+ }else
+ {
+ barGoLink bar(1);
+ bar.step();
+ outstring_log("");
+ outstring_log(">> Loaded 0 EventAI texts. DB table `eventai_texts` is empty.");
+ }
+
+ //Gather event data
+ result = TScriptDB.PQuery("SELECT id, position_x, position_y, position_z, orientation, spawntimesecs FROM eventai_summons");
+
+ //Drop Existing EventSummon Map
+ EventAI_Summon_Map.clear();
+
+ outstring_log("TSCR: Loading EventAI_Summons...");
+ if (result)
+ {
+ barGoLink bar(result->GetRowCount());
+ uint32 Count = 0;
+
+ do
+ {
+ bar.step();
+ Field *fields = result->Fetch();
+
+ EventAI_Summon temp;
+
+ uint32 i = fields[0].GetUInt32();
+ temp.position_x = fields[1].GetFloat();
+ temp.position_y = fields[2].GetFloat();
+ temp.position_z = fields[3].GetFloat();
+ temp.orientation = fields[4].GetFloat();
+ temp.SpawnTimeSecs = fields[5].GetUInt32();
+
+ //Add to map
+ EventAI_Summon_Map[i] = temp;
+ ++Count;
+ }while (result->NextRow());
+
+ delete result;
+
+ outstring_log("");
+ outstring_log(">> Loaded %u EventAI summon definitions", Count);
+ }else
+ {
+ barGoLink bar(1);
+ bar.step();
+ outstring_log("");
+ outstring_log(">> Loaded 0 EventAI Summon definitions. DB table `eventai_summons` is empty.");
+ }
+
+ //Gather event data
+ result = TScriptDB.PQuery("SELECT 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 "
+ "FROM eventai_scripts");
+
+ //Drop Existing EventAI List
+ EventAI_Event_List.clear();
+
+ outstring_log("TSCR: Loading EventAI_Scripts...");
+ if (result)
+ {
+ barGoLink bar(result->GetRowCount());
+ uint32 Count = 0;
+
+ do
+ {
+ bar.step();
+ Field *fields = result->Fetch();
+
+ EventAI_Event temp;
+
+ temp.event_id = fields[0].GetUInt32();
+ uint32 i = temp.event_id;
+ temp.creature_id = fields[1].GetUInt32();
+ temp.event_type = fields[2].GetUInt16();
+ temp.event_inverse_phase_mask = fields[3].GetUInt32();
+ temp.event_chance = fields[4].GetUInt8();
+ temp.event_flags = fields[5].GetUInt8();
+ temp.event_param1 = fields[6].GetUInt32();
+ temp.event_param2 = fields[7].GetUInt32();
+ temp.event_param3 = fields[8].GetUInt32();
+ temp.event_param4 = fields[9].GetUInt32();
+
+ //Report any errors in event
+ if (temp.event_type >= EVENT_T_END)
+ error_db_log("TSCR: Event %u has incorrect event type. Maybe DB requires updated version of SD2.", i);
+
+ //No chance of this event occuring
+ if (temp.event_chance == 0)
+ error_db_log("TSCR: Event %u has 0 percent chance. Event will never trigger!", i);
+
+ //Chance above 100, force it to be 100
+ if (temp.event_chance > 100)
+ {
+ error_db_log("TSCR: Creature %u are using event %u with more than 100 percent chance. Adjusting to 100 percent.", temp.creature_id, i);
+ temp.event_chance = 100;
+ }
+
+ //Individual event checks
+ switch (temp.event_type)
+ {
+ case EVENT_T_HP:
+ case EVENT_T_MANA:
+ case EVENT_T_TARGET_HP:
+ {
+ if (temp.event_param2 > 100)
+ error_db_log("TSCR: Creature %u are using percentage event(%u) with param2 (MinPercent) > 100. Event will never trigger! ", temp.creature_id, i);
+
+ if (temp.event_param1 <= temp.event_param2)
+ error_db_log("TSCR: Creature %u are using percentage event(%u) with param1 <= param2 (MaxPercent <= MinPercent). Event will never trigger! ", temp.creature_id, i);
+
+ if (temp.event_flags & EFLAG_REPEATABLE && !temp.event_param3 && !temp.event_param4)
+ {
+ error_db_log("TSCR: Creature %u has param3 and param4=0 (RepeatMin/RepeatMax) but cannot be repeatable without timers. Removing EFLAG_REPEATABLE for event %u.", temp.creature_id, i);
+ temp.event_flags &= ~EFLAG_REPEATABLE;
+ }
+ }
+ break;
+
+ case EVENT_T_SPELLHIT:
+ {
+ if (temp.event_param1)
+ {
+ SpellEntry const* pSpell = GetSpellStore()->LookupEntry(temp.event_param1);
+ if (!pSpell)
+ {
+ error_db_log("TSCR: Creature %u has non-existant SpellID(%u) defined in event %u.", temp.creature_id, temp.event_param1, i);
+ continue;
+ }
+
+ if (temp.event_param2_s != -1 && temp.event_param2 != pSpell->SchoolMask)
+ error_db_log("TSCR: Creature %u has param1(spellId %u) but param2 is not -1 and not equal to spell's school mask. Event %u can never trigger.", temp.creature_id, temp.event_param1, i);
+ }
+
+ //TODO: fix this system with SPELL_SCHOOL_MASK. Current complicate things, using int32(-1) instead of just 0
+ //SPELL_SCHOOL_MASK_NONE = 0 and does not exist, thus it can not ever trigger or be used in SpellHit()
+ if (temp.event_param2_s != -1 && temp.event_param2_s > SPELL_SCHOOL_MASK_ALL)
+ error_db_log("TSCR: Creature %u is using invalid SpellSchoolMask(%u) defined in event %u.", temp.creature_id, temp.event_param2, i);
+
+ if (temp.event_param4 < temp.event_param3)
+ error_db_log("TSCR: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
+ }
+ break;
+
+ case EVENT_T_RANGE:
+ case EVENT_T_OOC_LOS:
+ case EVENT_T_FRIENDLY_HP:
+ case EVENT_T_FRIENDLY_IS_CC:
+ case EVENT_T_FRIENDLY_MISSING_BUFF:
+ {
+ if (temp.event_param4 < temp.event_param3)
+ error_db_log("TSCR: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
+ }
+ break;
+
+ case EVENT_T_TIMER:
+ case EVENT_T_TIMER_OOC:
+ {
+ if (temp.event_param2 < temp.event_param1)
+ error_db_log("TSCR: Creature %u are using timed event(%u) with param2 < param1 (InitialMax < InitialMin). Event will never repeat.", temp.creature_id, i);
+
+ if (temp.event_param4 < temp.event_param3)
+ error_db_log("TSCR: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
+ }
+ break;
+
+ case EVENT_T_KILL:
+ case EVENT_T_TARGET_CASTING:
+ {
+ if (temp.event_param2 < temp.event_param1)
+ error_db_log("TSCR: Creature %u are using event(%u) with param2 < param1 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
+ }
+ break;
+
+ case EVENT_T_AGGRO:
+ case EVENT_T_DEATH:
+ case EVENT_T_EVADE:
+ case EVENT_T_SPAWNED:
+ {
+ if (temp.event_flags & EFLAG_REPEATABLE)
+ {
+ error_db_log("TSCR: Creature %u has EFLAG_REPEATABLE set. Event can never be repeatable. Removing flag for event %u.", temp.creature_id, i);
+ temp.event_flags &= ~EFLAG_REPEATABLE;
+ }
+ }
+ break;
+ }
+
+ for (uint32 j = 0; j < MAX_ACTIONS; j++)
+ {
+ temp.action[j].type = fields[10+(j*4)].GetUInt16();
+ temp.action[j].param1 = fields[11+(j*4)].GetUInt32();
+ temp.action[j].param2 = fields[12+(j*4)].GetUInt32();
+ temp.action[j].param3 = fields[13+(j*4)].GetUInt32();
+
+ //Report any errors in actions
+ switch (temp.action[j].type)
+ {
+ case ACTION_T_SAY:
+ case ACTION_T_YELL:
+ case ACTION_T_TEXTEMOTE:
+ if (GetEventAIText(temp.action[j].param1) == DEFAULT_TEXT)
+ error_db_log("TSCR: Event %u Action %u refrences missing Localized_Text entry", i, j+1);
+ break;
+
+ case ACTION_T_SOUND:
+ if (!GetSoundEntriesStore()->LookupEntry(temp.action[j].param1))
+ error_db_log("TSCR: Event %u Action %u uses non-existant SoundID %u.", i, j+1, temp.action[j].param1);
+ break;
+
+ case ACTION_T_RANDOM_SAY:
+ case ACTION_T_RANDOM_YELL:
+ case ACTION_T_RANDOM_TEXTEMOTE:
+ if ((temp.action[j].param1 != 0xffffffff && GetEventAIText(temp.action[j].param1) == DEFAULT_TEXT) ||
+ (temp.action[j].param2 != 0xffffffff && GetEventAIText(temp.action[j].param2) == DEFAULT_TEXT) ||
+ (temp.action[j].param3 != 0xffffffff && GetEventAIText(temp.action[j].param3) == DEFAULT_TEXT))
+ error_db_log("TSCR: Event %u Action %u refrences missing Localized_Text entry", i, j+1);
+ break;
+
+ case ACTION_T_CAST:
+ {
+ if (!GetSpellStore()->LookupEntry(temp.action[j].param1))
+ error_db_log("TSCR: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param1);
+
+ if (temp.action[j].param2 >= TARGET_T_END)
+ error_db_log("TSCR: Event %u Action %u uses incorrect Target type", i, j+1);
+ }
+ break;
+
+ case ACTION_T_REMOVEAURASFROMSPELL:
+ {
+ if (!GetSpellStore()->LookupEntry(temp.action[j].param2))
+ error_db_log("TSCR: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param2);
+
+ if (temp.action[j].param1 >= TARGET_T_END)
+ error_db_log("TSCR: Event %u Action %u uses incorrect Target type", i, j+1);
+ }
+ break;
+
+ case ACTION_T_CASTCREATUREGO:
+ {
+ if (!GetSpellStore()->LookupEntry(temp.action[j].param2))
+ error_db_log("TSCR: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param2);
+
+ if (temp.action[j].param3 >= TARGET_T_END)
+ error_db_log("TSCR: Event %u Action %u uses incorrect Target type", i, j+1);
+ }
+ break;
+
+ //2nd param target
+ case ACTION_T_SUMMON_ID:
+ {
+ if (EventAI_Summon_Map.find(temp.action[j].param3) == EventAI_Summon_Map.end())
+ error_db_log("TSCR: Event %u Action %u summons missing EventAI_Summon %u", i, j+1, temp.action[j].param3);
+
+ if (temp.action[j].param2 >= TARGET_T_END)
+ error_db_log("TSCR: Event %u Action %u uses incorrect Target type", i, j+1);
+ }
+ break;
+
+ case ACTION_T_SUMMON:
+ case ACTION_T_THREAT_SINGLE_PCT:
+ case ACTION_T_QUEST_EVENT:
+ case ACTION_T_SET_UNIT_FLAG:
+ case ACTION_T_REMOVE_UNIT_FLAG:
+ case ACTION_T_SET_INST_DATA64:
+ if (temp.action[j].param2 >= TARGET_T_END)
+ error_db_log("TSCR: Event %u Action %u uses incorrect Target type", i, j+1);
+ break;
+
+ //3rd param target
+ case ACTION_T_SET_UNIT_FIELD:
+ if (temp.action[j].param3 >= TARGET_T_END)
+ error_db_log("TSCR: Event %u Action %u uses incorrect Target type", i, j+1);
+ break;
+
+ case ACTION_T_SET_PHASE:
+ if (temp.action[j].param1 > 31)
+ error_db_log("TSCR: Event %u Action %u attempts to set phase > 31. Phase mask cannot be used past phase 31.", i, j+1);
+ break;
+
+ case ACTION_T_INC_PHASE:
+ if (!temp.action[j].param1)
+ error_db_log("TSCR: Event %u Action %u is incrementing phase by 0. Was this intended?", i, j+1);
+ break;
+
+ case ACTION_T_KILLED_MONSTER:
+ if (temp.event_type != EVENT_T_DEATH)
+ outstring_log("SD2 WARNING: Event %u Action %u calling ACTION_T_KILLED_MONSTER outside of EVENT_T_DEATH", i, j+1);
+ break;
+
+ case ACTION_T_SET_INST_DATA:
+ if (temp.action[j].param2 > 3)
+ error_db_log("TSCR: Event %u Action %u attempts to set instance data above encounter state 3. Custom case?", i, j+1);
+ break;
+
+ default:
+ if (temp.action[j].type >= ACTION_T_END)
+ error_db_log("TSCR: Event %u Action %u has incorrect action type. Maybe DB requires updated version of SD2.", i, j+1);
+ break;
+ }
+ }
+
+ //Add to list
+ EventAI_Event_List.push_back(temp);
+ ++Count;
+ } while (result->NextRow());
+
+ delete result;
+
+ outstring_log("");
+ outstring_log(">> Loaded %u EventAI scripts", Count);
+ }else
+ {
+ barGoLink bar(1);
+ bar.step();
+ outstring_log("");
+ outstring_log(">> Loaded 0 EventAI scripts. DB table `eventai_scripts` is empty.");
+ }
+
+ //Free database thread and resources
+ TScriptDB.HaltDelayThread();
+
+}
+
+struct TSpellSummary {
+ uint8 Targets; // set of enum SelectTarget
+ uint8 Effects; // set of enum SelectEffect
+}extern *SpellSummary;
+
+MANGOS_DLL_EXPORT
+void ScriptsFree()
+{
+ // Free Spell Summary
+ delete []SpellSummary;
+
+ // Free resources before library unload
+ for(int i=0;i 8)
+ {
+ Locale = 0;
+ error_log("TSCR: Locale set to invalid language id. Defaulting to 0.");
+ }
+
+ outstring_log("TSCR: Using locale %u", Locale);
+
+ EAI_ErrorLevel = TScriptConfig.GetIntDefault("EAIErrorLevel", 1);
+
+ switch (EAI_ErrorLevel)
+ {
+ case 0:
+ outstring_log("TSCR: EventAI Error Reporting level set to 0 (Startup Errors only)");
+ break;
+ case 1:
+ outstring_log("TSCR: EventAI Error Reporting level set to 1 (Startup errors and Runtime event errors)");
+ break;
+ case 2:
+ outstring_log("TSCR: EventAI Error Reporting level set to 2 (Startup errors, Runtime event errors, and Creation errors)");
+ break;
+ default:
+ outstring_log("TSCR: Unknown EventAI Error Reporting level. Defaulting to 1 (Startup errors and Runtime event errors)");
+ EAI_ErrorLevel = 1;
+ break;
+ }
+
+ outstring_log("");
+
+ //Load database (must be called after TScriptConfig.SetSource). In case it failed, no need to even try load.
+ if (CanLoadDB)
+ LoadDatabase();
+
+ outstring_log("TSCR: Loading C++ scripts");
+ barGoLink bar(1);
+ bar.step();
+ outstring_log("");
+
+ nrscripts = 0;
+ for(int i=0;i::iterator i = EventAI_LocalizedTextMap.find(entry);
+
+ if (i == EventAI_LocalizedTextMap.end())
+ {
+ error_log("TSCR: EventAI Localized Text %u not found", entry);
+ return DEFAULT_TEXT;
+ }
+
+ switch (Locale)
+ {
+ case 1:
+ temp = (*i).second.locale_1.c_str();
+ break;
+
+ case 2:
+ temp = (*i).second.locale_2.c_str();
+ break;
+
+ case 3:
+ temp = (*i).second.locale_3.c_str();
+ break;
+
+ case 4:
+ temp = (*i).second.locale_4.c_str();
+ break;
+
+ case 5:
+ temp = (*i).second.locale_5.c_str();
+ break;
+
+ case 6:
+ temp = (*i).second.locale_6.c_str();
+ break;
+
+ case 7:
+ temp = (*i).second.locale_7.c_str();
+ break;
+
+ case 8:
+ temp = (*i).second.locale_8.c_str();
+ break;
+ };
+
+ if (strlen(temp))
+ return temp;
+
+ return DEFAULT_TEXT;
+}
+
+const char* GetEventAIText(uint32 entry)
+{
+ if(entry == 0xffffffff)
+ error_log("TSCR: Entry = -1, GetEventAIText should not be called in this case.");
+
+ const char* str = NULL;
+
+ HM_NAMESPACE::hash_map::iterator itr = EventAI_Text_Map.find(entry);
+ if(itr == EventAI_Text_Map.end())
+ {
+ error_log("TSCR: Unable to find EventAI Text %u", entry);
+ return DEFAULT_TEXT;
+ }
+
+ str = (*itr).second.c_str();
+
+ if(strlen(str))
+ return str;
+
+ if(strlen((*itr).second.c_str()))
+ return (*itr).second.c_str();
+
+ return DEFAULT_TEXT;
+}
+
+void DoScriptText(int32 textEntry, WorldObject* pSource, Unit* target)
+{
+ if (!pSource)
+ {
+ error_log("TSCR: DoScriptText entry %i, invalid Source pointer.",textEntry);
+ return;
+ }
+
+ if (textEntry >= 0)
+ {
+ error_log("TSCR: DoScriptText attempts to process entry %i, but entry must be negative.",textEntry);
+ return;
+ }
+
+ HM_NAMESPACE::hash_map::iterator i = TextMap.find(textEntry);
+
+ if (i == TextMap.end())
+ {
+ error_log("TSCR: DoScriptText could not find text entry %i.",textEntry);
+ return;
+ }
+
+ if((*i).second.SoundId)
+ {
+ if( GetSoundEntriesStore()->LookupEntry((*i).second.SoundId) )
+ {
+ pSource->SendPlaySound((*i).second.SoundId, false);
+ }
+ else
+ error_log("TSCR: DoScriptText entry %i tried to process invalid sound id %u.",textEntry,(*i).second.SoundId);
+ }
+
+ switch((*i).second.Type)
+ {
+ case CHAT_TYPE_SAY:
+ pSource->MonsterSay(textEntry, (*i).second.Language, target ? target->GetGUID() : 0);
+ break;
+ case CHAT_TYPE_YELL:
+ pSource->MonsterYell(textEntry, (*i).second.Language, target ? target->GetGUID() : 0);
+ break;
+ case CHAT_TYPE_TEXT_EMOTE:
+ pSource->MonsterTextEmote(textEntry, target ? target->GetGUID() : 0);
+ break;
+ case CHAT_TYPE_BOSS_EMOTE:
+ pSource->MonsterTextEmote(textEntry, target ? target->GetGUID() : 0, true);
+ break;
+ case CHAT_TYPE_WHISPER:
+ {
+ if (target && target->GetTypeId() == TYPEID_PLAYER)
+ pSource->MonsterWhisper(textEntry, target->GetGUID());
+ else error_log("TSCR: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", textEntry);
+ }break;
+ case CHAT_TYPE_BOSS_WHISPER:
+ {
+ if (target && target->GetTypeId() == TYPEID_PLAYER)
+ pSource->MonsterWhisper(textEntry, target->GetGUID(), true);
+ else error_log("TSCR: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", textEntry);
+ }break;
+ }
+}
+
+Script* GetScriptByName(std::string Name)
+{
+ if(Name.empty())
+ return NULL;
+
+ for(int i=0;iName == Name )
+ return m_scripts[i];
+ }
+ return NULL;
+}
+
+//********************************
+//*** Functions to be Exported ***
+
+MANGOS_DLL_EXPORT
+bool GossipHello ( Player * player, Creature *_Creature )
+{
+ Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
+ if(!tmpscript || !tmpscript->pGossipHello) return false;
+
+ player->PlayerTalkClass->ClearMenus();
+ return tmpscript->pGossipHello(player,_Creature);
+}
+
+MANGOS_DLL_EXPORT
+bool GossipSelect( Player *player, Creature *_Creature, uint32 sender, uint32 action )
+{
+ debug_log("TSCR: Gossip selection, sender: %d, action: %d",sender, action);
+
+ Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
+ if(!tmpscript || !tmpscript->pGossipSelect) return false;
+
+ player->PlayerTalkClass->ClearMenus();
+ return tmpscript->pGossipSelect(player,_Creature,sender,action);
+}
+
+MANGOS_DLL_EXPORT
+bool GossipSelectWithCode( Player *player, Creature *_Creature, uint32 sender, uint32 action, const char* sCode )
+{
+ debug_log("TSCR: Gossip selection with code, sender: %d, action: %d",sender, action);
+
+ Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
+ if(!tmpscript || !tmpscript->pGossipSelectWithCode) return false;
+
+ player->PlayerTalkClass->ClearMenus();
+ return tmpscript->pGossipSelectWithCode(player,_Creature,sender,action,sCode);
+}
+
+MANGOS_DLL_EXPORT
+bool QuestAccept( Player *player, Creature *_Creature, Quest const *_Quest )
+{
+ Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
+ if(!tmpscript || !tmpscript->pQuestAccept) return false;
+
+ player->PlayerTalkClass->ClearMenus();
+ return tmpscript->pQuestAccept(player,_Creature,_Quest);
+}
+
+MANGOS_DLL_EXPORT
+bool QuestSelect( Player *player, Creature *_Creature, Quest const *_Quest )
+{
+ Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
+ if(!tmpscript || !tmpscript->pQuestSelect) return false;
+
+ player->PlayerTalkClass->ClearMenus();
+ return tmpscript->pQuestSelect(player,_Creature,_Quest);
+}
+
+MANGOS_DLL_EXPORT
+bool QuestComplete( Player *player, Creature *_Creature, Quest const *_Quest )
+{
+ Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
+ if(!tmpscript || !tmpscript->pQuestComplete) return false;
+
+ player->PlayerTalkClass->ClearMenus();
+ return tmpscript->pQuestComplete(player,_Creature,_Quest);
+}
+
+MANGOS_DLL_EXPORT
+bool ChooseReward( Player *player, Creature *_Creature, Quest const *_Quest, uint32 opt )
+{
+ Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
+ if(!tmpscript || !tmpscript->pChooseReward) return false;
+
+ player->PlayerTalkClass->ClearMenus();
+ return tmpscript->pChooseReward(player,_Creature,_Quest,opt);
+}
+
+MANGOS_DLL_EXPORT
+uint32 NPCDialogStatus( Player *player, Creature *_Creature )
+{
+ Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
+ if(!tmpscript || !tmpscript->pNPCDialogStatus) return 100;
+
+ player->PlayerTalkClass->ClearMenus();
+ return tmpscript->pNPCDialogStatus(player,_Creature);
+}
+
+MANGOS_DLL_EXPORT
+uint32 GODialogStatus( Player *player, GameObject *_GO )
+{
+ Script *tmpscript = GetScriptByName(_GO->GetGOInfo()->ScriptName);
+ if(!tmpscript || !tmpscript->pGODialogStatus) return 100;
+
+ player->PlayerTalkClass->ClearMenus();
+ return tmpscript->pGODialogStatus(player,_GO);
+}
+
+MANGOS_DLL_EXPORT
+bool ItemHello( Player *player, Item *_Item, Quest const *_Quest )
+{
+ Script *tmpscript = GetScriptByName(_Item->GetProto()->ScriptName);
+ if(!tmpscript || !tmpscript->pItemHello) return false;
+
+ player->PlayerTalkClass->ClearMenus();
+ return tmpscript->pItemHello(player,_Item,_Quest);
+}
+
+MANGOS_DLL_EXPORT
+bool ItemQuestAccept( Player *player, Item *_Item, Quest const *_Quest )
+{
+ Script *tmpscript = GetScriptByName(_Item->GetProto()->ScriptName);
+ if(!tmpscript || !tmpscript->pItemQuestAccept) return false;
+
+ player->PlayerTalkClass->ClearMenus();
+ return tmpscript->pItemQuestAccept(player,_Item,_Quest);
+}
+
+MANGOS_DLL_EXPORT
+bool GOHello( Player *player, GameObject *_GO )
+{
+ Script *tmpscript = GetScriptByName(_GO->GetGOInfo()->ScriptName);
+ if(!tmpscript || !tmpscript->pGOHello) return false;
+
+ player->PlayerTalkClass->ClearMenus();
+ return tmpscript->pGOHello(player,_GO);
+}
+
+MANGOS_DLL_EXPORT
+bool GOQuestAccept( Player *player, GameObject *_GO, Quest const *_Quest )
+{
+ Script *tmpscript = GetScriptByName(_GO->GetGOInfo()->ScriptName);
+ if(!tmpscript || !tmpscript->pGOQuestAccept) return false;
+
+ player->PlayerTalkClass->ClearMenus();
+ return tmpscript->pGOQuestAccept(player,_GO,_Quest);
+}
+
+MANGOS_DLL_EXPORT
+bool GOChooseReward( Player *player, GameObject *_GO, Quest const *_Quest, uint32 opt )
+{
+ Script *tmpscript = GetScriptByName(_GO->GetGOInfo()->ScriptName);
+ if(!tmpscript || !tmpscript->pGOChooseReward) return false;
+
+ player->PlayerTalkClass->ClearMenus();
+ return tmpscript->pGOChooseReward(player,_GO,_Quest,opt);
+}
+
+MANGOS_DLL_EXPORT
+bool AreaTrigger( Player *player, AreaTriggerEntry * atEntry)
+{
+ Script *tmpscript = NULL;
+
+ tmpscript = GetScriptByName(GetAreaTriggerScriptNameById(atEntry->id));
+ if(!tmpscript || !tmpscript->pAreaTrigger) return false;
+
+ return tmpscript->pAreaTrigger(player, atEntry);
+}
+
+MANGOS_DLL_EXPORT
+CreatureAI* GetAI(Creature *_Creature)
+{
+ Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
+
+ if(!tmpscript || !tmpscript->GetAI) return NULL;
+ return tmpscript->GetAI(_Creature);
+}
+
+MANGOS_DLL_EXPORT
+bool ItemUse( Player *player, Item* _Item, SpellCastTargets const& targets)
+{
+ Script *tmpscript = GetScriptByName(_Item->GetProto()->ScriptName);
+ if(!tmpscript || !tmpscript->pItemUse) return false;
+
+ return tmpscript->pItemUse(player,_Item,targets);
+}
+
+MANGOS_DLL_EXPORT
+bool ReceiveEmote( Player *player, Creature *_Creature, uint32 emote )
+{
+ Script *tmpscript = GetScriptByName(_Creature->GetScriptName());
+ if(!tmpscript || !tmpscript->pReceiveEmote) return false;
+
+ return tmpscript->pReceiveEmote(player, _Creature, emote);
+}
+
+MANGOS_DLL_EXPORT
+InstanceData* CreateInstanceData(Map *map)
+{
+ Script *tmpscript = NULL;
+
+ if(!map->IsDungeon()) return false;
+
+ tmpscript = GetScriptByName(((InstanceMap*)map)->GetScript());
+ if(!tmpscript || !tmpscript->GetInstanceData) return false;
+
+ return tmpscript->GetInstanceData(map);
+}
diff --git a/src/bindings/scripts/ScriptMgr.h b/src/bindings/scripts/ScriptMgr.h
index a0f541e23b0..8ff1ee3cfdd 100644
--- a/src/bindings/scripts/ScriptMgr.h
+++ b/src/bindings/scripts/ScriptMgr.h
@@ -1,94 +1,88 @@
-/* Copyright (C) 2006 - 2008 ScriptDev2
-* This program is free software licensed under GPL version 2
-* Please see the included DOCS/LICENSE.TXT for more information */
-
-#ifndef SCRIPTMGR_H
-#define SCRIPTMGR_H
-
-#include "Common.h"
-#include "Platform/CompilerDefs.h"
-#include "Database/DBCStructure.h"
-
-class Player;
-class Creature;
-class CreatureAI;
-class InstanceData;
-class Quest;
-class Item;
-class GameObject;
-class SpellCastTargets;
-class Map;
-class Unit;
-class WorldObject;
-
-#define MAX_SCRIPTS 1000 //72 bytes each (approx 71kb)
-
-//MAX visible range (size of grid)
-#define VISIBLE_RANGE (166.0f)
-
-#define DEFAULT_TEXT ""
-
-//
-struct Script
-{
- Script() :
-pGossipHello(NULL), pQuestAccept(NULL), pGossipSelect(NULL), pGossipSelectWithCode(NULL),
-pQuestSelect(NULL), pQuestComplete(NULL), pNPCDialogStatus(NULL), pGODialogStatus(NULL), pChooseReward(NULL),
-pItemHello(NULL), pGOHello(NULL), pAreaTrigger(NULL), pItemQuestAccept(NULL), pGOQuestAccept(NULL),
-pGOChooseReward(NULL),pReceiveEmote(NULL),pItemUse(NULL), GetAI(NULL), GetInstanceData(NULL)
-{}
-
-std::string Name;
-
-// -- Quest/gossip Methods to be scripted --
-bool (*pGossipHello )(Player*, Creature*);
-bool (*pQuestAccept )(Player*, Creature*, Quest const* );
-bool (*pGossipSelect )(Player*, Creature*, uint32 , uint32 );
-bool (*pGossipSelectWithCode)(Player*, Creature*, uint32 , uint32 , const char* );
-bool (*pQuestSelect )(Player*, Creature*, Quest const* );
-bool (*pQuestComplete )(Player*, Creature*, Quest const* );
-uint32 (*pNPCDialogStatus )(Player*, Creature* );
-uint32 (*pGODialogStatus )(Player *player, GameObject * _GO );
-bool (*pChooseReward )(Player*, Creature*, Quest const*, uint32 );
-bool (*pItemHello )(Player*, Item*, Quest const* );
-bool (*pGOHello )(Player*, GameObject* );
-bool (*pAreaTrigger )(Player*, AreaTriggerEntry* );
-bool (*pItemQuestAccept )(Player*, Item *, Quest const* );
-bool (*pGOQuestAccept )(Player*, GameObject*, Quest const* );
-bool (*pGOChooseReward )(Player*, GameObject*_GO, Quest const*, uint32 );
-bool (*pReceiveEmote )(Player*, Creature*, uint32 );
-bool (*pItemUse )(Player*, Item*, SpellCastTargets const& );
-
-CreatureAI* (*GetAI)(Creature*);
-InstanceData* (*GetInstanceData)(Map*);
-// -----------------------------------------
-};
-
-extern int nrscripts;
-extern Script *m_scripts[MAX_SCRIPTS];
-
-// Localized Text function
-const char* GetEventAILocalizedText(uint32 entry);
-const char* GetScriptLocalizedText(uint32 entry);
-
-//EventAI text function
-const char* GetEventAIText(uint32 entry); // TODO: Locales
-
-// Script Text function
-void ProcessScriptText(uint32 id, WorldObject* pSource, Unit* target = NULL); // TODO: Locales
-
-#if COMPILER == COMPILER_GNU
-#define FUNC_PTR(name,callconvention,returntype,parameters) typedef returntype(*name)parameters __attribute__ ((callconvention));
-#else
-#define FUNC_PTR(name, callconvention, returntype, parameters) typedef returntype(callconvention *name)parameters;
-#endif
-
-#ifdef WIN32
- #define MANGOS_DLL_EXPORT extern "C" __declspec(dllexport)
-#elif defined( __GNUC__ )
- #define MANGOS_DLL_EXPORT extern "C"
-#else
- #define MANGOS_DLL_EXPORT extern "C" export
-#endif
-
-#endif
+/* Copyright (C) 2006 - 2008 ScriptDev2
+ * This program is free software licensed under GPL version 2
+ * Please see the included DOCS/LICENSE.TXT for more information */
+
+#ifndef SCRIPTMGR_H
+#define SCRIPTMGR_H
+
+#include "Common.h"
+#include "Platform/CompilerDefs.h"
+#include "Database/DBCStructure.h"
+
+class Player;
+class Creature;
+class CreatureAI;
+class InstanceData;
+class Quest;
+class Item;
+class GameObject;
+class SpellCastTargets;
+class Map;
+class Unit;
+class WorldObject;
+
+#define MAX_SCRIPTS 1000 //72 bytes each (approx 71kb)
+#define VISIBLE_RANGE (166.0f) //MAX visible range (size of grid)
+#define DEFAULT_TEXT ""
+
+struct Script
+{
+ Script() :
+pGossipHello(NULL), pQuestAccept(NULL), pGossipSelect(NULL), pGossipSelectWithCode(NULL),
+pQuestSelect(NULL), pQuestComplete(NULL), pNPCDialogStatus(NULL), pGODialogStatus(NULL), pChooseReward(NULL),
+pItemHello(NULL), pGOHello(NULL), pAreaTrigger(NULL), pItemQuestAccept(NULL), pGOQuestAccept(NULL),
+pGOChooseReward(NULL),pReceiveEmote(NULL),pItemUse(NULL), GetAI(NULL), GetInstanceData(NULL)
+{}
+
+std::string Name;
+
+// Quest/gossip Methods to be scripted
+bool (*pGossipHello )(Player*, Creature*);
+bool (*pQuestAccept )(Player*, Creature*, Quest const* );
+bool (*pGossipSelect )(Player*, Creature*, uint32 , uint32 );
+bool (*pGossipSelectWithCode)(Player*, Creature*, uint32 , uint32 , const char* );
+bool (*pQuestSelect )(Player*, Creature*, Quest const* );
+bool (*pQuestComplete )(Player*, Creature*, Quest const* );
+uint32 (*pNPCDialogStatus )(Player*, Creature* );
+uint32 (*pGODialogStatus )(Player *player, GameObject * _GO );
+bool (*pChooseReward )(Player*, Creature*, Quest const*, uint32 );
+bool (*pItemHello )(Player*, Item*, Quest const* );
+bool (*pGOHello )(Player*, GameObject* );
+bool (*pAreaTrigger )(Player*, AreaTriggerEntry* );
+bool (*pItemQuestAccept )(Player*, Item *, Quest const* );
+bool (*pGOQuestAccept )(Player*, GameObject*, Quest const* );
+bool (*pGOChooseReward )(Player*, GameObject*_GO, Quest const*, uint32 );
+bool (*pReceiveEmote )(Player*, Creature*, uint32 );
+bool (*pItemUse )(Player*, Item*, SpellCastTargets const& );
+
+CreatureAI* (*GetAI)(Creature*);
+InstanceData* (*GetInstanceData)(Map*);
+};
+
+extern int nrscripts;
+extern Script *m_scripts[MAX_SCRIPTS];
+
+// Localized Text function
+const char* GetEventAILocalizedText(uint32 entry);
+
+//EventAI text function
+const char* GetEventAIText(uint32 entry); // TODO: Locales
+
+//Generic scripting text function
+void DoScriptText(int32 textEntry, WorldObject* pSource, Unit* target = NULL);
+
+#if COMPILER == COMPILER_GNU
+#define FUNC_PTR(name,callconvention,returntype,parameters) typedef returntype(*name)parameters __attribute__ ((callconvention));
+#else
+#define FUNC_PTR(name, callconvention, returntype, parameters) typedef returntype(callconvention *name)parameters;
+#endif
+
+#ifdef WIN32
+ #define MANGOS_DLL_EXPORT extern "C" __declspec(dllexport)
+#elif defined( __GNUC__ )
+ #define MANGOS_DLL_EXPORT extern "C"
+#else
+ #define MANGOS_DLL_EXPORT extern "C" export
+#endif
+
+#endif
diff --git a/src/bindings/scripts/scripts/zone/karazhan/boss_prince_malchezaar.cpp b/src/bindings/scripts/scripts/zone/karazhan/boss_prince_malchezaar.cpp
index 757745d7a15..40111e7c35c 100644
--- a/src/bindings/scripts/scripts/zone/karazhan/boss_prince_malchezaar.cpp
+++ b/src/bindings/scripts/scripts/zone/karazhan/boss_prince_malchezaar.cpp
@@ -399,7 +399,7 @@ struct MANGOS_DLL_DECL boss_malchezaarAI : public ScriptedAI
EnfeebleResetTimer=0;
}else EnfeebleResetTimer -= diff;
- if(m_creature->hasUnitState(UNIT_STAT_STUNDED)) //While shifting to phase 2 malchezaar stuns himself
+ if(m_creature->hasUnitState(UNIT_STAT_STUNNED)) //While shifting to phase 2 malchezaar stuns himself
return;
if(m_creature->GetUInt64Value(UNIT_FIELD_TARGET)!=m_creature->getVictim()->GetGUID())
diff --git a/src/bindings/scripts/scripts/zone/magisters_terrace/boss_priestess_delrissa.cpp b/src/bindings/scripts/scripts/zone/magisters_terrace/boss_priestess_delrissa.cpp
index a37069542cc..531fe4077aa 100644
--- a/src/bindings/scripts/scripts/zone/magisters_terrace/boss_priestess_delrissa.cpp
+++ b/src/bindings/scripts/scripts/zone/magisters_terrace/boss_priestess_delrissa.cpp
@@ -1002,7 +1002,7 @@ struct MANGOS_DLL_DECL boss_garaxxasAI : public boss_priestess_guestAI
Freezing_Trap_Timer = 30000;
}else Freezing_Trap_Timer -= diff;
- if(!m_creature->getVictim()->hasUnitState(UNIT_STAT_STUNDED | UNIT_STAT_ROOT | UNIT_STAT_CONFUSED | UNIT_STAT_DISTRACTED))
+ if(!m_creature->getVictim()->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_ROOT | UNIT_STAT_CONFUSED | UNIT_STAT_DISTRACTED))
DoMeleeAttackIfReady();
}else
{
diff --git a/src/bindings/scripts/scripts/zone/magisters_terrace/boss_selin_fireheart.cpp b/src/bindings/scripts/scripts/zone/magisters_terrace/boss_selin_fireheart.cpp
index 6f1da25f220..96f8a52ff4f 100644
--- a/src/bindings/scripts/scripts/zone/magisters_terrace/boss_selin_fireheart.cpp
+++ b/src/bindings/scripts/scripts/zone/magisters_terrace/boss_selin_fireheart.cpp
@@ -16,7 +16,7 @@
/* ScriptData
SDName: Boss_Selin_Fireheart
-SD%Complete: 99
+SD%Complete: 90
SDComment: Heroic and Normal Support. Needs further testing.
SDCategory: Magister's Terrace
EndScriptData */
@@ -73,7 +73,7 @@ struct MANGOS_DLL_DECL boss_selin_fireheartAI : public ScriptedAI
for(uint8 i = 0; i < size; ++i)
{
uint64 guid = pInstance->GetData64(DATA_FEL_CRYSTAL);
- outstring_log("Selin: Adding Fel Crystal %u to list", guid);
+ debug_log("SD2: Selin: Adding Fel Crystal %u to list", guid);
Crystals.push_back(guid);
}
}
@@ -116,9 +116,9 @@ struct MANGOS_DLL_DECL boss_selin_fireheartAI : public ScriptedAI
}
GameObject* Door = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_SELIN_ENCOUNTER_DOOR));
- if(Door)
- Door->SetGoState(0); // Close the door. Open it only in JustDied.
-
+ if( Door )
+ Door->SetGoState(0); // Open the big encounter door. Close it in Aggro and open it only in JustDied(and here)
+ // Small door opened after event are expected to be closed by default
// Set Inst data for encounter
pInstance->SetData(DATA_SELIN_EVENT, NOT_STARTED);
}else error_log(ERROR_INST_DATA);
@@ -160,10 +160,11 @@ struct MANGOS_DLL_DECL boss_selin_fireheartAI : public ScriptedAI
}
}
}
- if(CrystalChosen)
+ if( CrystalChosen )
{
DoYell(SAY_ENERGY, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(m_creature, SOUND_ENERGY);
+
CrystalChosen->CastSpell(CrystalChosen, SPELL_FEL_CRYSTAL_COSMETIC, true);
float x, y, z; // coords that we move to, close to the crystal.
@@ -185,7 +186,7 @@ struct MANGOS_DLL_DECL boss_selin_fireheartAI : public ScriptedAI
{
//Creature* pCrystal = ((Creature*)Unit::GetUnit(*m_creature, FelCrystals[i]));
Creature* pCrystal = ((Creature*)Unit::GetUnit(*m_creature, *itr));
- if(pCrystal && pCrystal->isAlive())
+ if( pCrystal && pCrystal->isAlive())
pCrystal->DealDamage(pCrystal, pCrystal->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
}
}
@@ -194,6 +195,13 @@ struct MANGOS_DLL_DECL boss_selin_fireheartAI : public ScriptedAI
{
DoYell(SAY_AGGRO, LANG_UNIVERSAL, NULL);
DoPlaySoundToSet(m_creature, SOUND_AGGRO);
+
+ if( pInstance )
+ {
+ GameObject* EncounterDoor = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_SELIN_ENCOUNTER_DOOR));
+ if( EncounterDoor )
+ EncounterDoor->SetGoState(1); //Close the encounter door, open it in JustDied/Reset
+ }
}
void KilledUnit(Unit* victim)
@@ -245,9 +253,14 @@ struct MANGOS_DLL_DECL boss_selin_fireheartAI : public ScriptedAI
}
pInstance->SetData(DATA_SELIN_EVENT, DONE); // Encounter complete!
+
GameObject* EncounterDoor = GameObject::GetGameObject((*m_creature), pInstance->GetData64(DATA_SELIN_ENCOUNTER_DOOR));
- if(EncounterDoor)
- EncounterDoor->SetGoState(1); // Open the door
+ if( EncounterDoor )
+ EncounterDoor->SetGoState(0); // Open the encounter door
+
+ GameObject* ContinueDoor = GameObject::GetGameObject(*m_creature, pInstance->GetData64(DATA_SELIN_DOOR));
+ if( ContinueDoor )
+ ContinueDoor->SetGoState(0); // Open the door leading further in
ShatterRemainingCrystals();
}
@@ -302,23 +315,27 @@ struct MANGOS_DLL_DECL boss_selin_fireheartAI : public ScriptedAI
}else
{
- if(IsDraining)
- if(EmpowerTimer < diff)
+ if( IsDraining )
{
- IsDraining = false;
- DrainingCrystal = false;
- DoYell(SAY_EMPOWERED, LANG_UNIVERSAL, NULL);
- DoPlaySoundToSet(m_creature, SOUND_EMPOWERED);
- Unit* CrystalChosen = Unit::GetUnit(*m_creature, CrystalGUID);
- if(CrystalChosen && CrystalChosen->isAlive())
- // Use Deal Damage to kill it, not setDeathState.
- CrystalChosen->DealDamage(CrystalChosen, CrystalChosen->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
+ if( EmpowerTimer < diff )
+ {
+ IsDraining = false;
+ DrainingCrystal = false;
- CrystalGUID = 0;
+ DoYell(SAY_EMPOWERED, LANG_UNIVERSAL, NULL);
+ DoPlaySoundToSet(m_creature, SOUND_EMPOWERED);
- m_creature->GetMotionMaster()->Clear();
- m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim());
- }else EmpowerTimer -= diff;
+ Unit* CrystalChosen = Unit::GetUnit(*m_creature, CrystalGUID);
+ if( CrystalChosen && CrystalChosen->isAlive() )
+ // Use Deal Damage to kill it, not setDeathState.
+ CrystalChosen->DealDamage(CrystalChosen, CrystalChosen->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
+
+ CrystalGUID = 0;
+
+ m_creature->GetMotionMaster()->Clear();
+ m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim());
+ }else EmpowerTimer -= diff;
+ }
}
DoMeleeAttackIfReady(); // No need to check if we are draining crystal here, as the spell has a stun.
diff --git a/src/bindings/scripts/scripts/zone/magisters_terrace/instance_magisters_terrace.cpp b/src/bindings/scripts/scripts/zone/magisters_terrace/instance_magisters_terrace.cpp
index b0d3e90f645..49303a06a2a 100644
--- a/src/bindings/scripts/scripts/zone/magisters_terrace/instance_magisters_terrace.cpp
+++ b/src/bindings/scripts/scripts/zone/magisters_terrace/instance_magisters_terrace.cpp
@@ -16,7 +16,7 @@
/* ScriptData
SDName: Instance_Magisters_Terrace
-SD%Complete: 100
+SD%Complete: 60
SDComment: Designed only for Selin Fireheart
SDCategory: Magister's Terrace
EndScriptData */
@@ -118,15 +118,24 @@ struct MANGOS_DLL_DECL instance_magisters_terrace : public ScriptedInstance
{
switch(entry)
{
- case 24723:
- SelinGUID = creature->GetGUID();
- break;
- case 24560:
- DelrissaGUID = creature->GetGUID();
- break;
- case 24722:
- FelCrystals.push_back(creature->GetGUID());
- break;
+ case 24723: SelinGUID = creature->GetGUID(); break;
+ case 24560: DelrissaGUID = creature->GetGUID(); break;
+ case 24722: FelCrystals.push_back(creature->GetGUID()); break;
+ }
+ }
+
+ void OnObjectCreate(GameObject* go)
+ {
+ switch(go->GetEntry())
+ {
+ case 187896: VexallusDoorGUID = go->GetGUID(); break;
+ //SunwellRaid Gate 02
+ case 187979: SelinDoorGUID = go->GetGUID(); break;
+ //Assembly Chamber Door
+ case 188065: SelinEncounterDoorGUID = go->GetGUID(); break;
+ case 187770: DelrissaDoorGUID = go->GetGUID(); break;
+ case 188165: KaelStatue[0] = go->GetGUID(); break;
+ case 188166: KaelStatue[1] = go->GetGUID(); break;
}
}
@@ -164,19 +173,6 @@ struct MANGOS_DLL_DECL instance_magisters_terrace : public ScriptedInstance
}
return 0;
}
-
- void OnObjectCreate(GameObject* go)
- {
- switch(go->GetEntry())
- {
- case 187896: VexallusDoorGUID = go->GetGUID(); break;
- case 187979: SelinDoorGUID = go->GetGUID(); break;
- case 188118: SelinEncounterDoorGUID = go->GetGUID(); break;
- case 187770: DelrissaDoorGUID = go->GetGUID(); break;
- case 188165: KaelStatue[0] = go->GetGUID(); break;
- case 188166: KaelStatue[1] = go->GetGUID(); break;
- }
- }
};
InstanceData* GetInstanceData_instance_magisters_terrace(Map* map)
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 e7bd93f5461..b2565f0e79a 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
@@ -87,7 +87,7 @@ struct MANGOS_DLL_DECL boss_twinemperorsAI : public ScriptedAI
AfterTeleportTimer = 0;
Abuse_Bug_Timer = 10000 + rand()%7000;
BugsTimer = 2000;
- m_creature->clearUnitState(UNIT_STAT_STUNDED);
+ m_creature->clearUnitState(UNIT_STAT_STUNNED);
DontYellWhenDead = false;
EnrageTimer = 15*60000;
}
@@ -290,7 +290,7 @@ struct MANGOS_DLL_DECL boss_twinemperorsAI : public ScriptedAI
DoStopAttack();
DoResetThreat();
DoCast(m_creature, SPELL_TWIN_TELEPORT_VISUAL);
- m_creature->addUnitState(UNIT_STAT_STUNDED);
+ m_creature->addUnitState(UNIT_STAT_STUNNED);
AfterTeleport = true;
AfterTeleportTimer = 2000;
tspellcasted = false;
@@ -302,9 +302,9 @@ struct MANGOS_DLL_DECL boss_twinemperorsAI : public ScriptedAI
{
if (!tspellcasted)
{
- m_creature->clearUnitState(UNIT_STAT_STUNDED);
+ m_creature->clearUnitState(UNIT_STAT_STUNNED);
DoCast(m_creature, SPELL_TWIN_TELEPORT);
- m_creature->addUnitState(UNIT_STAT_STUNDED);
+ m_creature->addUnitState(UNIT_STAT_STUNNED);
}
tspellcasted = true;
@@ -312,7 +312,7 @@ struct MANGOS_DLL_DECL boss_twinemperorsAI : public ScriptedAI
if (AfterTeleportTimer < diff)
{
AfterTeleport = false;
- m_creature->clearUnitState(UNIT_STAT_STUNDED);
+ m_creature->clearUnitState(UNIT_STAT_STUNNED);
Unit *nearu = PickNearestPlayer();
//DoYell(nearu->GetName(), LANG_UNIVERSAL, 0);
AttackStart(nearu);
diff --git a/src/bindings/scripts/sql/scriptdev2_structure.sql b/src/bindings/scripts/sql/scriptdev2_structure.sql
index 66ae5ac6cbf..122deb53357 100644
--- a/src/bindings/scripts/sql/scriptdev2_structure.sql
+++ b/src/bindings/scripts/sql/scriptdev2_structure.sql
@@ -73,31 +73,41 @@ PRIMARY KEY (`id`)
DROP TABLE IF EXISTS `script_texts`;
CREATE TABLE `script_texts` (
-`id` int(11) unsigned NOT NULL auto_increment COMMENT 'Identifier',
-`sound` int(11) unsigned NOT NULL default '0',
-`type` int(11) unsigned NOT NULL default '0',
-`language` int(11) unsigned NOT NULL default '0',
-`text` varchar(255) NOT NULL default '',
-`comment` varchar(255) NOT NULL default '',
-PRIMARY KEY (`id`)
+ `entry` mediumint(8) NOT NULL,
+ `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,
+ `sound` mediumint(8) unsigned NOT NULL default '0',
+ `type` tinyint unsigned NOT NULL default '0',
+ `language` tinyint unsigned NOT NULL default '0',
+ `comment` text,
+ PRIMARY KEY (`entry`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Script Texts';
-
-DROP TABLE IF EXISTS `script_localized_texts`;
-CREATE TABLE `script_localized_texts` (
-`id` int(11) unsigned NOT NULL auto_increment COMMENT 'Identifier',
-`locale_1` varchar(255) NOT NULL default '',
-`locale_2` varchar(255) NOT NULL default '',
-`locale_3` varchar(255) NOT NULL default '',
-`locale_4` varchar(255) NOT NULL default '',
-`locale_5` varchar(255) NOT NULL default '',
-`locale_6` varchar(255) NOT NULL default '',
-`locale_7` varchar(255) NOT NULL default '',
-`locale_8` varchar(255) NOT NULL default '',
-`comment` varchar(255) NOT NULL default '' COMMENT 'Text Comment',
-PRIMARY KEY (`id`)
-) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Localized Script Text';
-
+DROP TABLE IF EXISTS `custom_texts`;
+CREATE TABLE `custom_texts` (
+ `entry` mediumint(8) NOT NULL,
+ `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,
+ `sound` mediumint(8) unsigned NOT NULL default '0',
+ `type` tinyint unsigned NOT NULL default '0',
+ `language` tinyint unsigned NOT NULL default '0',
+ `comment` text,
+ PRIMARY KEY (`entry`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Custom Texts';
DROP TABLE IF EXISTS `script_db_version`;
CREATE TABLE `script_db_version` (
diff --git a/src/game/AggressorAI.cpp b/src/game/AggressorAI.cpp
index a4ef9e39f47..58604183660 100644
--- a/src/game/AggressorAI.cpp
+++ b/src/game/AggressorAI.cpp
@@ -47,7 +47,7 @@ AggressorAI::MoveInLineOfSight(Unit *u)
if( !i_creature.canFly() && i_creature.GetDistanceZ(u) > CREATURE_Z_ATTACK_RANGE )
return;
- if( !i_creature.getVictim() && !i_creature.hasUnitState(UNIT_STAT_STUNDED) && u->isTargetableForAttack() &&
+ if( !i_creature.getVictim() && !i_creature.hasUnitState(UNIT_STAT_STUNNED) && u->isTargetableForAttack() &&
( i_creature.IsHostileTo( u ) /*|| u->getVictim() && i_creature.IsFriendlyTo( u->getVictim() )*/ ) &&
u->isInAccessablePlaceFor(&i_creature) )
{
diff --git a/src/game/ArenaTeamHandler.cpp b/src/game/ArenaTeamHandler.cpp
index 33786e93532..58293cb96cb 100644
--- a/src/game/ArenaTeamHandler.cpp
+++ b/src/game/ArenaTeamHandler.cpp
@@ -1,462 +1,463 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS
- *
- * 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 "WorldSession.h"
-#include "WorldPacket.h"
-#include "Log.h"
-#include "Database/DatabaseEnv.h"
-#include "Player.h"
-#include "ObjectMgr.h"
-#include "ArenaTeam.h"
-#include "World.h"
-#include "SocialMgr.h"
-
-void WorldSession::HandleInspectArenaStatsOpcode(WorldPacket & recv_data)
-{
- sLog.outDebug("MSG_INSPECT_ARENA_TEAMS");
- //recv_data.hexlike();
-
- CHECK_PACKET_SIZE(recv_data, 8);
-
- uint64 guid;
- recv_data >> guid;
- sLog.outDebug("Inspect Arena stats " I64FMTD, guid);
-
- if(Player *plr = objmgr.GetPlayer(guid))
- {
- for (uint8 i = 0; i < MAX_ARENA_SLOT; i++)
- {
- if(uint32 a_id = plr->GetArenaTeamId(i))
- {
- if(ArenaTeam *at = objmgr.GetArenaTeamById(a_id))
- at->InspectStats(this, plr->GetGUID());
- }
- }
- }
-}
-
-void WorldSession::HandleArenaTeamQueryOpcode(WorldPacket & recv_data)
-{
- sLog.outDebug( "WORLD: Received CMSG_ARENA_TEAM_QUERY" );
- //recv_data.hexlike();
-
- CHECK_PACKET_SIZE(recv_data, 4);
-
- uint32 ArenaTeamId;
- recv_data >> ArenaTeamId;
-
- ArenaTeam *arenateam = objmgr.GetArenaTeamById(ArenaTeamId);
- if(!arenateam) // arena team not found
- return;
-
- arenateam->Query(this);
- arenateam->Stats(this);
-}
-
-void WorldSession::HandleArenaTeamRosterOpcode(WorldPacket & recv_data)
-{
- sLog.outDebug( "WORLD: Received CMSG_ARENA_TEAM_ROSTER" );
- //recv_data.hexlike();
-
- CHECK_PACKET_SIZE(recv_data, 4);
-
- uint32 ArenaTeamId; // arena team id
- recv_data >> ArenaTeamId;
-
- ArenaTeam *arenateam = objmgr.GetArenaTeamById(ArenaTeamId);
- if(!arenateam)
- return;
-
- arenateam->Roster(this);
-}
-
-void WorldSession::HandleArenaTeamAddMemberOpcode(WorldPacket & recv_data)
-{
- sLog.outDebug("CMSG_ARENA_TEAM_ADD_MEMBER");
- //recv_data.hexlike();
-
- CHECK_PACKET_SIZE(recv_data, 4+1);
-
- uint32 ArenaTeamId; // arena team id
- std::string Invitedname;
-
- Player * player = NULL;
-
- recv_data >> ArenaTeamId >> Invitedname;
-
- if(!Invitedname.empty())
- {
- if(!normalizePlayerName(Invitedname))
- return;
-
- player = ObjectAccessor::Instance().FindPlayerByName(Invitedname.c_str());
- }
-
- if(!player)
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", Invitedname, ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S);
- return;
- }
-
- if(player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
- {
- //SendArenaTeamCommandResult(ARENA_TEAM_INVITE_SS,"",Invitedname,ARENA_TEAM_PLAYER_NOT_FOUND_S);
- // can't find related opcode
- SendNotification("%s is not high enough level to join your team", player->GetName());
- return;
- }
-
- ArenaTeam *arenateam = objmgr.GetArenaTeamById(ArenaTeamId);
- if(!arenateam)
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM);
- return;
- }
-
- // OK result but not send invite
- if(player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow()))
- return;
-
- if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && player->GetTeam() != GetPlayer()->GetTeam())
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED);
- return;
- }
-
- if(player->GetArenaTeamId(arenateam->GetSlot()))
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, player->GetName(), "", ERR_ALREADY_IN_ARENA_TEAM_S);
- return;
- }
-
- if(player->GetArenaTeamIdInvited())
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, player->GetName(), "", ERR_ALREADY_INVITED_TO_ARENA_TEAM_S);
- return;
- }
-
- if(arenateam->GetMembersSize() >= arenateam->GetType() * 2)
- {
- // should send an "arena team is full" or the likes message, I just don't know the proper values so... ERR_INTERNAL
-// SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_INTERNAL);
- SendNotification("Your arena team is full, %s cannot join it.", player->GetName());
- return;
- }
-
- sLog.outDebug("Player %s Invited %s to Join his ArenaTeam", GetPlayer()->GetName(), Invitedname.c_str());
-
- player->SetArenaTeamIdInvited(arenateam->GetId());
-
- WorldPacket data(SMSG_ARENA_TEAM_INVITE, (8+10));
- data << GetPlayer()->GetName();
- data << arenateam->GetName();
- player->GetSession()->SendPacket(&data);
-
- sLog.outDebug("WORLD: Sent SMSG_ARENA_TEAM_INVITE");
-}
-
-void WorldSession::HandleArenaTeamInviteAcceptOpcode(WorldPacket & /*recv_data*/)
-{
- sLog.outDebug("CMSG_ARENA_TEAM_INVITE_ACCEPT"); // empty opcode
-
- ArenaTeam *at = objmgr.GetArenaTeamById(_player->GetArenaTeamIdInvited());
- if(!at)
- {
- // arena team not exist
- return;
- }
-
- if(_player->GetArenaTeamId(at->GetSlot()))
- {
- // already in arena team that size
- return;
- }
-
- // not let enemies sign petition
- if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && _player->GetTeam() != objmgr.GetPlayerTeamByGUID(at->GetCaptain()))
- return;
-
- if(!at->AddMember(_player->GetGUID()))
- return;
-
- // event
- WorldPacket data;
- BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_JOIN_SS, 2, _player->GetName(), at->GetName(), "");
- at->BroadcastPacket(&data);
-}
-
-void WorldSession::HandleArenaTeamInviteDeclineOpcode(WorldPacket & /*recv_data*/)
-{
- sLog.outDebug("CMSG_ARENA_TEAM_INVITE_DECLINE"); // empty opcode
-
- _player->SetArenaTeamIdInvited(0); // no more invited
-}
-
-void WorldSession::HandleArenaTeamLeaveOpcode(WorldPacket & recv_data)
-{
- sLog.outDebug("CMSG_ARENA_TEAM_LEAVE");
- //recv_data.hexlike();
-
- CHECK_PACKET_SIZE(recv_data, 4);
-
- uint32 ArenaTeamId; // arena team id
- recv_data >> ArenaTeamId;
-
- ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId);
- if(!at)
- {
- // send command result
- return;
- }
- if(_player->GetGUID() == at->GetCaptain() && at->GetMembersSize() > 1)
- {
- // check for correctness
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S);
- return;
- }
- // arena team has only one member (=captain)
- if(_player->GetGUID() == at->GetCaptain())
- {
- at->Disband(this);
- delete at;
- return;
- }
-
- at->DelMember(_player->GetGUID());
-
- // event
- WorldPacket data;
- BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_LEAVE_SS, 2, _player->GetName(), at->GetName(), "");
- at->BroadcastPacket(&data);
-
- //SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, at->GetName(), "", 0);
-}
-
-void WorldSession::HandleArenaTeamDisbandOpcode(WorldPacket & recv_data)
-{
- sLog.outDebug("CMSG_ARENA_TEAM_DISBAND");
- //recv_data.hexlike();
-
- CHECK_PACKET_SIZE(recv_data, 4);
-
- uint32 ArenaTeamId; // arena team id
- recv_data >> ArenaTeamId;
-
- ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId);
- if(!at)
- {
- // arena team not found
- return;
- }
-
- if(at->GetCaptain() != _player->GetGUID())
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS);
- return;
- }
-
- at->Disband(this);
- delete at;
-}
-
-void WorldSession::HandleArenaTeamRemoveFromTeamOpcode(WorldPacket & recv_data)
-{
- sLog.outDebug("CMSG_ARENA_TEAM_REMOVE_FROM_TEAM");
- //recv_data.hexlike();
-
- CHECK_PACKET_SIZE(recv_data, 4+1);
-
- uint32 ArenaTeamId;
- std::string name;
-
- recv_data >> ArenaTeamId;
- recv_data >> name;
-
- ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId);
- if(!at)
- {
- // arena team not found
- return;
- }
-
- uint64 guid = objmgr.GetPlayerGUIDByName(name);
- if(!guid)
- {
- // player guid not found
- return;
- }
-
- if(at->GetCaptain() == guid)
- {
- // unsure
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS);
- return;
- }
-
- if(at->GetCaptain() != _player->GetGUID())
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS);
- return;
- }
-
- if(at->GetCaptain() == guid)
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S);
- return;
- }
-
- at->DelMember(guid);
-
- // event
- WorldPacket data;
- BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_REMOVE_SSS, 3, name, at->GetName(), _player->GetName());
- at->BroadcastPacket(&data);
-}
-
-void WorldSession::HandleArenaTeamPromoteToCaptainOpcode(WorldPacket & recv_data)
-{
- sLog.outDebug("CMSG_ARENA_TEAM_PROMOTE_TO_CAPTAIN");
- //recv_data.hexlike();
-
- CHECK_PACKET_SIZE(recv_data, 4+1);
-
- uint32 ArenaTeamId;
- std::string name;
-
- recv_data >> ArenaTeamId;
- recv_data >> name;
-
- ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId);
- if(!at)
- {
- // arena team not found
- return;
- }
-
- uint64 guid = objmgr.GetPlayerGUIDByName(name);
- if(!guid)
- {
- // player guid not found
- return;
- }
-
- if(at->GetCaptain() == guid)
- {
- // target player already captain
- return;
- }
-
- if(at->GetCaptain() != _player->GetGUID())
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS);
- return;
- }
-
- at->SetCaptain(guid);
-
- // event
- WorldPacket data;
- BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_LEADER_CHANGED_SSS, 3, _player->GetName(), name, at->GetName());
- at->BroadcastPacket(&data);
-}
-
-void WorldSession::SendArenaTeamCommandResult(uint32 unk1, std::string str1, std::string str2, uint32 unk3)
-{
- WorldPacket data(SMSG_ARENA_TEAM_COMMAND_RESULT, 4+str1.length()+1+str2.length()+1+4);
- data << unk1;
- data << str1;
- data << str2;
- data << unk3;
- SendPacket(&data);
-}
-
-void WorldSession::BuildArenaTeamEventPacket(WorldPacket *data, uint8 eventid, uint8 str_count, std::string str1, std::string str2, std::string str3)
-{
- data->Initialize(SMSG_ARENA_TEAM_EVENT, 1+1+1);
- *data << eventid;
- *data << str_count;
- switch(str_count)
- {
- case 1:
- *data << str1;
- break;
- case 2:
- *data << str1;
- *data << str2;
- break;
- case 3:
- *data << str1;
- *data << str2;
- *data << str3;
- break;
- default:
- sLog.outError("Unhandled str_count %u in SendArenaTeamEvent()", str_count);
- return;
- }
-}
-
-void WorldSession::SendNotInArenaTeamPacket(uint8 type)
-{
- WorldPacket data(SMSG_ARENA_ERROR, 4+1); // 886 - You are not in a %uv%u arena team
- uint32 unk = 0;
- data << uint32(unk); // unk(0)
- if(!unk)
- data << uint8(type); // team type (2=2v2,3=3v3,5=5v5), can be used for custom types...
- SendPacket(&data);
-}
-
-/*
-+ERR_ARENA_NO_TEAM_II "You are not in a %dv%d arena team"
-
-+ERR_ARENA_TEAM_CREATE_S "%s created. To disband, use /teamdisband [2v2, 3v3, 5v5]."
-+ERR_ARENA_TEAM_INVITE_SS "You have invited %s to join %s"
-+ERR_ARENA_TEAM_QUIT_S "You are no longer a member of %s"
-ERR_ARENA_TEAM_FOUNDER_S "Congratulations, you are a founding member of %s! To leave, use /teamquit [2v2, 3v3, 5v5]."
-
-+ERR_ARENA_TEAM_INTERNAL "Internal arena team error"
-+ERR_ALREADY_IN_ARENA_TEAM "You are already in an arena team of that size"
-+ERR_ALREADY_IN_ARENA_TEAM_S "%s is already in an arena team of that size"
-+ERR_INVITED_TO_ARENA_TEAM "You have already been invited into an arena team"
-+ERR_ALREADY_INVITED_TO_ARENA_TEAM_S "%s has already been invited to an arena team"
-+ERR_ARENA_TEAM_NAME_INVALID "That name contains invalid characters, please enter a new name"
-+ERR_ARENA_TEAM_NAME_EXISTS_S "There is already an arena team named \"%s\""
-+ERR_ARENA_TEAM_LEADER_LEAVE_S "You must promote a new team captain using /teamcaptain before leaving the team"
-+ERR_ARENA_TEAM_PERMISSIONS "You don't have permission to do that"
-+ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM "You are not in an arena team of that size"
-+ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM_SS "%s is not in %s"
-+ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S "\"%s\" not found"
-+ERR_ARENA_TEAM_NOT_ALLIED "You cannot invite players from the opposing alliance"
-
-+ERR_ARENA_TEAM_JOIN_SS "%s has joined %s"
-+ERR_ARENA_TEAM_YOU_JOIN_S "You have joined %s. To leave, use /teamquit [2v2, 3v3, 5v5]."
-
-+ERR_ARENA_TEAM_LEAVE_SS "%s has left %s"
-
-+ERR_ARENA_TEAM_LEADER_IS_SS "%s is the captain of %s"
-+ERR_ARENA_TEAM_LEADER_CHANGED_SSS "%s has made %s the new captain of %s"
-
-+ERR_ARENA_TEAM_REMOVE_SSS "%s has been kicked out of %s by %s"
-
-+ERR_ARENA_TEAM_DISBANDED_S "%s has disbanded %s"
-
-ERR_ARENA_TEAM_TARGET_TOO_LOW_S "%s is not high enough level to join your team"
-
-ERR_ARENA_TEAM_TOO_MANY_MEMBERS_S "%s is full"
-
-ERR_ARENA_TEAM_LEVEL_TOO_LOW_I "You must be level %d to form an arena team"
-*/
+/*
+ * Copyright (C) 2005-2008 MaNGOS
+ *
+ * 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 "WorldSession.h"
+#include "WorldPacket.h"
+#include "Log.h"
+#include "Database/DatabaseEnv.h"
+#include "Player.h"
+#include "ObjectMgr.h"
+#include "ArenaTeam.h"
+#include "World.h"
+#include "SocialMgr.h"
+#include "Language.h"
+
+void WorldSession::HandleInspectArenaStatsOpcode(WorldPacket & recv_data)
+{
+ sLog.outDebug("MSG_INSPECT_ARENA_TEAMS");
+ //recv_data.hexlike();
+
+ CHECK_PACKET_SIZE(recv_data, 8);
+
+ uint64 guid;
+ recv_data >> guid;
+ sLog.outDebug("Inspect Arena stats " I64FMTD, guid);
+
+ if(Player *plr = objmgr.GetPlayer(guid))
+ {
+ for (uint8 i = 0; i < MAX_ARENA_SLOT; i++)
+ {
+ if(uint32 a_id = plr->GetArenaTeamId(i))
+ {
+ if(ArenaTeam *at = objmgr.GetArenaTeamById(a_id))
+ at->InspectStats(this, plr->GetGUID());
+ }
+ }
+ }
+}
+
+void WorldSession::HandleArenaTeamQueryOpcode(WorldPacket & recv_data)
+{
+ sLog.outDebug( "WORLD: Received CMSG_ARENA_TEAM_QUERY" );
+ //recv_data.hexlike();
+
+ CHECK_PACKET_SIZE(recv_data, 4);
+
+ uint32 ArenaTeamId;
+ recv_data >> ArenaTeamId;
+
+ ArenaTeam *arenateam = objmgr.GetArenaTeamById(ArenaTeamId);
+ if(!arenateam) // arena team not found
+ return;
+
+ arenateam->Query(this);
+ arenateam->Stats(this);
+}
+
+void WorldSession::HandleArenaTeamRosterOpcode(WorldPacket & recv_data)
+{
+ sLog.outDebug( "WORLD: Received CMSG_ARENA_TEAM_ROSTER" );
+ //recv_data.hexlike();
+
+ CHECK_PACKET_SIZE(recv_data, 4);
+
+ uint32 ArenaTeamId; // arena team id
+ recv_data >> ArenaTeamId;
+
+ ArenaTeam *arenateam = objmgr.GetArenaTeamById(ArenaTeamId);
+ if(!arenateam)
+ return;
+
+ arenateam->Roster(this);
+}
+
+void WorldSession::HandleArenaTeamAddMemberOpcode(WorldPacket & recv_data)
+{
+ sLog.outDebug("CMSG_ARENA_TEAM_ADD_MEMBER");
+ //recv_data.hexlike();
+
+ CHECK_PACKET_SIZE(recv_data, 4+1);
+
+ uint32 ArenaTeamId; // arena team id
+ std::string Invitedname;
+
+ Player * player = NULL;
+
+ recv_data >> ArenaTeamId >> Invitedname;
+
+ if(!Invitedname.empty())
+ {
+ if(!normalizePlayerName(Invitedname))
+ return;
+
+ player = ObjectAccessor::Instance().FindPlayerByName(Invitedname.c_str());
+ }
+
+ if(!player)
+ {
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", Invitedname, ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S);
+ return;
+ }
+
+ if(player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
+ {
+ //SendArenaTeamCommandResult(ARENA_TEAM_INVITE_SS,"",Invitedname,ARENA_TEAM_PLAYER_NOT_FOUND_S);
+ // can't find related opcode
+ SendNotification(LANG_HIS_ARENA_LEVEL_REQ_ERROR, player->GetName());
+ return;
+ }
+
+ ArenaTeam *arenateam = objmgr.GetArenaTeamById(ArenaTeamId);
+ if(!arenateam)
+ {
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM);
+ return;
+ }
+
+ // OK result but not send invite
+ if(player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow()))
+ return;
+
+ if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && player->GetTeam() != GetPlayer()->GetTeam())
+ {
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_NOT_ALLIED);
+ return;
+ }
+
+ if(player->GetArenaTeamId(arenateam->GetSlot()))
+ {
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, player->GetName(), "", ERR_ALREADY_IN_ARENA_TEAM_S);
+ return;
+ }
+
+ if(player->GetArenaTeamIdInvited())
+ {
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, player->GetName(), "", ERR_ALREADY_INVITED_TO_ARENA_TEAM_S);
+ return;
+ }
+
+ if(arenateam->GetMembersSize() >= arenateam->GetType() * 2)
+ {
+ // should send an "arena team is full" or the likes message, I just don't know the proper values so... ERR_INTERNAL
+// SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_INTERNAL);
+ SendNotification(LANG_YOUR_ARENA_TEAM_FULL, player->GetName());
+ return;
+ }
+
+ sLog.outDebug("Player %s Invited %s to Join his ArenaTeam", GetPlayer()->GetName(), Invitedname.c_str());
+
+ player->SetArenaTeamIdInvited(arenateam->GetId());
+
+ WorldPacket data(SMSG_ARENA_TEAM_INVITE, (8+10));
+ data << GetPlayer()->GetName();
+ data << arenateam->GetName();
+ player->GetSession()->SendPacket(&data);
+
+ sLog.outDebug("WORLD: Sent SMSG_ARENA_TEAM_INVITE");
+}
+
+void WorldSession::HandleArenaTeamInviteAcceptOpcode(WorldPacket & /*recv_data*/)
+{
+ sLog.outDebug("CMSG_ARENA_TEAM_INVITE_ACCEPT"); // empty opcode
+
+ ArenaTeam *at = objmgr.GetArenaTeamById(_player->GetArenaTeamIdInvited());
+ if(!at)
+ {
+ // arena team not exist
+ return;
+ }
+
+ if(_player->GetArenaTeamId(at->GetSlot()))
+ {
+ // already in arena team that size
+ return;
+ }
+
+ // not let enemies sign petition
+ if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && _player->GetTeam() != objmgr.GetPlayerTeamByGUID(at->GetCaptain()))
+ return;
+
+ if(!at->AddMember(_player->GetGUID()))
+ return;
+
+ // event
+ WorldPacket data;
+ BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_JOIN_SS, 2, _player->GetName(), at->GetName(), "");
+ at->BroadcastPacket(&data);
+}
+
+void WorldSession::HandleArenaTeamInviteDeclineOpcode(WorldPacket & /*recv_data*/)
+{
+ sLog.outDebug("CMSG_ARENA_TEAM_INVITE_DECLINE"); // empty opcode
+
+ _player->SetArenaTeamIdInvited(0); // no more invited
+}
+
+void WorldSession::HandleArenaTeamLeaveOpcode(WorldPacket & recv_data)
+{
+ sLog.outDebug("CMSG_ARENA_TEAM_LEAVE");
+ //recv_data.hexlike();
+
+ CHECK_PACKET_SIZE(recv_data, 4);
+
+ uint32 ArenaTeamId; // arena team id
+ recv_data >> ArenaTeamId;
+
+ ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId);
+ if(!at)
+ {
+ // send command result
+ return;
+ }
+ if(_player->GetGUID() == at->GetCaptain() && at->GetMembersSize() > 1)
+ {
+ // check for correctness
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S);
+ return;
+ }
+ // arena team has only one member (=captain)
+ if(_player->GetGUID() == at->GetCaptain())
+ {
+ at->Disband(this);
+ delete at;
+ return;
+ }
+
+ at->DelMember(_player->GetGUID());
+
+ // event
+ WorldPacket data;
+ BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_LEAVE_SS, 2, _player->GetName(), at->GetName(), "");
+ at->BroadcastPacket(&data);
+
+ //SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, at->GetName(), "", 0);
+}
+
+void WorldSession::HandleArenaTeamDisbandOpcode(WorldPacket & recv_data)
+{
+ sLog.outDebug("CMSG_ARENA_TEAM_DISBAND");
+ //recv_data.hexlike();
+
+ CHECK_PACKET_SIZE(recv_data, 4);
+
+ uint32 ArenaTeamId; // arena team id
+ recv_data >> ArenaTeamId;
+
+ ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId);
+ if(!at)
+ {
+ // arena team not found
+ return;
+ }
+
+ if(at->GetCaptain() != _player->GetGUID())
+ {
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS);
+ return;
+ }
+
+ at->Disband(this);
+ delete at;
+}
+
+void WorldSession::HandleArenaTeamRemoveFromTeamOpcode(WorldPacket & recv_data)
+{
+ sLog.outDebug("CMSG_ARENA_TEAM_REMOVE_FROM_TEAM");
+ //recv_data.hexlike();
+
+ CHECK_PACKET_SIZE(recv_data, 4+1);
+
+ uint32 ArenaTeamId;
+ std::string name;
+
+ recv_data >> ArenaTeamId;
+ recv_data >> name;
+
+ ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId);
+ if(!at)
+ {
+ // arena team not found
+ return;
+ }
+
+ uint64 guid = objmgr.GetPlayerGUIDByName(name);
+ if(!guid)
+ {
+ // player guid not found
+ return;
+ }
+
+ if(at->GetCaptain() == guid)
+ {
+ // unsure
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS);
+ return;
+ }
+
+ if(at->GetCaptain() != _player->GetGUID())
+ {
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS);
+ return;
+ }
+
+ if(at->GetCaptain() == guid)
+ {
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S);
+ return;
+ }
+
+ at->DelMember(guid);
+
+ // event
+ WorldPacket data;
+ BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_REMOVE_SSS, 3, name, at->GetName(), _player->GetName());
+ at->BroadcastPacket(&data);
+}
+
+void WorldSession::HandleArenaTeamPromoteToCaptainOpcode(WorldPacket & recv_data)
+{
+ sLog.outDebug("CMSG_ARENA_TEAM_PROMOTE_TO_CAPTAIN");
+ //recv_data.hexlike();
+
+ CHECK_PACKET_SIZE(recv_data, 4+1);
+
+ uint32 ArenaTeamId;
+ std::string name;
+
+ recv_data >> ArenaTeamId;
+ recv_data >> name;
+
+ ArenaTeam *at = objmgr.GetArenaTeamById(ArenaTeamId);
+ if(!at)
+ {
+ // arena team not found
+ return;
+ }
+
+ uint64 guid = objmgr.GetPlayerGUIDByName(name);
+ if(!guid)
+ {
+ // player guid not found
+ return;
+ }
+
+ if(at->GetCaptain() == guid)
+ {
+ // target player already captain
+ return;
+ }
+
+ if(at->GetCaptain() != _player->GetGUID())
+ {
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, "", "", ERR_ARENA_TEAM_PERMISSIONS);
+ return;
+ }
+
+ at->SetCaptain(guid);
+
+ // event
+ WorldPacket data;
+ BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_LEADER_CHANGED_SSS, 3, _player->GetName(), name, at->GetName());
+ at->BroadcastPacket(&data);
+}
+
+void WorldSession::SendArenaTeamCommandResult(uint32 unk1, std::string str1, std::string str2, uint32 unk3)
+{
+ WorldPacket data(SMSG_ARENA_TEAM_COMMAND_RESULT, 4+str1.length()+1+str2.length()+1+4);
+ data << unk1;
+ data << str1;
+ data << str2;
+ data << unk3;
+ SendPacket(&data);
+}
+
+void WorldSession::BuildArenaTeamEventPacket(WorldPacket *data, uint8 eventid, uint8 str_count, std::string str1, std::string str2, std::string str3)
+{
+ data->Initialize(SMSG_ARENA_TEAM_EVENT, 1+1+1);
+ *data << eventid;
+ *data << str_count;
+ switch(str_count)
+ {
+ case 1:
+ *data << str1;
+ break;
+ case 2:
+ *data << str1;
+ *data << str2;
+ break;
+ case 3:
+ *data << str1;
+ *data << str2;
+ *data << str3;
+ break;
+ default:
+ sLog.outError("Unhandled str_count %u in SendArenaTeamEvent()", str_count);
+ return;
+ }
+}
+
+void WorldSession::SendNotInArenaTeamPacket(uint8 type)
+{
+ WorldPacket data(SMSG_ARENA_ERROR, 4+1); // 886 - You are not in a %uv%u arena team
+ uint32 unk = 0;
+ data << uint32(unk); // unk(0)
+ if(!unk)
+ data << uint8(type); // team type (2=2v2,3=3v3,5=5v5), can be used for custom types...
+ SendPacket(&data);
+}
+
+/*
++ERR_ARENA_NO_TEAM_II "You are not in a %dv%d arena team"
+
++ERR_ARENA_TEAM_CREATE_S "%s created. To disband, use /teamdisband [2v2, 3v3, 5v5]."
++ERR_ARENA_TEAM_INVITE_SS "You have invited %s to join %s"
++ERR_ARENA_TEAM_QUIT_S "You are no longer a member of %s"
+ERR_ARENA_TEAM_FOUNDER_S "Congratulations, you are a founding member of %s! To leave, use /teamquit [2v2, 3v3, 5v5]."
+
++ERR_ARENA_TEAM_INTERNAL "Internal arena team error"
++ERR_ALREADY_IN_ARENA_TEAM "You are already in an arena team of that size"
++ERR_ALREADY_IN_ARENA_TEAM_S "%s is already in an arena team of that size"
++ERR_INVITED_TO_ARENA_TEAM "You have already been invited into an arena team"
++ERR_ALREADY_INVITED_TO_ARENA_TEAM_S "%s has already been invited to an arena team"
++ERR_ARENA_TEAM_NAME_INVALID "That name contains invalid characters, please enter a new name"
++ERR_ARENA_TEAM_NAME_EXISTS_S "There is already an arena team named \"%s\""
++ERR_ARENA_TEAM_LEADER_LEAVE_S "You must promote a new team captain using /teamcaptain before leaving the team"
++ERR_ARENA_TEAM_PERMISSIONS "You don't have permission to do that"
++ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM "You are not in an arena team of that size"
++ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM_SS "%s is not in %s"
++ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S "\"%s\" not found"
++ERR_ARENA_TEAM_NOT_ALLIED "You cannot invite players from the opposing alliance"
+
++ERR_ARENA_TEAM_JOIN_SS "%s has joined %s"
++ERR_ARENA_TEAM_YOU_JOIN_S "You have joined %s. To leave, use /teamquit [2v2, 3v3, 5v5]."
+
++ERR_ARENA_TEAM_LEAVE_SS "%s has left %s"
+
++ERR_ARENA_TEAM_LEADER_IS_SS "%s is the captain of %s"
++ERR_ARENA_TEAM_LEADER_CHANGED_SSS "%s has made %s the new captain of %s"
+
++ERR_ARENA_TEAM_REMOVE_SSS "%s has been kicked out of %s by %s"
+
++ERR_ARENA_TEAM_DISBANDED_S "%s has disbanded %s"
+
+ERR_ARENA_TEAM_TARGET_TOO_LOW_S "%s is not high enough level to join your team"
+
+ERR_ARENA_TEAM_TOO_MANY_MEMBERS_S "%s is full"
+
+ERR_ARENA_TEAM_LEVEL_TOO_LOW_I "You must be level %d to form an arena team"
+*/
diff --git a/src/game/BattleGroundHandler.cpp b/src/game/BattleGroundHandler.cpp
index 486f828fbda..eb9a593decf 100644
--- a/src/game/BattleGroundHandler.cpp
+++ b/src/game/BattleGroundHandler.cpp
@@ -1,952 +1,952 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS
- *
- * 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 "WorldPacket.h"
-#include "Opcodes.h"
-#include "Log.h"
-#include "Player.h"
-#include "ObjectMgr.h"
-#include "WorldSession.h"
-#include "MapManager.h"
-#include "ObjectAccessor.h"
-#include "Object.h"
-#include "Chat.h"
-#include "Language.h"
-#include "BattleGroundMgr.h"
-#include "BattleGroundWS.h"
-#include "BattleGround.h"
-#include "ArenaTeam.h"
-
-void WorldSession::HandleBattleGroundHelloOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 8);
-
- uint64 guid;
- recv_data >> guid;
- sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_HELLO Message from: " I64FMT, guid);
-
- Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
- if(!unit)
- return;
-
- if(!unit->isBattleMaster()) // it's not battlemaster
- return;
-
- // Stop the npc if moving
- unit->StopMoving();
-
- uint32 bgTypeId = objmgr.GetBattleMasterBG(unit->GetEntry());
-
- if(!_player->GetBGAccessByLevel(bgTypeId))
- {
- // temp, must be gossip message...
- SendNotification("You don't meet Battleground level requirements");
- return;
- }
-
- SendBattlegGroundList(guid, bgTypeId);
-}
-
-void WorldSession::SendBattlegGroundList( uint64 guid, uint32 bgTypeId )
-{
- WorldPacket data;
- sBattleGroundMgr.BuildBattleGroundListPacket(&data, guid, _player, bgTypeId);
- SendPacket( &data );
-}
-
-void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 8+4+4+1);
-
- uint64 guid;
- uint32 bgTypeId;
- uint32 instanceId;
- uint8 joinAsGroup;
- Group * grp;
-
- recv_data >> guid; // battlemaster guid
- recv_data >> bgTypeId; // battleground type id (DBC id)
- recv_data >> instanceId; // instance id, 0 if First Available selected
- recv_data >> joinAsGroup; // join as group
-
- if(bgTypeId >= MAX_BATTLEGROUND_TYPES)
- {
- sLog.outError("Battleground: invalid bgtype received. possible cheater? player guid %u",_player->GetGUIDLow());
- return;
- }
-
- sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from: " I64FMT, guid);
-
- // can do this, since it's battleground, not arena
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, 0);
-
- // ignore if we already in BG or BG queue
- if(_player->InBattleGround())
- return;
-
- Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
- if(!unit)
- return;
-
- if(!unit->isBattleMaster()) // it's not battlemaster
- return;
-
- // get bg instance or bg template if instance not found
- BattleGround * bg = 0;
- if(instanceId)
- BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId);
-
- if(!bg && !(bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId)))
- {
- sLog.outError("Battleground: no available bg / template found");
- return;
- }
-
- // check queueing conditions
- if(!joinAsGroup)
- {
- // check Deserter debuff
- if( !_player->CanJoinToBattleground() )
- {
- WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
- data << (uint32) 0xFFFFFFFE;
- _player->GetSession()->SendPacket(&data);
- return;
- }
- // check if already in queue
- if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
- //player is already in this queue
- return;
- // check if has free queue slots
- if(!_player->HasFreeBattleGroundQueueId())
- return;
- }
- else
- {
- grp = _player->GetGroup();
- // no group found, error
- if(!grp)
- return;
- uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0);
- switch(err)
- {
- // TODO: add error-based feedback to players in all cases
- case BG_JOIN_ERR_GROUP_TOO_MANY:
- {
- WorldPacket data;
- ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_TOO_LARGE), NULL);
- SendPacket(&data);
- }
- return;
- break;
- case BG_JOIN_ERR_OFFLINE_MEMBER:
- {
- WorldPacket data;
- ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_OFFLINE_MEMBER), NULL);
- SendPacket(&data);
- }
- return;
- break;
- case BG_JOIN_ERR_MIXED_FACTION:
- {
- WorldPacket data;
- ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MIXED_FACTION), NULL);
- SendPacket(&data);
- }
- return;
- break;
- case BG_JOIN_ERR_MIXED_LEVELS:
- {
- WorldPacket data;
- ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MIXED_LEVELS), NULL);
- SendPacket(&data);
- }
- return;
- break;
- case BG_JOIN_ERR_GROUP_MEMBER_ALREADY_IN_QUEUE:
- {
- WorldPacket data;
- ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE), NULL);
- SendPacket(&data);
- }
- return;
- break;
- case BG_JOIN_ERR_GROUP_DESERTER:
- {
- WorldPacket data;
- ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MEMBER_DESERTER), NULL);
- SendPacket(&data);
- }
- return;
- break;
- case BG_JOIN_ERR_ALL_QUEUES_USED:
- {
- WorldPacket data;
- ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS), NULL);
- SendPacket(&data);
- }
- return;
- break;
- // all ok, can join
- case BG_JOIN_ERR_OK:
- break;
- // these aren't possible outcomes in bgs
- case BG_JOIN_ERR_GROUP_NOT_ENOUGH:
- case BG_JOIN_ERR_MIXED_ARENATEAM:
- return;
- break;
- // not the above? shouldn't happen, don't let join
- default:
- return;
- break;
- };
- }
-
- // if we're here, then the conditions to join a bg are met. We can proceed in joining.
-
- // _player->GetGroup() was already checked, grp is already initialized
- if(joinAsGroup /* && _player->GetGroup()*/)
- {
- sLog.outDebug("Battleground: the following players are joining as group:");
- GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, 0);
- for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
- {
- Player *member = itr->getSource();
- if(!member) continue; // this should never happen
-
- uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId); // add to queue
-
- // store entry point coords (same as leader entry point)
- member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
-
- WorldPacket data;
- // send status packet (in queue)
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);
- member->GetSession()->SendPacket(&data);
- sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
- member->GetSession()->SendPacket(&data);
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo);
- sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName());
- }
- sLog.outDebug("Battleground: group end");
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel());
- }
- else
- {
- // already checked if queueSlot is valid, now just get it
- uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
- // store entry point coords
- _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
-
- WorldPacket data;
- // send status packet (in queue)
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);
- SendPacket(&data);
-
- GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, 0);
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel());
- sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName());
- }
-}
-
-void WorldSession::HandleBattleGroundPlayerPositionsOpcode( WorldPacket & /*recv_data*/ )
-{
- // empty opcode
- sLog.outDebug("WORLD: Recvd MSG_BATTLEGROUND_PLAYER_POSITIONS Message");
-
- BattleGround *bg = _player->GetBattleGround();
- if(!bg) // can't be received if player not in battleground
- return;
-
- if(bg->GetTypeID() == BATTLEGROUND_WS)
- {
- uint32 count1 = 0;
- uint32 count2 = 0;
-
- Player *ap = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetAllianceFlagPickerGUID());
- if(ap) ++count2;
-
- Player *hp = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetHordeFlagPickerGUID());
- if(hp) ++count2;
-
- WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4+16*count1+16*count2));
- data << count1; // alliance flag holders count
- /*for(uint8 i = 0; i < count1; i++)
- {
- data << uint64(0); // guid
- data << (float)0; // x
- data << (float)0; // y
- }*/
- data << count2; // horde flag holders count
- if(ap)
- {
- data << (uint64)ap->GetGUID();
- data << (float)ap->GetPositionX();
- data << (float)ap->GetPositionY();
- }
- if(hp)
- {
- data << (uint64)hp->GetGUID();
- data << (float)hp->GetPositionX();
- data << (float)hp->GetPositionY();
- }
-
- SendPacket(&data);
- }
-}
-
-void WorldSession::HandleBattleGroundPVPlogdataOpcode( WorldPacket & /*recv_data*/ )
-{
- sLog.outDebug( "WORLD: Recvd MSG_PVP_LOG_DATA Message");
-
- BattleGround *bg = _player->GetBattleGround();
- if(!bg)
- return;
-
- WorldPacket data;
- sBattleGroundMgr.BuildPvpLogDataPacket(&data, bg);
- SendPacket(&data);
-
- sLog.outDebug( "WORLD: Sent MSG_PVP_LOG_DATA Message");
-}
-
-void WorldSession::HandleBattleGroundListOpcode( WorldPacket &recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 4);
-
- sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message");
-
- uint32 bgTypeId;
- recv_data >> bgTypeId; // id from DBC
-
- if(bgTypeId >= MAX_BATTLEGROUND_TYPES)
- {
- sLog.outError("Battleground: invalid bgtype received.");
- return;
- }
-
- BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
-
- if(!bl)
- return;
-
- WorldPacket data;
- sBattleGroundMgr.BuildBattleGroundListPacket(&data, _player->GetGUID(), _player, bgTypeId);
- SendPacket( &data );
-}
-
-void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 1+1+4+2+1);
-
- sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message");
-
- uint8 type; // arenatype if arena
- uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1
- uint32 instanceId;
- uint32 bgTypeId; // type id from dbc
- uint16 unk; // 0x1F90 constant?
- uint8 action; // enter battle 0x1, leave queue 0x0
-
- recv_data >> type >> unk2 >> bgTypeId >> unk >> action;
-
- if(bgTypeId >= MAX_BATTLEGROUND_TYPES)
- {
- sLog.outError("Battleground: invalid bgtype received.");
- // update battleground slots for the player to fix his UI and sent data.
- // this is a HACK, I don't know why the client starts sending invalid packets in the first place.
- // it usually happens with extremely high latency (if debugging / stepping in the code for example)
- if(_player->InBattleGroundQueue())
- {
- // update all queues, send invitation info if player is invited, queue info if queued
- for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
- {
- uint32 queue_id = _player->GetBattleGroundQueueId(i);
- if(!queue_id)
- continue;
- BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
- // if the player is not in queue, contine
- if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())
- continue;
-
- // no group information, this should never happen
- if(!itrPlayerStatus->second.GroupInfo)
- continue;
-
- BattleGround * bg = NULL;
-
- // get possibly needed data from groupinfo
- bgTypeId = itrPlayerStatus->second.GroupInfo->BgTypeId;
- uint8 arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;
- uint8 israted = itrPlayerStatus->second.GroupInfo->IsRated;
- uint8 status = 0;
-
-
- if(!itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID)
- {
- // not invited to bg, get template
- bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
- status = STATUS_WAIT_QUEUE;
- }
- else
- {
- // get the bg we're invited to
- BattleGround * bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID);
- status = STATUS_WAIT_JOIN;
- }
-
- // if bg not found, then continue
- if(!bg)
- continue;
-
- // don't invite if already in the instance
- if(_player->InBattleGround() && _player->GetBattleGround() && _player->GetBattleGround()->GetInstanceID() == bg->GetInstanceID())
- continue;
-
- // re - invite player with proper data
- WorldPacket data;
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, itrPlayerStatus->second.GroupInfo->Team?itrPlayerStatus->second.GroupInfo->Team:_player->GetTeam(), i, status, INVITE_ACCEPT_WAIT_TIME, 0, arenatype, israted);
- SendPacket(&data);
- }
- }
- return;
- }
-
- uint32 bgQueueTypeId = 0;
- // get the bg what we were invited to
- BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus;
- bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId,type);
- itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
-
- if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())
- {
- sLog.outError("Battleground: itrplayerstatus not found.");
- return;
- }
- instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID;
-
- // if action == 1, then instanceId is _required_
- if(!instanceId && action == 1)
- {
- sLog.outError("Battleground: instance not found.");
- return;
- }
-
- BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId);
-
- // bg template might and must be used in case of leaving queue, when instance is not created yet
- if(!bg && action == 0)
- bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
-
- if(!bg)
- {
- sLog.outError("Battleground: bg not found.");
- return;
- }
-
- bgTypeId = bg->GetTypeID();
-
- if(_player->InBattleGroundQueue())
- {
- uint32 queueSlot = 0;
- uint32 team = 0;
- uint32 arenatype = 0;
- uint32 israted = 0;
- uint32 rating = 0;
- // get the team info from the queue
- BattleGroundQueue::QueuedPlayersMap::iterator pitr = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
- if(pitr !=sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end()
- && pitr->second.GroupInfo )
- {
- team = pitr->second.GroupInfo->Team;
- arenatype = pitr->second.GroupInfo->ArenaType;
- israted = pitr->second.GroupInfo->IsRated;
- rating = pitr->second.GroupInfo->ArenaTeamRating;
- }
- else
- {
- sLog.outError("Battleground: Invalid player queue info!");
- return;
- }
- WorldPacket data;
- switch(action)
- {
- case 1: // port to battleground
- if(!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId))
- return; // cheating?
- // resurrect the player
- if(!_player->isAlive())
- {
- _player->ResurrectPlayer(1.0f,false);
- _player->SpawnCorpseBones();
- }
- // stop taxi flight at port
- if(_player->isInFlight())
- {
- _player->GetMotionMaster()->MovementExpired();
- _player->m_taxi.ClearTaxiDestinations();
- }
- _player->RemoveFromGroup();
- queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime());
- _player->GetSession()->SendPacket(&data);
- // remove battleground queue status from BGmgr
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), false);
- // this is still needed here if battleground "jumping" shouldn't add deserter debuff
- // also this required to prevent stuck at old battleground after SetBattleGroundId set to new
- if( BattleGround *currentBg = _player->GetBattleGround() )
- currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
-
- // set the destination instance id
- _player->SetBattleGroundId(bg->GetInstanceID());
- // set the destination team
- _player->SetBGTeam(team);
- // bg->HandleBeforeTeleportToBattleGround(_player);
- sBattleGroundMgr.SendToBattleGround(_player, instanceId);
- // add only in HandleMoveWorldPortAck()
- // bg->AddPlayer(_player,team);
- sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.",_player->GetName(),_player->GetGUIDLow(),bg->GetInstanceID(),bg->GetTypeID(),bgQueueTypeId);
- break;
- case 0: // leave queue
- queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
- _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_NONE, 0, 0);
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true);
- // player left queue, we should update it, maybe now his group fits in
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId,_player->GetBattleGroundQueueIdFromLevel(),arenatype,israted,rating);
- SendPacket(&data);
- sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.",_player->GetName(),_player->GetGUIDLow(),bg->GetTypeID(),bgQueueTypeId);
- break;
- default:
- sLog.outError("Battleground port: unknown action %u", action);
- break;
- }
- }
-}
-
-void WorldSession::HandleBattleGroundLeaveOpcode( WorldPacket & /*recv_data*/ )
-{
- //CHECK_PACKET_SIZE(recv_data, 1+1+4+2);
-
- sLog.outDebug( "WORLD: Recvd CMSG_LEAVE_BATTLEFIELD Message");
-
- //uint8 unk1, unk2;
- //uint32 bgTypeId; // id from DBC
- //uint16 unk3;
-
- //recv_data >> unk1 >> unk2 >> bgTypeId >> unk3; - no used currently
-
- //if(bgTypeId >= MAX_BATTLEGROUND_TYPES) // cheating? but not important in this case
- // return;
-
- // not allow leave battleground in combat
- if(_player->isInCombat())
- if(BattleGround* bg = _player->GetBattleGround())
- if(bg->GetStatus() != STATUS_WAIT_LEAVE)
- return;
-
- _player->LeaveBattleground();
-}
-
-void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ )
-{
- // empty opcode
- sLog.outDebug( "WORLD: Battleground status" );
-
- WorldPacket data;
-
- // TODO: we must put player back to battleground in case disconnect (< 5 minutes offline time) or teleport player on login(!) from battleground map to entry point
- if(_player->InBattleGround())
- {
- BattleGround *bg = _player->GetBattleGround();
- if(bg)
- {
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
- uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
- if((bg->GetStatus() <= STATUS_IN_PROGRESS))
- {
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime());
- SendPacket(&data);
- }
- for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
- {
- uint32 queue_id = _player->GetBattleGroundQueueId(i); // battlegroundqueueid stores the type id, not the instance id, so this is definitely wrong
- uint8 arenatype = sBattleGroundMgr.BGArenaType(queue_id);
- uint8 isRated = 0;
- if (i == queueSlot || !queue_id) // we need to get the instance ids
- continue;
- BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
- if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())
- continue;
- if(itrPlayerStatus->second.GroupInfo)
- {
- arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;
- isRated = itrPlayerStatus->second.GroupInfo->IsRated;
- }
- BattleGround *bg2 = sBattleGroundMgr.GetBattleGroundTemplate(sBattleGroundMgr.BGTemplateId(queue_id)); // try this
- if(bg2)
- {
- //in this call is small bug, this call should be filled by player's waiting time in queue
- //this call nulls all timers for client :
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg2, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0,arenatype,isRated);
- SendPacket(&data);
- }
- }
- }
- }
- else
- {
- // we should update all queues? .. i'm not sure if this code is correct
- for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
- {
- uint32 queue_id = _player->GetBattleGroundQueueId(i);
- if(!queue_id)
- continue;
- uint32 bgTypeId = sBattleGroundMgr.BGTemplateId(queue_id);
- uint8 arenatype = sBattleGroundMgr.BGArenaType(queue_id);
- uint8 isRated = 0;
- BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
- BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
- if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())
- continue;
- if(itrPlayerStatus->second.GroupInfo)
- {
- arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;
- isRated = itrPlayerStatus->second.GroupInfo->IsRated;
- }
- if(bg && queue_id)
- {
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated);
- SendPacket(&data);
- }
- }
- }
-/* else // not sure if it needed...
- {
- for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
- {
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, NULL, _player->GetTeam(),i , STATUS_NONE, 0, 0);
- SendPacket(&data);
- }
- }*/
-}
-
-void WorldSession::HandleAreaSpiritHealerQueryOpcode( WorldPacket & recv_data )
-{
- sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUERY");
-
- CHECK_PACKET_SIZE(recv_data, 8);
-
- BattleGround *bg = _player->GetBattleGround();
- if(!bg)
- return;
-
- uint64 guid;
- recv_data >> guid;
-
- Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
- if(!unit)
- return;
-
- if(!unit->isSpiritService()) // it's not spirit service
- return;
-
- sBattleGroundMgr.SendAreaSpiritHealerQueryOpcode(_player, bg, guid);
-}
-
-void WorldSession::HandleAreaSpiritHealerQueueOpcode( WorldPacket & recv_data )
-{
- sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUEUE");
-
- CHECK_PACKET_SIZE(recv_data, 8);
-
- BattleGround *bg = _player->GetBattleGround();
- if(!bg)
- return;
-
- uint64 guid;
- recv_data >> guid;
-
- Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
- if(!unit)
- return;
-
- if(!unit->isSpiritService()) // it's not spirit service
- return;
-
- bg->AddPlayerToResurrectQueue(guid, _player->GetGUID());
-}
-
-void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 8+1+1+1);
-
- sLog.outDebug("WORLD: CMSG_BATTLEMASTER_JOIN_ARENA");
- recv_data.hexlike();
-
- // ignore if we already in BG or BG queue
- if(_player->InBattleGround())
- return;
-
- uint64 guid; // arena Battlemaster guid
- uint8 type; // 2v2, 3v3 or 5v5
- uint8 asGroup; // asGroup
- uint8 isRated; // isRated
- Group * grp;
-
- recv_data >> guid >> type >> asGroup >> isRated;
-
- Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
- if(!unit)
- return;
-
- if(!unit->isBattleMaster()) // it's not battle master
- return;
-
- uint8 arenatype = 0;
- uint32 arenaRating = 0;
-
- switch(type)
- {
- case 0:
- arenatype = ARENA_TYPE_2v2;
- break;
- case 1:
- arenatype = ARENA_TYPE_3v3;
- break;
- case 2:
- arenatype = ARENA_TYPE_5v5;
- break;
- default:
- sLog.outError("Unknown arena type %u at HandleBattleGroundArenaJoin()", type);
- return;
- }
-
- //check existance
- BattleGround* bg = NULL;
- if( !(bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA)) )
- {
- sLog.outError("Battleground: template bg (all arenas) not found");
- return;
- }
-
- uint8 bgTypeId = bg->GetTypeID();
- uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, arenatype);
-
- // check queueing conditions
- if(!asGroup)
- {
- // check if already in queue
- if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
- //player is already in this queue
- return;
- // check if has free queue slots
- if(!_player->HasFreeBattleGroundQueueId())
- return;
- }
- else
- {
- grp = _player->GetGroup();
- // no group found, error
- if(!grp)
- return;
- uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, arenatype, arenatype, (bool)isRated, type);
- switch(err)
- {
- // TODO: add error-based feedback to players in all cases
- case BG_JOIN_ERR_GROUP_TOO_MANY:
- {
- WorldPacket data;
- ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_ARENA_GROUP_TOO_LARGE), NULL);
- SendPacket(&data);
- }
- return;
- break;
- case BG_JOIN_ERR_GROUP_NOT_ENOUGH:
- {
- WorldPacket data;
- ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_ARENA_NOT_ENOUGH_PLAYERS), NULL);
- SendPacket(&data);
- }
- return;
- break;
- case BG_JOIN_ERR_MIXED_ARENATEAM:
- {
- WorldPacket data;
- ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_ARENA_YOUR_TEAM_ONLY), NULL);
- SendPacket(&data);
- }
- return;
- break;
- case BG_JOIN_ERR_OFFLINE_MEMBER:
- {
- WorldPacket data;
- ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_OFFLINE_MEMBER), NULL);
- SendPacket(&data);
- }
- return;
- break;
- case BG_JOIN_ERR_MIXED_FACTION:
- {
- WorldPacket data;
- ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MIXED_FACTION), NULL);
- SendPacket(&data);
- }
- return;
- break;
- case BG_JOIN_ERR_MIXED_LEVELS:
- {
- WorldPacket data;
- ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MIXED_LEVELS), NULL);
- SendPacket(&data);
- }
- return;
- break;
- case BG_JOIN_ERR_GROUP_MEMBER_ALREADY_IN_QUEUE:
- {
- WorldPacket data;
- ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE), NULL);
- SendPacket(&data);
- }
- return;
- break;
- case BG_JOIN_ERR_GROUP_DESERTER:
- {
- WorldPacket data;
- ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MEMBER_DESERTER), NULL);
- SendPacket(&data);
- }
- return;
- break;
- case BG_JOIN_ERR_ALL_QUEUES_USED:
- {
- WorldPacket data;
- ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS), NULL);
- SendPacket(&data);
- }
- return;
- break;
- // all ok, can join
- case BG_JOIN_ERR_OK:
- break;
- // not the above? shouldn't happen, don't let join
- default:
- return;
- break;
- };
- }
-
- uint32 ateamId = 0;
-
- if(isRated)
- {
- ateamId = _player->GetArenaTeamId(type);
- // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice)
- ArenaTeam * at = objmgr.GetArenaTeamById(ateamId);
- if(!at)
- {
- _player->GetSession()->SendNotInArenaTeamPacket(arenatype);
- return;
- }
- // get the team rating for queueing
- arenaRating = at->GetRating();
- // the arenateam id must match for everyone in the group
- // get the personal ratings for queueing
- uint32 avg_pers_rating = 0;
- for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
- {
- Player *member = itr->getSource();
-
- // calc avg personal rating
- avg_pers_rating += member->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (type*6) + 5);
- }
-
- if( arenatype )
- avg_pers_rating /= arenatype;
-
- // if avg personal rating is more than 150 points below the team’s rating, the team will be queued against an opponent matching or similar to the average personal rating
- if(avg_pers_rating + 150 < arenaRating)
- arenaRating = avg_pers_rating;
- }
-
- if(asGroup)
- {
- GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating, ateamId);
- sLog.outDebug("Battleground: arena join as group start");
- if(isRated)
- sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(type),_player->GetName(),arenaRating,arenatype);
- for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
- {
- Player *member = itr->getSource();
- if(!member) continue;
-
- uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId);// add to queue
-
- // store entry point coords (same as leader entry point)
- member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
-
- WorldPacket data;
- // send status packet (in queue)
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated);
- member->GetSession()->SendPacket(&data);
- sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
- member->GetSession()->SendPacket(&data);
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo);
- sLog.outDebug("Battleground: player joined queue for arena as group bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName());
- }
- sLog.outDebug("Battleground: arena join as group end");
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(), arenatype, isRated, arenaRating);
- }
- else
- {
- uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
-
- // store entry point coords
- _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
-
- WorldPacket data;
- // send status packet (in queue)
- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated);
- SendPacket(&data);
- GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating);
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);
- sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(), arenatype, isRated, arenaRating);
- sLog.outDebug("Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName());
- }
-}
-
-void WorldSession::HandleBattleGroundReportAFK( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 8);
-
- uint64 playerGuid;
- recv_data >> playerGuid;
- Player *reportedPlayer = objmgr.GetPlayer(playerGuid);
-
- if(!reportedPlayer)
- {
- sLog.outDebug("WorldSession::HandleBattleGroundReportAFK: player not found");
- return;
- }
-
- sLog.outDebug("WorldSession::HandleBattleGroundReportAFK: %s reported %s", _player->GetName(), reportedPlayer->GetName());
-
- reportedPlayer->ReportedAfkBy(_player);
-}
+/*
+ * Copyright (C) 2005-2008 MaNGOS
+ *
+ * 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 "WorldPacket.h"
+#include "Opcodes.h"
+#include "Log.h"
+#include "Player.h"
+#include "ObjectMgr.h"
+#include "WorldSession.h"
+#include "MapManager.h"
+#include "ObjectAccessor.h"
+#include "Object.h"
+#include "Chat.h"
+#include "Language.h"
+#include "BattleGroundMgr.h"
+#include "BattleGroundWS.h"
+#include "BattleGround.h"
+#include "ArenaTeam.h"
+
+void WorldSession::HandleBattleGroundHelloOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 8);
+
+ uint64 guid;
+ recv_data >> guid;
+ sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_HELLO Message from: " I64FMT, guid);
+
+ Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
+ if(!unit)
+ return;
+
+ if(!unit->isBattleMaster()) // it's not battlemaster
+ return;
+
+ // Stop the npc if moving
+ unit->StopMoving();
+
+ uint32 bgTypeId = objmgr.GetBattleMasterBG(unit->GetEntry());
+
+ if(!_player->GetBGAccessByLevel(bgTypeId))
+ {
+ // temp, must be gossip message...
+ SendNotification(LANG_YOUR_BG_LEVEL_REQ_ERROR);
+ return;
+ }
+
+ SendBattlegGroundList(guid, bgTypeId);
+}
+
+void WorldSession::SendBattlegGroundList( uint64 guid, uint32 bgTypeId )
+{
+ WorldPacket data;
+ sBattleGroundMgr.BuildBattleGroundListPacket(&data, guid, _player, bgTypeId);
+ SendPacket( &data );
+}
+
+void WorldSession::HandleBattleGroundJoinOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 8+4+4+1);
+
+ uint64 guid;
+ uint32 bgTypeId;
+ uint32 instanceId;
+ uint8 joinAsGroup;
+ Group * grp;
+
+ recv_data >> guid; // battlemaster guid
+ recv_data >> bgTypeId; // battleground type id (DBC id)
+ recv_data >> instanceId; // instance id, 0 if First Available selected
+ recv_data >> joinAsGroup; // join as group
+
+ if(bgTypeId >= MAX_BATTLEGROUND_TYPES)
+ {
+ sLog.outError("Battleground: invalid bgtype received. possible cheater? player guid %u",_player->GetGUIDLow());
+ return;
+ }
+
+ sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from: " I64FMT, guid);
+
+ // can do this, since it's battleground, not arena
+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, 0);
+
+ // ignore if we already in BG or BG queue
+ if(_player->InBattleGround())
+ return;
+
+ Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
+ if(!unit)
+ return;
+
+ if(!unit->isBattleMaster()) // it's not battlemaster
+ return;
+
+ // get bg instance or bg template if instance not found
+ BattleGround * bg = 0;
+ if(instanceId)
+ BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId);
+
+ if(!bg && !(bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId)))
+ {
+ sLog.outError("Battleground: no available bg / template found");
+ return;
+ }
+
+ // check queueing conditions
+ if(!joinAsGroup)
+ {
+ // check Deserter debuff
+ if( !_player->CanJoinToBattleground() )
+ {
+ WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);
+ data << (uint32) 0xFFFFFFFE;
+ _player->GetSession()->SendPacket(&data);
+ return;
+ }
+ // check if already in queue
+ if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
+ //player is already in this queue
+ return;
+ // check if has free queue slots
+ if(!_player->HasFreeBattleGroundQueueId())
+ return;
+ }
+ else
+ {
+ grp = _player->GetGroup();
+ // no group found, error
+ if(!grp)
+ return;
+ uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0);
+ switch(err)
+ {
+ // TODO: add error-based feedback to players in all cases
+ case BG_JOIN_ERR_GROUP_TOO_MANY:
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_TOO_LARGE), NULL);
+ SendPacket(&data);
+ }
+ return;
+ break;
+ case BG_JOIN_ERR_OFFLINE_MEMBER:
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_OFFLINE_MEMBER), NULL);
+ SendPacket(&data);
+ }
+ return;
+ break;
+ case BG_JOIN_ERR_MIXED_FACTION:
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MIXED_FACTION), NULL);
+ SendPacket(&data);
+ }
+ return;
+ break;
+ case BG_JOIN_ERR_MIXED_LEVELS:
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MIXED_LEVELS), NULL);
+ SendPacket(&data);
+ }
+ return;
+ break;
+ case BG_JOIN_ERR_GROUP_MEMBER_ALREADY_IN_QUEUE:
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE), NULL);
+ SendPacket(&data);
+ }
+ return;
+ break;
+ case BG_JOIN_ERR_GROUP_DESERTER:
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MEMBER_DESERTER), NULL);
+ SendPacket(&data);
+ }
+ return;
+ break;
+ case BG_JOIN_ERR_ALL_QUEUES_USED:
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS), NULL);
+ SendPacket(&data);
+ }
+ return;
+ break;
+ // all ok, can join
+ case BG_JOIN_ERR_OK:
+ break;
+ // these aren't possible outcomes in bgs
+ case BG_JOIN_ERR_GROUP_NOT_ENOUGH:
+ case BG_JOIN_ERR_MIXED_ARENATEAM:
+ return;
+ break;
+ // not the above? shouldn't happen, don't let join
+ default:
+ return;
+ break;
+ };
+ }
+
+ // if we're here, then the conditions to join a bg are met. We can proceed in joining.
+
+ // _player->GetGroup() was already checked, grp is already initialized
+ if(joinAsGroup /* && _player->GetGroup()*/)
+ {
+ sLog.outDebug("Battleground: the following players are joining as group:");
+ GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, 0);
+ for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player *member = itr->getSource();
+ if(!member) continue; // this should never happen
+
+ uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId); // add to queue
+
+ // store entry point coords (same as leader entry point)
+ member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
+
+ WorldPacket data;
+ // send status packet (in queue)
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);
+ member->GetSession()->SendPacket(&data);
+ sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
+ member->GetSession()->SendPacket(&data);
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo);
+ sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName());
+ }
+ sLog.outDebug("Battleground: group end");
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel());
+ }
+ else
+ {
+ // already checked if queueSlot is valid, now just get it
+ uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
+ // store entry point coords
+ _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
+
+ WorldPacket data;
+ // send status packet (in queue)
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);
+ SendPacket(&data);
+
+ GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, 0);
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel());
+ sLog.outDebug("Battleground: player joined queue for bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName());
+ }
+}
+
+void WorldSession::HandleBattleGroundPlayerPositionsOpcode( WorldPacket & /*recv_data*/ )
+{
+ // empty opcode
+ sLog.outDebug("WORLD: Recvd MSG_BATTLEGROUND_PLAYER_POSITIONS Message");
+
+ BattleGround *bg = _player->GetBattleGround();
+ if(!bg) // can't be received if player not in battleground
+ return;
+
+ if(bg->GetTypeID() == BATTLEGROUND_WS)
+ {
+ uint32 count1 = 0;
+ uint32 count2 = 0;
+
+ Player *ap = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetAllianceFlagPickerGUID());
+ if(ap) ++count2;
+
+ Player *hp = objmgr.GetPlayer(((BattleGroundWS*)bg)->GetHordeFlagPickerGUID());
+ if(hp) ++count2;
+
+ WorldPacket data(MSG_BATTLEGROUND_PLAYER_POSITIONS, (4+4+16*count1+16*count2));
+ data << count1; // alliance flag holders count
+ /*for(uint8 i = 0; i < count1; i++)
+ {
+ data << uint64(0); // guid
+ data << (float)0; // x
+ data << (float)0; // y
+ }*/
+ data << count2; // horde flag holders count
+ if(ap)
+ {
+ data << (uint64)ap->GetGUID();
+ data << (float)ap->GetPositionX();
+ data << (float)ap->GetPositionY();
+ }
+ if(hp)
+ {
+ data << (uint64)hp->GetGUID();
+ data << (float)hp->GetPositionX();
+ data << (float)hp->GetPositionY();
+ }
+
+ SendPacket(&data);
+ }
+}
+
+void WorldSession::HandleBattleGroundPVPlogdataOpcode( WorldPacket & /*recv_data*/ )
+{
+ sLog.outDebug( "WORLD: Recvd MSG_PVP_LOG_DATA Message");
+
+ BattleGround *bg = _player->GetBattleGround();
+ if(!bg)
+ return;
+
+ WorldPacket data;
+ sBattleGroundMgr.BuildPvpLogDataPacket(&data, bg);
+ SendPacket(&data);
+
+ sLog.outDebug( "WORLD: Sent MSG_PVP_LOG_DATA Message");
+}
+
+void WorldSession::HandleBattleGroundListOpcode( WorldPacket &recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 4);
+
+ sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_LIST Message");
+
+ uint32 bgTypeId;
+ recv_data >> bgTypeId; // id from DBC
+
+ if(bgTypeId >= MAX_BATTLEGROUND_TYPES)
+ {
+ sLog.outError("Battleground: invalid bgtype received.");
+ return;
+ }
+
+ BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId);
+
+ if(!bl)
+ return;
+
+ WorldPacket data;
+ sBattleGroundMgr.BuildBattleGroundListPacket(&data, _player->GetGUID(), _player, bgTypeId);
+ SendPacket( &data );
+}
+
+void WorldSession::HandleBattleGroundPlayerPortOpcode( WorldPacket &recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 1+1+4+2+1);
+
+ sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message");
+
+ uint8 type; // arenatype if arena
+ uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1
+ uint32 instanceId;
+ uint32 bgTypeId; // type id from dbc
+ uint16 unk; // 0x1F90 constant?
+ uint8 action; // enter battle 0x1, leave queue 0x0
+
+ recv_data >> type >> unk2 >> bgTypeId >> unk >> action;
+
+ if(bgTypeId >= MAX_BATTLEGROUND_TYPES)
+ {
+ sLog.outError("Battleground: invalid bgtype received.");
+ // update battleground slots for the player to fix his UI and sent data.
+ // this is a HACK, I don't know why the client starts sending invalid packets in the first place.
+ // it usually happens with extremely high latency (if debugging / stepping in the code for example)
+ if(_player->InBattleGroundQueue())
+ {
+ // update all queues, send invitation info if player is invited, queue info if queued
+ for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
+ {
+ uint32 queue_id = _player->GetBattleGroundQueueId(i);
+ if(!queue_id)
+ continue;
+ BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
+ // if the player is not in queue, contine
+ if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())
+ continue;
+
+ // no group information, this should never happen
+ if(!itrPlayerStatus->second.GroupInfo)
+ continue;
+
+ BattleGround * bg = NULL;
+
+ // get possibly needed data from groupinfo
+ bgTypeId = itrPlayerStatus->second.GroupInfo->BgTypeId;
+ uint8 arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;
+ uint8 israted = itrPlayerStatus->second.GroupInfo->IsRated;
+ uint8 status = 0;
+
+
+ if(!itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID)
+ {
+ // not invited to bg, get template
+ bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
+ status = STATUS_WAIT_QUEUE;
+ }
+ else
+ {
+ // get the bg we're invited to
+ BattleGround * bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID);
+ status = STATUS_WAIT_JOIN;
+ }
+
+ // if bg not found, then continue
+ if(!bg)
+ continue;
+
+ // don't invite if already in the instance
+ if(_player->InBattleGround() && _player->GetBattleGround() && _player->GetBattleGround()->GetInstanceID() == bg->GetInstanceID())
+ continue;
+
+ // re - invite player with proper data
+ WorldPacket data;
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, itrPlayerStatus->second.GroupInfo->Team?itrPlayerStatus->second.GroupInfo->Team:_player->GetTeam(), i, status, INVITE_ACCEPT_WAIT_TIME, 0, arenatype, israted);
+ SendPacket(&data);
+ }
+ }
+ return;
+ }
+
+ uint32 bgQueueTypeId = 0;
+ // get the bg what we were invited to
+ BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus;
+ bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId,type);
+ itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
+
+ if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())
+ {
+ sLog.outError("Battleground: itrplayerstatus not found.");
+ return;
+ }
+ instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID;
+
+ // if action == 1, then instanceId is _required_
+ if(!instanceId && action == 1)
+ {
+ sLog.outError("Battleground: instance not found.");
+ return;
+ }
+
+ BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId);
+
+ // bg template might and must be used in case of leaving queue, when instance is not created yet
+ if(!bg && action == 0)
+ bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
+
+ if(!bg)
+ {
+ sLog.outError("Battleground: bg not found.");
+ return;
+ }
+
+ bgTypeId = bg->GetTypeID();
+
+ if(_player->InBattleGroundQueue())
+ {
+ uint32 queueSlot = 0;
+ uint32 team = 0;
+ uint32 arenatype = 0;
+ uint32 israted = 0;
+ uint32 rating = 0;
+ // get the team info from the queue
+ BattleGroundQueue::QueuedPlayersMap::iterator pitr = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
+ if(pitr !=sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end()
+ && pitr->second.GroupInfo )
+ {
+ team = pitr->second.GroupInfo->Team;
+ arenatype = pitr->second.GroupInfo->ArenaType;
+ israted = pitr->second.GroupInfo->IsRated;
+ rating = pitr->second.GroupInfo->ArenaTeamRating;
+ }
+ else
+ {
+ sLog.outError("Battleground: Invalid player queue info!");
+ return;
+ }
+ WorldPacket data;
+ switch(action)
+ {
+ case 1: // port to battleground
+ if(!_player->IsInvitedForBattleGroundQueueType(bgQueueTypeId))
+ return; // cheating?
+ // resurrect the player
+ if(!_player->isAlive())
+ {
+ _player->ResurrectPlayer(1.0f,false);
+ _player->SpawnCorpseBones();
+ }
+ // stop taxi flight at port
+ if(_player->isInFlight())
+ {
+ _player->GetMotionMaster()->MovementExpired();
+ _player->m_taxi.ClearTaxiDestinations();
+ }
+ _player->RemoveFromGroup();
+ queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime());
+ _player->GetSession()->SendPacket(&data);
+ // remove battleground queue status from BGmgr
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), false);
+ // this is still needed here if battleground "jumping" shouldn't add deserter debuff
+ // also this required to prevent stuck at old battleground after SetBattleGroundId set to new
+ if( BattleGround *currentBg = _player->GetBattleGround() )
+ currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true);
+
+ // set the destination instance id
+ _player->SetBattleGroundId(bg->GetInstanceID());
+ // set the destination team
+ _player->SetBGTeam(team);
+ // bg->HandleBeforeTeleportToBattleGround(_player);
+ sBattleGroundMgr.SendToBattleGround(_player, instanceId);
+ // add only in HandleMoveWorldPortAck()
+ // bg->AddPlayer(_player,team);
+ sLog.outDebug("Battleground: player %s (%u) joined battle for bg %u, bgtype %u, queue type %u.",_player->GetName(),_player->GetGUIDLow(),bg->GetInstanceID(),bg->GetTypeID(),bgQueueTypeId);
+ break;
+ case 0: // leave queue
+ queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
+ _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_NONE, 0, 0);
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true);
+ // player left queue, we should update it, maybe now his group fits in
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId,_player->GetBattleGroundQueueIdFromLevel(),arenatype,israted,rating);
+ SendPacket(&data);
+ sLog.outDebug("Battleground: player %s (%u) left queue for bgtype %u, queue type %u.",_player->GetName(),_player->GetGUIDLow(),bg->GetTypeID(),bgQueueTypeId);
+ break;
+ default:
+ sLog.outError("Battleground port: unknown action %u", action);
+ break;
+ }
+ }
+}
+
+void WorldSession::HandleBattleGroundLeaveOpcode( WorldPacket & /*recv_data*/ )
+{
+ //CHECK_PACKET_SIZE(recv_data, 1+1+4+2);
+
+ sLog.outDebug( "WORLD: Recvd CMSG_LEAVE_BATTLEFIELD Message");
+
+ //uint8 unk1, unk2;
+ //uint32 bgTypeId; // id from DBC
+ //uint16 unk3;
+
+ //recv_data >> unk1 >> unk2 >> bgTypeId >> unk3; - no used currently
+
+ //if(bgTypeId >= MAX_BATTLEGROUND_TYPES) // cheating? but not important in this case
+ // return;
+
+ // not allow leave battleground in combat
+ if(_player->isInCombat())
+ if(BattleGround* bg = _player->GetBattleGround())
+ if(bg->GetStatus() != STATUS_WAIT_LEAVE)
+ return;
+
+ _player->LeaveBattleground();
+}
+
+void WorldSession::HandleBattlefieldStatusOpcode( WorldPacket & /*recv_data*/ )
+{
+ // empty opcode
+ sLog.outDebug( "WORLD: Battleground status" );
+
+ WorldPacket data;
+
+ // TODO: we must put player back to battleground in case disconnect (< 5 minutes offline time) or teleport player on login(!) from battleground map to entry point
+ if(_player->InBattleGround())
+ {
+ BattleGround *bg = _player->GetBattleGround();
+ if(bg)
+ {
+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());
+ uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);
+ if((bg->GetStatus() <= STATUS_IN_PROGRESS))
+ {
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime());
+ SendPacket(&data);
+ }
+ for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
+ {
+ uint32 queue_id = _player->GetBattleGroundQueueId(i); // battlegroundqueueid stores the type id, not the instance id, so this is definitely wrong
+ uint8 arenatype = sBattleGroundMgr.BGArenaType(queue_id);
+ uint8 isRated = 0;
+ if (i == queueSlot || !queue_id) // we need to get the instance ids
+ continue;
+ BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
+ if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())
+ continue;
+ if(itrPlayerStatus->second.GroupInfo)
+ {
+ arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;
+ isRated = itrPlayerStatus->second.GroupInfo->IsRated;
+ }
+ BattleGround *bg2 = sBattleGroundMgr.GetBattleGroundTemplate(sBattleGroundMgr.BGTemplateId(queue_id)); // try this
+ if(bg2)
+ {
+ //in this call is small bug, this call should be filled by player's waiting time in queue
+ //this call nulls all timers for client :
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg2, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0,arenatype,isRated);
+ SendPacket(&data);
+ }
+ }
+ }
+ }
+ else
+ {
+ // we should update all queues? .. i'm not sure if this code is correct
+ for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
+ {
+ uint32 queue_id = _player->GetBattleGroundQueueId(i);
+ if(!queue_id)
+ continue;
+ uint32 bgTypeId = sBattleGroundMgr.BGTemplateId(queue_id);
+ uint8 arenatype = sBattleGroundMgr.BGArenaType(queue_id);
+ uint8 isRated = 0;
+ BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);
+ BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());
+ if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())
+ continue;
+ if(itrPlayerStatus->second.GroupInfo)
+ {
+ arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;
+ isRated = itrPlayerStatus->second.GroupInfo->IsRated;
+ }
+ if(bg && queue_id)
+ {
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated);
+ SendPacket(&data);
+ }
+ }
+ }
+/* else // not sure if it needed...
+ {
+ for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)
+ {
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, NULL, _player->GetTeam(),i , STATUS_NONE, 0, 0);
+ SendPacket(&data);
+ }
+ }*/
+}
+
+void WorldSession::HandleAreaSpiritHealerQueryOpcode( WorldPacket & recv_data )
+{
+ sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUERY");
+
+ CHECK_PACKET_SIZE(recv_data, 8);
+
+ BattleGround *bg = _player->GetBattleGround();
+ if(!bg)
+ return;
+
+ uint64 guid;
+ recv_data >> guid;
+
+ Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
+ if(!unit)
+ return;
+
+ if(!unit->isSpiritService()) // it's not spirit service
+ return;
+
+ sBattleGroundMgr.SendAreaSpiritHealerQueryOpcode(_player, bg, guid);
+}
+
+void WorldSession::HandleAreaSpiritHealerQueueOpcode( WorldPacket & recv_data )
+{
+ sLog.outDebug("WORLD: CMSG_AREA_SPIRIT_HEALER_QUEUE");
+
+ CHECK_PACKET_SIZE(recv_data, 8);
+
+ BattleGround *bg = _player->GetBattleGround();
+ if(!bg)
+ return;
+
+ uint64 guid;
+ recv_data >> guid;
+
+ Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
+ if(!unit)
+ return;
+
+ if(!unit->isSpiritService()) // it's not spirit service
+ return;
+
+ bg->AddPlayerToResurrectQueue(guid, _player->GetGUID());
+}
+
+void WorldSession::HandleBattleGroundArenaJoin( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 8+1+1+1);
+
+ sLog.outDebug("WORLD: CMSG_BATTLEMASTER_JOIN_ARENA");
+ recv_data.hexlike();
+
+ // ignore if we already in BG or BG queue
+ if(_player->InBattleGround())
+ return;
+
+ uint64 guid; // arena Battlemaster guid
+ uint8 type; // 2v2, 3v3 or 5v5
+ uint8 asGroup; // asGroup
+ uint8 isRated; // isRated
+ Group * grp;
+
+ recv_data >> guid >> type >> asGroup >> isRated;
+
+ Creature *unit = ObjectAccessor::GetCreature(*_player, guid);
+ if(!unit)
+ return;
+
+ if(!unit->isBattleMaster()) // it's not battle master
+ return;
+
+ uint8 arenatype = 0;
+ uint32 arenaRating = 0;
+
+ switch(type)
+ {
+ case 0:
+ arenatype = ARENA_TYPE_2v2;
+ break;
+ case 1:
+ arenatype = ARENA_TYPE_3v3;
+ break;
+ case 2:
+ arenatype = ARENA_TYPE_5v5;
+ break;
+ default:
+ sLog.outError("Unknown arena type %u at HandleBattleGroundArenaJoin()", type);
+ return;
+ }
+
+ //check existance
+ BattleGround* bg = NULL;
+ if( !(bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA)) )
+ {
+ sLog.outError("Battleground: template bg (all arenas) not found");
+ return;
+ }
+
+ uint8 bgTypeId = bg->GetTypeID();
+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, arenatype);
+
+ // check queueing conditions
+ if(!asGroup)
+ {
+ // check if already in queue
+ if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)
+ //player is already in this queue
+ return;
+ // check if has free queue slots
+ if(!_player->HasFreeBattleGroundQueueId())
+ return;
+ }
+ else
+ {
+ grp = _player->GetGroup();
+ // no group found, error
+ if(!grp)
+ return;
+ uint32 err = grp->CanJoinBattleGroundQueue(bgTypeId, bgQueueTypeId, arenatype, arenatype, (bool)isRated, type);
+ switch(err)
+ {
+ // TODO: add error-based feedback to players in all cases
+ case BG_JOIN_ERR_GROUP_TOO_MANY:
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_ARENA_GROUP_TOO_LARGE), NULL);
+ SendPacket(&data);
+ }
+ return;
+ break;
+ case BG_JOIN_ERR_GROUP_NOT_ENOUGH:
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_ARENA_NOT_ENOUGH_PLAYERS), NULL);
+ SendPacket(&data);
+ }
+ return;
+ break;
+ case BG_JOIN_ERR_MIXED_ARENATEAM:
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_ARENA_YOUR_TEAM_ONLY), NULL);
+ SendPacket(&data);
+ }
+ return;
+ break;
+ case BG_JOIN_ERR_OFFLINE_MEMBER:
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_OFFLINE_MEMBER), NULL);
+ SendPacket(&data);
+ }
+ return;
+ break;
+ case BG_JOIN_ERR_MIXED_FACTION:
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MIXED_FACTION), NULL);
+ SendPacket(&data);
+ }
+ return;
+ break;
+ case BG_JOIN_ERR_MIXED_LEVELS:
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MIXED_LEVELS), NULL);
+ SendPacket(&data);
+ }
+ return;
+ break;
+ case BG_JOIN_ERR_GROUP_MEMBER_ALREADY_IN_QUEUE:
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE), NULL);
+ SendPacket(&data);
+ }
+ return;
+ break;
+ case BG_JOIN_ERR_GROUP_DESERTER:
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MEMBER_DESERTER), NULL);
+ SendPacket(&data);
+ }
+ return;
+ break;
+ case BG_JOIN_ERR_ALL_QUEUES_USED:
+ {
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, GetMangosString(LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS), NULL);
+ SendPacket(&data);
+ }
+ return;
+ break;
+ // all ok, can join
+ case BG_JOIN_ERR_OK:
+ break;
+ // not the above? shouldn't happen, don't let join
+ default:
+ return;
+ break;
+ };
+ }
+
+ uint32 ateamId = 0;
+
+ if(isRated)
+ {
+ ateamId = _player->GetArenaTeamId(type);
+ // check real arenateam existence only here (if it was moved to group->CanJoin .. () then we would ahve to get it twice)
+ ArenaTeam * at = objmgr.GetArenaTeamById(ateamId);
+ if(!at)
+ {
+ _player->GetSession()->SendNotInArenaTeamPacket(arenatype);
+ return;
+ }
+ // get the team rating for queueing
+ arenaRating = at->GetRating();
+ // the arenateam id must match for everyone in the group
+ // get the personal ratings for queueing
+ uint32 avg_pers_rating = 0;
+ for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player *member = itr->getSource();
+
+ // calc avg personal rating
+ avg_pers_rating += member->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (type*6) + 5);
+ }
+
+ if( arenatype )
+ avg_pers_rating /= arenatype;
+
+ // if avg personal rating is more than 150 points below the team’s rating, the team will be queued against an opponent matching or similar to the average personal rating
+ if(avg_pers_rating + 150 < arenaRating)
+ arenaRating = avg_pers_rating;
+ }
+
+ if(asGroup)
+ {
+ GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating, ateamId);
+ sLog.outDebug("Battleground: arena join as group start");
+ if(isRated)
+ sLog.outDebug("Battleground: arena team id %u, leader %s queued with rating %u for type %u",_player->GetArenaTeamId(type),_player->GetName(),arenaRating,arenatype);
+ for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player *member = itr->getSource();
+ if(!member) continue;
+
+ uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId);// add to queue
+
+ // store entry point coords (same as leader entry point)
+ member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
+
+ WorldPacket data;
+ // send status packet (in queue)
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated);
+ member->GetSession()->SendPacket(&data);
+ sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId);
+ member->GetSession()->SendPacket(&data);
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo);
+ sLog.outDebug("Battleground: player joined queue for arena as group bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,member->GetGUIDLow(), member->GetName());
+ }
+ sLog.outDebug("Battleground: arena join as group end");
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(), arenatype, isRated, arenaRating);
+ }
+ else
+ {
+ uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId);
+
+ // store entry point coords
+ _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());
+
+ WorldPacket data;
+ // send status packet (in queue)
+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated);
+ SendPacket(&data);
+ GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating);
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);
+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(), arenatype, isRated, arenaRating);
+ sLog.outDebug("Battleground: player joined queue for arena, skirmish, bg queue type %u bg type %u: GUID %u, NAME %s",bgQueueTypeId,bgTypeId,_player->GetGUIDLow(), _player->GetName());
+ }
+}
+
+void WorldSession::HandleBattleGroundReportAFK( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 8);
+
+ uint64 playerGuid;
+ recv_data >> playerGuid;
+ Player *reportedPlayer = objmgr.GetPlayer(playerGuid);
+
+ if(!reportedPlayer)
+ {
+ sLog.outDebug("WorldSession::HandleBattleGroundReportAFK: player not found");
+ return;
+ }
+
+ sLog.outDebug("WorldSession::HandleBattleGroundReportAFK: %s reported %s", _player->GetName(), reportedPlayer->GetName());
+
+ reportedPlayer->ReportedAfkBy(_player);
+}
diff --git a/src/game/CharacterHandler.cpp b/src/game/CharacterHandler.cpp
index 929a0543f0b..f6dc47e7b60 100644
--- a/src/game/CharacterHandler.cpp
+++ b/src/game/CharacterHandler.cpp
@@ -1,1065 +1,1066 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS
- *
- * 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 "SharedDefines.h"
-#include "WorldSession.h"
-#include "Opcodes.h"
-#include "Log.h"
-#include "World.h"
-#include "ObjectMgr.h"
-#include "Player.h"
-#include "Guild.h"
-#include "UpdateMask.h"
-#include "Auth/md5.h"
-#include "MapManager.h"
-#include "ObjectAccessor.h"
-#include "Group.h"
-#include "Database/DatabaseImpl.h"
-#include "PlayerDump.h"
-#include "SocialMgr.h"
-#include "Util.h"
-
-class LoginQueryHolder : public SqlQueryHolder
-{
- private:
- uint32 m_accountId;
- uint64 m_guid;
- public:
- LoginQueryHolder(uint32 accountId, uint64 guid)
- : m_accountId(accountId), m_guid(guid) { }
- uint64 GetGuid() const { return m_guid; }
- uint32 GetAccountId() const { return m_accountId; }
- bool Initialize();
-};
-
-bool LoginQueryHolder::Initialize()
-{
- SetSize(MAX_PLAYER_LOGIN_QUERY);
-
- bool res = true;
-
- // NOTE: all fields in `characters` must be read to prevent lost character data at next save in case wrong DB structure.
- // !!! NOTE: including unused `zone`,`online`
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, gmstate, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid));
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGROUP, "SELECT leaderGuid FROM group_member WHERE memberGuid ='%u'", GUID_LOPART(m_guid));
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES, "SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = '%u'", GUID_LOPART(m_guid));
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADAURAS, "SELECT caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'", GUID_LOPART(m_guid));
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSPELLS, "SELECT spell,slot,active,disabled FROM character_spell WHERE guid = '%u'", GUID_LOPART(m_guid));
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS, "SELECT quest,status,rewarded,explored,timer,mobcount1,mobcount2,mobcount3,mobcount4,itemcount1,itemcount2,itemcount3,itemcount4 FROM character_queststatus WHERE guid = '%u'", GUID_LOPART(m_guid));
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS,"SELECT quest,time FROM character_queststatus_daily WHERE guid = '%u'", GUID_LOPART(m_guid));
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADTUTORIALS, "SELECT tut0,tut1,tut2,tut3,tut4,tut5,tut6,tut7 FROM character_tutorial WHERE account = '%u' AND realmid = '%u'", GetAccountId(), realmID);
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADREPUTATION, "SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'", GUID_LOPART(m_guid));
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADINVENTORY, "SELECT data,bag,slot,item,item_template FROM character_inventory JOIN item_instance ON character_inventory.item = item_instance.guid WHERE character_inventory.guid = '%u' ORDER BY bag,slot", GUID_LOPART(m_guid));
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACTIONS, "SELECT button,action,type,misc FROM character_action WHERE guid = '%u' ORDER BY button", GUID_LOPART(m_guid));
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILCOUNT, "SELECT COUNT(id) FROM mail WHERE receiver = '%u' AND (checked & 1)=0 AND deliver_time <= '" I64FMTD "'", GUID_LOPART(m_guid),(uint64)time(NULL));
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILDATE, "SELECT MIN(deliver_time) FROM mail WHERE receiver = '%u' AND (checked & 1)=0", GUID_LOPART(m_guid));
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSOCIALLIST, "SELECT friend,flags,note FROM character_social WHERE guid = '%u' LIMIT 255", GUID_LOPART(m_guid));
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADHOMEBIND, "SELECT map,zone,position_x,position_y,position_z FROM character_homebind WHERE guid = '%u'", GUID_LOPART(m_guid));
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSPELLCOOLDOWNS, "SELECT spell,item,time FROM character_spell_cooldown WHERE guid = '%u'", GUID_LOPART(m_guid));
- if(sWorld.getConfig(CONFIG_DECLINED_NAMES_USED))
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_declinedname WHERE guid = '%u'",GUID_LOPART(m_guid));
- // in other case still be dummy query
- res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGUILD, "SELECT guildid,rank FROM guild_member WHERE guid = '%u'", GUID_LOPART(m_guid));
-
- return res;
-}
-
-// don't call WorldSession directly
-// it may get deleted before the query callbacks get executed
-// instead pass an account id to this handler
-class CharacterHandler
-{
- public:
- void HandleCharEnumCallback(QueryResult * result, uint32 account)
- {
- WorldSession * session = sWorld.FindSession(account);
- if(!session)
- {
- delete result;
- return;
- }
- session->HandleCharEnum(result);
- }
- void HandlePlayerLoginCallback(QueryResult * /*dummy*/, SqlQueryHolder * holder)
- {
- if (!holder) return;
- WorldSession *session = sWorld.FindSession(((LoginQueryHolder*)holder)->GetAccountId());
- if(!session)
- {
- delete holder;
- return;
- }
- session->HandlePlayerLogin((LoginQueryHolder*)holder);
- }
-} chrHandler;
-
-void WorldSession::HandleCharEnum(QueryResult * result)
-{
- // keys can be non cleared if player open realm list and close it by 'cancel'
- loginDatabase.PExecute("UPDATE account SET v = '0', s = '0' WHERE id = '%u'", GetAccountId());
-
- WorldPacket data(SMSG_CHAR_ENUM, 100); // we guess size
-
- uint8 num = 0;
-
- data << num;
-
- if( result )
- {
- Player *plr = new Player(this);
- do
- {
- sLog.outDetail("Loading char guid %u from account %u.",(*result)[0].GetUInt32(),GetAccountId());
-
- if(plr->MinimalLoadFromDB( result, (*result)[0].GetUInt32() ))
- {
- plr->BuildEnumData( result, &data );
- ++num;
- }
- }
- while( result->NextRow() );
-
- delete plr;
- delete result;
- }
-
- data.put(0, num);
-
- SendPacket( &data );
-}
-
-void WorldSession::HandleCharEnumOpcode( WorldPacket & /*recv_data*/ )
-{
- /// get all the data necessary for loading all characters (along with their pets) on the account
- CharacterDatabase.AsyncPQuery(&chrHandler, &CharacterHandler::HandleCharEnumCallback, GetAccountId(),
- !sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) ?
- // ------- Query Without Declined Names --------
- // 0 1 2 3 4 5 6 7 8
- "SELECT characters.data, characters.name, characters.position_x, characters.position_y, characters.position_z, characters.map, characters.totaltime, characters.leveltime, characters.at_login, "
- // 9 10 11
- "character_pet.entry, character_pet.modelid, character_pet.level "
- "FROM characters LEFT JOIN character_pet ON characters.guid=character_pet.owner AND character_pet.slot='0' "
- "WHERE characters.account = '%u' ORDER BY characters.guid"
- :
- // --------- Query With Declined Names ---------
- // 0 1 2 3 4 5 6 7 8
- "SELECT characters.data, characters.name, characters.position_x, characters.position_y, characters.position_z, characters.map, characters.totaltime, characters.leveltime, characters.at_login, "
- // 9 10 11 12
- "character_pet.entry, character_pet.modelid, character_pet.level, 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 "
- "WHERE characters.account = '%u' ORDER BY characters.guid",
- GetAccountId());
-}
-
-void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data,1+1+1+1+1+1+1+1+1+1);
-
- std::string name;
- uint8 race_,class_;
- bool pTbc = this->IsTBC() && sWorld.getConfig(CONFIG_EXPANSION) > 0;
- recv_data >> name;
-
- // recheck with known string size
- CHECK_PACKET_SIZE(recv_data,(name.size()+1)+1+1+1+1+1+1+1+1+1);
-
- recv_data >> race_;
- recv_data >> class_;
-
- WorldPacket data(SMSG_CHAR_CREATE, 1); // returned with diff.values in all cases
-
- if(GetSecurity() == SEC_PLAYER)
- {
- if(uint32 mask = sWorld.getConfig(CONFIG_CHARACTERS_CREATING_DISABLED))
- {
- bool disabled = false;
-
- uint32 team = Player::TeamForRace(race_);
- switch(team)
- {
- case ALLIANCE: disabled = mask & (1<<0); break;
- case HORDE: disabled = mask & (1<<1); break;
- }
-
- if(disabled)
- {
- data << (uint8)CHAR_CREATE_DISABLED;
- SendPacket( &data );
- return;
- }
- }
- }
-
- if (!sChrClassesStore.LookupEntry(class_)||
- !sChrRacesStore.LookupEntry(race_))
- {
- data << (uint8)CHAR_CREATE_FAILED;
- SendPacket( &data );
- sLog.outError("Class: %u or Race %u not found in DBC (Wrong DBC files?) or Cheater?", class_, race_);
- return;
- }
-
- // prevent character creating Expansion race without Expansion account
- if (!pTbc&&(race_>RACE_TROLL))
- {
- data << (uint8)CHAR_CREATE_EXPANSION;
- sLog.outError("No Expansion Account:[%d] but tried to Create TBC character",GetAccountId());
- SendPacket( &data );
- return;
- }
-
- // prevent character creating with invalid name
- if(!normalizePlayerName(name))
- {
- data << (uint8)CHAR_NAME_INVALID_CHARACTER;
- SendPacket( &data );
- sLog.outError("Account:[%d] but tried to Create character with empty [name] ",GetAccountId());
- return;
- }
-
- // check name limitations
- if(!ObjectMgr::IsValidName(name,true))
- {
- data << (uint8)CHAR_NAME_INVALID_CHARACTER;
- SendPacket( &data );
- return;
- }
-
- if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(name))
- {
- data << (uint8)CHAR_NAME_RESERVED;
- SendPacket( &data );
- return;
- }
-
- if(objmgr.GetPlayerGUIDByName(name))
- {
- data << (uint8)CHAR_CREATE_NAME_IN_USE;
- SendPacket( &data );
- return;
- }
-
- QueryResult *resultacct = loginDatabase.PQuery("SELECT SUM(numchars) FROM realmcharacters WHERE acctid = '%d'", GetAccountId());
- if ( resultacct )
- {
- Field *fields=resultacct->Fetch();
- uint32 acctcharcount = fields[0].GetUInt32();
- delete resultacct;
-
- if (acctcharcount >= sWorld.getConfig(CONFIG_CHARACTERS_PER_ACCOUNT))
- {
- data << (uint8)CHAR_CREATE_ACCOUNT_LIMIT;
- SendPacket( &data );
- return;
- }
- }
-
- QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(guid) FROM characters WHERE account = '%d'", GetAccountId());
- uint8 charcount = 0;
- if ( result )
- {
- Field *fields=result->Fetch();
- charcount = fields[0].GetUInt8();
- delete result;
-
- if (charcount >= sWorld.getConfig(CONFIG_CHARACTERS_PER_REALM))
- {
- data << (uint8)CHAR_CREATE_SERVER_LIMIT;
- SendPacket( &data );
- return;
- }
- }
-
- bool AllowTwoSideAccounts = !sWorld.IsPvPRealm() || sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS) || GetSecurity() > SEC_PLAYER;
- uint32 skipCinematics = sWorld.getConfig(CONFIG_SKIP_CINEMATICS);
-
- bool have_same_race = false;
- if(!AllowTwoSideAccounts || skipCinematics == 1)
- {
- QueryResult *result2 = CharacterDatabase.PQuery("SELECT DISTINCT race FROM characters WHERE account = '%u' %s", GetAccountId(),skipCinematics == 1 ? "" : "LIMIT 1");
- if(result2)
- {
- uint32 team_= Player::TeamForRace(race_);
-
- Field* field = result2->Fetch();
- uint8 race = field[0].GetUInt32();
-
- // need to check team only for first character
- // TODO: what to if account already has characters of both races?
- if (!AllowTwoSideAccounts)
- {
- uint32 team=0;
- if(race > 0)
- team = Player::TeamForRace(race);
-
- if(team != team_)
- {
- data << (uint8)CHAR_CREATE_PVP_TEAMS_VIOLATION;
- SendPacket( &data );
- delete result2;
- return;
- }
- }
-
- if (skipCinematics == 1)
- {
- // TODO: check if cinematic already shown? (already logged in?; cinematic field)
- while (race_ != race && result2->NextRow())
- {
- field = result2->Fetch();
- race = field[0].GetUInt32();
- }
- have_same_race = race_ == race;
- }
- delete result2;
- }
- }
-
- // extract other data required for player creating
- uint8 gender, skin, face, hairStyle, hairColor, facialHair, outfitId;
- recv_data >> gender >> skin >> face;
- recv_data >> hairStyle >> hairColor >> facialHair >> outfitId;
-
- Player * pNewChar = new Player(this);
- if(!pNewChar->Create( objmgr.GenerateLowGuid(HIGHGUID_PLAYER), name, race_, class_, gender, skin, face, hairStyle, hairColor, facialHair, outfitId ))
- {
- // Player not create (race/class problem?)
- delete pNewChar;
-
- data << (uint8)CHAR_CREATE_ERROR;
- SendPacket( &data );
-
- return;
- }
-
- if(have_same_race && skipCinematics == 1 || skipCinematics == 2)
- pNewChar->setCinematic(1); // not show intro
-
- // Player created, save it now
- pNewChar->SaveToDB();
- charcount+=1;
-
- loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", GetAccountId(), realmID);
- loginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charcount, GetAccountId(), realmID);
-
- delete pNewChar; // created only to call SaveToDB()
-
- data << (uint8)CHAR_CREATE_SUCCESS;
- SendPacket( &data );
-
- std::string IP_str = GetRemoteAddress().c_str();
- sLog.outBasic("Account: %d (IP: %s) Create Character:[%s]",GetAccountId(),IP_str.c_str(),name.c_str());
- sLog.outChar("Account: %d (IP: %s) Create Character:[%s]",GetAccountId(),IP_str.c_str(),name.c_str());
-}
-
-void WorldSession::HandleCharDeleteOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data,8);
-
- uint64 guid;
- recv_data >> guid;
-
- // can't delete loaded character
- if(objmgr.GetPlayer(guid))
- return;
-
- uint32 accountId = 0;
- std::string name;
-
- // is guild leader
- if(objmgr.GetGuildByLeader(guid))
- {
- WorldPacket data(SMSG_CHAR_DELETE, 1);
- data << (uint8)CHAR_DELETE_FAILED_GUILD_LEADER;
- SendPacket( &data );
- return;
- }
-
- // is arena team captain
- if(objmgr.GetArenaTeamByCapitan(guid))
- {
- WorldPacket data(SMSG_CHAR_DELETE, 1);
- data << (uint8)CHAR_DELETE_FAILED_ARENA_CAPTAIN;
- SendPacket( &data );
- return;
- }
-
- QueryResult *result = CharacterDatabase.PQuery("SELECT account,name FROM characters WHERE guid='%u'", GUID_LOPART(guid));
- if(result)
- {
- Field *fields = result->Fetch();
- accountId = fields[0].GetUInt32();
- name = fields[1].GetCppString();
- delete result;
- }
-
- // prevent deleting other players' characters using cheating tools
- if(accountId != GetAccountId())
- return;
-
- std::string IP_str = GetRemoteAddress();
- sLog.outBasic("Account: %d (IP: %s) Delete Character:[%s] (guid:%u)",GetAccountId(),IP_str.c_str(),name.c_str(),GUID_LOPART(guid));
- sLog.outChar("Account: %d (IP: %s) Delete Character:[%s] (guid: %u)",GetAccountId(),IP_str.c_str(),name.c_str(),GUID_LOPART(guid));
-
- if(sLog.IsOutCharDump()) // optimize GetPlayerDump call
- {
- std::string dump = PlayerDumpWriter().GetDump(GUID_LOPART(guid));
- sLog.outCharDump(dump.c_str(),GetAccountId(),GUID_LOPART(guid),name.c_str());
- }
-
- Player::DeleteFromDB(guid, GetAccountId());
-
- WorldPacket data(SMSG_CHAR_DELETE, 1);
- data << (uint8)CHAR_DELETE_SUCCESS;
- SendPacket( &data );
-}
-
-void WorldSession::HandlePlayerLoginOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data,8);
-
- m_playerLoading = true;
- uint64 playerGuid = 0;
-
- DEBUG_LOG( "WORLD: Recvd Player Logon Message" );
-
- recv_data >> playerGuid;
-
- LoginQueryHolder *holder = new LoginQueryHolder(GetAccountId(), playerGuid);
- if(!holder->Initialize())
- {
- delete holder; // delete all unprocessed queries
- m_playerLoading = false;
- return;
- }
-
- CharacterDatabase.DelayQueryHolder(&chrHandler, &CharacterHandler::HandlePlayerLoginCallback, holder);
-}
-
-void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
-{
- uint64 playerGuid = holder->GetGuid();
-
- Player* pCurrChar = new Player(this);
- pCurrChar->GetMotionMaster()->Initialize();
-
- // "GetAccountId()==db stored account id" checked in LoadFromDB (prevent login not own character using cheating tools)
- if(!pCurrChar->LoadFromDB(GUID_LOPART(playerGuid), holder))
- {
- KickPlayer(); // disconnect client, player no set to session and it will not deleted or saved at kick
- delete pCurrChar; // delete it manually
- delete holder; // delete all unprocessed queries
- m_playerLoading = false;
- return;
- }
-
- SetPlayer(pCurrChar);
-
- pCurrChar->SendDungeonDifficulty(false);
-
- WorldPacket data( SMSG_LOGIN_VERIFY_WORLD, 20 );
- data << pCurrChar->GetMapId();
- data << pCurrChar->GetPositionX();
- data << pCurrChar->GetPositionY();
- data << pCurrChar->GetPositionZ();
- data << pCurrChar->GetOrientation();
- SendPacket(&data);
-
- data.Initialize( SMSG_ACCOUNT_DATA_TIMES, 128 );
- for(int i = 0; i < 32; i++)
- data << uint32(0);
- SendPacket(&data);
-
- data.Initialize(SMSG_FEATURE_SYSTEM_STATUS, 2); // added in 2.2.0
- data << uint8(2); // unknown value
- data << uint8(0); // enable(1)/disable(0) voice chat interface in client
- SendPacket(&data);
-
- // Send MOTD
- {
- data.Initialize(SMSG_MOTD, 50); // new in 2.0.1
- data << (uint32)0;
-
- uint32 linecount=0;
- std::string str_motd = sWorld.GetMotd();
- std::string::size_type pos, nextpos;
-
- pos = 0;
- while ( (nextpos= str_motd.find('@',pos)) != std::string::npos )
- {
- if (nextpos != pos)
- {
- data << str_motd.substr(pos,nextpos-pos);
- ++linecount;
- }
- pos = nextpos+1;
- }
-
- if (posGetGuildId() != 0)
- {
- Guild* guild = objmgr.GetGuildById(pCurrChar->GetGuildId());
- if(guild)
- {
- data.Initialize(SMSG_GUILD_EVENT, (2+guild->GetMOTD().size()+1));
- data << (uint8)GE_MOTD;
- data << (uint8)1;
- data << guild->GetMOTD();
- SendPacket(&data);
- DEBUG_LOG( "WORLD: Sent guild-motd (SMSG_GUILD_EVENT)" );
-
- data.Initialize(SMSG_GUILD_EVENT, (5+10)); // we guess size
- data<<(uint8)GE_SIGNED_ON;
- data<<(uint8)1;
- data<GetName();
- data<GetGUID();
- guild->BroadcastPacket(&data);
- DEBUG_LOG( "WORLD: Sent guild-signed-on (SMSG_GUILD_EVENT)" );
-
- // Increment online members of the guild
- guild->IncOnlineMemberCount();
- }
- else
- {
- // 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());
- }
- }
-
- if(!pCurrChar->isAlive())
- pCurrChar->SendCorpseReclaimDelay(true);
-
- pCurrChar->SendInitialPacketsBeforeAddToMap();
-
- //Show cinematic at the first time that player login
- if( !pCurrChar->getCinematic() )
- {
- pCurrChar->setCinematic(1);
-
- ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(pCurrChar->getRace());
- if(rEntry)
- {
- data.Initialize( SMSG_TRIGGER_CINEMATIC,4 );
- data << uint32(rEntry->startmovie);
- SendPacket( &data );
- }
- }
-
- //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 (!MapManager::Instance().GetMap(pCurrChar->GetMapId(), pCurrChar)->Add(pCurrChar))
- {
- AreaTrigger const* at = objmgr.GetGoBackTrigger(pCurrChar->GetMapId());
- if(at)
- pCurrChar->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, pCurrChar->GetOrientation());
- else
- pCurrChar->TeleportTo(pCurrChar->m_homebindMapId, pCurrChar->m_homebindX, pCurrChar->m_homebindY, pCurrChar->m_homebindZ, pCurrChar->GetOrientation());
- }
-
- ObjectAccessor::Instance().AddObject(pCurrChar);
- //sLog.outDebug("Player %s added to Map.",pCurrChar->GetName());
- pCurrChar->GetSocial()->SendSocialList();
-
- pCurrChar->SendInitialPacketsAfterAddToMap();
-
- CharacterDatabase.PExecute("UPDATE characters SET online = 1 WHERE guid = '%u'", pCurrChar->GetGUIDLow());
- loginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = '%u'", GetAccountId());
- pCurrChar->SetInGameTime( getMSTime() );
-
- // announce group about member online (must be after add to player list to receive announce to self)
- if(Group *group = pCurrChar->GetGroup())
- {
- //pCurrChar->groupInfo.group->SendInit(this); // useless
- group->SendUpdate();
- }
-
- // friend status
- sSocialMgr.SendFriendStatus(pCurrChar, FRIEND_ONLINE, pCurrChar->GetGUIDLow(), "", true);
-
- // Place character in world (and load zone) before some object loading
- pCurrChar->LoadCorpse();
-
- // setting Ghost+speed if dead
- //if ( pCurrChar->m_deathState == DEAD )
- if (pCurrChar->m_deathState != ALIVE)
- {
- // not blizz like, we must correctly save and load player instead...
- if(pCurrChar->getRace() == RACE_NIGHTELF)
- pCurrChar->CastSpell(pCurrChar, 20584, true, 0);// auras SPELL_AURA_INCREASE_SPEED(+speed in wisp form), SPELL_AURA_INCREASE_SWIM_SPEED(+swim speed in wisp form), SPELL_AURA_TRANSFORM (to wisp form)
- pCurrChar->CastSpell(pCurrChar, 8326, true, 0); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?)
-
- //pCurrChar->SetUInt32Value(UNIT_FIELD_AURA+41, 8326);
- //pCurrChar->SetUInt32Value(UNIT_FIELD_AURA+42, 20584);
- //pCurrChar->SetUInt32Value(UNIT_FIELD_AURAFLAGS+6, 238);
- //pCurrChar->SetUInt32Value(UNIT_FIELD_AURALEVELS+11, 514);
- //pCurrChar->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS+11, 65535);
- //pCurrChar->SetUInt32Value(UNIT_FIELD_DISPLAYID, 1825);
- //if (pCurrChar->getRace() == RACE_NIGHTELF)
- //{
- // pCurrChar->SetSpeed(MOVE_RUN, 1.5f*1.2f, true);
- // pCurrChar->SetSpeed(MOVE_SWIM, 1.5f*1.2f, true);
- //}
- //else
- //{
- // pCurrChar->SetSpeed(MOVE_RUN, 1.5f, true);
- // pCurrChar->SetSpeed(MOVE_SWIM, 1.5f, true);
- //}
- pCurrChar->SetMovement(MOVE_WATER_WALK);
- }
-
- if(uint32 sourceNode = pCurrChar->m_taxi.GetTaxiSource())
- {
-
- sLog.outDebug( "WORLD: Restart character %u taxi flight", pCurrChar->GetGUIDLow() );
-
- uint32 MountId = objmgr.GetTaxiMount(sourceNode, pCurrChar->GetTeam());
- uint32 path = pCurrChar->m_taxi.GetCurrentTaxiPath();
-
- // search appropriate start path node
- uint32 startNode = 0;
-
- TaxiPathNodeList const& nodeList = sTaxiPathNodesByPath[path];
-
- float distPrev = MAP_SIZE*MAP_SIZE;
- float distNext =
- (nodeList[0].x-pCurrChar->GetPositionX())*(nodeList[0].x-pCurrChar->GetPositionX())+
- (nodeList[0].y-pCurrChar->GetPositionY())*(nodeList[0].y-pCurrChar->GetPositionY())+
- (nodeList[0].z-pCurrChar->GetPositionZ())*(nodeList[0].z-pCurrChar->GetPositionZ());
-
- for(uint32 i = 1; i < nodeList.size(); ++i)
- {
- TaxiPathNode const& node = nodeList[i];
- TaxiPathNode const& prevNode = nodeList[i-1];
-
- // skip nodes at another map
- if(node.mapid != pCurrChar->GetMapId())
- continue;
-
- distPrev = distNext;
-
- distNext =
- (node.x-pCurrChar->GetPositionX())*(node.x-pCurrChar->GetPositionX())+
- (node.y-pCurrChar->GetPositionY())*(node.y-pCurrChar->GetPositionY())+
- (node.z-pCurrChar->GetPositionZ())*(node.z-pCurrChar->GetPositionZ());
-
- float distNodes =
- (node.x-prevNode.x)*(node.x-prevNode.x)+
- (node.y-prevNode.y)*(node.y-prevNode.y)+
- (node.z-prevNode.z)*(node.z-prevNode.z);
-
- if(distNext + distPrev < distNodes)
- {
- startNode = i;
- break;
- }
- }
-
- SendDoFlight( MountId, path, startNode );
- }
-
- // Load pet if any and player is alive and not in taxi flight
- if(pCurrChar->isAlive() && pCurrChar->m_taxi.GetTaxiSource()==0)
- pCurrChar->LoadPet();
-
- // Set FFA PvP for non GM in non-rest mode
- if(sWorld.IsFFAPvPRealm() && !pCurrChar->isGameMaster() && !pCurrChar->HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_RESTING) )
- pCurrChar->SetFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP);
-
- if(pCurrChar->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP))
- pCurrChar->SetContestedPvP();
-
- // Apply at_login requests
- if(pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_SPELLS))
- {
- pCurrChar->resetSpells();
- SendNotification("Spells has been reset.");
- }
-
- if(pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_TALENTS))
- {
- pCurrChar->resetTalents(true);
- SendNotification("Talents has been reset.");
- }
-
- // show time before shutdown if shutdown planned.
- if(sWorld.IsShutdowning())
- sWorld.ShutdownMsg(true,pCurrChar);
-
- if(pCurrChar->isGameMaster())
- SendNotification("GM mode is ON");
-
- std::string IP_str = GetRemoteAddress();
- sLog.outChar("Account: %d (IP: %s) Login Character:[%s] (guid:%u)",GetAccountId(),IP_str.c_str(),pCurrChar->GetName() ,pCurrChar->GetGUID());
-
- m_playerLoading = false;
- delete holder;
-}
-
-void WorldSession::HandleSetFactionAtWar( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data,4+1);
-
- DEBUG_LOG( "WORLD: Received CMSG_SET_FACTION_ATWAR" );
-
- uint32 repListID;
- uint8 flag;
-
- recv_data >> repListID;
- recv_data >> flag;
-
- FactionStateList::iterator itr = GetPlayer()->m_factions.find(repListID);
- if (itr == GetPlayer()->m_factions.end())
- return;
-
- // always invisible or hidden faction can't change war state
- if(itr->second.Flags & (FACTION_FLAG_INVISIBLE_FORCED|FACTION_FLAG_HIDDEN) )
- return;
-
- GetPlayer()->SetFactionAtWar(&itr->second,flag);
-}
-
-//I think this function is never used :/ I dunno, but i guess this opcode not exists
-void WorldSession::HandleSetFactionCheat( WorldPacket & /*recv_data*/ )
-{
- //CHECK_PACKET_SIZE(recv_data,4+4);
-
- //sLog.outDebug("WORLD SESSION: HandleSetFactionCheat");
- /*
- uint32 FactionID;
- uint32 Standing;
-
- recv_data >> FactionID;
- recv_data >> Standing;
-
- std::list::iterator itr;
-
- for(itr = GetPlayer()->factions.begin(); itr != GetPlayer()->factions.end(); ++itr)
- {
- if(itr->ReputationListID == FactionID)
- {
- itr->Standing += Standing;
- itr->Flags = (itr->Flags | 1);
- break;
- }
- }
- */
- GetPlayer()->UpdateReputation();
-}
-
-void WorldSession::HandleMeetingStoneInfo( WorldPacket & /*recv_data*/ )
-{
- DEBUG_LOG( "WORLD: Received CMSG_MEETING_STONE_INFO" );
-
- WorldPacket data(SMSG_MEETINGSTONE_SETQUEUE, 5);
- data << uint32(0) << uint8(6);
- SendPacket(&data);
-}
-
-void WorldSession::HandleTutorialFlag( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data,4);
-
- uint32 iFlag;
- recv_data >> iFlag;
-
- uint32 wInt = (iFlag / 32);
- if (wInt >= 8)
- {
- //sLog.outError("CHEATER? Account:[%d] Guid[%u] tried to send wrong CMSG_TUTORIAL_FLAG", GetAccountId(),GetGUID());
- return;
- }
- uint32 rInt = (iFlag % 32);
-
- uint32 tutflag = GetPlayer()->GetTutorialInt( wInt );
- tutflag |= (1 << rInt);
- GetPlayer()->SetTutorialInt( wInt, tutflag );
-
- //sLog.outDebug("Received Tutorial Flag Set {%u}.", iFlag);
-}
-
-void WorldSession::HandleTutorialClear( WorldPacket & /*recv_data*/ )
-{
- for ( uint32 iI = 0; iI < 8; iI++)
- GetPlayer()->SetTutorialInt( iI, 0xFFFFFFFF );
-}
-
-void WorldSession::HandleTutorialReset( WorldPacket & /*recv_data*/ )
-{
- for ( uint32 iI = 0; iI < 8; iI++)
- GetPlayer()->SetTutorialInt( iI, 0x00000000 );
-}
-
-void WorldSession::HandleSetWatchedFactionIndexOpcode(WorldPacket & recv_data)
-{
- CHECK_PACKET_SIZE(recv_data,4);
-
- DEBUG_LOG("WORLD: Received CMSG_SET_WATCHED_FACTION");
- uint32 fact;
- recv_data >> fact;
- GetPlayer()->SetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fact);
-}
-
-void WorldSession::HandleSetWatchedFactionInactiveOpcode(WorldPacket & recv_data)
-{
- CHECK_PACKET_SIZE(recv_data,4+1);
-
- DEBUG_LOG("WORLD: Received CMSG_SET_FACTION_INACTIVE");
- uint32 replistid;
- uint8 inactive;
- recv_data >> replistid >> inactive;
-
- FactionStateList::iterator itr = _player->m_factions.find(replistid);
- if (itr == _player->m_factions.end())
- return;
-
- _player->SetFactionInactive(&itr->second, inactive);
-}
-
-void WorldSession::HandleToggleHelmOpcode( WorldPacket & /*recv_data*/ )
-{
- DEBUG_LOG("CMSG_TOGGLE_HELM for %s", _player->GetName());
- _player->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM);
-}
-
-void WorldSession::HandleToggleCloakOpcode( WorldPacket & /*recv_data*/ )
-{
- DEBUG_LOG("CMSG_TOGGLE_CLOAK for %s", _player->GetName());
- _player->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK);
-}
-
-void WorldSession::HandleChangePlayerNameOpcode(WorldPacket& recv_data)
-{
- CHECK_PACKET_SIZE(recv_data,8+1);
-
- uint64 guid;
- std::string newname;
- std::string oldname;
-
- CHECK_PACKET_SIZE(recv_data, 8+1);
-
- recv_data >> guid;
- recv_data >> newname;
-
- QueryResult *result = CharacterDatabase.PQuery("SELECT at_login FROM characters WHERE guid ='%u'", GUID_LOPART(guid));
- if (result)
- {
- uint32 at_loginFlags;
- Field *fields = result->Fetch();
- at_loginFlags = fields[0].GetUInt32();
- delete result;
-
- if (!(at_loginFlags & AT_LOGIN_RENAME))
- {
- WorldPacket data(SMSG_CHAR_RENAME, 1);
- data << (uint8)CHAR_CREATE_ERROR;
- SendPacket( &data );
- return;
- }
- }
- else
- {
- WorldPacket data(SMSG_CHAR_RENAME, 1);
- data << (uint8)CHAR_CREATE_ERROR;
- SendPacket( &data );
- return;
- }
-
- if(!objmgr.GetPlayerNameByGUID(guid, oldname)) // character not exist, because we have no name for this guid
- {
- WorldPacket data(SMSG_CHAR_RENAME, 1);
- data << (uint8)CHAR_LOGIN_NO_CHARACTER;
- SendPacket( &data );
- return;
- }
-
- // prevent character rename to invalid name
- if(!normalizePlayerName(newname))
- {
- WorldPacket data(SMSG_CHAR_RENAME, 1);
- data << (uint8)CHAR_NAME_NO_NAME;
- SendPacket( &data );
- return;
- }
-
- if(!ObjectMgr::IsValidName(newname,true))
- {
- WorldPacket data(SMSG_CHAR_RENAME, 1);
- data << (uint8)CHAR_NAME_INVALID_CHARACTER;
- SendPacket( &data );
- return;
- }
-
- // check name limitations
- if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname))
- {
- WorldPacket data(SMSG_CHAR_RENAME, 1);
- data << (uint8)CHAR_NAME_RESERVED;
- SendPacket( &data );
- return;
- }
-
- if(objmgr.GetPlayerGUIDByName(newname)) // character with this name already exist
- {
- WorldPacket data(SMSG_CHAR_RENAME, 1);
- data << (uint8)CHAR_CREATE_ERROR;
- SendPacket( &data );
- return;
- }
-
- if(newname == oldname) // checked by client
- {
- WorldPacket data(SMSG_CHAR_RENAME, 1);
- data << (uint8)CHAR_NAME_FAILURE;
- SendPacket( &data );
- return;
- }
-
- // we have to check character at_login_flag & AT_LOGIN_RENAME also (fake packets hehe)
-
- CharacterDatabase.escape_string(newname);
- CharacterDatabase.PExecute("UPDATE characters set name = '%s', at_login = at_login & ~ %u WHERE guid ='%u'", newname.c_str(), uint32(AT_LOGIN_RENAME),GUID_LOPART(guid));
- CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid ='%u'", GUID_LOPART(guid));
-
- std::string IP_str = GetRemoteAddress();
- sLog.outChar("Account: %d (IP: %s) Character:[%s] (guid:%u) Changed name to: %s",GetAccountId(),IP_str.c_str(),oldname.c_str(),GUID_LOPART(guid),newname.c_str());
-
- WorldPacket data(SMSG_CHAR_RENAME,1+8+(newname.size()+1));
- data << (uint8)RESPONSE_SUCCESS;
- data << guid;
- data << newname;
- SendPacket(&data);
-}
-
-void WorldSession::HandleDeclinedPlayerNameOpcode(WorldPacket& recv_data)
-{
- uint64 guid;
-
- CHECK_PACKET_SIZE(recv_data, 8+6);
- recv_data >> guid;
-
- // not accept declined names for unsupported languages
- std::string name;
- if(!objmgr.GetPlayerNameByGUID(guid,name))
- {
- WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT,4+8);
- data << (uint32)1;
- data << guid;
- SendPacket(&data);
- return;
- }
-
- std::wstring wname;
- if(!Utf8toWStr(name,wname))
- {
- WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT,4+8);
- data << (uint32)1;
- data << guid;
- SendPacket(&data);
- return;
- }
-
- if(!isCyrillicCharacter(wname[0])) // name already stored as only single alphabet using
- {
- WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT,4+8);
- data << (uint32)1;
- data << guid;
- SendPacket(&data);
- return;
- }
-
- std::string name2;
- DeclinedName declinedname;
-
- recv_data >> name2;
-
- if(name2!=name) // character have different name
- {
- WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT,4+8);
- data << (uint32)1;
- data << guid;
- SendPacket(&data);
- return;
- }
-
- for(int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
- {
- recv_data >> declinedname.name[i];
- if(!normalizePlayerName(declinedname.name[i]))
- {
- WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT,4+8);
- data << (uint32)1;
- data << guid;
- SendPacket(&data);
- return;
- }
- }
-
- if(!ObjectMgr::CheckDeclinedNames(GetMainPartOfName(wname,0),declinedname))
- {
- WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT,4+8);
- data << (uint32)1;
- data << guid;
- SendPacket(&data);
- return;
- }
-
- for(int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
- CharacterDatabase.escape_string(declinedname.name[i]);
-
- CharacterDatabase.BeginTransaction();
- CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid = '%u'", GUID_LOPART(guid));
- CharacterDatabase.PExecute("INSERT INTO character_declinedname (guid, genitive, dative, accusative, instrumental, prepositional) VALUES ('%u','%s','%s','%s','%s','%s')",
- GUID_LOPART(guid), declinedname.name[0].c_str(),declinedname.name[1].c_str(),declinedname.name[2].c_str(),declinedname.name[3].c_str(),declinedname.name[4].c_str());
- CharacterDatabase.CommitTransaction();
-
- WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT,4+8);
- data << (uint32)0; // OK
- data << guid;
- SendPacket(&data);
-}
+/*
+ * Copyright (C) 2005-2008 MaNGOS
+ *
+ * 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 "SharedDefines.h"
+#include "WorldSession.h"
+#include "Opcodes.h"
+#include "Log.h"
+#include "World.h"
+#include "ObjectMgr.h"
+#include "Player.h"
+#include "Guild.h"
+#include "UpdateMask.h"
+#include "Auth/md5.h"
+#include "MapManager.h"
+#include "ObjectAccessor.h"
+#include "Group.h"
+#include "Database/DatabaseImpl.h"
+#include "PlayerDump.h"
+#include "SocialMgr.h"
+#include "Util.h"
+#include "Language.h"
+
+class LoginQueryHolder : public SqlQueryHolder
+{
+ private:
+ uint32 m_accountId;
+ uint64 m_guid;
+ public:
+ LoginQueryHolder(uint32 accountId, uint64 guid)
+ : m_accountId(accountId), m_guid(guid) { }
+ uint64 GetGuid() const { return m_guid; }
+ uint32 GetAccountId() const { return m_accountId; }
+ bool Initialize();
+};
+
+bool LoginQueryHolder::Initialize()
+{
+ SetSize(MAX_PLAYER_LOGIN_QUERY);
+
+ bool res = true;
+
+ // NOTE: all fields in `characters` must be read to prevent lost character data at next save in case wrong DB structure.
+ // !!! NOTE: including unused `zone`,`online`
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADFROM, "SELECT guid, account, data, name, race, class, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, gmstate, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty FROM characters WHERE guid = '%u'", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGROUP, "SELECT leaderGuid FROM group_member WHERE memberGuid ='%u'", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES, "SELECT id, permanent, map, difficulty, resettime FROM character_instance LEFT JOIN instance ON instance = id WHERE guid = '%u'", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADAURAS, "SELECT caster_guid,spell,effect_index,amount,maxduration,remaintime,remaincharges FROM character_aura WHERE guid = '%u'", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSPELLS, "SELECT spell,slot,active,disabled FROM character_spell WHERE guid = '%u'", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS, "SELECT quest,status,rewarded,explored,timer,mobcount1,mobcount2,mobcount3,mobcount4,itemcount1,itemcount2,itemcount3,itemcount4 FROM character_queststatus WHERE guid = '%u'", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS,"SELECT quest,time FROM character_queststatus_daily WHERE guid = '%u'", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADTUTORIALS, "SELECT tut0,tut1,tut2,tut3,tut4,tut5,tut6,tut7 FROM character_tutorial WHERE account = '%u' AND realmid = '%u'", GetAccountId(), realmID);
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADREPUTATION, "SELECT faction,standing,flags FROM character_reputation WHERE guid = '%u'", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADINVENTORY, "SELECT data,bag,slot,item,item_template FROM character_inventory JOIN item_instance ON character_inventory.item = item_instance.guid WHERE character_inventory.guid = '%u' ORDER BY bag,slot", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADACTIONS, "SELECT button,action,type,misc FROM character_action WHERE guid = '%u' ORDER BY button", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILCOUNT, "SELECT COUNT(id) FROM mail WHERE receiver = '%u' AND (checked & 1)=0 AND deliver_time <= '" I64FMTD "'", GUID_LOPART(m_guid),(uint64)time(NULL));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADMAILDATE, "SELECT MIN(deliver_time) FROM mail WHERE receiver = '%u' AND (checked & 1)=0", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSOCIALLIST, "SELECT friend,flags,note FROM character_social WHERE guid = '%u' LIMIT 255", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADHOMEBIND, "SELECT map,zone,position_x,position_y,position_z FROM character_homebind WHERE guid = '%u'", GUID_LOPART(m_guid));
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADSPELLCOOLDOWNS, "SELECT spell,item,time FROM character_spell_cooldown WHERE guid = '%u'", GUID_LOPART(m_guid));
+ if(sWorld.getConfig(CONFIG_DECLINED_NAMES_USED))
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES, "SELECT genitive, dative, accusative, instrumental, prepositional FROM character_declinedname WHERE guid = '%u'",GUID_LOPART(m_guid));
+ // in other case still be dummy query
+ res &= SetPQuery(PLAYER_LOGIN_QUERY_LOADGUILD, "SELECT guildid,rank FROM guild_member WHERE guid = '%u'", GUID_LOPART(m_guid));
+
+ return res;
+}
+
+// don't call WorldSession directly
+// it may get deleted before the query callbacks get executed
+// instead pass an account id to this handler
+class CharacterHandler
+{
+ public:
+ void HandleCharEnumCallback(QueryResult * result, uint32 account)
+ {
+ WorldSession * session = sWorld.FindSession(account);
+ if(!session)
+ {
+ delete result;
+ return;
+ }
+ session->HandleCharEnum(result);
+ }
+ void HandlePlayerLoginCallback(QueryResult * /*dummy*/, SqlQueryHolder * holder)
+ {
+ if (!holder) return;
+ WorldSession *session = sWorld.FindSession(((LoginQueryHolder*)holder)->GetAccountId());
+ if(!session)
+ {
+ delete holder;
+ return;
+ }
+ session->HandlePlayerLogin((LoginQueryHolder*)holder);
+ }
+} chrHandler;
+
+void WorldSession::HandleCharEnum(QueryResult * result)
+{
+ // keys can be non cleared if player open realm list and close it by 'cancel'
+ loginDatabase.PExecute("UPDATE account SET v = '0', s = '0' WHERE id = '%u'", GetAccountId());
+
+ WorldPacket data(SMSG_CHAR_ENUM, 100); // we guess size
+
+ uint8 num = 0;
+
+ data << num;
+
+ if( result )
+ {
+ Player *plr = new Player(this);
+ do
+ {
+ sLog.outDetail("Loading char guid %u from account %u.",(*result)[0].GetUInt32(),GetAccountId());
+
+ if(plr->MinimalLoadFromDB( result, (*result)[0].GetUInt32() ))
+ {
+ plr->BuildEnumData( result, &data );
+ ++num;
+ }
+ }
+ while( result->NextRow() );
+
+ delete plr;
+ delete result;
+ }
+
+ data.put(0, num);
+
+ SendPacket( &data );
+}
+
+void WorldSession::HandleCharEnumOpcode( WorldPacket & /*recv_data*/ )
+{
+ /// get all the data necessary for loading all characters (along with their pets) on the account
+ CharacterDatabase.AsyncPQuery(&chrHandler, &CharacterHandler::HandleCharEnumCallback, GetAccountId(),
+ !sWorld.getConfig(CONFIG_DECLINED_NAMES_USED) ?
+ // ------- Query Without Declined Names --------
+ // 0 1 2 3 4 5 6 7 8
+ "SELECT characters.data, characters.name, characters.position_x, characters.position_y, characters.position_z, characters.map, characters.totaltime, characters.leveltime, characters.at_login, "
+ // 9 10 11
+ "character_pet.entry, character_pet.modelid, character_pet.level "
+ "FROM characters LEFT JOIN character_pet ON characters.guid=character_pet.owner AND character_pet.slot='0' "
+ "WHERE characters.account = '%u' ORDER BY characters.guid"
+ :
+ // --------- Query With Declined Names ---------
+ // 0 1 2 3 4 5 6 7 8
+ "SELECT characters.data, characters.name, characters.position_x, characters.position_y, characters.position_z, characters.map, characters.totaltime, characters.leveltime, characters.at_login, "
+ // 9 10 11 12
+ "character_pet.entry, character_pet.modelid, character_pet.level, 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 "
+ "WHERE characters.account = '%u' ORDER BY characters.guid",
+ GetAccountId());
+}
+
+void WorldSession::HandleCharCreateOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data,1+1+1+1+1+1+1+1+1+1);
+
+ std::string name;
+ uint8 race_,class_;
+ bool pTbc = this->IsTBC() && sWorld.getConfig(CONFIG_EXPANSION) > 0;
+ recv_data >> name;
+
+ // recheck with known string size
+ CHECK_PACKET_SIZE(recv_data,(name.size()+1)+1+1+1+1+1+1+1+1+1);
+
+ recv_data >> race_;
+ recv_data >> class_;
+
+ WorldPacket data(SMSG_CHAR_CREATE, 1); // returned with diff.values in all cases
+
+ if(GetSecurity() == SEC_PLAYER)
+ {
+ if(uint32 mask = sWorld.getConfig(CONFIG_CHARACTERS_CREATING_DISABLED))
+ {
+ bool disabled = false;
+
+ uint32 team = Player::TeamForRace(race_);
+ switch(team)
+ {
+ case ALLIANCE: disabled = mask & (1<<0); break;
+ case HORDE: disabled = mask & (1<<1); break;
+ }
+
+ if(disabled)
+ {
+ data << (uint8)CHAR_CREATE_DISABLED;
+ SendPacket( &data );
+ return;
+ }
+ }
+ }
+
+ if (!sChrClassesStore.LookupEntry(class_)||
+ !sChrRacesStore.LookupEntry(race_))
+ {
+ data << (uint8)CHAR_CREATE_FAILED;
+ SendPacket( &data );
+ sLog.outError("Class: %u or Race %u not found in DBC (Wrong DBC files?) or Cheater?", class_, race_);
+ return;
+ }
+
+ // prevent character creating Expansion race without Expansion account
+ if (!pTbc&&(race_>RACE_TROLL))
+ {
+ data << (uint8)CHAR_CREATE_EXPANSION;
+ sLog.outError("No Expansion Account:[%d] but tried to Create TBC character",GetAccountId());
+ SendPacket( &data );
+ return;
+ }
+
+ // prevent character creating with invalid name
+ if(!normalizePlayerName(name))
+ {
+ data << (uint8)CHAR_NAME_INVALID_CHARACTER;
+ SendPacket( &data );
+ sLog.outError("Account:[%d] but tried to Create character with empty [name] ",GetAccountId());
+ return;
+ }
+
+ // check name limitations
+ if(!ObjectMgr::IsValidName(name,true))
+ {
+ data << (uint8)CHAR_NAME_INVALID_CHARACTER;
+ SendPacket( &data );
+ return;
+ }
+
+ if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(name))
+ {
+ data << (uint8)CHAR_NAME_RESERVED;
+ SendPacket( &data );
+ return;
+ }
+
+ if(objmgr.GetPlayerGUIDByName(name))
+ {
+ data << (uint8)CHAR_CREATE_NAME_IN_USE;
+ SendPacket( &data );
+ return;
+ }
+
+ QueryResult *resultacct = loginDatabase.PQuery("SELECT SUM(numchars) FROM realmcharacters WHERE acctid = '%d'", GetAccountId());
+ if ( resultacct )
+ {
+ Field *fields=resultacct->Fetch();
+ uint32 acctcharcount = fields[0].GetUInt32();
+ delete resultacct;
+
+ if (acctcharcount >= sWorld.getConfig(CONFIG_CHARACTERS_PER_ACCOUNT))
+ {
+ data << (uint8)CHAR_CREATE_ACCOUNT_LIMIT;
+ SendPacket( &data );
+ return;
+ }
+ }
+
+ QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(guid) FROM characters WHERE account = '%d'", GetAccountId());
+ uint8 charcount = 0;
+ if ( result )
+ {
+ Field *fields=result->Fetch();
+ charcount = fields[0].GetUInt8();
+ delete result;
+
+ if (charcount >= sWorld.getConfig(CONFIG_CHARACTERS_PER_REALM))
+ {
+ data << (uint8)CHAR_CREATE_SERVER_LIMIT;
+ SendPacket( &data );
+ return;
+ }
+ }
+
+ bool AllowTwoSideAccounts = !sWorld.IsPvPRealm() || sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ACCOUNTS) || GetSecurity() > SEC_PLAYER;
+ uint32 skipCinematics = sWorld.getConfig(CONFIG_SKIP_CINEMATICS);
+
+ bool have_same_race = false;
+ if(!AllowTwoSideAccounts || skipCinematics == 1)
+ {
+ QueryResult *result2 = CharacterDatabase.PQuery("SELECT DISTINCT race FROM characters WHERE account = '%u' %s", GetAccountId(),skipCinematics == 1 ? "" : "LIMIT 1");
+ if(result2)
+ {
+ uint32 team_= Player::TeamForRace(race_);
+
+ Field* field = result2->Fetch();
+ uint8 race = field[0].GetUInt32();
+
+ // need to check team only for first character
+ // TODO: what to if account already has characters of both races?
+ if (!AllowTwoSideAccounts)
+ {
+ uint32 team=0;
+ if(race > 0)
+ team = Player::TeamForRace(race);
+
+ if(team != team_)
+ {
+ data << (uint8)CHAR_CREATE_PVP_TEAMS_VIOLATION;
+ SendPacket( &data );
+ delete result2;
+ return;
+ }
+ }
+
+ if (skipCinematics == 1)
+ {
+ // TODO: check if cinematic already shown? (already logged in?; cinematic field)
+ while (race_ != race && result2->NextRow())
+ {
+ field = result2->Fetch();
+ race = field[0].GetUInt32();
+ }
+ have_same_race = race_ == race;
+ }
+ delete result2;
+ }
+ }
+
+ // extract other data required for player creating
+ uint8 gender, skin, face, hairStyle, hairColor, facialHair, outfitId;
+ recv_data >> gender >> skin >> face;
+ recv_data >> hairStyle >> hairColor >> facialHair >> outfitId;
+
+ Player * pNewChar = new Player(this);
+ if(!pNewChar->Create( objmgr.GenerateLowGuid(HIGHGUID_PLAYER), name, race_, class_, gender, skin, face, hairStyle, hairColor, facialHair, outfitId ))
+ {
+ // Player not create (race/class problem?)
+ delete pNewChar;
+
+ data << (uint8)CHAR_CREATE_ERROR;
+ SendPacket( &data );
+
+ return;
+ }
+
+ if(have_same_race && skipCinematics == 1 || skipCinematics == 2)
+ pNewChar->setCinematic(1); // not show intro
+
+ // Player created, save it now
+ pNewChar->SaveToDB();
+ charcount+=1;
+
+ loginDatabase.PExecute("DELETE FROM realmcharacters WHERE acctid= '%d' AND realmid = '%d'", GetAccountId(), realmID);
+ loginDatabase.PExecute("INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (%u, %u, %u)", charcount, GetAccountId(), realmID);
+
+ delete pNewChar; // created only to call SaveToDB()
+
+ data << (uint8)CHAR_CREATE_SUCCESS;
+ SendPacket( &data );
+
+ std::string IP_str = GetRemoteAddress().c_str();
+ sLog.outBasic("Account: %d (IP: %s) Create Character:[%s]",GetAccountId(),IP_str.c_str(),name.c_str());
+ sLog.outChar("Account: %d (IP: %s) Create Character:[%s]",GetAccountId(),IP_str.c_str(),name.c_str());
+}
+
+void WorldSession::HandleCharDeleteOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data,8);
+
+ uint64 guid;
+ recv_data >> guid;
+
+ // can't delete loaded character
+ if(objmgr.GetPlayer(guid))
+ return;
+
+ uint32 accountId = 0;
+ std::string name;
+
+ // is guild leader
+ if(objmgr.GetGuildByLeader(guid))
+ {
+ WorldPacket data(SMSG_CHAR_DELETE, 1);
+ data << (uint8)CHAR_DELETE_FAILED_GUILD_LEADER;
+ SendPacket( &data );
+ return;
+ }
+
+ // is arena team captain
+ if(objmgr.GetArenaTeamByCapitan(guid))
+ {
+ WorldPacket data(SMSG_CHAR_DELETE, 1);
+ data << (uint8)CHAR_DELETE_FAILED_ARENA_CAPTAIN;
+ SendPacket( &data );
+ return;
+ }
+
+ QueryResult *result = CharacterDatabase.PQuery("SELECT account,name FROM characters WHERE guid='%u'", GUID_LOPART(guid));
+ if(result)
+ {
+ Field *fields = result->Fetch();
+ accountId = fields[0].GetUInt32();
+ name = fields[1].GetCppString();
+ delete result;
+ }
+
+ // prevent deleting other players' characters using cheating tools
+ if(accountId != GetAccountId())
+ return;
+
+ std::string IP_str = GetRemoteAddress();
+ sLog.outBasic("Account: %d (IP: %s) Delete Character:[%s] (guid:%u)",GetAccountId(),IP_str.c_str(),name.c_str(),GUID_LOPART(guid));
+ sLog.outChar("Account: %d (IP: %s) Delete Character:[%s] (guid: %u)",GetAccountId(),IP_str.c_str(),name.c_str(),GUID_LOPART(guid));
+
+ if(sLog.IsOutCharDump()) // optimize GetPlayerDump call
+ {
+ std::string dump = PlayerDumpWriter().GetDump(GUID_LOPART(guid));
+ sLog.outCharDump(dump.c_str(),GetAccountId(),GUID_LOPART(guid),name.c_str());
+ }
+
+ Player::DeleteFromDB(guid, GetAccountId());
+
+ WorldPacket data(SMSG_CHAR_DELETE, 1);
+ data << (uint8)CHAR_DELETE_SUCCESS;
+ SendPacket( &data );
+}
+
+void WorldSession::HandlePlayerLoginOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data,8);
+
+ m_playerLoading = true;
+ uint64 playerGuid = 0;
+
+ DEBUG_LOG( "WORLD: Recvd Player Logon Message" );
+
+ recv_data >> playerGuid;
+
+ LoginQueryHolder *holder = new LoginQueryHolder(GetAccountId(), playerGuid);
+ if(!holder->Initialize())
+ {
+ delete holder; // delete all unprocessed queries
+ m_playerLoading = false;
+ return;
+ }
+
+ CharacterDatabase.DelayQueryHolder(&chrHandler, &CharacterHandler::HandlePlayerLoginCallback, holder);
+}
+
+void WorldSession::HandlePlayerLogin(LoginQueryHolder * holder)
+{
+ uint64 playerGuid = holder->GetGuid();
+
+ Player* pCurrChar = new Player(this);
+ pCurrChar->GetMotionMaster()->Initialize();
+
+ // "GetAccountId()==db stored account id" checked in LoadFromDB (prevent login not own character using cheating tools)
+ if(!pCurrChar->LoadFromDB(GUID_LOPART(playerGuid), holder))
+ {
+ KickPlayer(); // disconnect client, player no set to session and it will not deleted or saved at kick
+ delete pCurrChar; // delete it manually
+ delete holder; // delete all unprocessed queries
+ m_playerLoading = false;
+ return;
+ }
+
+ SetPlayer(pCurrChar);
+
+ pCurrChar->SendDungeonDifficulty(false);
+
+ WorldPacket data( SMSG_LOGIN_VERIFY_WORLD, 20 );
+ data << pCurrChar->GetMapId();
+ data << pCurrChar->GetPositionX();
+ data << pCurrChar->GetPositionY();
+ data << pCurrChar->GetPositionZ();
+ data << pCurrChar->GetOrientation();
+ SendPacket(&data);
+
+ data.Initialize( SMSG_ACCOUNT_DATA_TIMES, 128 );
+ for(int i = 0; i < 32; i++)
+ data << uint32(0);
+ SendPacket(&data);
+
+ data.Initialize(SMSG_FEATURE_SYSTEM_STATUS, 2); // added in 2.2.0
+ data << uint8(2); // unknown value
+ data << uint8(0); // enable(1)/disable(0) voice chat interface in client
+ SendPacket(&data);
+
+ // Send MOTD
+ {
+ data.Initialize(SMSG_MOTD, 50); // new in 2.0.1
+ data << (uint32)0;
+
+ uint32 linecount=0;
+ std::string str_motd = sWorld.GetMotd();
+ std::string::size_type pos, nextpos;
+
+ pos = 0;
+ while ( (nextpos= str_motd.find('@',pos)) != std::string::npos )
+ {
+ if (nextpos != pos)
+ {
+ data << str_motd.substr(pos,nextpos-pos);
+ ++linecount;
+ }
+ pos = nextpos+1;
+ }
+
+ if (posGetGuildId() != 0)
+ {
+ Guild* guild = objmgr.GetGuildById(pCurrChar->GetGuildId());
+ if(guild)
+ {
+ data.Initialize(SMSG_GUILD_EVENT, (2+guild->GetMOTD().size()+1));
+ data << (uint8)GE_MOTD;
+ data << (uint8)1;
+ data << guild->GetMOTD();
+ SendPacket(&data);
+ DEBUG_LOG( "WORLD: Sent guild-motd (SMSG_GUILD_EVENT)" );
+
+ data.Initialize(SMSG_GUILD_EVENT, (5+10)); // we guess size
+ data<<(uint8)GE_SIGNED_ON;
+ data<<(uint8)1;
+ data<GetName();
+ data<GetGUID();
+ guild->BroadcastPacket(&data);
+ DEBUG_LOG( "WORLD: Sent guild-signed-on (SMSG_GUILD_EVENT)" );
+
+ // Increment online members of the guild
+ guild->IncOnlineMemberCount();
+ }
+ else
+ {
+ // 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());
+ }
+ }
+
+ if(!pCurrChar->isAlive())
+ pCurrChar->SendCorpseReclaimDelay(true);
+
+ pCurrChar->SendInitialPacketsBeforeAddToMap();
+
+ //Show cinematic at the first time that player login
+ if( !pCurrChar->getCinematic() )
+ {
+ pCurrChar->setCinematic(1);
+
+ ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(pCurrChar->getRace());
+ if(rEntry)
+ {
+ data.Initialize( SMSG_TRIGGER_CINEMATIC,4 );
+ data << uint32(rEntry->startmovie);
+ SendPacket( &data );
+ }
+ }
+
+ //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 (!MapManager::Instance().GetMap(pCurrChar->GetMapId(), pCurrChar)->Add(pCurrChar))
+ {
+ AreaTrigger const* at = objmgr.GetGoBackTrigger(pCurrChar->GetMapId());
+ if(at)
+ pCurrChar->TeleportTo(at->target_mapId, at->target_X, at->target_Y, at->target_Z, pCurrChar->GetOrientation());
+ else
+ pCurrChar->TeleportTo(pCurrChar->m_homebindMapId, pCurrChar->m_homebindX, pCurrChar->m_homebindY, pCurrChar->m_homebindZ, pCurrChar->GetOrientation());
+ }
+
+ ObjectAccessor::Instance().AddObject(pCurrChar);
+ //sLog.outDebug("Player %s added to Map.",pCurrChar->GetName());
+ pCurrChar->GetSocial()->SendSocialList();
+
+ pCurrChar->SendInitialPacketsAfterAddToMap();
+
+ CharacterDatabase.PExecute("UPDATE characters SET online = 1 WHERE guid = '%u'", pCurrChar->GetGUIDLow());
+ loginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = '%u'", GetAccountId());
+ pCurrChar->SetInGameTime( getMSTime() );
+
+ // announce group about member online (must be after add to player list to receive announce to self)
+ if(Group *group = pCurrChar->GetGroup())
+ {
+ //pCurrChar->groupInfo.group->SendInit(this); // useless
+ group->SendUpdate();
+ }
+
+ // friend status
+ sSocialMgr.SendFriendStatus(pCurrChar, FRIEND_ONLINE, pCurrChar->GetGUIDLow(), "", true);
+
+ // Place character in world (and load zone) before some object loading
+ pCurrChar->LoadCorpse();
+
+ // setting Ghost+speed if dead
+ //if ( pCurrChar->m_deathState == DEAD )
+ if (pCurrChar->m_deathState != ALIVE)
+ {
+ // not blizz like, we must correctly save and load player instead...
+ if(pCurrChar->getRace() == RACE_NIGHTELF)
+ pCurrChar->CastSpell(pCurrChar, 20584, true, 0);// auras SPELL_AURA_INCREASE_SPEED(+speed in wisp form), SPELL_AURA_INCREASE_SWIM_SPEED(+swim speed in wisp form), SPELL_AURA_TRANSFORM (to wisp form)
+ pCurrChar->CastSpell(pCurrChar, 8326, true, 0); // auras SPELL_AURA_GHOST, SPELL_AURA_INCREASE_SPEED(why?), SPELL_AURA_INCREASE_SWIM_SPEED(why?)
+
+ //pCurrChar->SetUInt32Value(UNIT_FIELD_AURA+41, 8326);
+ //pCurrChar->SetUInt32Value(UNIT_FIELD_AURA+42, 20584);
+ //pCurrChar->SetUInt32Value(UNIT_FIELD_AURAFLAGS+6, 238);
+ //pCurrChar->SetUInt32Value(UNIT_FIELD_AURALEVELS+11, 514);
+ //pCurrChar->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS+11, 65535);
+ //pCurrChar->SetUInt32Value(UNIT_FIELD_DISPLAYID, 1825);
+ //if (pCurrChar->getRace() == RACE_NIGHTELF)
+ //{
+ // pCurrChar->SetSpeed(MOVE_RUN, 1.5f*1.2f, true);
+ // pCurrChar->SetSpeed(MOVE_SWIM, 1.5f*1.2f, true);
+ //}
+ //else
+ //{
+ // pCurrChar->SetSpeed(MOVE_RUN, 1.5f, true);
+ // pCurrChar->SetSpeed(MOVE_SWIM, 1.5f, true);
+ //}
+ pCurrChar->SetMovement(MOVE_WATER_WALK);
+ }
+
+ if(uint32 sourceNode = pCurrChar->m_taxi.GetTaxiSource())
+ {
+
+ sLog.outDebug( "WORLD: Restart character %u taxi flight", pCurrChar->GetGUIDLow() );
+
+ uint32 MountId = objmgr.GetTaxiMount(sourceNode, pCurrChar->GetTeam());
+ uint32 path = pCurrChar->m_taxi.GetCurrentTaxiPath();
+
+ // search appropriate start path node
+ uint32 startNode = 0;
+
+ TaxiPathNodeList const& nodeList = sTaxiPathNodesByPath[path];
+
+ float distPrev = MAP_SIZE*MAP_SIZE;
+ float distNext =
+ (nodeList[0].x-pCurrChar->GetPositionX())*(nodeList[0].x-pCurrChar->GetPositionX())+
+ (nodeList[0].y-pCurrChar->GetPositionY())*(nodeList[0].y-pCurrChar->GetPositionY())+
+ (nodeList[0].z-pCurrChar->GetPositionZ())*(nodeList[0].z-pCurrChar->GetPositionZ());
+
+ for(uint32 i = 1; i < nodeList.size(); ++i)
+ {
+ TaxiPathNode const& node = nodeList[i];
+ TaxiPathNode const& prevNode = nodeList[i-1];
+
+ // skip nodes at another map
+ if(node.mapid != pCurrChar->GetMapId())
+ continue;
+
+ distPrev = distNext;
+
+ distNext =
+ (node.x-pCurrChar->GetPositionX())*(node.x-pCurrChar->GetPositionX())+
+ (node.y-pCurrChar->GetPositionY())*(node.y-pCurrChar->GetPositionY())+
+ (node.z-pCurrChar->GetPositionZ())*(node.z-pCurrChar->GetPositionZ());
+
+ float distNodes =
+ (node.x-prevNode.x)*(node.x-prevNode.x)+
+ (node.y-prevNode.y)*(node.y-prevNode.y)+
+ (node.z-prevNode.z)*(node.z-prevNode.z);
+
+ if(distNext + distPrev < distNodes)
+ {
+ startNode = i;
+ break;
+ }
+ }
+
+ SendDoFlight( MountId, path, startNode );
+ }
+
+ // Load pet if any and player is alive and not in taxi flight
+ if(pCurrChar->isAlive() && pCurrChar->m_taxi.GetTaxiSource()==0)
+ pCurrChar->LoadPet();
+
+ // Set FFA PvP for non GM in non-rest mode
+ if(sWorld.IsFFAPvPRealm() && !pCurrChar->isGameMaster() && !pCurrChar->HasFlag(PLAYER_FLAGS,PLAYER_FLAGS_RESTING) )
+ pCurrChar->SetFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP);
+
+ if(pCurrChar->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_CONTESTED_PVP))
+ pCurrChar->SetContestedPvP();
+
+ // Apply at_login requests
+ if(pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_SPELLS))
+ {
+ pCurrChar->resetSpells();
+ SendNotification(LANG_RESET_SPELLS);
+ }
+
+ if(pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_TALENTS))
+ {
+ pCurrChar->resetTalents(true);
+ SendNotification(LANG_RESET_TALENTS);
+ }
+
+ // show time before shutdown if shutdown planned.
+ if(sWorld.IsShutdowning())
+ sWorld.ShutdownMsg(true,pCurrChar);
+
+ if(pCurrChar->isGameMaster())
+ SendNotification(LANG_GM_ON);
+
+ std::string IP_str = GetRemoteAddress();
+ sLog.outChar("Account: %d (IP: %s) Login Character:[%s] (guid:%u)",GetAccountId(),IP_str.c_str(),pCurrChar->GetName() ,pCurrChar->GetGUID());
+
+ m_playerLoading = false;
+ delete holder;
+}
+
+void WorldSession::HandleSetFactionAtWar( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data,4+1);
+
+ DEBUG_LOG( "WORLD: Received CMSG_SET_FACTION_ATWAR" );
+
+ uint32 repListID;
+ uint8 flag;
+
+ recv_data >> repListID;
+ recv_data >> flag;
+
+ FactionStateList::iterator itr = GetPlayer()->m_factions.find(repListID);
+ if (itr == GetPlayer()->m_factions.end())
+ return;
+
+ // always invisible or hidden faction can't change war state
+ if(itr->second.Flags & (FACTION_FLAG_INVISIBLE_FORCED|FACTION_FLAG_HIDDEN) )
+ return;
+
+ GetPlayer()->SetFactionAtWar(&itr->second,flag);
+}
+
+//I think this function is never used :/ I dunno, but i guess this opcode not exists
+void WorldSession::HandleSetFactionCheat( WorldPacket & /*recv_data*/ )
+{
+ //CHECK_PACKET_SIZE(recv_data,4+4);
+
+ //sLog.outDebug("WORLD SESSION: HandleSetFactionCheat");
+ /*
+ uint32 FactionID;
+ uint32 Standing;
+
+ recv_data >> FactionID;
+ recv_data >> Standing;
+
+ std::list::iterator itr;
+
+ for(itr = GetPlayer()->factions.begin(); itr != GetPlayer()->factions.end(); ++itr)
+ {
+ if(itr->ReputationListID == FactionID)
+ {
+ itr->Standing += Standing;
+ itr->Flags = (itr->Flags | 1);
+ break;
+ }
+ }
+ */
+ GetPlayer()->UpdateReputation();
+}
+
+void WorldSession::HandleMeetingStoneInfo( WorldPacket & /*recv_data*/ )
+{
+ DEBUG_LOG( "WORLD: Received CMSG_MEETING_STONE_INFO" );
+
+ WorldPacket data(SMSG_MEETINGSTONE_SETQUEUE, 5);
+ data << uint32(0) << uint8(6);
+ SendPacket(&data);
+}
+
+void WorldSession::HandleTutorialFlag( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data,4);
+
+ uint32 iFlag;
+ recv_data >> iFlag;
+
+ uint32 wInt = (iFlag / 32);
+ if (wInt >= 8)
+ {
+ //sLog.outError("CHEATER? Account:[%d] Guid[%u] tried to send wrong CMSG_TUTORIAL_FLAG", GetAccountId(),GetGUID());
+ return;
+ }
+ uint32 rInt = (iFlag % 32);
+
+ uint32 tutflag = GetPlayer()->GetTutorialInt( wInt );
+ tutflag |= (1 << rInt);
+ GetPlayer()->SetTutorialInt( wInt, tutflag );
+
+ //sLog.outDebug("Received Tutorial Flag Set {%u}.", iFlag);
+}
+
+void WorldSession::HandleTutorialClear( WorldPacket & /*recv_data*/ )
+{
+ for ( uint32 iI = 0; iI < 8; iI++)
+ GetPlayer()->SetTutorialInt( iI, 0xFFFFFFFF );
+}
+
+void WorldSession::HandleTutorialReset( WorldPacket & /*recv_data*/ )
+{
+ for ( uint32 iI = 0; iI < 8; iI++)
+ GetPlayer()->SetTutorialInt( iI, 0x00000000 );
+}
+
+void WorldSession::HandleSetWatchedFactionIndexOpcode(WorldPacket & recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data,4);
+
+ DEBUG_LOG("WORLD: Received CMSG_SET_WATCHED_FACTION");
+ uint32 fact;
+ recv_data >> fact;
+ GetPlayer()->SetUInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, fact);
+}
+
+void WorldSession::HandleSetWatchedFactionInactiveOpcode(WorldPacket & recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data,4+1);
+
+ DEBUG_LOG("WORLD: Received CMSG_SET_FACTION_INACTIVE");
+ uint32 replistid;
+ uint8 inactive;
+ recv_data >> replistid >> inactive;
+
+ FactionStateList::iterator itr = _player->m_factions.find(replistid);
+ if (itr == _player->m_factions.end())
+ return;
+
+ _player->SetFactionInactive(&itr->second, inactive);
+}
+
+void WorldSession::HandleToggleHelmOpcode( WorldPacket & /*recv_data*/ )
+{
+ DEBUG_LOG("CMSG_TOGGLE_HELM for %s", _player->GetName());
+ _player->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM);
+}
+
+void WorldSession::HandleToggleCloakOpcode( WorldPacket & /*recv_data*/ )
+{
+ DEBUG_LOG("CMSG_TOGGLE_CLOAK for %s", _player->GetName());
+ _player->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK);
+}
+
+void WorldSession::HandleChangePlayerNameOpcode(WorldPacket& recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data,8+1);
+
+ uint64 guid;
+ std::string newname;
+ std::string oldname;
+
+ CHECK_PACKET_SIZE(recv_data, 8+1);
+
+ recv_data >> guid;
+ recv_data >> newname;
+
+ QueryResult *result = CharacterDatabase.PQuery("SELECT at_login FROM characters WHERE guid ='%u'", GUID_LOPART(guid));
+ if (result)
+ {
+ uint32 at_loginFlags;
+ Field *fields = result->Fetch();
+ at_loginFlags = fields[0].GetUInt32();
+ delete result;
+
+ if (!(at_loginFlags & AT_LOGIN_RENAME))
+ {
+ WorldPacket data(SMSG_CHAR_RENAME, 1);
+ data << (uint8)CHAR_CREATE_ERROR;
+ SendPacket( &data );
+ return;
+ }
+ }
+ else
+ {
+ WorldPacket data(SMSG_CHAR_RENAME, 1);
+ data << (uint8)CHAR_CREATE_ERROR;
+ SendPacket( &data );
+ return;
+ }
+
+ if(!objmgr.GetPlayerNameByGUID(guid, oldname)) // character not exist, because we have no name for this guid
+ {
+ WorldPacket data(SMSG_CHAR_RENAME, 1);
+ data << (uint8)CHAR_LOGIN_NO_CHARACTER;
+ SendPacket( &data );
+ return;
+ }
+
+ // prevent character rename to invalid name
+ if(!normalizePlayerName(newname))
+ {
+ WorldPacket data(SMSG_CHAR_RENAME, 1);
+ data << (uint8)CHAR_NAME_NO_NAME;
+ SendPacket( &data );
+ return;
+ }
+
+ if(!ObjectMgr::IsValidName(newname,true))
+ {
+ WorldPacket data(SMSG_CHAR_RENAME, 1);
+ data << (uint8)CHAR_NAME_INVALID_CHARACTER;
+ SendPacket( &data );
+ return;
+ }
+
+ // check name limitations
+ if(GetSecurity() == SEC_PLAYER && objmgr.IsReservedName(newname))
+ {
+ WorldPacket data(SMSG_CHAR_RENAME, 1);
+ data << (uint8)CHAR_NAME_RESERVED;
+ SendPacket( &data );
+ return;
+ }
+
+ if(objmgr.GetPlayerGUIDByName(newname)) // character with this name already exist
+ {
+ WorldPacket data(SMSG_CHAR_RENAME, 1);
+ data << (uint8)CHAR_CREATE_ERROR;
+ SendPacket( &data );
+ return;
+ }
+
+ if(newname == oldname) // checked by client
+ {
+ WorldPacket data(SMSG_CHAR_RENAME, 1);
+ data << (uint8)CHAR_NAME_FAILURE;
+ SendPacket( &data );
+ return;
+ }
+
+ // we have to check character at_login_flag & AT_LOGIN_RENAME also (fake packets hehe)
+
+ CharacterDatabase.escape_string(newname);
+ CharacterDatabase.PExecute("UPDATE characters set name = '%s', at_login = at_login & ~ %u WHERE guid ='%u'", newname.c_str(), uint32(AT_LOGIN_RENAME),GUID_LOPART(guid));
+ CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid ='%u'", GUID_LOPART(guid));
+
+ std::string IP_str = GetRemoteAddress();
+ sLog.outChar("Account: %d (IP: %s) Character:[%s] (guid:%u) Changed name to: %s",GetAccountId(),IP_str.c_str(),oldname.c_str(),GUID_LOPART(guid),newname.c_str());
+
+ WorldPacket data(SMSG_CHAR_RENAME,1+8+(newname.size()+1));
+ data << (uint8)RESPONSE_SUCCESS;
+ data << guid;
+ data << newname;
+ SendPacket(&data);
+}
+
+void WorldSession::HandleDeclinedPlayerNameOpcode(WorldPacket& recv_data)
+{
+ uint64 guid;
+
+ CHECK_PACKET_SIZE(recv_data, 8+6);
+ recv_data >> guid;
+
+ // not accept declined names for unsupported languages
+ std::string name;
+ if(!objmgr.GetPlayerNameByGUID(guid,name))
+ {
+ WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT,4+8);
+ data << (uint32)1;
+ data << guid;
+ SendPacket(&data);
+ return;
+ }
+
+ std::wstring wname;
+ if(!Utf8toWStr(name,wname))
+ {
+ WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT,4+8);
+ data << (uint32)1;
+ data << guid;
+ SendPacket(&data);
+ return;
+ }
+
+ if(!isCyrillicCharacter(wname[0])) // name already stored as only single alphabet using
+ {
+ WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT,4+8);
+ data << (uint32)1;
+ data << guid;
+ SendPacket(&data);
+ return;
+ }
+
+ std::string name2;
+ DeclinedName declinedname;
+
+ recv_data >> name2;
+
+ if(name2!=name) // character have different name
+ {
+ WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT,4+8);
+ data << (uint32)1;
+ data << guid;
+ SendPacket(&data);
+ return;
+ }
+
+ for(int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
+ {
+ recv_data >> declinedname.name[i];
+ if(!normalizePlayerName(declinedname.name[i]))
+ {
+ WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT,4+8);
+ data << (uint32)1;
+ data << guid;
+ SendPacket(&data);
+ return;
+ }
+ }
+
+ if(!ObjectMgr::CheckDeclinedNames(GetMainPartOfName(wname,0),declinedname))
+ {
+ WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT,4+8);
+ data << (uint32)1;
+ data << guid;
+ SendPacket(&data);
+ return;
+ }
+
+ for(int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
+ CharacterDatabase.escape_string(declinedname.name[i]);
+
+ CharacterDatabase.BeginTransaction();
+ CharacterDatabase.PExecute("DELETE FROM character_declinedname WHERE guid = '%u'", GUID_LOPART(guid));
+ CharacterDatabase.PExecute("INSERT INTO character_declinedname (guid, genitive, dative, accusative, instrumental, prepositional) VALUES ('%u','%s','%s','%s','%s','%s')",
+ GUID_LOPART(guid), declinedname.name[0].c_str(),declinedname.name[1].c_str(),declinedname.name[2].c_str(),declinedname.name[3].c_str(),declinedname.name[4].c_str());
+ CharacterDatabase.CommitTransaction();
+
+ WorldPacket data(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT,4+8);
+ data << (uint32)0; // OK
+ data << guid;
+ SendPacket(&data);
+}
diff --git a/src/game/Chat.cpp b/src/game/Chat.cpp
index e85053a2204..e8867c516f4 100644
--- a/src/game/Chat.cpp
+++ b/src/game/Chat.cpp
@@ -353,6 +353,7 @@ ChatCommand * ChatHandler::getCommandTable()
static ChatCommand gmCommandTable[] =
{
+ { "chat", SEC_MODERATOR, &ChatHandler::HandleGMChatCommand, "", NULL },
{ "list", SEC_PLAYER, &ChatHandler::HandleGMListCommand, "", NULL },
{ "visible", SEC_MODERATOR, &ChatHandler::HandleVisibleCommand, "", NULL },
{ "fly", SEC_ADMINISTRATOR, &ChatHandler::HandleFlyModeCommand, "", NULL },
@@ -507,18 +508,29 @@ const char *ChatHandler::GetMangosString(int32 entry)
return m_session->GetMangosString(entry);
}
-bool ChatHandler::hasStringAbbr(const char* s1, const char* s2)
+bool ChatHandler::hasStringAbbr(const char* name, const char* part)
{
- for(;;)
+ // non "" command
+ if( *name )
{
- if( !*s2 )
- return true;
- else if( !*s1 )
+ // "" part from non-"" command
+ if( !*part )
return false;
- else if( tolower( *s1 ) != tolower( *s2 ) )
- return false;
- ++s1; ++s2;
+
+ for(;;)
+ {
+ if( !*part )
+ return true;
+ else if( !*name )
+ return false;
+ else if( tolower( *name ) != tolower( *part ) )
+ return false;
+ ++name; ++part;
+ }
}
+ // allow with any for ""
+
+ return true;
}
void ChatHandler::SendSysMessage(const char *str)
@@ -594,13 +606,9 @@ bool ChatHandler::ExecuteCommandInTable(ChatCommand *table, const char* text, st
while (*text == ' ') ++text;
- if(!cmd.length())
- return false;
-
for(uint32 i = 0; table[i].Name != NULL; i++)
{
- // allow pass "" command name in table
- if(strlen(table[i].Name) && !hasStringAbbr(table[i].Name, cmd.c_str()))
+ if( !hasStringAbbr(table[i].Name, cmd.c_str()) )
continue;
// select subcommand from child commands list
@@ -688,8 +696,7 @@ bool ChatHandler::ShowHelpForSubCommands(ChatCommand *table, char const* cmd, ch
if(m_session->GetSecurity() < table[i].SecurityLevel)
continue;
- if(strlen(table[i].Name) && !hasStringAbbr(table[i].Name, subcmd))
- continue;
+ if( !hasStringAbbr(table[i].Name, subcmd) )
(list += "\n ") += table[i].Name;
}
@@ -717,7 +724,7 @@ bool ChatHandler::ShowHelpForCommand(ChatCommand *table, const char* cmd)
if(m_session->GetSecurity() < table[i].SecurityLevel)
continue;
- if(strlen(table[i].Name) && !hasStringAbbr(table[i].Name, cmd))
+ if( !hasStringAbbr(table[i].Name, cmd) )
continue;
// have subcommand
diff --git a/src/game/Chat.h b/src/game/Chat.h
index 26e3a3a969a..74366659f66 100644
--- a/src/game/Chat.h
+++ b/src/game/Chat.h
@@ -69,7 +69,7 @@ class ChatHandler
int ParseCommands(const char* text);
protected:
- bool hasStringAbbr(const char* s1, const char* s2);
+ bool hasStringAbbr(const char* name, const char* part);
void SendGlobalSysMessage(const char *str);
bool ExecuteCommandInTable(ChatCommand *table, const char* text, std::string fullcommand);
@@ -94,6 +94,7 @@ class ChatHandler
bool HandleAnnounceCommand(const char* args);
bool HandleNotifyCommand(const char* args);
bool HandleGMmodeCommand(const char* args);
+ bool HandleGMChatCommand(const char* args);
bool HandleVisibleCommand(const char* args);
bool HandleGPSCommand(const char* args);
bool HandleTaxiCheatCommand(const char* args);
diff --git a/src/game/ChatHandler.cpp b/src/game/ChatHandler.cpp
index dd3a711858d..3a3f2d1d1db 100644
--- a/src/game/ChatHandler.cpp
+++ b/src/game/ChatHandler.cpp
@@ -1,583 +1,583 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS
- *
- * 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 "Log.h"
-#include "WorldPacket.h"
-#include "WorldSession.h"
-#include "World.h"
-#include "Opcodes.h"
-#include "ObjectMgr.h"
-#include "Chat.h"
-#include "Database/DatabaseEnv.h"
-#include "ChannelMgr.h"
-#include "Group.h"
-#include "Guild.h"
-#include "MapManager.h"
-#include "ObjectAccessor.h"
-#include "ScriptCalls.h"
-#include "Player.h"
-#include "SpellAuras.h"
-#include "Language.h"
-#include "Util.h"
-
-void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data,4+4+1);
-
- uint32 type;
- uint32 lang;
-
- recv_data >> type;
- recv_data >> lang;
-
- if(type >= MAX_CHAT_MSG_TYPE)
- {
- sLog.outError("CHAT: Wrong message type received: %u", type);
- return;
- }
-
- //sLog.outDebug("CHAT: packet received. type %u, lang %u", type, lang );
-
- // prevent talking at unknown language (cheating)
- LanguageDesc const* langDesc = GetLanguageDescByID(lang);
- if(!langDesc)
- {
- SendNotification("Unknown language");
- return;
- }
- if(langDesc->skill_id != 0 && !_player->HasSkill(langDesc->skill_id))
- {
- // also check SPELL_AURA_COMPREHEND_LANGUAGE (client offers option to speak in that language)
- Unit::AuraList const& langAuras = _player->GetAurasByType(SPELL_AURA_COMPREHEND_LANGUAGE);
- bool foundAura = false;
- for(Unit::AuraList::const_iterator i = langAuras.begin();i != langAuras.end(); ++i)
- {
- if((*i)->GetModifier()->m_miscvalue == lang)
- {
- foundAura = true;
- break;
- }
- }
- if(!foundAura)
- {
- SendNotification("You don't know that language");
- return;
- }
- }
-
- if(lang == LANG_ADDON)
- {
- // Disabled addon channel?
- if(!sWorld.getConfig(CONFIG_ADDON_CHANNEL))
- return;
- }
- // LANG_ADDON should not be changed nor be affected by flood control
- else
- {
- // send in universal language if player in .gmon mode (ignore spell effects)
- if (_player->isGameMaster())
- lang = LANG_UNIVERSAL;
- else
- {
- // send in universal language in two side iteration allowed mode
- if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT))
- lang = LANG_UNIVERSAL;
- else
- {
- switch(type)
- {
- case CHAT_MSG_PARTY:
- case CHAT_MSG_RAID:
- case CHAT_MSG_RAID_LEADER:
- case CHAT_MSG_RAID_WARNING:
- // allow two side chat at group channel if two side group allowed
- if(sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
- lang = LANG_UNIVERSAL;
- break;
- case CHAT_MSG_GUILD:
- case CHAT_MSG_OFFICER:
- // allow two side chat at guild channel if two side guild allowed
- if(sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD))
- lang = LANG_UNIVERSAL;
- break;
- }
- }
-
- // but overwrite it by SPELL_AURA_MOD_LANGUAGE auras (only single case used)
- Unit::AuraList const& ModLangAuras = _player->GetAurasByType(SPELL_AURA_MOD_LANGUAGE);
- if(!ModLangAuras.empty())
- lang = ModLangAuras.front()->GetModifier()->m_miscvalue;
- }
-
- if (!_player->CanSpeak())
- {
- std::string timeStr = secsToTimeString(m_muteTime - time(NULL));
- SendNotification(GetMangosString(LANG_WAIT_BEFORE_SPEAKING),timeStr.c_str());
- return;
- }
-
- if (type != CHAT_MSG_AFK && type != CHAT_MSG_DND)
- GetPlayer()->UpdateSpeakTime();
- }
-
- switch(type)
- {
- case CHAT_MSG_SAY:
- case CHAT_MSG_EMOTE:
- case CHAT_MSG_YELL:
- {
- std::string msg = "";
- recv_data >> msg;
-
- if(msg.empty())
- break;
-
- if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
- break;
-
- // strip invisible characters for non-addon messages
- if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
- stripLineInvisibleChars(msg);
-
- if(msg.empty())
- break;
-
- if(type == CHAT_MSG_SAY)
- GetPlayer()->Say(msg, lang);
- else if(type == CHAT_MSG_EMOTE)
- GetPlayer()->TextEmote(msg);
- else if(type == CHAT_MSG_YELL)
- GetPlayer()->Yell(msg, lang);
- } break;
-
- case CHAT_MSG_WHISPER:
- {
- std::string to, msg;
- recv_data >> to;
- CHECK_PACKET_SIZE(recv_data,4+4+(to.size()+1)+1);
- recv_data >> msg;
-
- // strip invisible characters for non-addon messages
- if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
- stripLineInvisibleChars(msg);
-
- if(msg.empty())
- break;
-
- if(!normalizePlayerName(to))
- {
- WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, (to.size()+1));
- data<GetSession()->GetSecurity() : 0;
- if(!player || tSecurity == SEC_PLAYER && pSecurity > SEC_PLAYER && !player->isAcceptWhispers())
- {
- WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, (to.size()+1));
- data<GetTeam();
- uint32 sideb = player->GetTeam();
- if( sidea != sideb )
- {
- WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, (to.size()+1));
- data<Whisper(msg, lang,player->GetGUID());
- } break;
-
- case CHAT_MSG_PARTY:
- {
- std::string msg = "";
- recv_data >> msg;
-
- if(msg.empty())
- break;
-
- if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
- break;
-
- // strip invisible characters for non-addon messages
- if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
- stripLineInvisibleChars(msg);
-
- if(msg.empty())
- break;
-
- Group *group = GetPlayer()->GetGroup();
- if(!group)
- return;
-
- WorldPacket data;
- ChatHandler::FillMessageData(&data, this, CHAT_MSG_PARTY, lang, NULL, 0, msg.c_str(),NULL);
- group->BroadcastPacket(&data, group->GetMemberGroup(GetPlayer()->GetGUID()));
- }
- break;
- case CHAT_MSG_GUILD:
- {
- std::string msg = "";
- recv_data >> msg;
-
- if(msg.empty())
- break;
-
- if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
- break;
-
- // strip invisible characters for non-addon messages
- if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
- stripLineInvisibleChars(msg);
-
- if(msg.empty())
- break;
-
- if (GetPlayer()->GetGuildId())
- {
- Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId());
- if (guild)
- guild->BroadcastToGuild(this, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL);
- }
-
- break;
- }
- case CHAT_MSG_OFFICER:
- {
- std::string msg = "";
- recv_data >> msg;
-
- if(msg.empty())
- break;
-
- if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
- break;
-
- // strip invisible characters for non-addon messages
- if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
- stripLineInvisibleChars(msg);
-
- if(msg.empty())
- break;
-
- if (GetPlayer()->GetGuildId())
- {
- Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId());
- if (guild)
- guild->BroadcastToOfficers(this, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL);
- }
- break;
- }
- case CHAT_MSG_RAID:
- {
- std::string msg="";
- recv_data >> msg;
-
- if(msg.empty())
- break;
-
- if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
- break;
-
- // strip invisible characters for non-addon messages
- if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
- stripLineInvisibleChars(msg);
-
- if(msg.empty())
- break;
-
- Group *group = GetPlayer()->GetGroup();
- if(!group || !group->isRaidGroup())
- return;
-
- WorldPacket data;
- ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID, lang, "", 0, msg.c_str(),NULL);
- group->BroadcastPacket(&data);
- } break;
- case CHAT_MSG_RAID_LEADER:
- {
- std::string msg="";
- recv_data >> msg;
-
- if(msg.empty())
- break;
-
- if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
- break;
-
- // strip invisible characters for non-addon messages
- if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
- stripLineInvisibleChars(msg);
-
- if(msg.empty())
- break;
-
- Group *group = GetPlayer()->GetGroup();
- if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID()))
- return;
-
- WorldPacket data;
- ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_LEADER, lang, "", 0, msg.c_str(),NULL);
- group->BroadcastPacket(&data);
- } break;
- case CHAT_MSG_RAID_WARNING:
- {
- std::string msg="";
- recv_data >> msg;
-
- // strip invisible characters for non-addon messages
- if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
- stripLineInvisibleChars(msg);
-
- if(msg.empty())
- break;
-
- Group *group = GetPlayer()->GetGroup();
- if(!group || !group->isRaidGroup() || !(group->IsLeader(GetPlayer()->GetGUID()) || group->IsAssistant(GetPlayer()->GetGUID())))
- return;
-
- WorldPacket data;
- ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_WARNING, lang, "", 0, msg.c_str(),NULL);
- group->BroadcastPacket(&data);
- } break;
-
- case CHAT_MSG_BATTLEGROUND:
- {
- std::string msg="";
- recv_data >> msg;
-
- // strip invisible characters for non-addon messages
- if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
- stripLineInvisibleChars(msg);
-
- if(msg.empty())
- break;
-
- Group *group = GetPlayer()->GetGroup();
- if(!group || !group->isRaidGroup())
- return;
-
- WorldPacket data;
- ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND, lang, "", 0, msg.c_str(),NULL);
- group->BroadcastPacket(&data);
- } break;
-
- case CHAT_MSG_BATTLEGROUND_LEADER:
- {
- std::string msg="";
- recv_data >> msg;
-
- // strip invisible characters for non-addon messages
- if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
- stripLineInvisibleChars(msg);
-
- if(msg.empty())
- break;
-
- Group *group = GetPlayer()->GetGroup();
- if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID()))
- return;
-
- WorldPacket data;
- ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND_LEADER, lang, "", 0, msg.c_str(),NULL);
- group->BroadcastPacket(&data);
- } break;
-
- case CHAT_MSG_CHANNEL:
- {
- std::string channel = "", msg = "";
- recv_data >> channel;
-
- // recheck
- CHECK_PACKET_SIZE(recv_data,4+4+(channel.size()+1)+1);
-
- recv_data >> msg;
-
- // strip invisible characters for non-addon messages
- if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
- stripLineInvisibleChars(msg);
-
- if(msg.empty())
- break;
-
- if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
- {
- if(Channel *chn = cMgr->GetChannel(channel,_player))
- chn->Say(_player->GetGUID(),msg.c_str(),lang);
- }
- } break;
-
- case CHAT_MSG_AFK:
- {
- std::string msg;
- recv_data >> msg;
-
- if((msg.empty() || !_player->isAFK()) && !_player->isInCombat() )
- {
- if(!_player->isAFK())
- {
- if(msg.empty())
- msg = GetMangosString(LANG_PLAYER_AFK_DEFAULT);
- _player->afkMsg = msg;
- }
- _player->ToggleAFK();
- if(_player->isAFK() && _player->isDND())
- _player->ToggleDND();
- }
- } break;
-
- case CHAT_MSG_DND:
- {
- std::string msg;
- recv_data >> msg;
-
- if(msg.empty() || !_player->isDND())
- {
- if(!_player->isDND())
- {
- if(msg.empty())
- msg = GetMangosString(LANG_PLAYER_DND_DEFAULT);
- _player->dndMsg = msg;
- }
- _player->ToggleDND();
- if(_player->isDND() && _player->isAFK())
- _player->ToggleAFK();
- }
- } break;
-
- default:
- sLog.outError("CHAT: unknown message type %u, lang: %u", type, lang);
- break;
- }
-}
-
-void WorldSession::HandleEmoteOpcode( WorldPacket & recv_data )
-{
- if(!GetPlayer()->isAlive())
- return;
- CHECK_PACKET_SIZE(recv_data,4);
-
- uint32 emote;
- recv_data >> emote;
- GetPlayer()->HandleEmoteCommand(emote);
-}
-
-void WorldSession::HandleTextEmoteOpcode( WorldPacket & recv_data )
-{
- if(!GetPlayer()->isAlive())
- return;
-
- if (!GetPlayer()->CanSpeak())
- {
- std::string timeStr = secsToTimeString(m_muteTime - time(NULL));
- SendNotification(GetMangosString(LANG_WAIT_BEFORE_SPEAKING),timeStr.c_str());
- return;
- }
-
- CHECK_PACKET_SIZE(recv_data,4+4+8);
-
- uint32 text_emote, emoteNum;
- uint64 guid;
-
- recv_data >> text_emote;
- recv_data >> emoteNum;
- recv_data >> guid;
-
- const char *nam = 0;
- uint32 namlen = 1;
-
- Unit* unit = ObjectAccessor::GetUnit(*_player, guid);
- Creature *pCreature = dynamic_cast(unit);
- if(unit)
- {
- nam = unit->GetName();
- namlen = (nam ? strlen(nam) : 0) + 1;
- }
-
- EmotesTextEntry const *em = sEmotesTextStore.LookupEntry(text_emote);
- if (em)
- {
- uint32 emote_anim = em->textid;
-
- WorldPacket data;
-
- switch(emote_anim)
- {
- case EMOTE_STATE_SLEEP:
- case EMOTE_STATE_SIT:
- case EMOTE_STATE_KNEEL:
- case EMOTE_ONESHOT_NONE:
- break;
- default:
- GetPlayer()->HandleEmoteCommand(emote_anim);
- break;
- }
-
- data.Initialize(SMSG_TEXT_EMOTE, (20+namlen));
- data << GetPlayer()->GetGUID();
- data << (uint32)text_emote;
- data << emoteNum;
- data << (uint32)namlen;
- if( namlen > 1 )
- {
- data.append(nam, namlen);
- }
- else
- {
- data << (uint8)0x00;
- }
-
- GetPlayer()->SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true);
-
- //Send scripted event call
- if (pCreature && Script)
- Script->ReceiveEmote(GetPlayer(),pCreature,text_emote);
- }
-}
-
-void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 8+1);
-
- uint64 iguid;
- uint8 unk;
- //sLog.outDebug("WORLD: Received CMSG_CHAT_IGNORED");
-
- recv_data >> iguid;
- recv_data >> unk; // probably related to spam reporting
-
- Player *player = objmgr.GetPlayer(iguid);
- if(!player || !player->GetSession())
- return;
-
- WorldPacket data;
- ChatHandler::FillMessageData(&data, this, CHAT_MSG_IGNORED, LANG_UNIVERSAL, NULL, GetPlayer()->GetGUID(), GetPlayer()->GetName(),NULL);
- player->GetSession()->SendPacket(&data);
-}
+/*
+ * Copyright (C) 2005-2008 MaNGOS
+ *
+ * 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 "Log.h"
+#include "WorldPacket.h"
+#include "WorldSession.h"
+#include "World.h"
+#include "Opcodes.h"
+#include "ObjectMgr.h"
+#include "Chat.h"
+#include "Database/DatabaseEnv.h"
+#include "ChannelMgr.h"
+#include "Group.h"
+#include "Guild.h"
+#include "MapManager.h"
+#include "ObjectAccessor.h"
+#include "ScriptCalls.h"
+#include "Player.h"
+#include "SpellAuras.h"
+#include "Language.h"
+#include "Util.h"
+
+void WorldSession::HandleMessagechatOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data,4+4+1);
+
+ uint32 type;
+ uint32 lang;
+
+ recv_data >> type;
+ recv_data >> lang;
+
+ if(type >= MAX_CHAT_MSG_TYPE)
+ {
+ sLog.outError("CHAT: Wrong message type received: %u", type);
+ return;
+ }
+
+ //sLog.outDebug("CHAT: packet received. type %u, lang %u", type, lang );
+
+ // prevent talking at unknown language (cheating)
+ LanguageDesc const* langDesc = GetLanguageDescByID(lang);
+ if(!langDesc)
+ {
+ SendNotification(LANG_UNKNOWN_LANGUAGE);
+ return;
+ }
+ if(langDesc->skill_id != 0 && !_player->HasSkill(langDesc->skill_id))
+ {
+ // also check SPELL_AURA_COMPREHEND_LANGUAGE (client offers option to speak in that language)
+ Unit::AuraList const& langAuras = _player->GetAurasByType(SPELL_AURA_COMPREHEND_LANGUAGE);
+ bool foundAura = false;
+ for(Unit::AuraList::const_iterator i = langAuras.begin();i != langAuras.end(); ++i)
+ {
+ if((*i)->GetModifier()->m_miscvalue == lang)
+ {
+ foundAura = true;
+ break;
+ }
+ }
+ if(!foundAura)
+ {
+ SendNotification(LANG_NOT_LEARNED_LANGUAGE);
+ return;
+ }
+ }
+
+ if(lang == LANG_ADDON)
+ {
+ // Disabled addon channel?
+ if(!sWorld.getConfig(CONFIG_ADDON_CHANNEL))
+ return;
+ }
+ // LANG_ADDON should not be changed nor be affected by flood control
+ else
+ {
+ // send in universal language if player in .gmon mode (ignore spell effects)
+ if (_player->isGameMaster())
+ lang = LANG_UNIVERSAL;
+ else
+ {
+ // send in universal language in two side iteration allowed mode
+ if (sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CHAT))
+ lang = LANG_UNIVERSAL;
+ else
+ {
+ switch(type)
+ {
+ case CHAT_MSG_PARTY:
+ case CHAT_MSG_RAID:
+ case CHAT_MSG_RAID_LEADER:
+ case CHAT_MSG_RAID_WARNING:
+ // allow two side chat at group channel if two side group allowed
+ if(sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP))
+ lang = LANG_UNIVERSAL;
+ break;
+ case CHAT_MSG_GUILD:
+ case CHAT_MSG_OFFICER:
+ // allow two side chat at guild channel if two side guild allowed
+ if(sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD))
+ lang = LANG_UNIVERSAL;
+ break;
+ }
+ }
+
+ // but overwrite it by SPELL_AURA_MOD_LANGUAGE auras (only single case used)
+ Unit::AuraList const& ModLangAuras = _player->GetAurasByType(SPELL_AURA_MOD_LANGUAGE);
+ if(!ModLangAuras.empty())
+ lang = ModLangAuras.front()->GetModifier()->m_miscvalue;
+ }
+
+ if (!_player->CanSpeak())
+ {
+ std::string timeStr = secsToTimeString(m_muteTime - time(NULL));
+ SendNotification(GetMangosString(LANG_WAIT_BEFORE_SPEAKING),timeStr.c_str());
+ return;
+ }
+
+ if (type != CHAT_MSG_AFK && type != CHAT_MSG_DND)
+ GetPlayer()->UpdateSpeakTime();
+ }
+
+ switch(type)
+ {
+ case CHAT_MSG_SAY:
+ case CHAT_MSG_EMOTE:
+ case CHAT_MSG_YELL:
+ {
+ std::string msg = "";
+ recv_data >> msg;
+
+ if(msg.empty())
+ break;
+
+ if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
+ break;
+
+ // strip invisible characters for non-addon messages
+ if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
+ stripLineInvisibleChars(msg);
+
+ if(msg.empty())
+ break;
+
+ if(type == CHAT_MSG_SAY)
+ GetPlayer()->Say(msg, lang);
+ else if(type == CHAT_MSG_EMOTE)
+ GetPlayer()->TextEmote(msg);
+ else if(type == CHAT_MSG_YELL)
+ GetPlayer()->Yell(msg, lang);
+ } break;
+
+ case CHAT_MSG_WHISPER:
+ {
+ std::string to, msg;
+ recv_data >> to;
+ CHECK_PACKET_SIZE(recv_data,4+4+(to.size()+1)+1);
+ recv_data >> msg;
+
+ // strip invisible characters for non-addon messages
+ if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
+ stripLineInvisibleChars(msg);
+
+ if(msg.empty())
+ break;
+
+ if(!normalizePlayerName(to))
+ {
+ WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, (to.size()+1));
+ data<GetSession()->GetSecurity() : 0;
+ if(!player || tSecurity == SEC_PLAYER && pSecurity > SEC_PLAYER && !player->isAcceptWhispers())
+ {
+ WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, (to.size()+1));
+ data<GetTeam();
+ uint32 sideb = player->GetTeam();
+ if( sidea != sideb )
+ {
+ WorldPacket data(SMSG_CHAT_PLAYER_NOT_FOUND, (to.size()+1));
+ data<Whisper(msg, lang,player->GetGUID());
+ } break;
+
+ case CHAT_MSG_PARTY:
+ {
+ std::string msg = "";
+ recv_data >> msg;
+
+ if(msg.empty())
+ break;
+
+ if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
+ break;
+
+ // strip invisible characters for non-addon messages
+ if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
+ stripLineInvisibleChars(msg);
+
+ if(msg.empty())
+ break;
+
+ Group *group = GetPlayer()->GetGroup();
+ if(!group)
+ return;
+
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, this, CHAT_MSG_PARTY, lang, NULL, 0, msg.c_str(),NULL);
+ group->BroadcastPacket(&data, group->GetMemberGroup(GetPlayer()->GetGUID()));
+ }
+ break;
+ case CHAT_MSG_GUILD:
+ {
+ std::string msg = "";
+ recv_data >> msg;
+
+ if(msg.empty())
+ break;
+
+ if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
+ break;
+
+ // strip invisible characters for non-addon messages
+ if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
+ stripLineInvisibleChars(msg);
+
+ if(msg.empty())
+ break;
+
+ if (GetPlayer()->GetGuildId())
+ {
+ Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId());
+ if (guild)
+ guild->BroadcastToGuild(this, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL);
+ }
+
+ break;
+ }
+ case CHAT_MSG_OFFICER:
+ {
+ std::string msg = "";
+ recv_data >> msg;
+
+ if(msg.empty())
+ break;
+
+ if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
+ break;
+
+ // strip invisible characters for non-addon messages
+ if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
+ stripLineInvisibleChars(msg);
+
+ if(msg.empty())
+ break;
+
+ if (GetPlayer()->GetGuildId())
+ {
+ Guild *guild = objmgr.GetGuildById(GetPlayer()->GetGuildId());
+ if (guild)
+ guild->BroadcastToOfficers(this, msg, lang == LANG_ADDON ? LANG_ADDON : LANG_UNIVERSAL);
+ }
+ break;
+ }
+ case CHAT_MSG_RAID:
+ {
+ std::string msg="";
+ recv_data >> msg;
+
+ if(msg.empty())
+ break;
+
+ if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
+ break;
+
+ // strip invisible characters for non-addon messages
+ if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
+ stripLineInvisibleChars(msg);
+
+ if(msg.empty())
+ break;
+
+ Group *group = GetPlayer()->GetGroup();
+ if(!group || !group->isRaidGroup())
+ return;
+
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID, lang, "", 0, msg.c_str(),NULL);
+ group->BroadcastPacket(&data);
+ } break;
+ case CHAT_MSG_RAID_LEADER:
+ {
+ std::string msg="";
+ recv_data >> msg;
+
+ if(msg.empty())
+ break;
+
+ if (ChatHandler(this).ParseCommands(msg.c_str()) > 0)
+ break;
+
+ // strip invisible characters for non-addon messages
+ if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
+ stripLineInvisibleChars(msg);
+
+ if(msg.empty())
+ break;
+
+ Group *group = GetPlayer()->GetGroup();
+ if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID()))
+ return;
+
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_LEADER, lang, "", 0, msg.c_str(),NULL);
+ group->BroadcastPacket(&data);
+ } break;
+ case CHAT_MSG_RAID_WARNING:
+ {
+ std::string msg="";
+ recv_data >> msg;
+
+ // strip invisible characters for non-addon messages
+ if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
+ stripLineInvisibleChars(msg);
+
+ if(msg.empty())
+ break;
+
+ Group *group = GetPlayer()->GetGroup();
+ if(!group || !group->isRaidGroup() || !(group->IsLeader(GetPlayer()->GetGUID()) || group->IsAssistant(GetPlayer()->GetGUID())))
+ return;
+
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, this, CHAT_MSG_RAID_WARNING, lang, "", 0, msg.c_str(),NULL);
+ group->BroadcastPacket(&data);
+ } break;
+
+ case CHAT_MSG_BATTLEGROUND:
+ {
+ std::string msg="";
+ recv_data >> msg;
+
+ // strip invisible characters for non-addon messages
+ if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
+ stripLineInvisibleChars(msg);
+
+ if(msg.empty())
+ break;
+
+ Group *group = GetPlayer()->GetGroup();
+ if(!group || !group->isRaidGroup())
+ return;
+
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND, lang, "", 0, msg.c_str(),NULL);
+ group->BroadcastPacket(&data);
+ } break;
+
+ case CHAT_MSG_BATTLEGROUND_LEADER:
+ {
+ std::string msg="";
+ recv_data >> msg;
+
+ // strip invisible characters for non-addon messages
+ if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
+ stripLineInvisibleChars(msg);
+
+ if(msg.empty())
+ break;
+
+ Group *group = GetPlayer()->GetGroup();
+ if(!group || !group->isRaidGroup() || !group->IsLeader(GetPlayer()->GetGUID()))
+ return;
+
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, this, CHAT_MSG_BATTLEGROUND_LEADER, lang, "", 0, msg.c_str(),NULL);
+ group->BroadcastPacket(&data);
+ } break;
+
+ case CHAT_MSG_CHANNEL:
+ {
+ std::string channel = "", msg = "";
+ recv_data >> channel;
+
+ // recheck
+ CHECK_PACKET_SIZE(recv_data,4+4+(channel.size()+1)+1);
+
+ recv_data >> msg;
+
+ // strip invisible characters for non-addon messages
+ if (lang != LANG_ADDON && sWorld.getConfig(CONFIG_CHAT_FAKE_MESSAGE_PREVENTING))
+ stripLineInvisibleChars(msg);
+
+ if(msg.empty())
+ break;
+
+ if(ChannelMgr* cMgr = channelMgr(_player->GetTeam()))
+ {
+ if(Channel *chn = cMgr->GetChannel(channel,_player))
+ chn->Say(_player->GetGUID(),msg.c_str(),lang);
+ }
+ } break;
+
+ case CHAT_MSG_AFK:
+ {
+ std::string msg;
+ recv_data >> msg;
+
+ if((msg.empty() || !_player->isAFK()) && !_player->isInCombat() )
+ {
+ if(!_player->isAFK())
+ {
+ if(msg.empty())
+ msg = GetMangosString(LANG_PLAYER_AFK_DEFAULT);
+ _player->afkMsg = msg;
+ }
+ _player->ToggleAFK();
+ if(_player->isAFK() && _player->isDND())
+ _player->ToggleDND();
+ }
+ } break;
+
+ case CHAT_MSG_DND:
+ {
+ std::string msg;
+ recv_data >> msg;
+
+ if(msg.empty() || !_player->isDND())
+ {
+ if(!_player->isDND())
+ {
+ if(msg.empty())
+ msg = GetMangosString(LANG_PLAYER_DND_DEFAULT);
+ _player->dndMsg = msg;
+ }
+ _player->ToggleDND();
+ if(_player->isDND() && _player->isAFK())
+ _player->ToggleAFK();
+ }
+ } break;
+
+ default:
+ sLog.outError("CHAT: unknown message type %u, lang: %u", type, lang);
+ break;
+ }
+}
+
+void WorldSession::HandleEmoteOpcode( WorldPacket & recv_data )
+{
+ if(!GetPlayer()->isAlive())
+ return;
+ CHECK_PACKET_SIZE(recv_data,4);
+
+ uint32 emote;
+ recv_data >> emote;
+ GetPlayer()->HandleEmoteCommand(emote);
+}
+
+void WorldSession::HandleTextEmoteOpcode( WorldPacket & recv_data )
+{
+ if(!GetPlayer()->isAlive())
+ return;
+
+ if (!GetPlayer()->CanSpeak())
+ {
+ std::string timeStr = secsToTimeString(m_muteTime - time(NULL));
+ SendNotification(GetMangosString(LANG_WAIT_BEFORE_SPEAKING),timeStr.c_str());
+ return;
+ }
+
+ CHECK_PACKET_SIZE(recv_data,4+4+8);
+
+ uint32 text_emote, emoteNum;
+ uint64 guid;
+
+ recv_data >> text_emote;
+ recv_data >> emoteNum;
+ recv_data >> guid;
+
+ const char *nam = 0;
+ uint32 namlen = 1;
+
+ Unit* unit = ObjectAccessor::GetUnit(*_player, guid);
+ Creature *pCreature = dynamic_cast(unit);
+ if(unit)
+ {
+ nam = unit->GetName();
+ namlen = (nam ? strlen(nam) : 0) + 1;
+ }
+
+ EmotesTextEntry const *em = sEmotesTextStore.LookupEntry(text_emote);
+ if (em)
+ {
+ uint32 emote_anim = em->textid;
+
+ WorldPacket data;
+
+ switch(emote_anim)
+ {
+ case EMOTE_STATE_SLEEP:
+ case EMOTE_STATE_SIT:
+ case EMOTE_STATE_KNEEL:
+ case EMOTE_ONESHOT_NONE:
+ break;
+ default:
+ GetPlayer()->HandleEmoteCommand(emote_anim);
+ break;
+ }
+
+ data.Initialize(SMSG_TEXT_EMOTE, (20+namlen));
+ data << GetPlayer()->GetGUID();
+ data << (uint32)text_emote;
+ data << emoteNum;
+ data << (uint32)namlen;
+ if( namlen > 1 )
+ {
+ data.append(nam, namlen);
+ }
+ else
+ {
+ data << (uint8)0x00;
+ }
+
+ GetPlayer()->SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true);
+
+ //Send scripted event call
+ if (pCreature && Script)
+ Script->ReceiveEmote(GetPlayer(),pCreature,text_emote);
+ }
+}
+
+void WorldSession::HandleChatIgnoredOpcode(WorldPacket& recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 8+1);
+
+ uint64 iguid;
+ uint8 unk;
+ //sLog.outDebug("WORLD: Received CMSG_CHAT_IGNORED");
+
+ recv_data >> iguid;
+ recv_data >> unk; // probably related to spam reporting
+
+ Player *player = objmgr.GetPlayer(iguid);
+ if(!player || !player->GetSession())
+ return;
+
+ WorldPacket data;
+ ChatHandler::FillMessageData(&data, this, CHAT_MSG_IGNORED, LANG_UNIVERSAL, NULL, GetPlayer()->GetGUID(), GetPlayer()->GetName(),NULL);
+ player->GetSession()->SendPacket(&data);
+}
diff --git a/src/game/ConfusedMovementGenerator.cpp b/src/game/ConfusedMovementGenerator.cpp
index f1e7c2c1548..7b4c5b91f71 100644
--- a/src/game/ConfusedMovementGenerator.cpp
+++ b/src/game/ConfusedMovementGenerator.cpp
@@ -1,155 +1,155 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS
- *
- * 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 "Creature.h"
-#include "MapManager.h"
-#include "Opcodes.h"
-#include "ConfusedMovementGenerator.h"
-#include "DestinationHolderImp.h"
-
-template
-void
-ConfusedMovementGenerator::Initialize(T &unit)
-{
- const float wander_distance=11;
- float x,y,z;
- x = unit.GetPositionX();
- y = unit.GetPositionY();
- z = unit.GetPositionZ();
- uint32 mapid=unit.GetMapId();
-
- Map const* map = MapManager::Instance().GetBaseMap(mapid);
-
- i_nextMove = 1;
-
- bool is_water_ok, is_land_ok;
- _InitSpecific(unit, is_water_ok, is_land_ok);
-
- for(unsigned int idx=0; idx < MAX_CONF_WAYPOINTS+1; ++idx)
- {
- const float wanderX=wander_distance*rand_norm() - wander_distance/2;
- const float wanderY=wander_distance*rand_norm() - wander_distance/2;
-
- i_waypoints[idx][0] = x + wanderX;
- i_waypoints[idx][1] = y + wanderY;
-
- // prevent invalid coordinates generation
- MaNGOS::NormalizeMapCoord(i_waypoints[idx][0]);
- MaNGOS::NormalizeMapCoord(i_waypoints[idx][1]);
-
- bool is_water = map->IsInWater(i_waypoints[idx][0],i_waypoints[idx][1],z);
- // if generated wrong path just ignore
- if( is_water && !is_water_ok || !is_water && !is_land_ok )
- {
- i_waypoints[idx][0] = idx > 0 ? i_waypoints[idx-1][0] : x;
- i_waypoints[idx][1] = idx > 0 ? i_waypoints[idx-1][1] : y;
- }
- unit.UpdateGroundPositionZ(i_waypoints[idx][0],i_waypoints[idx][1],z);
- i_waypoints[idx][2] = z;
- }
-
- unit.StopMoving();
- unit.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
- unit.addUnitState(UNIT_STAT_CONFUSED);
-}
-
-template<>
-void
-ConfusedMovementGenerator::_InitSpecific(Creature &creature, bool &is_water_ok, bool &is_land_ok)
-{
- is_water_ok = creature.canSwim();
- is_land_ok = creature.canWalk();
-}
-
-template<>
-void
-ConfusedMovementGenerator::_InitSpecific(Player &, bool &is_water_ok, bool &is_land_ok)
-{
- is_water_ok = true;
- is_land_ok = true;
-}
-
-template
-void
-ConfusedMovementGenerator::Reset(T &unit)
-{
- i_nextMove = 1;
- i_nextMoveTime.Reset(0);
- i_destinationHolder.ResetUpdate();
- unit.StopMoving();
-}
-
-template
-bool
-ConfusedMovementGenerator::Update(T &unit, const uint32 &diff)
-{
- if(!&unit)
- return true;
-
- if(unit.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED | UNIT_STAT_DISTRACTED))
- return true;
-
- if( i_nextMoveTime.Passed() )
- {
- // currently moving, update location
- Traveller traveller(unit);
- if( i_destinationHolder.UpdateTraveller(traveller, diff, false))
- {
- if( i_destinationHolder.HasArrived())
- {
- // arrived, stop and wait a bit
- unit.StopMoving();
-
- i_nextMove = urand(1,MAX_CONF_WAYPOINTS);
- i_nextMoveTime.Reset(urand(0, 1500-1)); // TODO: check the minimum reset time, should be probably higher
- }
- }
- }
- else
- {
- // waiting for next move
- i_nextMoveTime.Update(diff);
- if( i_nextMoveTime.Passed() )
- {
- // start moving
- assert( i_nextMove <= MAX_CONF_WAYPOINTS );
- const float x = i_waypoints[i_nextMove][0];
- const float y = i_waypoints[i_nextMove][1];
- const float z = i_waypoints[i_nextMove][2];
- Traveller traveller(unit);
- i_destinationHolder.SetDestination(traveller, x, y, z);
- }
- }
- return true;
-}
-
-template
-void
-ConfusedMovementGenerator::Finalize(T &unit)
-{
- unit.clearUnitState(UNIT_STAT_CONFUSED);
-}
-
-template void ConfusedMovementGenerator::Initialize(Player &player);
-template void ConfusedMovementGenerator::Initialize(Creature &creature);
-template void ConfusedMovementGenerator::Finalize(Player &player);
-template void ConfusedMovementGenerator::Finalize(Creature &creature);
-template void ConfusedMovementGenerator::Reset(Player &player);
-template void ConfusedMovementGenerator::Reset(Creature &creature);
-template bool ConfusedMovementGenerator::Update(Player &player, const uint32 &diff);
-template bool ConfusedMovementGenerator::Update(Creature &creature, const uint32 &diff);
+/*
+ * Copyright (C) 2005-2008 MaNGOS
+ *
+ * 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 "Creature.h"
+#include "MapManager.h"
+#include "Opcodes.h"
+#include "ConfusedMovementGenerator.h"
+#include "DestinationHolderImp.h"
+
+template
+void
+ConfusedMovementGenerator::Initialize(T &unit)
+{
+ const float wander_distance=11;
+ float x,y,z;
+ x = unit.GetPositionX();
+ y = unit.GetPositionY();
+ z = unit.GetPositionZ();
+ uint32 mapid=unit.GetMapId();
+
+ Map const* map = MapManager::Instance().GetBaseMap(mapid);
+
+ i_nextMove = 1;
+
+ bool is_water_ok, is_land_ok;
+ _InitSpecific(unit, is_water_ok, is_land_ok);
+
+ for(unsigned int idx=0; idx < MAX_CONF_WAYPOINTS+1; ++idx)
+ {
+ const float wanderX=wander_distance*rand_norm() - wander_distance/2;
+ const float wanderY=wander_distance*rand_norm() - wander_distance/2;
+
+ i_waypoints[idx][0] = x + wanderX;
+ i_waypoints[idx][1] = y + wanderY;
+
+ // prevent invalid coordinates generation
+ MaNGOS::NormalizeMapCoord(i_waypoints[idx][0]);
+ MaNGOS::NormalizeMapCoord(i_waypoints[idx][1]);
+
+ bool is_water = map->IsInWater(i_waypoints[idx][0],i_waypoints[idx][1],z);
+ // if generated wrong path just ignore
+ if( is_water && !is_water_ok || !is_water && !is_land_ok )
+ {
+ i_waypoints[idx][0] = idx > 0 ? i_waypoints[idx-1][0] : x;
+ i_waypoints[idx][1] = idx > 0 ? i_waypoints[idx-1][1] : y;
+ }
+ unit.UpdateGroundPositionZ(i_waypoints[idx][0],i_waypoints[idx][1],z);
+ i_waypoints[idx][2] = z;
+ }
+
+ unit.StopMoving();
+ unit.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
+ unit.addUnitState(UNIT_STAT_CONFUSED);
+}
+
+template<>
+void
+ConfusedMovementGenerator::_InitSpecific(Creature &creature, bool &is_water_ok, bool &is_land_ok)
+{
+ is_water_ok = creature.canSwim();
+ is_land_ok = creature.canWalk();
+}
+
+template<>
+void
+ConfusedMovementGenerator::_InitSpecific(Player &, bool &is_water_ok, bool &is_land_ok)
+{
+ is_water_ok = true;
+ is_land_ok = true;
+}
+
+template
+void
+ConfusedMovementGenerator::Reset(T &unit)
+{
+ i_nextMove = 1;
+ i_nextMoveTime.Reset(0);
+ i_destinationHolder.ResetUpdate();
+ unit.StopMoving();
+}
+
+template
+bool
+ConfusedMovementGenerator::Update(T &unit, const uint32 &diff)
+{
+ if(!&unit)
+ return true;
+
+ if(unit.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
+ return true;
+
+ if( i_nextMoveTime.Passed() )
+ {
+ // currently moving, update location
+ Traveller traveller(unit);
+ if( i_destinationHolder.UpdateTraveller(traveller, diff, false))
+ {
+ if( i_destinationHolder.HasArrived())
+ {
+ // arrived, stop and wait a bit
+ unit.StopMoving();
+
+ i_nextMove = urand(1,MAX_CONF_WAYPOINTS);
+ i_nextMoveTime.Reset(urand(0, 1500-1)); // TODO: check the minimum reset time, should be probably higher
+ }
+ }
+ }
+ else
+ {
+ // waiting for next move
+ i_nextMoveTime.Update(diff);
+ if( i_nextMoveTime.Passed() )
+ {
+ // start moving
+ assert( i_nextMove <= MAX_CONF_WAYPOINTS );
+ const float x = i_waypoints[i_nextMove][0];
+ const float y = i_waypoints[i_nextMove][1];
+ const float z = i_waypoints[i_nextMove][2];
+ Traveller traveller(unit);
+ i_destinationHolder.SetDestination(traveller, x, y, z);
+ }
+ }
+ return true;
+}
+
+template
+void
+ConfusedMovementGenerator::Finalize(T &unit)
+{
+ unit.clearUnitState(UNIT_STAT_CONFUSED);
+}
+
+template void ConfusedMovementGenerator::Initialize(Player &player);
+template void ConfusedMovementGenerator::Initialize(Creature &creature);
+template void ConfusedMovementGenerator::Finalize(Player &player);
+template void ConfusedMovementGenerator::Finalize(Creature &creature);
+template void ConfusedMovementGenerator::Reset(Player &player);
+template void ConfusedMovementGenerator::Reset(Creature &creature);
+template bool ConfusedMovementGenerator::Update(Player &player, const uint32 &diff);
+template bool ConfusedMovementGenerator::Update(Creature &creature, const uint32 &diff);
diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp
index 555bb4db02a..814b133a1b3 100644
--- a/src/game/Creature.cpp
+++ b/src/game/Creature.cpp
@@ -75,6 +75,14 @@ bool VendorItemData::RemoveItem( uint32 item_id )
return false;
}
+size_t VendorItemData::FindItemSlot(uint32 item_id) const
+{
+ for(size_t i = 0; i < m_items.size(); ++i )
+ if(m_items[i]->item==item_id)
+ return i;
+ return m_items.size();
+}
+
VendorItem const* VendorItemData::FindItem(uint32 item_id) const
{
for(VendorItemList::const_iterator i = m_items.begin(); i != m_items.end(); ++i )
@@ -1910,26 +1918,29 @@ time_t Creature::GetRespawnTimeEx() const
void Creature::GetRespawnCoord( float &x, float &y, float &z, float* ori, float* dist ) const
{
- if(CreatureData const* data = objmgr.GetCreatureData(GetDBTableGUIDLow()))
+ if (m_DBTableGuid)
{
- x = data->posX;
- y = data->posY;
- z = data->posZ;
- if(ori)
- *ori = data->orientation;
- if(dist)
- *dist = data->spawndist;
- }
- else
- {
- x = GetPositionX();
- y = GetPositionY();
- z = GetPositionZ();
- if(ori)
- *ori = GetOrientation();
- if(dist)
- *dist = 0;
+ if (CreatureData const* data = objmgr.GetCreatureData(GetDBTableGUIDLow()))
+ {
+ x = data->posX;
+ y = data->posY;
+ z = data->posZ;
+ if(ori)
+ *ori = data->orientation;
+ if(dist)
+ *dist = data->spawndist;
+
+ return;
+ }
}
+
+ x = GetPositionX();
+ y = GetPositionY();
+ z = GetPositionZ();
+ if(ori)
+ *ori = GetOrientation();
+ if(dist)
+ *dist = 0;
}
void Creature::AllLootRemovedFromCorpse()
diff --git a/src/game/Creature.h b/src/game/Creature.h
index 6145b946892..c32ac7327b9 100644
--- a/src/game/Creature.h
+++ b/src/game/Creature.h
@@ -308,6 +308,7 @@ struct VendorItemData
}
bool RemoveItem( uint32 item_id );
VendorItem const* FindItem(uint32 item_id) const;
+ size_t FindItemSlot(uint32 item_id) const;
void Clear()
{
diff --git a/src/game/FleeingMovementGenerator.cpp b/src/game/FleeingMovementGenerator.cpp
index 80ecf13922f..97862eac567 100644
--- a/src/game/FleeingMovementGenerator.cpp
+++ b/src/game/FleeingMovementGenerator.cpp
@@ -1,379 +1,379 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS
- *
- * 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 "Creature.h"
-#include "MapManager.h"
-#include "FleeingMovementGenerator.h"
-#include "DestinationHolderImp.h"
-#include "ObjectAccessor.h"
-
-#define MIN_QUIET_DISTANCE 28.0f
-#define MAX_QUIET_DISTANCE 43.0f
-
-template
-void
-FleeingMovementGenerator::_setTargetLocation(T &owner)
-{
- if( !&owner )
- return;
-
- if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED) )
- return;
-
- if(!_setMoveData(owner))
- return;
-
- float x, y, z;
- if(!_getPoint(owner, x, y, z))
- return;
-
- owner.addUnitState(UNIT_STAT_FLEEING);
- Traveller traveller(owner);
- i_destinationHolder.SetDestination(traveller, x, y, z);
-}
-
-template
-bool
-FleeingMovementGenerator::_getPoint(T &owner, float &x, float &y, float &z)
-{
- if(!&owner)
- return false;
-
- x = owner.GetPositionX();
- y = owner.GetPositionY();
- z = owner.GetPositionZ();
-
- float temp_x, temp_y, angle;
- const Map * _map = MapManager::Instance().GetBaseMap(owner.GetMapId());
- //primitive path-finding
- for(uint8 i = 0; i < 18; i++)
- {
- if(i_only_forward && i > 2)
- break;
-
- float distance = 5.0f;
-
- switch(i)
- {
- case 0:
- angle = i_cur_angle;
- break;
- case 1:
- angle = i_cur_angle;
- distance /= 2;
- break;
- case 2:
- angle = i_cur_angle;
- distance /= 4;
- break;
- case 3:
- angle = i_cur_angle + M_PI/4.0f;
- break;
- case 4:
- angle = i_cur_angle - M_PI/4.0f;
- break;
- case 5:
- angle = i_cur_angle + M_PI/4.0f;
- distance /= 2;
- break;
- case 6:
- angle = i_cur_angle - M_PI/4.0f;
- distance /= 2;
- break;
- case 7:
- angle = i_cur_angle + M_PI/2.0f;
- break;
- case 8:
- angle = i_cur_angle - M_PI/2.0f;
- break;
- case 9:
- angle = i_cur_angle + M_PI/2.0f;
- distance /= 2;
- break;
- case 10:
- angle = i_cur_angle - M_PI/2.0f;
- distance /= 2;
- break;
- case 11:
- angle = i_cur_angle + M_PI/4.0f;
- distance /= 4;
- break;
- case 12:
- angle = i_cur_angle - M_PI/4.0f;
- distance /= 4;
- break;
- case 13:
- angle = i_cur_angle + M_PI/2.0f;
- distance /= 4;
- break;
- case 14:
- angle = i_cur_angle - M_PI/2.0f;
- distance /= 4;
- break;
- case 15:
- angle = i_cur_angle + M_PI*3/4.0f;
- distance /= 2;
- break;
- case 16:
- angle = i_cur_angle - M_PI*3/4.0f;
- distance /= 2;
- break;
- case 17:
- angle = i_cur_angle + M_PI;
- distance /= 2;
- break;
- }
- temp_x = x + distance * cos(angle);
- temp_y = y + distance * sin(angle);
- MaNGOS::NormalizeMapCoord(temp_x);
- MaNGOS::NormalizeMapCoord(temp_y);
- if( owner.IsWithinLOS(temp_x,temp_y,z))
- {
- bool is_water_now = _map->IsInWater(x,y,z);
-
- if(is_water_now && _map->IsInWater(temp_x,temp_y,z))
- {
- x = temp_x;
- y = temp_y;
- return true;
- }
- float new_z = _map->GetHeight(temp_x,temp_y,z,true);
-
- if(new_z <= INVALID_HEIGHT)
- continue;
-
- bool is_water_next = _map->IsInWater(temp_x,temp_y,new_z);
-
- if((is_water_now && !is_water_next && !is_land_ok) || (!is_water_now && is_water_next && !is_water_ok))
- continue;
-
- if( !(new_z - z) || distance / fabs(new_z - z) > 1.0f)
- {
- float new_z_left = _map->GetHeight(temp_x + 1.0f*cos(angle+M_PI/2),temp_y + 1.0f*sin(angle+M_PI/2),z,true);
- float new_z_right = _map->GetHeight(temp_x + 1.0f*cos(angle-M_PI/2),temp_y + 1.0f*sin(angle-M_PI/2),z,true);
- if(fabs(new_z_left - new_z) < 1.2f && fabs(new_z_right - new_z) < 1.2f)
- {
- x = temp_x;
- y = temp_y;
- z = new_z;
- return true;
- }
- }
- }
- }
- i_to_distance_from_caster = 0.0f;
- i_nextCheckTime.Reset( urand(500,1000) );
- return false;
-}
-
-template
-bool
-FleeingMovementGenerator::_setMoveData(T &owner)
-{
- float cur_dist_xyz = owner.GetDistance(i_caster_x, i_caster_y, i_caster_z);
-
- if(i_to_distance_from_caster > 0.0f)
- {
- if((i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz < i_to_distance_from_caster) ||
- // if we reach lower distance
- (i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz > i_last_distance_from_caster) ||
- // if we can't be close
- (i_last_distance_from_caster < i_to_distance_from_caster && cur_dist_xyz > i_to_distance_from_caster) ||
- // if we reach bigger distance
- (cur_dist_xyz > MAX_QUIET_DISTANCE) || // if we are too far
- (i_last_distance_from_caster > MIN_QUIET_DISTANCE && cur_dist_xyz < MIN_QUIET_DISTANCE) )
- // if we leave 'quiet zone'
- {
- // we are very far or too close, stopping
- i_to_distance_from_caster = 0.0f;
- i_nextCheckTime.Reset( urand(500,1000) );
- return false;
- }
- else
- {
- // now we are running, continue
- i_last_distance_from_caster = cur_dist_xyz;
- return true;
- }
- }
-
- float cur_dist;
- float angle_to_caster;
-
- Unit * fright = ObjectAccessor::GetUnit(owner, i_frightGUID);
-
- if(fright)
- {
- cur_dist = fright->GetDistance(&owner);
- if(cur_dist < cur_dist_xyz)
- {
- i_caster_x = fright->GetPositionX();
- i_caster_y = fright->GetPositionY();
- i_caster_z = fright->GetPositionZ();
- angle_to_caster = fright->GetAngle(&owner);
- }
- else
- {
- cur_dist = cur_dist_xyz;
- angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + M_PI;
- }
- }
- else
- {
- cur_dist = cur_dist_xyz;
- angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + M_PI;
- }
-
- // if we too close may use 'path-finding' else just stop
- i_only_forward = cur_dist >= MIN_QUIET_DISTANCE/3;
-
- //get angle and 'distance from caster' to run
- float angle;
-
- if(i_cur_angle == 0.0f && i_last_distance_from_caster == 0.0f) //just started, first time
- {
- angle = rand_norm()*(1.0f - cur_dist/MIN_QUIET_DISTANCE) * M_PI/3 + rand_norm()*M_PI*2/3;
- i_to_distance_from_caster = MIN_QUIET_DISTANCE;
- i_only_forward = true;
- }
- else if(cur_dist < MIN_QUIET_DISTANCE)
- {
- angle = M_PI/6 + rand_norm()*M_PI*2/3;
- i_to_distance_from_caster = cur_dist*2/3 + rand_norm()*(MIN_QUIET_DISTANCE - cur_dist*2/3);
- }
- else if(cur_dist > MAX_QUIET_DISTANCE)
- {
- angle = rand_norm()*M_PI/3 + M_PI*2/3;
- i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
- }
- else
- {
- angle = rand_norm()*M_PI;
- i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
- }
-
- int8 sign = rand_norm() > 0.5f ? 1 : -1;
- i_cur_angle = sign*angle + angle_to_caster;
-
- // current distance
- i_last_distance_from_caster = cur_dist;
-
- return true;
-}
-
-template
-void
-FleeingMovementGenerator::Initialize(T &owner)
-{
- if(!&owner)
- return;
-
- Unit * fright = ObjectAccessor::GetUnit(owner, i_frightGUID);
- if(!fright)
- return;
-
- _Init(owner);
- owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
- i_caster_x = fright->GetPositionX();
- i_caster_y = fright->GetPositionY();
- i_caster_z = fright->GetPositionZ();
- i_only_forward = true;
- i_cur_angle = 0.0f;
- i_last_distance_from_caster = 0.0f;
- i_to_distance_from_caster = 0.0f;
- _setTargetLocation(owner);
-}
-
-template<>
-void
-FleeingMovementGenerator::_Init(Creature &owner)
-{
- if(!&owner)
- return;
- owner.SetUInt64Value(UNIT_FIELD_TARGET, 0);
- is_water_ok = owner.canSwim();
- is_land_ok = owner.canWalk();
-}
-
-template<>
-void
-FleeingMovementGenerator::_Init(Player &)
-{
- is_water_ok = true;
- is_land_ok = true;
-}
-
-template
-void
-FleeingMovementGenerator::Finalize(T &owner)
-{
- owner.clearUnitState(UNIT_STAT_FLEEING);
-}
-
-template
-void
-FleeingMovementGenerator::Reset(T &owner)
-{
- Initialize(owner);
-}
-
-template
-bool
-FleeingMovementGenerator::Update(T &owner, const uint32 & time_diff)
-{
- if( !&owner || !owner.isAlive() )
- return false;
- if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED) )
- return true;
-
- Traveller traveller(owner);
-
- i_nextCheckTime.Update(time_diff);
-
- if( (owner.IsStopped() && !i_destinationHolder.HasArrived()) || !i_destinationHolder.HasDestination() )
- {
- _setTargetLocation(owner);
- return true;
- }
-
- if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false))
- {
- i_destinationHolder.ResetUpdate(50);
- if(i_nextCheckTime.Passed() && i_destinationHolder.HasArrived())
- {
- _setTargetLocation(owner);
- return true;
- }
- }
- return true;
-}
-
-template void FleeingMovementGenerator::Initialize(Player &);
-template void FleeingMovementGenerator::Initialize(Creature &);
-template bool FleeingMovementGenerator::_setMoveData(Player &);
-template bool FleeingMovementGenerator::_setMoveData(Creature &);
-template bool FleeingMovementGenerator::_getPoint(Player &, float &, float &, float &);
-template bool FleeingMovementGenerator::_getPoint(Creature &, float &, float &, float &);
-template void FleeingMovementGenerator::_setTargetLocation(Player &);
-template void FleeingMovementGenerator::_setTargetLocation(Creature &);
-template void FleeingMovementGenerator::Finalize(Player &);
-template void FleeingMovementGenerator::Finalize(Creature &);
-template void FleeingMovementGenerator::Reset(Player &);
-template void FleeingMovementGenerator::Reset(Creature &);
-template bool FleeingMovementGenerator::Update(Player &, const uint32 &);
-template bool FleeingMovementGenerator::Update(Creature &, const uint32 &);
+/*
+ * Copyright (C) 2005-2008 MaNGOS
+ *
+ * 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 "Creature.h"
+#include "MapManager.h"
+#include "FleeingMovementGenerator.h"
+#include "DestinationHolderImp.h"
+#include "ObjectAccessor.h"
+
+#define MIN_QUIET_DISTANCE 28.0f
+#define MAX_QUIET_DISTANCE 43.0f
+
+template
+void
+FleeingMovementGenerator::_setTargetLocation(T &owner)
+{
+ if( !&owner )
+ return;
+
+ if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED) )
+ return;
+
+ if(!_setMoveData(owner))
+ return;
+
+ float x, y, z;
+ if(!_getPoint(owner, x, y, z))
+ return;
+
+ owner.addUnitState(UNIT_STAT_FLEEING);
+ Traveller traveller(owner);
+ i_destinationHolder.SetDestination(traveller, x, y, z);
+}
+
+template
+bool
+FleeingMovementGenerator::_getPoint(T &owner, float &x, float &y, float &z)
+{
+ if(!&owner)
+ return false;
+
+ x = owner.GetPositionX();
+ y = owner.GetPositionY();
+ z = owner.GetPositionZ();
+
+ float temp_x, temp_y, angle;
+ const Map * _map = MapManager::Instance().GetBaseMap(owner.GetMapId());
+ //primitive path-finding
+ for(uint8 i = 0; i < 18; i++)
+ {
+ if(i_only_forward && i > 2)
+ break;
+
+ float distance = 5.0f;
+
+ switch(i)
+ {
+ case 0:
+ angle = i_cur_angle;
+ break;
+ case 1:
+ angle = i_cur_angle;
+ distance /= 2;
+ break;
+ case 2:
+ angle = i_cur_angle;
+ distance /= 4;
+ break;
+ case 3:
+ angle = i_cur_angle + M_PI/4.0f;
+ break;
+ case 4:
+ angle = i_cur_angle - M_PI/4.0f;
+ break;
+ case 5:
+ angle = i_cur_angle + M_PI/4.0f;
+ distance /= 2;
+ break;
+ case 6:
+ angle = i_cur_angle - M_PI/4.0f;
+ distance /= 2;
+ break;
+ case 7:
+ angle = i_cur_angle + M_PI/2.0f;
+ break;
+ case 8:
+ angle = i_cur_angle - M_PI/2.0f;
+ break;
+ case 9:
+ angle = i_cur_angle + M_PI/2.0f;
+ distance /= 2;
+ break;
+ case 10:
+ angle = i_cur_angle - M_PI/2.0f;
+ distance /= 2;
+ break;
+ case 11:
+ angle = i_cur_angle + M_PI/4.0f;
+ distance /= 4;
+ break;
+ case 12:
+ angle = i_cur_angle - M_PI/4.0f;
+ distance /= 4;
+ break;
+ case 13:
+ angle = i_cur_angle + M_PI/2.0f;
+ distance /= 4;
+ break;
+ case 14:
+ angle = i_cur_angle - M_PI/2.0f;
+ distance /= 4;
+ break;
+ case 15:
+ angle = i_cur_angle + M_PI*3/4.0f;
+ distance /= 2;
+ break;
+ case 16:
+ angle = i_cur_angle - M_PI*3/4.0f;
+ distance /= 2;
+ break;
+ case 17:
+ angle = i_cur_angle + M_PI;
+ distance /= 2;
+ break;
+ }
+ temp_x = x + distance * cos(angle);
+ temp_y = y + distance * sin(angle);
+ MaNGOS::NormalizeMapCoord(temp_x);
+ MaNGOS::NormalizeMapCoord(temp_y);
+ if( owner.IsWithinLOS(temp_x,temp_y,z))
+ {
+ bool is_water_now = _map->IsInWater(x,y,z);
+
+ if(is_water_now && _map->IsInWater(temp_x,temp_y,z))
+ {
+ x = temp_x;
+ y = temp_y;
+ return true;
+ }
+ float new_z = _map->GetHeight(temp_x,temp_y,z,true);
+
+ if(new_z <= INVALID_HEIGHT)
+ continue;
+
+ bool is_water_next = _map->IsInWater(temp_x,temp_y,new_z);
+
+ if((is_water_now && !is_water_next && !is_land_ok) || (!is_water_now && is_water_next && !is_water_ok))
+ continue;
+
+ if( !(new_z - z) || distance / fabs(new_z - z) > 1.0f)
+ {
+ float new_z_left = _map->GetHeight(temp_x + 1.0f*cos(angle+M_PI/2),temp_y + 1.0f*sin(angle+M_PI/2),z,true);
+ float new_z_right = _map->GetHeight(temp_x + 1.0f*cos(angle-M_PI/2),temp_y + 1.0f*sin(angle-M_PI/2),z,true);
+ if(fabs(new_z_left - new_z) < 1.2f && fabs(new_z_right - new_z) < 1.2f)
+ {
+ x = temp_x;
+ y = temp_y;
+ z = new_z;
+ return true;
+ }
+ }
+ }
+ }
+ i_to_distance_from_caster = 0.0f;
+ i_nextCheckTime.Reset( urand(500,1000) );
+ return false;
+}
+
+template
+bool
+FleeingMovementGenerator::_setMoveData(T &owner)
+{
+ float cur_dist_xyz = owner.GetDistance(i_caster_x, i_caster_y, i_caster_z);
+
+ if(i_to_distance_from_caster > 0.0f)
+ {
+ if((i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz < i_to_distance_from_caster) ||
+ // if we reach lower distance
+ (i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz > i_last_distance_from_caster) ||
+ // if we can't be close
+ (i_last_distance_from_caster < i_to_distance_from_caster && cur_dist_xyz > i_to_distance_from_caster) ||
+ // if we reach bigger distance
+ (cur_dist_xyz > MAX_QUIET_DISTANCE) || // if we are too far
+ (i_last_distance_from_caster > MIN_QUIET_DISTANCE && cur_dist_xyz < MIN_QUIET_DISTANCE) )
+ // if we leave 'quiet zone'
+ {
+ // we are very far or too close, stopping
+ i_to_distance_from_caster = 0.0f;
+ i_nextCheckTime.Reset( urand(500,1000) );
+ return false;
+ }
+ else
+ {
+ // now we are running, continue
+ i_last_distance_from_caster = cur_dist_xyz;
+ return true;
+ }
+ }
+
+ float cur_dist;
+ float angle_to_caster;
+
+ Unit * fright = ObjectAccessor::GetUnit(owner, i_frightGUID);
+
+ if(fright)
+ {
+ cur_dist = fright->GetDistance(&owner);
+ if(cur_dist < cur_dist_xyz)
+ {
+ i_caster_x = fright->GetPositionX();
+ i_caster_y = fright->GetPositionY();
+ i_caster_z = fright->GetPositionZ();
+ angle_to_caster = fright->GetAngle(&owner);
+ }
+ else
+ {
+ cur_dist = cur_dist_xyz;
+ angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + M_PI;
+ }
+ }
+ else
+ {
+ cur_dist = cur_dist_xyz;
+ angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + M_PI;
+ }
+
+ // if we too close may use 'path-finding' else just stop
+ i_only_forward = cur_dist >= MIN_QUIET_DISTANCE/3;
+
+ //get angle and 'distance from caster' to run
+ float angle;
+
+ if(i_cur_angle == 0.0f && i_last_distance_from_caster == 0.0f) //just started, first time
+ {
+ angle = rand_norm()*(1.0f - cur_dist/MIN_QUIET_DISTANCE) * M_PI/3 + rand_norm()*M_PI*2/3;
+ i_to_distance_from_caster = MIN_QUIET_DISTANCE;
+ i_only_forward = true;
+ }
+ else if(cur_dist < MIN_QUIET_DISTANCE)
+ {
+ angle = M_PI/6 + rand_norm()*M_PI*2/3;
+ i_to_distance_from_caster = cur_dist*2/3 + rand_norm()*(MIN_QUIET_DISTANCE - cur_dist*2/3);
+ }
+ else if(cur_dist > MAX_QUIET_DISTANCE)
+ {
+ angle = rand_norm()*M_PI/3 + M_PI*2/3;
+ i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
+ }
+ else
+ {
+ angle = rand_norm()*M_PI;
+ i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f);
+ }
+
+ int8 sign = rand_norm() > 0.5f ? 1 : -1;
+ i_cur_angle = sign*angle + angle_to_caster;
+
+ // current distance
+ i_last_distance_from_caster = cur_dist;
+
+ return true;
+}
+
+template
+void
+FleeingMovementGenerator::Initialize(T &owner)
+{
+ if(!&owner)
+ return;
+
+ Unit * fright = ObjectAccessor::GetUnit(owner, i_frightGUID);
+ if(!fright)
+ return;
+
+ _Init(owner);
+ owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
+ i_caster_x = fright->GetPositionX();
+ i_caster_y = fright->GetPositionY();
+ i_caster_z = fright->GetPositionZ();
+ i_only_forward = true;
+ i_cur_angle = 0.0f;
+ i_last_distance_from_caster = 0.0f;
+ i_to_distance_from_caster = 0.0f;
+ _setTargetLocation(owner);
+}
+
+template<>
+void
+FleeingMovementGenerator::_Init(Creature &owner)
+{
+ if(!&owner)
+ return;
+ owner.SetUInt64Value(UNIT_FIELD_TARGET, 0);
+ is_water_ok = owner.canSwim();
+ is_land_ok = owner.canWalk();
+}
+
+template<>
+void
+FleeingMovementGenerator::_Init(Player &)
+{
+ is_water_ok = true;
+ is_land_ok = true;
+}
+
+template
+void
+FleeingMovementGenerator::Finalize(T &owner)
+{
+ owner.clearUnitState(UNIT_STAT_FLEEING);
+}
+
+template
+void
+FleeingMovementGenerator::Reset(T &owner)
+{
+ Initialize(owner);
+}
+
+template
+bool
+FleeingMovementGenerator::Update(T &owner, const uint32 & time_diff)
+{
+ if( !&owner || !owner.isAlive() )
+ return false;
+ if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED) )
+ return true;
+
+ Traveller traveller(owner);
+
+ i_nextCheckTime.Update(time_diff);
+
+ if( (owner.IsStopped() && !i_destinationHolder.HasArrived()) || !i_destinationHolder.HasDestination() )
+ {
+ _setTargetLocation(owner);
+ return true;
+ }
+
+ if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false))
+ {
+ i_destinationHolder.ResetUpdate(50);
+ if(i_nextCheckTime.Passed() && i_destinationHolder.HasArrived())
+ {
+ _setTargetLocation(owner);
+ return true;
+ }
+ }
+ return true;
+}
+
+template void FleeingMovementGenerator::Initialize(Player &);
+template void FleeingMovementGenerator::Initialize(Creature &);
+template bool FleeingMovementGenerator::_setMoveData(Player &);
+template bool FleeingMovementGenerator::_setMoveData(Creature &);
+template bool FleeingMovementGenerator::_getPoint(Player &, float &, float &, float &);
+template bool FleeingMovementGenerator::_getPoint(Creature &, float &, float &, float &);
+template void FleeingMovementGenerator::_setTargetLocation(Player &);
+template void FleeingMovementGenerator::_setTargetLocation(Creature &);
+template void FleeingMovementGenerator::Finalize(Player &);
+template void FleeingMovementGenerator::Finalize(Creature &);
+template void FleeingMovementGenerator::Reset(Player &);
+template void FleeingMovementGenerator::Reset(Creature &);
+template bool FleeingMovementGenerator::Update(Player &, const uint32 &);
+template bool FleeingMovementGenerator::Update(Creature &, const uint32 &);
diff --git a/src/game/GridNotifiers.h b/src/game/GridNotifiers.h
index 70d5d7c8928..8eb69b4f6b6 100644
--- a/src/game/GridNotifiers.h
+++ b/src/game/GridNotifiers.h
@@ -852,7 +852,7 @@ namespace MaNGOS
bool operator()(Unit* u)
{
if(u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) &&
- (u->isFeared() || u->isCharmed() || u->isFrozen() || u->hasUnitState(UNIT_STAT_STUNDED) || u->hasUnitState(UNIT_STAT_STUNDED) || u->hasUnitState(UNIT_STAT_CONFUSED)))
+ (u->isFeared() || u->isCharmed() || u->isFrozen() || u->hasUnitState(UNIT_STAT_STUNNED) || u->hasUnitState(UNIT_STAT_CONFUSED)))
{
return true;
}
diff --git a/src/game/Group.cpp b/src/game/Group.cpp
index 1d4850ca82d..273edc135b9 100644
--- a/src/game/Group.cpp
+++ b/src/game/Group.cpp
@@ -1,1454 +1,1454 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS
- *
- * 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 "Opcodes.h"
-#include "WorldPacket.h"
-#include "WorldSession.h"
-#include "Player.h"
-#include "World.h"
-#include "ObjectMgr.h"
-#include "Group.h"
-#include "ObjectAccessor.h"
-#include "BattleGround.h"
-#include "MapManager.h"
-#include "InstanceSaveMgr.h"
-#include "MapInstanced.h"
-#include "Util.h"
-
-Group::Group()
-{
- m_leaderGuid = 0;
- m_mainTank = 0;
- m_mainAssistant = 0;
- m_groupType = (GroupType)0;
- m_bgGroup = NULL;
- m_lootMethod = (LootMethod)0;
- m_looterGuid = 0;
- m_lootThreshold = ITEM_QUALITY_UNCOMMON;
-
- for(int i=0; iGetBgRaid(ALLIANCE) == this) m_bgGroup->SetBgRaid(ALLIANCE, NULL);
- else if(m_bgGroup->GetBgRaid(HORDE) == this) m_bgGroup->SetBgRaid(HORDE, NULL);
- else sLog.outError("Group::~Group: battleground group is not linked to the correct battleground.");
- }
- Rolls::iterator itr;
- while(!RollId.empty())
- {
- itr = RollId.begin();
- Roll *r = *itr;
- RollId.erase(itr);
- delete(r);
- }
-
- // it is undefined whether objectmgr (which stores the groups) or instancesavemgr
- // will be unloaded first so we must be prepared for both cases
- // this may unload some instance saves
- for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++)
- for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
- itr->second.save->RemoveGroup(this);
-}
-
-bool Group::Create(const uint64 &guid, const char * name)
-{
- m_leaderGuid = guid;
- m_leaderName = name;
-
- m_groupType = isBGGroup() ? GROUPTYPE_RAID : GROUPTYPE_NORMAL;
- m_lootMethod = GROUP_LOOT;
- m_lootThreshold = ITEM_QUALITY_UNCOMMON;
- m_looterGuid = guid;
-
- m_difficulty = DIFFICULTY_NORMAL;
- if(!isBGGroup())
- {
- Player *leader = objmgr.GetPlayer(guid);
- if(leader) m_difficulty = leader->GetDifficulty();
-
- Player::ConvertInstancesToGroup(leader, this, guid);
-
- // store group in database
- CharacterDatabase.BeginTransaction();
- CharacterDatabase.PExecute("DELETE FROM groups WHERE leaderGuid ='%u'", GUID_LOPART(m_leaderGuid));
- CharacterDatabase.PExecute("DELETE FROM group_member WHERE leaderGuid ='%u'", GUID_LOPART(m_leaderGuid));
- CharacterDatabase.PExecute("INSERT INTO groups(leaderGuid,mainTank,mainAssistant,lootMethod,looterGuid,lootThreshold,icon1,icon2,icon3,icon4,icon5,icon6,icon7,icon8,isRaid,difficulty) "
- "VALUES('%u','%u','%u','%u','%u','%u','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "','%u','%u')",
- GUID_LOPART(m_leaderGuid), GUID_LOPART(m_mainTank), GUID_LOPART(m_mainAssistant), uint32(m_lootMethod),
- GUID_LOPART(m_looterGuid), uint32(m_lootThreshold), m_targetIcons[0], m_targetIcons[1], m_targetIcons[2], m_targetIcons[3], m_targetIcons[4], m_targetIcons[5], m_targetIcons[6], m_targetIcons[7], isRaidGroup(), m_difficulty);
- }
-
- if(!AddMember(guid, name))
- return false;
-
- if(!isBGGroup()) CharacterDatabase.CommitTransaction();
-
- return true;
-}
-
-bool Group::LoadGroupFromDB(const uint64 &leaderGuid, QueryResult *result, bool loadMembers)
-{
- if(isBGGroup())
- return false;
-
- bool external = true;
- if(!result)
- {
- external = false;
- // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
- result = CharacterDatabase.PQuery("SELECT mainTank, mainAssistant, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, isRaid, difficulty FROM groups WHERE leaderGuid ='%u'", GUID_LOPART(leaderGuid));
- if(!result)
- return false;
- }
-
- m_leaderGuid = leaderGuid;
-
- // group leader not exist
- if(!objmgr.GetPlayerNameByGUID(m_leaderGuid, m_leaderName))
- {
- if(!external) delete result;
- return false;
- }
-
- m_groupType = (*result)[13].GetBool() ? GROUPTYPE_RAID : GROUPTYPE_NORMAL;
- m_difficulty = (*result)[14].GetUInt8();
- m_mainTank = (*result)[0].GetUInt64();
- m_mainAssistant = (*result)[1].GetUInt64();
- m_lootMethod = (LootMethod)(*result)[2].GetUInt8();
- m_looterGuid = MAKE_NEW_GUID((*result)[3].GetUInt32(), 0, HIGHGUID_PLAYER);
- m_lootThreshold = (ItemQualities)(*result)[4].GetUInt16();
-
- for(int i=0; iNextRow() );
- delete result;
- // group too small
- if(GetMembersCount() < 2)
- return false;
- }
-
- return true;
-}
-
-bool Group::LoadMemberFromDB(uint32 guidLow, uint8 subgroup, bool assistant)
-{
- MemberSlot member;
- member.guid = MAKE_NEW_GUID(guidLow, 0, HIGHGUID_PLAYER);
-
- // skip non-existed member
- if(!objmgr.GetPlayerNameByGUID(member.guid, member.name))
- return false;
-
- member.group = subgroup;
- member.assistant = assistant;
- m_memberSlots.push_back(member);
- return true;
-}
-
-bool Group::AddInvite(Player *player)
-{
- if(!player || player->GetGroupInvite() || player->GetGroup())
- return false;
-
- RemoveInvite(player);
-
- m_invitees.insert(player->GetGUID());
-
- player->SetGroupInvite(this);
-
- return true;
-}
-
-bool Group::AddLeaderInvite(Player *player)
-{
- if(!AddInvite(player))
- return false;
-
- m_leaderGuid = player->GetGUID();
- m_leaderName = player->GetName();
- return true;
-}
-
-uint32 Group::RemoveInvite(Player *player)
-{
- for(InvitesList::iterator itr=m_invitees.begin(); itr!=m_invitees.end(); ++itr)
- {
- if((*itr) == player->GetGUID())
- {
- m_invitees.erase(itr);
- break;
- }
- }
-
- player->SetGroupInvite(NULL);
- return GetMembersCount();
-}
-
-void Group::RemoveAllInvites()
-{
- for(InvitesList::iterator itr=m_invitees.begin(); itr!=m_invitees.end(); ++itr)
- {
- Player *invitee = objmgr.GetPlayer(*itr);
- if(invitee)
- invitee->SetGroupInvite(NULL);
- }
- m_invitees.clear();
-}
-
-bool Group::AddMember(const uint64 &guid, const char* name)
-{
- if(!_addMember(guid, name))
- return false;
- SendUpdate();
-
- Player *player = objmgr.GetPlayer(guid);
- if(player)
- {
- if(!IsLeader(player->GetGUID()) && !isBGGroup())
- {
- // reset the new member's instances, unless he is currently in one of them
- // including raid/heroic instances that they are not permanently bound to!
- player->ResetInstances(INSTANCE_RESET_GROUP_JOIN);
-
- if(player->getLevel() >= LEVELREQUIREMENT_HEROIC && player->GetDifficulty() != GetDifficulty() )
- {
- player->SetDifficulty(m_difficulty);
- player->SendDungeonDifficulty(true);
- }
- }
- player->SetGroupUpdateFlag(GROUP_UPDATE_FULL);
- UpdatePlayerOutOfRange(player);
- }
-
- return true;
-}
-
-uint32 Group::RemoveMember(const uint64 &guid, const uint8 &method)
-{
- // remove member and change leader (if need) only if strong more 2 members _before_ member remove
- if(GetMembersCount() > (isBGGroup() ? 1 : 2)) // in BG group case allow 1 members group
- {
- bool leaderChanged = _removeMember(guid);
-
- Player *player = objmgr.GetPlayer( guid );
- if (player)
- {
- WorldPacket data;
-
- if(method == 1)
- {
- data.Initialize( SMSG_GROUP_UNINVITE, 0 );
- player->GetSession()->SendPacket( &data );
- }
-
- data.Initialize(SMSG_GROUP_LIST, 24);
- data << uint64(0) << uint64(0) << uint64(0);
- player->GetSession()->SendPacket(&data);
-
- _homebindIfInstance(player);
- }
-
- if(leaderChanged)
- {
- WorldPacket data(SMSG_GROUP_SET_LEADER, (m_memberSlots.front().name.size()+1));
- data << m_memberSlots.front().name;
- BroadcastPacket(&data);
- }
-
- SendUpdate();
- }
- // if group before remove <= 2 disband it
- else
- Disband(true);
-
- return m_memberSlots.size();
-}
-
-void Group::ChangeLeader(const uint64 &guid)
-{
- member_citerator slot = _getMemberCSlot(guid);
-
- if(slot==m_memberSlots.end())
- return;
-
- _setLeader(guid);
-
- WorldPacket data(SMSG_GROUP_SET_LEADER, slot->name.size()+1);
- data << slot->name;
- BroadcastPacket(&data);
- SendUpdate();
-}
-
-void Group::Disband(bool hideDestroy)
-{
- Player *player;
-
- for(member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
- {
- player = objmgr.GetPlayer(citr->guid);
- if(!player)
- continue;
-
- player->SetGroup(NULL);
-
- if(!player->GetSession())
- continue;
-
- WorldPacket data;
- if(!hideDestroy)
- {
- data.Initialize(SMSG_GROUP_DESTROYED, 0);
- player->GetSession()->SendPacket(&data);
- }
-
- data.Initialize(SMSG_GROUP_LIST, 24);
- data << uint64(0) << uint64(0) << uint64(0);
- player->GetSession()->SendPacket(&data);
-
- _homebindIfInstance(player);
- }
- RollId.clear();
- m_memberSlots.clear();
-
- RemoveAllInvites();
-
- if(!isBGGroup())
- {
- CharacterDatabase.BeginTransaction();
- CharacterDatabase.PExecute("DELETE FROM groups WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid));
- CharacterDatabase.PExecute("DELETE FROM group_member WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid));
- CharacterDatabase.CommitTransaction();
- ResetInstances(INSTANCE_RESET_GROUP_DISBAND, NULL);
- }
-
- m_leaderGuid = 0;
- m_leaderName = "";
-}
-
-/*********************************************************/
-/*** LOOT SYSTEM ***/
-/*********************************************************/
-
-void Group::SendLootStartRoll(uint32 CountDown, const Roll &r)
-{
- WorldPacket data(SMSG_LOOT_START_ROLL, (8+4+4+4+4+4));
- data << uint64(r.itemGUID); // guid of rolled item
- data << uint32(r.totalPlayersRolling); // maybe the number of players rolling for it???
- data << uint32(r.itemid); // the itemEntryId for the item that shall be rolled for
- data << uint32(r.itemRandomSuffix); // randomSuffix
- data << uint32(r.itemRandomPropId); // item random property ID
- data << uint32(CountDown); // the countdown time to choose "need" or "greed"
-
- for (Roll::PlayerVote::const_iterator itr=r.playerVote.begin(); itr!=r.playerVote.end(); ++itr)
- {
- Player *p = objmgr.GetPlayer(itr->first);
- if(!p || !p->GetSession())
- continue;
-
- if(itr->second != NOT_VALID)
- p->GetSession()->SendPacket( &data );
- }
-}
-
-void Group::SendLootRoll(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r)
-{
- WorldPacket data(SMSG_LOOT_ROLL, (8+4+8+4+4+4+1+1));
- data << uint64(SourceGuid); // guid of the item rolled
- data << uint32(0); // unknown, maybe amount of players
- data << uint64(TargetGuid);
- data << uint32(r.itemid); // the itemEntryId for the item that shall be rolled for
- data << uint32(r.itemRandomSuffix); // randomSuffix
- data << uint32(r.itemRandomPropId); // Item random property ID
- data << uint8(RollNumber); // 0: "Need for: [item name]" > 127: "you passed on: [item name]" Roll number
- data << uint8(RollType); // 0: "Need for: [item name]" 0: "You have selected need for [item name] 1: need roll 2: greed roll
- data << uint8(0); // 2.4.0
-
- for( Roll::PlayerVote::const_iterator itr=r.playerVote.begin(); itr!=r.playerVote.end(); ++itr)
- {
- Player *p = objmgr.GetPlayer(itr->first);
- if(!p || !p->GetSession())
- continue;
-
- if(itr->second != NOT_VALID)
- p->GetSession()->SendPacket( &data );
- }
-}
-
-void Group::SendLootRollWon(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r)
-{
- WorldPacket data(SMSG_LOOT_ROLL_WON, (8+4+4+4+4+8+1+1));
- data << uint64(SourceGuid); // guid of the item rolled
- data << uint32(0); // unknown, maybe amount of players
- data << uint32(r.itemid); // the itemEntryId for the item that shall be rolled for
- data << uint32(r.itemRandomSuffix); // randomSuffix
- data << uint32(r.itemRandomPropId); // Item random property
- data << uint64(TargetGuid); // guid of the player who won.
- data << uint8(RollNumber); // rollnumber realted to SMSG_LOOT_ROLL
- data << uint8(RollType); // Rolltype related to SMSG_LOOT_ROLL
-
- for( Roll::PlayerVote::const_iterator itr=r.playerVote.begin(); itr!=r.playerVote.end(); ++itr)
- {
- Player *p = objmgr.GetPlayer(itr->first);
- if(!p || !p->GetSession())
- continue;
-
- if(itr->second != NOT_VALID)
- p->GetSession()->SendPacket( &data );
- }
-}
-
-void Group::SendLootAllPassed(uint32 NumberOfPlayers, const Roll &r)
-{
- WorldPacket data(SMSG_LOOT_ALL_PASSED, (8+4+4+4+4));
- data << uint64(r.itemGUID); // Guid of the item rolled
- data << uint32(NumberOfPlayers); // The number of players rolling for it???
- data << uint32(r.itemid); // The itemEntryId for the item that shall be rolled for
- data << uint32(r.itemRandomPropId); // Item random property ID
- data << uint32(r.itemRandomSuffix); // Item random suffix ID
-
- for( Roll::PlayerVote::const_iterator itr=r.playerVote.begin(); itr!=r.playerVote.end(); ++itr)
- {
- Player *p = objmgr.GetPlayer(itr->first);
- if(!p || !p->GetSession())
- continue;
-
- if(itr->second != NOT_VALID)
- p->GetSession()->SendPacket( &data );
- }
-}
-
-void Group::GroupLoot(uint64 playerGUID, Loot *loot, Creature *creature)
-{
- std::vector::iterator i;
- ItemPrototype const *item;
- uint8 itemSlot = 0;
- Player *player = objmgr.GetPlayer(playerGUID);
- Group *group = player->GetGroup();
-
- for (i=loot->items.begin(); i != loot->items.end(); ++i, ++itemSlot)
- {
- item = objmgr.GetItemPrototype(i->itemid);
- if (!item)
- {
- //sLog.outDebug("Group::GroupLoot: missing item prototype for item with id: %d", i->itemid);
- continue;
- }
-
- //roll for over-threshold item if it's one-player loot
- if (item->Quality >= uint32(m_lootThreshold) && !i->freeforall)
- {
- uint64 newitemGUID = MAKE_NEW_GUID(objmgr.GenerateLowGuid(HIGHGUID_ITEM),0,HIGHGUID_ITEM);
- Roll* r=new Roll(newitemGUID,*i);
-
- //a vector is filled with only near party members
- for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
- {
- Player *member = itr->getSource();
- if(!member || !member->GetSession())
- continue;
- if ( i->AllowedForPlayer(member) )
- {
- if (member->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
- {
- r->playerVote[member->GetGUID()] = NOT_EMITED_YET;
- ++r->totalPlayersRolling;
- }
- }
- }
-
- r->setLoot(loot);
- r->itemSlot = itemSlot;
-
- group->SendLootStartRoll(60000, *r);
-
- loot->items[itemSlot].is_blocked = true;
- creature->m_groupLootTimer = 60000;
- creature->lootingGroupLeaderGUID = GetLeaderGUID();
-
- RollId.push_back(r);
- }
- else
- i->is_underthreshold=1;
-
- }
-}
-
-void Group::NeedBeforeGreed(uint64 playerGUID, Loot *loot, Creature *creature)
-{
- ItemPrototype const *item;
- Player *player = objmgr.GetPlayer(playerGUID);
- Group *group = player->GetGroup();
-
- uint8 itemSlot = 0;
- for(std::vector::iterator i=loot->items.begin(); i != loot->items.end(); ++i, ++itemSlot)
- {
- item = objmgr.GetItemPrototype(i->itemid);
-
- //only roll for one-player items, not for ones everyone can get
- if (item->Quality >= uint32(m_lootThreshold) && !i->freeforall)
- {
- uint64 newitemGUID = MAKE_NEW_GUID(objmgr.GenerateLowGuid(HIGHGUID_ITEM),0,HIGHGUID_ITEM);
- Roll* r=new Roll(newitemGUID,*i);
-
- for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
- {
- Player *playerToRoll = itr->getSource();
- if(!playerToRoll || !playerToRoll->GetSession())
- continue;
-
- if (playerToRoll->CanUseItem(item) && i->AllowedForPlayer(playerToRoll) )
- {
- if (playerToRoll->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
- {
- r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET;
- ++r->totalPlayersRolling;
- }
- }
- }
-
- if (r->totalPlayersRolling > 0)
- {
- r->setLoot(loot);
- r->itemSlot = itemSlot;
-
- group->SendLootStartRoll(60000, *r);
-
- loot->items[itemSlot].is_blocked = true;
-
- RollId.push_back(r);
- }
- else
- {
- delete r;
- }
- }
- else
- i->is_underthreshold=1;
- }
-}
-
-void Group::MasterLoot(uint64 playerGUID, Loot* /*loot*/, Creature *creature)
-{
- Player *player = objmgr.GetPlayer(playerGUID);
- if(!player)
- return;
-
- sLog.outDebug("Group::MasterLoot (SMSG_LOOT_MASTER_LIST, 330) player = [%s].", player->GetName());
-
- uint32 real_count = 0;
-
- WorldPacket data(SMSG_LOOT_MASTER_LIST, 330);
- data << (uint8)GetMembersCount();
-
- for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
- {
- Player *looter = itr->getSource();
- if (!looter->IsInWorld())
- continue;
-
- if (looter->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
- {
- data << looter->GetGUID();
- ++real_count;
- }
- }
-
- data.put(0,real_count);
-
- for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
- {
- Player *looter = itr->getSource();
- if (looter->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
- looter->GetSession()->SendPacket(&data);
- }
-}
-
-void Group::CountRollVote(uint64 playerGUID, uint64 Guid, uint32 NumberOfPlayers, uint8 Choise)
-{
- Rolls::iterator rollI = GetRoll(Guid);
- if (rollI == RollId.end())
- return;
- Roll* roll = *rollI;
-
- Roll::PlayerVote::iterator itr = roll->playerVote.find(playerGUID);
- // this condition means that player joins to the party after roll begins
- if (itr == roll->playerVote.end())
- return;
-
- if (roll->getLoot())
- if (roll->getLoot()->items.empty())
- return;
-
- switch (Choise)
- {
- case 0: //Player choose pass
- {
- SendLootRoll(0, playerGUID, 128, 128, *roll);
- ++roll->totalPass;
- itr->second = PASS;
- }
- break;
- case 1: //player choose Need
- {
- SendLootRoll(0, playerGUID, 1, 1, *roll);
- ++roll->totalNeed;
- itr->second = NEED;
- }
- break;
- case 2: //player choose Greed
- {
- SendLootRoll(0, playerGUID, 2, 2, *roll);
- ++roll->totalGreed;
- itr->second = GREED;
- }
- break;
- }
- if (roll->totalPass + roll->totalGreed + roll->totalNeed >= roll->totalPlayersRolling)
- {
- CountTheRoll(rollI, NumberOfPlayers);
- }
-}
-
-//called when roll timer expires
-void Group::EndRoll()
-{
- Rolls::iterator itr;
- while(!RollId.empty())
- {
- //need more testing here, if rolls disappear
- itr = RollId.begin();
- CountTheRoll(itr, GetMembersCount()); //i don't have to edit player votes, who didn't vote ... he will pass
- }
-}
-
-void Group::CountTheRoll(Rolls::iterator rollI, uint32 NumberOfPlayers)
-{
- Roll* roll = *rollI;
- if(!roll->isValid()) // is loot already deleted ?
- {
- RollId.erase(rollI);
- delete roll;
- return;
- }
- //end of the roll
- if (roll->totalNeed > 0)
- {
- if(!roll->playerVote.empty())
- {
- uint8 maxresul = 0;
- uint64 maxguid = (*roll->playerVote.begin()).first;
- Player *player;
-
- for( Roll::PlayerVote::const_iterator itr=roll->playerVote.begin(); itr!=roll->playerVote.end(); ++itr)
- {
- if (itr->second != NEED)
- continue;
-
- uint8 randomN = urand(1, 99);
- SendLootRoll(0, itr->first, randomN, 1, *roll);
- if (maxresul < randomN)
- {
- maxguid = itr->first;
- maxresul = randomN;
- }
- }
- SendLootRollWon(0, maxguid, maxresul, 1, *roll);
- player = objmgr.GetPlayer(maxguid);
-
- if(player && player->GetSession())
- {
- ItemPosCountVec dest;
- LootItem *item = &(roll->getLoot()->items[roll->itemSlot]);
- uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count );
- if ( msg == EQUIP_ERR_OK )
- {
- item->is_looted = true;
- roll->getLoot()->NotifyItemRemoved(roll->itemSlot);
- --roll->getLoot()->unlootedCount;
- player->StoreNewItem( dest, roll->itemid, true, item->randomPropertyId);
- }
- else
- {
- item->is_blocked = false;
- player->SendEquipError( msg, NULL, NULL );
- }
- }
- }
- }
- else if (roll->totalGreed > 0)
- {
- if(!roll->playerVote.empty())
- {
- uint8 maxresul = 0;
- uint64 maxguid = (*roll->playerVote.begin()).first;
- Player *player;
-
- Roll::PlayerVote::iterator itr;
- for (itr=roll->playerVote.begin(); itr!=roll->playerVote.end(); ++itr)
- {
- if (itr->second != GREED)
- continue;
-
- uint8 randomN = urand(1, 99);
- SendLootRoll(0, itr->first, randomN, 2, *roll);
- if (maxresul < randomN)
- {
- maxguid = itr->first;
- maxresul = randomN;
- }
- }
- SendLootRollWon(0, maxguid, maxresul, 2, *roll);
- player = objmgr.GetPlayer(maxguid);
-
- if(player && player->GetSession())
- {
- ItemPosCountVec dest;
- LootItem *item = &(roll->getLoot()->items[roll->itemSlot]);
- uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count );
- if ( msg == EQUIP_ERR_OK )
- {
- item->is_looted = true;
- roll->getLoot()->NotifyItemRemoved(roll->itemSlot);
- --roll->getLoot()->unlootedCount;
- player->StoreNewItem( dest, roll->itemid, true, item->randomPropertyId);
- }
- else
- {
- item->is_blocked = false;
- player->SendEquipError( msg, NULL, NULL );
- }
- }
- }
- }
- else
- {
- SendLootAllPassed(NumberOfPlayers, *roll);
- LootItem *item = &(roll->getLoot()->items[roll->itemSlot]);
- if(item) item->is_blocked = false;
- }
- RollId.erase(rollI);
- delete roll;
-}
-
-void Group::SetTargetIcon(uint8 id, uint64 guid)
-{
- if(id >= TARGETICONCOUNT)
- return;
-
- // clean other icons
- if( guid != 0 )
- for(int i=0; inext())
- {
- Player* member = itr->getSource();
- if(!member || !member->isAlive()) // only for alive
- continue;
-
- if(!member->IsAtGroupRewardDistance(victim)) // at req. distance
- continue;
-
- ++count;
- sum_level += member->getLevel();
- if(!member_with_max_level || member_with_max_level->getLevel() < member->getLevel())
- member_with_max_level = member;
- }
-}
-
-void Group::SendTargetIconList(WorldSession *session)
-{
- if(!session)
- return;
-
- WorldPacket data(MSG_RAID_TARGET_UPDATE, (1+TARGETICONCOUNT*9));
- data << (uint8)1;
-
- for(int i=0; iSendPacket(&data);
-}
-
-void Group::SendUpdate()
-{
- Player *player;
-
- for(member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
- {
- player = objmgr.GetPlayer(citr->guid);
- if(!player || !player->GetSession())
- continue;
- // guess size
- WorldPacket data(SMSG_GROUP_LIST, (1+1+1+1+8+4+GetMembersCount()*20));
- data << (uint8)m_groupType; // group type
- data << (uint8)(isBGGroup() ? 1 : 0); // 2.0.x, isBattleGroundGroup?
- data << (uint8)(citr->group); // groupid
- data << (uint8)(citr->assistant?0x01:0); // 0x2 main assist, 0x4 main tank
- data << uint64(0x50000000FFFFFFFELL); // related to voice chat?
- data << uint32(GetMembersCount()-1);
- for(member_citerator citr2 = m_memberSlots.begin(); citr2 != m_memberSlots.end(); ++citr2)
- {
- if(citr->guid == citr2->guid)
- continue;
-
- data << citr2->name;
- data << (uint64)citr2->guid;
- // online-state
- data << (uint8)(objmgr.GetPlayer(citr2->guid) ? 1 : 0);
- data << (uint8)(citr2->group); // groupid
- data << (uint8)(citr2->assistant?0x01:0); // 0x2 main assist, 0x4 main tank
- }
-
- data << uint64(m_leaderGuid); // leader guid
- if(GetMembersCount()-1)
- {
- data << (uint8)m_lootMethod; // loot method
- data << (uint64)m_looterGuid; // looter guid
- data << (uint8)m_lootThreshold; // loot threshold
- data << (uint8)m_difficulty; // Heroic Mod Group
-
- }
- player->GetSession()->SendPacket( &data );
- }
-}
-
-void Group::UpdatePlayerOutOfRange(Player* pPlayer)
-{
- if(!pPlayer)
- return;
-
- Player *player;
- WorldPacket data;
- pPlayer->GetSession()->BuildPartyMemberStatsChangedPacket(pPlayer, &data);
-
- for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
- {
- player = itr->getSource();
- if (player && player != pPlayer && !pPlayer->isVisibleFor(player))
- player->GetSession()->SendPacket(&data);
- }
-}
-
-void Group::BroadcastPacket(WorldPacket *packet, int group, uint64 ignore)
-{
- for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
- {
- Player *pl = itr->getSource();
- if(!pl || (ignore != 0 && pl->GetGUID() == ignore))
- continue;
-
- if (pl->GetSession() && (group==-1 || itr->getSubGroup()==group))
- pl->GetSession()->SendPacket(packet);
- }
-}
-
-void Group::BroadcastReadyCheck(WorldPacket *packet)
-{
- for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
- {
- Player *pl = itr->getSource();
- if(pl && pl->GetSession())
- if(IsLeader(pl->GetGUID()) || IsAssistant(pl->GetGUID()))
- pl->GetSession()->SendPacket(packet);
- }
-}
-
-void Group::OfflineReadyCheck()
-{
- for(member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
- {
- Player *pl = objmgr.GetPlayer(citr->guid);
- if (!pl || !pl->GetSession())
- {
- WorldPacket data(MSG_RAID_READY_CHECK_CONFIRM, 9);
- data << citr->guid;
- data << (uint8)0;
- BroadcastReadyCheck(&data);
- }
- }
-}
-
-bool Group::_addMember(const uint64 &guid, const char* name, bool isAssistant)
-{
- // get first not-full group
- uint8 groupid = 0;
- std::vector temp(MAXRAIDSIZE/MAXGROUPSIZE);
- for(member_citerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr)
- {
- if (itr->group >= temp.size()) continue;
- ++temp[itr->group];
- if(temp[groupid] >= MAXGROUPSIZE)
- ++groupid;
- }
-
- return _addMember(guid, name, isAssistant, groupid);
-}
-
-bool Group::_addMember(const uint64 &guid, const char* name, bool isAssistant, uint8 group)
-{
- if(IsFull())
- return false;
-
- if(!guid)
- return false;
-
- Player *player = objmgr.GetPlayer(guid);
-
- MemberSlot member;
- member.guid = guid;
- member.name = name;
- member.group = group;
- member.assistant = isAssistant;
- m_memberSlots.push_back(member);
-
- if(player)
- {
- player->SetGroupInvite(NULL);
- player->SetGroup(this, group);
- // if the same group invites the player back, cancel the homebind timer
- InstanceGroupBind *bind = GetBoundInstance(player->GetMapId(), player->GetDifficulty());
- if(bind && bind->save->GetInstanceId() == player->GetInstanceId())
- player->m_InstanceValid = true;
- }
-
- if(!isRaidGroup()) // reset targetIcons for non-raid-groups
- {
- for(int i=0; iSetGroup(NULL);
- }
-
- _removeRolls(guid);
-
- member_witerator slot = _getMemberWSlot(guid);
- if (slot != m_memberSlots.end())
- m_memberSlots.erase(slot);
-
- if(!isBGGroup())
- CharacterDatabase.PExecute("DELETE FROM group_member WHERE memberGuid='%u'", GUID_LOPART(guid));
-
- if(m_leaderGuid == guid) // leader was removed
- {
- if(GetMembersCount() > 0)
- _setLeader(m_memberSlots.front().guid);
- return true;
- }
-
- return false;
-}
-
-void Group::_setLeader(const uint64 &guid)
-{
- member_citerator slot = _getMemberCSlot(guid);
- if(slot==m_memberSlots.end())
- return;
-
- if(!isBGGroup())
- {
- // TODO: set a time limit to have this function run rarely cause it can be slow
- CharacterDatabase.BeginTransaction();
-
- // update the group's bound instances when changing leaders
-
- // remove all permanent binds from the group
- // in the DB also remove solo binds that will be replaced with permbinds
- // from the new leader
- CharacterDatabase.PExecute(
- "DELETE FROM group_instance WHERE leaderguid='%u' AND (permanent = 1 OR "
- "instance IN (SELECT instance FROM character_instance WHERE guid = '%u')"
- ")", GUID_LOPART(m_leaderGuid), GUID_LOPART(slot->guid)
- );
-
- Player *player = objmgr.GetPlayer(slot->guid);
- if(player)
- {
- for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++)
- {
- for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end();)
- {
- if(itr->second.perm)
- {
- itr->second.save->RemoveGroup(this);
- m_boundInstances[i].erase(itr++);
- }
- else
- ++itr;
- }
- }
- }
-
- // update the group's solo binds to the new leader
- CharacterDatabase.PExecute("UPDATE group_instance SET leaderGuid='%u' WHERE leaderGuid = '%u'", GUID_LOPART(slot->guid), GUID_LOPART(m_leaderGuid));
-
- // copy the permanent binds from the new leader to the group
- // overwriting the solo binds with permanent ones if necessary
- // in the DB those have been deleted already
- Player::ConvertInstancesToGroup(player, this, slot->guid);
-
- // update the group leader
- CharacterDatabase.PExecute("UPDATE groups SET leaderGuid='%u' WHERE leaderGuid='%u'", GUID_LOPART(slot->guid), GUID_LOPART(m_leaderGuid));
- CharacterDatabase.PExecute("UPDATE group_member SET leaderGuid='%u' WHERE leaderGuid='%u'", GUID_LOPART(slot->guid), GUID_LOPART(m_leaderGuid));
- CharacterDatabase.CommitTransaction();
- }
-
- m_leaderGuid = slot->guid;
- m_leaderName = slot->name;
-}
-
-void Group::_removeRolls(const uint64 &guid)
-{
- for (Rolls::iterator it = RollId.begin(); it < RollId.end(); it++)
- {
- Roll* roll = *it;
- Roll::PlayerVote::iterator itr2 = roll->playerVote.find(guid);
- if(itr2 == roll->playerVote.end())
- continue;
-
- if (itr2->second == GREED) --roll->totalGreed;
- if (itr2->second == NEED) --roll->totalNeed;
- if (itr2->second == PASS) --roll->totalPass;
- if (itr2->second != NOT_VALID) --roll->totalPlayersRolling;
-
- roll->playerVote.erase(itr2);
-
- CountRollVote(guid, roll->itemGUID, GetMembersCount()-1, 3);
- }
-}
-
-void Group::_convertToRaid()
-{
- m_groupType = GROUPTYPE_RAID;
-
- if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE groups SET isRaid = 1 WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid));
-}
-
-bool Group::_setMembersGroup(const uint64 &guid, const uint8 &group)
-{
- member_witerator slot = _getMemberWSlot(guid);
- if(slot==m_memberSlots.end())
- return false;
-
- slot->group = group;
- if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE group_member SET subgroup='%u' WHERE memberGuid='%u'", group, GUID_LOPART(guid));
- return true;
-}
-
-bool Group::_setAssistantFlag(const uint64 &guid, const bool &state)
-{
- member_witerator slot = _getMemberWSlot(guid);
- if(slot==m_memberSlots.end())
- return false;
-
- slot->assistant = state;
- if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE group_member SET assistant='%u' WHERE memberGuid='%u'", (state==true)?1:0, GUID_LOPART(guid));
- return true;
-}
-
-bool Group::_setMainTank(const uint64 &guid)
-{
- member_citerator slot = _getMemberCSlot(guid);
- if(slot==m_memberSlots.end())
- return false;
-
- if(m_mainAssistant == guid)
- _setMainAssistant(0);
- m_mainTank = guid;
- if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE groups SET mainTank='%u' WHERE leaderGuid='%u'", GUID_LOPART(m_mainTank), GUID_LOPART(m_leaderGuid));
- return true;
-}
-
-bool Group::_setMainAssistant(const uint64 &guid)
-{
- member_witerator slot = _getMemberWSlot(guid);
- if(slot==m_memberSlots.end())
- return false;
-
- if(m_mainTank == guid)
- _setMainTank(0);
- m_mainAssistant = guid;
- if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE groups SET mainAssistant='%u' WHERE leaderGuid='%u'", GUID_LOPART(m_mainAssistant), GUID_LOPART(m_leaderGuid));
- return true;
-}
-
-bool Group::SameSubGroup(Player const* member1, Player const* member2) const
-{
- if(!member1 || !member2) return false;
- if (member1->GetGroup() != this || member2->GetGroup() != this) return false;
- else return member1->GetSubGroup() == member2->GetSubGroup();
-}
-
-// allows setting subgroup for offline members
-void Group::ChangeMembersGroup(const uint64 &guid, const uint8 &group)
-{
- if(!isRaidGroup())
- return;
- Player *player = objmgr.GetPlayer(guid);
- if (!player)
- {
- if(_setMembersGroup(guid, group))
- SendUpdate();
- }
- else ChangeMembersGroup(player, group);
-}
-
-// only for online members
-void Group::ChangeMembersGroup(Player *player, const uint8 &group)
-{
- if(!player || !isRaidGroup())
- return;
- if(_setMembersGroup(player->GetGUID(), group))
- {
- player->GetGroupRef().setSubGroup(group);
- SendUpdate();
- }
-}
-
-void Group::UpdateLooterGuid( Creature* creature, bool ifneed )
-{
- switch (GetLootMethod())
- {
- case MASTER_LOOT:
- case FREE_FOR_ALL:
- return;
- default:
- // round robin style looting applies for all low
- // quality items in each loot method except free for all and master loot
- break;
- }
-
- member_citerator guid_itr = _getMemberCSlot(GetLooterGuid());
- if(guid_itr != m_memberSlots.end())
- {
- if(ifneed)
- {
- // not update if only update if need and ok
- Player* looter = ObjectAccessor::FindPlayer(guid_itr->guid);
- if(looter && looter->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
- return;
- }
- ++guid_itr;
- }
-
- // search next after current
- if(guid_itr != m_memberSlots.end())
- {
- for(member_citerator itr = guid_itr; itr != m_memberSlots.end(); ++itr)
- {
- if(Player* pl = ObjectAccessor::FindPlayer(itr->guid))
- {
- if (pl->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
- {
- bool refresh = pl->GetLootGUID()==creature->GetGUID();
-
- //if(refresh) // update loot for new looter
- // pl->GetSession()->DoLootRelease(pl->GetLootGUID());
- SetLooterGuid(pl->GetGUID());
- SendUpdate();
- if(refresh) // update loot for new looter
- pl->SendLoot(creature->GetGUID(),LOOT_CORPSE);
- return;
- }
- }
- }
- }
-
- // search from start
- for(member_citerator itr = m_memberSlots.begin(); itr != guid_itr; ++itr)
- {
- if(Player* pl = ObjectAccessor::FindPlayer(itr->guid))
- {
- if (pl->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
- {
- bool refresh = pl->GetLootGUID()==creature->GetGUID();
-
- //if(refresh) // update loot for new looter
- // pl->GetSession()->DoLootRelease(pl->GetLootGUID());
- SetLooterGuid(pl->GetGUID());
- SendUpdate();
- if(refresh) // update loot for new looter
- pl->SendLoot(creature->GetGUID(),LOOT_CORPSE);
- return;
- }
- }
- }
-
- SetLooterGuid(0);
- SendUpdate();
-}
-
-uint32 Group::CanJoinBattleGroundQueue(uint32 bgTypeId, uint32 bgQueueType, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot)
-{
- // check for min / max count
- uint32 memberscount = GetMembersCount();
- if(memberscount < MinPlayerCount)
- return BG_JOIN_ERR_GROUP_NOT_ENOUGH;
- if(memberscount > MaxPlayerCount)
- return BG_JOIN_ERR_GROUP_TOO_MANY;
-
- // get a player as reference, to compare other players' stats to (arena team id, queue id based on level, etc.)
- Player * reference = GetFirstMember()->getSource();
- // no reference found, can't join this way
- if(!reference)
- return BG_JOIN_ERR_OFFLINE_MEMBER;
-
- uint32 bgQueueId = reference->GetBattleGroundQueueIdFromLevel();
- uint32 arenaTeamId = reference->GetArenaTeamId(arenaSlot);
- uint32 team = reference->GetTeam();
-
- // check every member of the group to be able to join
- for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
- {
- Player *member = itr->getSource();
- // offline member? don't let join
- if(!member)
- return BG_JOIN_ERR_OFFLINE_MEMBER;
- // don't allow cross-faction join as group
- if(member->GetTeam() != team)
- return BG_JOIN_ERR_MIXED_FACTION;
- // not in the same battleground level braket, don't let join
- if(member->GetBattleGroundQueueIdFromLevel() != bgQueueId)
- return BG_JOIN_ERR_MIXED_LEVELS;
- // don't let join rated matches if the arena team id doesn't match
- if(isRated && member->GetArenaTeamId(arenaSlot) != arenaTeamId)
- return BG_JOIN_ERR_MIXED_ARENATEAM;
- // don't let join if someone from the group is already in that bg queue
- if(member->InBattleGroundQueueForBattleGroundQueueType(bgQueueType))
- return BG_JOIN_ERR_GROUP_MEMBER_ALREADY_IN_QUEUE;
- // check for deserter debuff in case not arena queue
- if(bgTypeId != BATTLEGROUND_AA && !member->CanJoinToBattleground())
- return BG_JOIN_ERR_GROUP_DESERTER;
- // check if member can join any more battleground queues
- if(!member->HasFreeBattleGroundQueueId())
- return BG_JOIN_ERR_ALL_QUEUES_USED;
- }
- return BG_JOIN_ERR_OK;
-}
-
-//===================================================
-//============== Roll ===============================
-//===================================================
-
-void Roll::targetObjectBuildLink()
-{
- // called from link()
- this->getTarget()->addLootValidatorRef(this);
-}
-
-void Group::SetDifficulty(uint8 difficulty)
-{
- m_difficulty = difficulty;
- if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE groups SET difficulty = %u WHERE leaderGuid ='%u'", m_difficulty, GUID_LOPART(m_leaderGuid));
-
- for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
- {
- Player *player = itr->getSource();
- if(!player->GetSession() || player->getLevel() < LEVELREQUIREMENT_HEROIC)
- continue;
- player->SetDifficulty(difficulty);
- player->SendDungeonDifficulty(true);
- }
-}
-
-bool Group::InCombatToInstance(uint32 instanceId)
-{
- for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
- {
- Player *pPlayer = itr->getSource();
- if(pPlayer->getAttackers().size() && pPlayer->GetInstanceId() == instanceId)
- return true;
- }
- return false;
-}
-
-void Group::ResetInstances(uint8 method, Player* SendMsgTo)
-{
- if(isBGGroup())
- return;
-
- // method can be INSTANCE_RESET_ALL, INSTANCE_RESET_CHANGE_DIFFICULTY, INSTANCE_RESET_GROUP_DISBAND
-
- // we assume that when the difficulty changes, all instances that can be reset will be
- uint8 dif = GetDifficulty();
-
- for(BoundInstancesMap::iterator itr = m_boundInstances[dif].begin(); itr != m_boundInstances[dif].end();)
- {
- InstanceSave *p = itr->second.save;
- const MapEntry *entry = sMapStore.LookupEntry(itr->first);
- if(!entry || (!p->CanReset() && method != INSTANCE_RESET_GROUP_DISBAND))
- {
- ++itr;
- continue;
- }
-
- if(method == INSTANCE_RESET_ALL)
- {
- // the "reset all instances" method can only reset normal maps
- if(dif == DIFFICULTY_HEROIC || entry->map_type == MAP_RAID)
- {
- ++itr;
- continue;
- }
- }
-
- bool isEmpty = true;
- // if the map is loaded, reset it
- Map *map = MapManager::Instance().FindMap(p->GetMapId(), p->GetInstanceId());
- if(map && map->IsDungeon())
- isEmpty = ((InstanceMap*)map)->Reset(method);
-
- if(SendMsgTo)
- {
- if(isEmpty) SendMsgTo->SendResetInstanceSuccess(p->GetMapId());
- else SendMsgTo->SendResetInstanceFailed(0, p->GetMapId());
- }
-
- if(isEmpty || method == INSTANCE_RESET_GROUP_DISBAND || method == INSTANCE_RESET_CHANGE_DIFFICULTY)
- {
- // do not reset the instance, just unbind if others are permanently bound to it
- if(p->CanReset()) p->DeleteFromDB();
- else CharacterDatabase.PExecute("DELETE FROM group_instance WHERE instance = '%u'", p->GetInstanceId());
- // i don't know for sure if hash_map iterators
- m_boundInstances[dif].erase(itr);
- itr = m_boundInstances[dif].begin();
- // this unloads the instance save unless online players are bound to it
- // (eg. permanent binds or GM solo binds)
- p->RemoveGroup(this);
- }
- else
- ++itr;
- }
-}
-
-InstanceGroupBind* Group::GetBoundInstance(uint32 mapid, uint8 difficulty)
-{
- // some instances only have one difficulty
- const MapEntry* entry = sMapStore.LookupEntry(mapid);
- if(!entry || !entry->SupportsHeroicMode()) difficulty = DIFFICULTY_NORMAL;
-
- BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid);
- if(itr != m_boundInstances[difficulty].end())
- return &itr->second;
- else
- return NULL;
-}
-
-InstanceGroupBind* Group::BindToInstance(InstanceSave *save, bool permanent, bool load)
-{
- if(save && !isBGGroup())
- {
- InstanceGroupBind& bind = m_boundInstances[save->GetDifficulty()][save->GetMapId()];
- if(bind.save)
- {
- // when a boss is killed or when copying the players's binds to the group
- if(permanent != bind.perm || save != bind.save)
- if(!load) CharacterDatabase.PExecute("UPDATE group_instance SET instance = '%u', permanent = '%u' WHERE leaderGuid = '%u' AND instance = '%u'", save->GetInstanceId(), permanent, GUID_LOPART(GetLeaderGUID()), bind.save->GetInstanceId());
- }
- else
- if(!load) CharacterDatabase.PExecute("INSERT INTO group_instance (leaderGuid, instance, permanent) VALUES ('%u', '%u', '%u')", GUID_LOPART(GetLeaderGUID()), save->GetInstanceId(), permanent);
-
- if(bind.save != save)
- {
- if(bind.save) bind.save->RemoveGroup(this);
- save->AddGroup(this);
- }
-
- bind.save = save;
- bind.perm = permanent;
- if(!load) sLog.outDebug("Group::BindToInstance: %d is now bound to map %d, instance %d, difficulty %d", GUID_LOPART(GetLeaderGUID()), save->GetMapId(), save->GetInstanceId(), save->GetDifficulty());
- return &bind;
- }
- else
- return NULL;
-}
-
-void Group::UnbindInstance(uint32 mapid, uint8 difficulty, bool unload)
-{
- BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid);
- if(itr != m_boundInstances[difficulty].end())
- {
- if(!unload) CharacterDatabase.PExecute("DELETE FROM group_instance WHERE leaderGuid = '%u' AND instance = '%u'", GUID_LOPART(GetLeaderGUID()), itr->second.save->GetInstanceId());
- itr->second.save->RemoveGroup(this); // save can become invalid
- m_boundInstances[difficulty].erase(itr);
- }
-}
-
-void Group::_homebindIfInstance(Player *player)
-{
- if(player && !player->isGameMaster() && sMapStore.LookupEntry(player->GetMapId())->IsDungeon())
- {
- // leaving the group in an instance, the homebind timer is started
- // unless the player is permanently saved to the instance
- InstanceSave *save = sInstanceSaveManager.GetInstanceSave(player->GetInstanceId());
- InstancePlayerBind *playerBind = save ? player->GetBoundInstance(save->GetMapId(), save->GetDifficulty()) : NULL;
- if(!playerBind || !playerBind->perm)
- player->m_InstanceValid = false;
- }
-}
+/*
+ * Copyright (C) 2005-2008 MaNGOS
+ *
+ * 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 "Opcodes.h"
+#include "WorldPacket.h"
+#include "WorldSession.h"
+#include "Player.h"
+#include "World.h"
+#include "ObjectMgr.h"
+#include "Group.h"
+#include "ObjectAccessor.h"
+#include "BattleGround.h"
+#include "MapManager.h"
+#include "InstanceSaveMgr.h"
+#include "MapInstanced.h"
+#include "Util.h"
+
+Group::Group()
+{
+ m_leaderGuid = 0;
+ m_mainTank = 0;
+ m_mainAssistant = 0;
+ m_groupType = (GroupType)0;
+ m_bgGroup = NULL;
+ m_lootMethod = (LootMethod)0;
+ m_looterGuid = 0;
+ m_lootThreshold = ITEM_QUALITY_UNCOMMON;
+
+ for(int i=0; iGetBgRaid(ALLIANCE) == this) m_bgGroup->SetBgRaid(ALLIANCE, NULL);
+ else if(m_bgGroup->GetBgRaid(HORDE) == this) m_bgGroup->SetBgRaid(HORDE, NULL);
+ else sLog.outError("Group::~Group: battleground group is not linked to the correct battleground.");
+ }
+ Rolls::iterator itr;
+ while(!RollId.empty())
+ {
+ itr = RollId.begin();
+ Roll *r = *itr;
+ RollId.erase(itr);
+ delete(r);
+ }
+
+ // it is undefined whether objectmgr (which stores the groups) or instancesavemgr
+ // will be unloaded first so we must be prepared for both cases
+ // this may unload some instance saves
+ for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++)
+ for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr)
+ itr->second.save->RemoveGroup(this);
+}
+
+bool Group::Create(const uint64 &guid, const char * name)
+{
+ m_leaderGuid = guid;
+ m_leaderName = name;
+
+ m_groupType = isBGGroup() ? GROUPTYPE_RAID : GROUPTYPE_NORMAL;
+ m_lootMethod = GROUP_LOOT;
+ m_lootThreshold = ITEM_QUALITY_UNCOMMON;
+ m_looterGuid = guid;
+
+ m_difficulty = DIFFICULTY_NORMAL;
+ if(!isBGGroup())
+ {
+ Player *leader = objmgr.GetPlayer(guid);
+ if(leader) m_difficulty = leader->GetDifficulty();
+
+ Player::ConvertInstancesToGroup(leader, this, guid);
+
+ // store group in database
+ CharacterDatabase.BeginTransaction();
+ CharacterDatabase.PExecute("DELETE FROM groups WHERE leaderGuid ='%u'", GUID_LOPART(m_leaderGuid));
+ CharacterDatabase.PExecute("DELETE FROM group_member WHERE leaderGuid ='%u'", GUID_LOPART(m_leaderGuid));
+ CharacterDatabase.PExecute("INSERT INTO groups(leaderGuid,mainTank,mainAssistant,lootMethod,looterGuid,lootThreshold,icon1,icon2,icon3,icon4,icon5,icon6,icon7,icon8,isRaid,difficulty) "
+ "VALUES('%u','%u','%u','%u','%u','%u','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "','" I64FMTD "','%u','%u')",
+ GUID_LOPART(m_leaderGuid), GUID_LOPART(m_mainTank), GUID_LOPART(m_mainAssistant), uint32(m_lootMethod),
+ GUID_LOPART(m_looterGuid), uint32(m_lootThreshold), m_targetIcons[0], m_targetIcons[1], m_targetIcons[2], m_targetIcons[3], m_targetIcons[4], m_targetIcons[5], m_targetIcons[6], m_targetIcons[7], isRaidGroup(), m_difficulty);
+ }
+
+ if(!AddMember(guid, name))
+ return false;
+
+ if(!isBGGroup()) CharacterDatabase.CommitTransaction();
+
+ return true;
+}
+
+bool Group::LoadGroupFromDB(const uint64 &leaderGuid, QueryResult *result, bool loadMembers)
+{
+ if(isBGGroup())
+ return false;
+
+ bool external = true;
+ if(!result)
+ {
+ external = false;
+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
+ result = CharacterDatabase.PQuery("SELECT mainTank, mainAssistant, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6, icon7, icon8, isRaid, difficulty FROM groups WHERE leaderGuid ='%u'", GUID_LOPART(leaderGuid));
+ if(!result)
+ return false;
+ }
+
+ m_leaderGuid = leaderGuid;
+
+ // group leader not exist
+ if(!objmgr.GetPlayerNameByGUID(m_leaderGuid, m_leaderName))
+ {
+ if(!external) delete result;
+ return false;
+ }
+
+ m_groupType = (*result)[13].GetBool() ? GROUPTYPE_RAID : GROUPTYPE_NORMAL;
+ m_difficulty = (*result)[14].GetUInt8();
+ m_mainTank = (*result)[0].GetUInt64();
+ m_mainAssistant = (*result)[1].GetUInt64();
+ m_lootMethod = (LootMethod)(*result)[2].GetUInt8();
+ m_looterGuid = MAKE_NEW_GUID((*result)[3].GetUInt32(), 0, HIGHGUID_PLAYER);
+ m_lootThreshold = (ItemQualities)(*result)[4].GetUInt16();
+
+ for(int i=0; iNextRow() );
+ delete result;
+ // group too small
+ if(GetMembersCount() < 2)
+ return false;
+ }
+
+ return true;
+}
+
+bool Group::LoadMemberFromDB(uint32 guidLow, uint8 subgroup, bool assistant)
+{
+ MemberSlot member;
+ member.guid = MAKE_NEW_GUID(guidLow, 0, HIGHGUID_PLAYER);
+
+ // skip non-existed member
+ if(!objmgr.GetPlayerNameByGUID(member.guid, member.name))
+ return false;
+
+ member.group = subgroup;
+ member.assistant = assistant;
+ m_memberSlots.push_back(member);
+ return true;
+}
+
+bool Group::AddInvite(Player *player)
+{
+ if(!player || player->GetGroupInvite() || player->GetGroup())
+ return false;
+
+ RemoveInvite(player);
+
+ m_invitees.insert(player->GetGUID());
+
+ player->SetGroupInvite(this);
+
+ return true;
+}
+
+bool Group::AddLeaderInvite(Player *player)
+{
+ if(!AddInvite(player))
+ return false;
+
+ m_leaderGuid = player->GetGUID();
+ m_leaderName = player->GetName();
+ return true;
+}
+
+uint32 Group::RemoveInvite(Player *player)
+{
+ for(InvitesList::iterator itr=m_invitees.begin(); itr!=m_invitees.end(); ++itr)
+ {
+ if((*itr) == player->GetGUID())
+ {
+ m_invitees.erase(itr);
+ break;
+ }
+ }
+
+ player->SetGroupInvite(NULL);
+ return GetMembersCount();
+}
+
+void Group::RemoveAllInvites()
+{
+ for(InvitesList::iterator itr=m_invitees.begin(); itr!=m_invitees.end(); ++itr)
+ {
+ Player *invitee = objmgr.GetPlayer(*itr);
+ if(invitee)
+ invitee->SetGroupInvite(NULL);
+ }
+ m_invitees.clear();
+}
+
+bool Group::AddMember(const uint64 &guid, const char* name)
+{
+ if(!_addMember(guid, name))
+ return false;
+ SendUpdate();
+
+ Player *player = objmgr.GetPlayer(guid);
+ if(player)
+ {
+ if(!IsLeader(player->GetGUID()) && !isBGGroup())
+ {
+ // reset the new member's instances, unless he is currently in one of them
+ // including raid/heroic instances that they are not permanently bound to!
+ player->ResetInstances(INSTANCE_RESET_GROUP_JOIN);
+
+ if(player->getLevel() >= LEVELREQUIREMENT_HEROIC && player->GetDifficulty() != GetDifficulty() )
+ {
+ player->SetDifficulty(m_difficulty);
+ player->SendDungeonDifficulty(true);
+ }
+ }
+ player->SetGroupUpdateFlag(GROUP_UPDATE_FULL);
+ UpdatePlayerOutOfRange(player);
+ }
+
+ return true;
+}
+
+uint32 Group::RemoveMember(const uint64 &guid, const uint8 &method)
+{
+ // remove member and change leader (if need) only if strong more 2 members _before_ member remove
+ if(GetMembersCount() > (isBGGroup() ? 1 : 2)) // in BG group case allow 1 members group
+ {
+ bool leaderChanged = _removeMember(guid);
+
+ Player *player = objmgr.GetPlayer( guid );
+ if (player)
+ {
+ WorldPacket data;
+
+ if(method == 1)
+ {
+ data.Initialize( SMSG_GROUP_UNINVITE, 0 );
+ player->GetSession()->SendPacket( &data );
+ }
+
+ data.Initialize(SMSG_GROUP_LIST, 24);
+ data << uint64(0) << uint64(0) << uint64(0);
+ player->GetSession()->SendPacket(&data);
+
+ _homebindIfInstance(player);
+ }
+
+ if(leaderChanged)
+ {
+ WorldPacket data(SMSG_GROUP_SET_LEADER, (m_memberSlots.front().name.size()+1));
+ data << m_memberSlots.front().name;
+ BroadcastPacket(&data);
+ }
+
+ SendUpdate();
+ }
+ // if group before remove <= 2 disband it
+ else
+ Disband(true);
+
+ return m_memberSlots.size();
+}
+
+void Group::ChangeLeader(const uint64 &guid)
+{
+ member_citerator slot = _getMemberCSlot(guid);
+
+ if(slot==m_memberSlots.end())
+ return;
+
+ _setLeader(guid);
+
+ WorldPacket data(SMSG_GROUP_SET_LEADER, slot->name.size()+1);
+ data << slot->name;
+ BroadcastPacket(&data);
+ SendUpdate();
+}
+
+void Group::Disband(bool hideDestroy)
+{
+ Player *player;
+
+ for(member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
+ {
+ player = objmgr.GetPlayer(citr->guid);
+ if(!player)
+ continue;
+
+ player->SetGroup(NULL);
+
+ if(!player->GetSession())
+ continue;
+
+ WorldPacket data;
+ if(!hideDestroy)
+ {
+ data.Initialize(SMSG_GROUP_DESTROYED, 0);
+ player->GetSession()->SendPacket(&data);
+ }
+
+ data.Initialize(SMSG_GROUP_LIST, 24);
+ data << uint64(0) << uint64(0) << uint64(0);
+ player->GetSession()->SendPacket(&data);
+
+ _homebindIfInstance(player);
+ }
+ RollId.clear();
+ m_memberSlots.clear();
+
+ RemoveAllInvites();
+
+ if(!isBGGroup())
+ {
+ CharacterDatabase.BeginTransaction();
+ CharacterDatabase.PExecute("DELETE FROM groups WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid));
+ CharacterDatabase.PExecute("DELETE FROM group_member WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid));
+ CharacterDatabase.CommitTransaction();
+ ResetInstances(INSTANCE_RESET_GROUP_DISBAND, NULL);
+ }
+
+ m_leaderGuid = 0;
+ m_leaderName = "";
+}
+
+/*********************************************************/
+/*** LOOT SYSTEM ***/
+/*********************************************************/
+
+void Group::SendLootStartRoll(uint32 CountDown, const Roll &r)
+{
+ WorldPacket data(SMSG_LOOT_START_ROLL, (8+4+4+4+4+4));
+ data << uint64(r.itemGUID); // guid of rolled item
+ data << uint32(r.totalPlayersRolling); // maybe the number of players rolling for it???
+ data << uint32(r.itemid); // the itemEntryId for the item that shall be rolled for
+ data << uint32(r.itemRandomSuffix); // randomSuffix
+ data << uint32(r.itemRandomPropId); // item random property ID
+ data << uint32(CountDown); // the countdown time to choose "need" or "greed"
+
+ for (Roll::PlayerVote::const_iterator itr=r.playerVote.begin(); itr!=r.playerVote.end(); ++itr)
+ {
+ Player *p = objmgr.GetPlayer(itr->first);
+ if(!p || !p->GetSession())
+ continue;
+
+ if(itr->second != NOT_VALID)
+ p->GetSession()->SendPacket( &data );
+ }
+}
+
+void Group::SendLootRoll(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r)
+{
+ WorldPacket data(SMSG_LOOT_ROLL, (8+4+8+4+4+4+1+1));
+ data << uint64(SourceGuid); // guid of the item rolled
+ data << uint32(0); // unknown, maybe amount of players
+ data << uint64(TargetGuid);
+ data << uint32(r.itemid); // the itemEntryId for the item that shall be rolled for
+ data << uint32(r.itemRandomSuffix); // randomSuffix
+ data << uint32(r.itemRandomPropId); // Item random property ID
+ data << uint8(RollNumber); // 0: "Need for: [item name]" > 127: "you passed on: [item name]" Roll number
+ data << uint8(RollType); // 0: "Need for: [item name]" 0: "You have selected need for [item name] 1: need roll 2: greed roll
+ data << uint8(0); // 2.4.0
+
+ for( Roll::PlayerVote::const_iterator itr=r.playerVote.begin(); itr!=r.playerVote.end(); ++itr)
+ {
+ Player *p = objmgr.GetPlayer(itr->first);
+ if(!p || !p->GetSession())
+ continue;
+
+ if(itr->second != NOT_VALID)
+ p->GetSession()->SendPacket( &data );
+ }
+}
+
+void Group::SendLootRollWon(uint64 SourceGuid, uint64 TargetGuid, uint8 RollNumber, uint8 RollType, const Roll &r)
+{
+ WorldPacket data(SMSG_LOOT_ROLL_WON, (8+4+4+4+4+8+1+1));
+ data << uint64(SourceGuid); // guid of the item rolled
+ data << uint32(0); // unknown, maybe amount of players
+ data << uint32(r.itemid); // the itemEntryId for the item that shall be rolled for
+ data << uint32(r.itemRandomSuffix); // randomSuffix
+ data << uint32(r.itemRandomPropId); // Item random property
+ data << uint64(TargetGuid); // guid of the player who won.
+ data << uint8(RollNumber); // rollnumber realted to SMSG_LOOT_ROLL
+ data << uint8(RollType); // Rolltype related to SMSG_LOOT_ROLL
+
+ for( Roll::PlayerVote::const_iterator itr=r.playerVote.begin(); itr!=r.playerVote.end(); ++itr)
+ {
+ Player *p = objmgr.GetPlayer(itr->first);
+ if(!p || !p->GetSession())
+ continue;
+
+ if(itr->second != NOT_VALID)
+ p->GetSession()->SendPacket( &data );
+ }
+}
+
+void Group::SendLootAllPassed(uint32 NumberOfPlayers, const Roll &r)
+{
+ WorldPacket data(SMSG_LOOT_ALL_PASSED, (8+4+4+4+4));
+ data << uint64(r.itemGUID); // Guid of the item rolled
+ data << uint32(NumberOfPlayers); // The number of players rolling for it???
+ data << uint32(r.itemid); // The itemEntryId for the item that shall be rolled for
+ data << uint32(r.itemRandomPropId); // Item random property ID
+ data << uint32(r.itemRandomSuffix); // Item random suffix ID
+
+ for( Roll::PlayerVote::const_iterator itr=r.playerVote.begin(); itr!=r.playerVote.end(); ++itr)
+ {
+ Player *p = objmgr.GetPlayer(itr->first);
+ if(!p || !p->GetSession())
+ continue;
+
+ if(itr->second != NOT_VALID)
+ p->GetSession()->SendPacket( &data );
+ }
+}
+
+void Group::GroupLoot(uint64 playerGUID, Loot *loot, Creature *creature)
+{
+ std::vector::iterator i;
+ ItemPrototype const *item;
+ uint8 itemSlot = 0;
+ Player *player = objmgr.GetPlayer(playerGUID);
+ Group *group = player->GetGroup();
+
+ for (i=loot->items.begin(); i != loot->items.end(); ++i, ++itemSlot)
+ {
+ item = objmgr.GetItemPrototype(i->itemid);
+ if (!item)
+ {
+ //sLog.outDebug("Group::GroupLoot: missing item prototype for item with id: %d", i->itemid);
+ continue;
+ }
+
+ //roll for over-threshold item if it's one-player loot
+ if (item->Quality >= uint32(m_lootThreshold) && !i->freeforall)
+ {
+ uint64 newitemGUID = MAKE_NEW_GUID(objmgr.GenerateLowGuid(HIGHGUID_ITEM),0,HIGHGUID_ITEM);
+ Roll* r=new Roll(newitemGUID,*i);
+
+ //a vector is filled with only near party members
+ for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player *member = itr->getSource();
+ if(!member || !member->GetSession())
+ continue;
+ if ( i->AllowedForPlayer(member) )
+ {
+ if (member->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
+ {
+ r->playerVote[member->GetGUID()] = NOT_EMITED_YET;
+ ++r->totalPlayersRolling;
+ }
+ }
+ }
+
+ r->setLoot(loot);
+ r->itemSlot = itemSlot;
+
+ group->SendLootStartRoll(60000, *r);
+
+ loot->items[itemSlot].is_blocked = true;
+ creature->m_groupLootTimer = 60000;
+ creature->lootingGroupLeaderGUID = GetLeaderGUID();
+
+ RollId.push_back(r);
+ }
+ else
+ i->is_underthreshold=1;
+
+ }
+}
+
+void Group::NeedBeforeGreed(uint64 playerGUID, Loot *loot, Creature *creature)
+{
+ ItemPrototype const *item;
+ Player *player = objmgr.GetPlayer(playerGUID);
+ Group *group = player->GetGroup();
+
+ uint8 itemSlot = 0;
+ for(std::vector::iterator i=loot->items.begin(); i != loot->items.end(); ++i, ++itemSlot)
+ {
+ item = objmgr.GetItemPrototype(i->itemid);
+
+ //only roll for one-player items, not for ones everyone can get
+ if (item->Quality >= uint32(m_lootThreshold) && !i->freeforall)
+ {
+ uint64 newitemGUID = MAKE_NEW_GUID(objmgr.GenerateLowGuid(HIGHGUID_ITEM),0,HIGHGUID_ITEM);
+ Roll* r=new Roll(newitemGUID,*i);
+
+ for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player *playerToRoll = itr->getSource();
+ if(!playerToRoll || !playerToRoll->GetSession())
+ continue;
+
+ if (playerToRoll->CanUseItem(item) && i->AllowedForPlayer(playerToRoll) )
+ {
+ if (playerToRoll->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
+ {
+ r->playerVote[playerToRoll->GetGUID()] = NOT_EMITED_YET;
+ ++r->totalPlayersRolling;
+ }
+ }
+ }
+
+ if (r->totalPlayersRolling > 0)
+ {
+ r->setLoot(loot);
+ r->itemSlot = itemSlot;
+
+ group->SendLootStartRoll(60000, *r);
+
+ loot->items[itemSlot].is_blocked = true;
+
+ RollId.push_back(r);
+ }
+ else
+ {
+ delete r;
+ }
+ }
+ else
+ i->is_underthreshold=1;
+ }
+}
+
+void Group::MasterLoot(uint64 playerGUID, Loot* /*loot*/, Creature *creature)
+{
+ Player *player = objmgr.GetPlayer(playerGUID);
+ if(!player)
+ return;
+
+ sLog.outDebug("Group::MasterLoot (SMSG_LOOT_MASTER_LIST, 330) player = [%s].", player->GetName());
+
+ uint32 real_count = 0;
+
+ WorldPacket data(SMSG_LOOT_MASTER_LIST, 330);
+ data << (uint8)GetMembersCount();
+
+ for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player *looter = itr->getSource();
+ if (!looter->IsInWorld())
+ continue;
+
+ if (looter->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
+ {
+ data << looter->GetGUID();
+ ++real_count;
+ }
+ }
+
+ data.put(0,real_count);
+
+ for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player *looter = itr->getSource();
+ if (looter->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
+ looter->GetSession()->SendPacket(&data);
+ }
+}
+
+void Group::CountRollVote(uint64 playerGUID, uint64 Guid, uint32 NumberOfPlayers, uint8 Choise)
+{
+ Rolls::iterator rollI = GetRoll(Guid);
+ if (rollI == RollId.end())
+ return;
+ Roll* roll = *rollI;
+
+ Roll::PlayerVote::iterator itr = roll->playerVote.find(playerGUID);
+ // this condition means that player joins to the party after roll begins
+ if (itr == roll->playerVote.end())
+ return;
+
+ if (roll->getLoot())
+ if (roll->getLoot()->items.empty())
+ return;
+
+ switch (Choise)
+ {
+ case 0: //Player choose pass
+ {
+ SendLootRoll(0, playerGUID, 128, 128, *roll);
+ ++roll->totalPass;
+ itr->second = PASS;
+ }
+ break;
+ case 1: //player choose Need
+ {
+ SendLootRoll(0, playerGUID, 0, 0, *roll);
+ ++roll->totalNeed;
+ itr->second = NEED;
+ }
+ break;
+ case 2: //player choose Greed
+ {
+ SendLootRoll(0, playerGUID, 128, 2, *roll);
+ ++roll->totalGreed;
+ itr->second = GREED;
+ }
+ break;
+ }
+ if (roll->totalPass + roll->totalGreed + roll->totalNeed >= roll->totalPlayersRolling)
+ {
+ CountTheRoll(rollI, NumberOfPlayers);
+ }
+}
+
+//called when roll timer expires
+void Group::EndRoll()
+{
+ Rolls::iterator itr;
+ while(!RollId.empty())
+ {
+ //need more testing here, if rolls disappear
+ itr = RollId.begin();
+ CountTheRoll(itr, GetMembersCount()); //i don't have to edit player votes, who didn't vote ... he will pass
+ }
+}
+
+void Group::CountTheRoll(Rolls::iterator rollI, uint32 NumberOfPlayers)
+{
+ Roll* roll = *rollI;
+ if(!roll->isValid()) // is loot already deleted ?
+ {
+ RollId.erase(rollI);
+ delete roll;
+ return;
+ }
+ //end of the roll
+ if (roll->totalNeed > 0)
+ {
+ if(!roll->playerVote.empty())
+ {
+ uint8 maxresul = 0;
+ uint64 maxguid = (*roll->playerVote.begin()).first;
+ Player *player;
+
+ for( Roll::PlayerVote::const_iterator itr=roll->playerVote.begin(); itr!=roll->playerVote.end(); ++itr)
+ {
+ if (itr->second != NEED)
+ continue;
+
+ uint8 randomN = urand(1, 99);
+ SendLootRoll(0, itr->first, randomN, 1, *roll);
+ if (maxresul < randomN)
+ {
+ maxguid = itr->first;
+ maxresul = randomN;
+ }
+ }
+ SendLootRollWon(0, maxguid, maxresul, 1, *roll);
+ player = objmgr.GetPlayer(maxguid);
+
+ if(player && player->GetSession())
+ {
+ ItemPosCountVec dest;
+ LootItem *item = &(roll->getLoot()->items[roll->itemSlot]);
+ uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count );
+ if ( msg == EQUIP_ERR_OK )
+ {
+ item->is_looted = true;
+ roll->getLoot()->NotifyItemRemoved(roll->itemSlot);
+ --roll->getLoot()->unlootedCount;
+ player->StoreNewItem( dest, roll->itemid, true, item->randomPropertyId);
+ }
+ else
+ {
+ item->is_blocked = false;
+ player->SendEquipError( msg, NULL, NULL );
+ }
+ }
+ }
+ }
+ else if (roll->totalGreed > 0)
+ {
+ if(!roll->playerVote.empty())
+ {
+ uint8 maxresul = 0;
+ uint64 maxguid = (*roll->playerVote.begin()).first;
+ Player *player;
+
+ Roll::PlayerVote::iterator itr;
+ for (itr=roll->playerVote.begin(); itr!=roll->playerVote.end(); ++itr)
+ {
+ if (itr->second != GREED)
+ continue;
+
+ uint8 randomN = urand(1, 99);
+ SendLootRoll(0, itr->first, randomN, 2, *roll);
+ if (maxresul < randomN)
+ {
+ maxguid = itr->first;
+ maxresul = randomN;
+ }
+ }
+ SendLootRollWon(0, maxguid, maxresul, 2, *roll);
+ player = objmgr.GetPlayer(maxguid);
+
+ if(player && player->GetSession())
+ {
+ ItemPosCountVec dest;
+ LootItem *item = &(roll->getLoot()->items[roll->itemSlot]);
+ uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, roll->itemid, item->count );
+ if ( msg == EQUIP_ERR_OK )
+ {
+ item->is_looted = true;
+ roll->getLoot()->NotifyItemRemoved(roll->itemSlot);
+ --roll->getLoot()->unlootedCount;
+ player->StoreNewItem( dest, roll->itemid, true, item->randomPropertyId);
+ }
+ else
+ {
+ item->is_blocked = false;
+ player->SendEquipError( msg, NULL, NULL );
+ }
+ }
+ }
+ }
+ else
+ {
+ SendLootAllPassed(NumberOfPlayers, *roll);
+ LootItem *item = &(roll->getLoot()->items[roll->itemSlot]);
+ if(item) item->is_blocked = false;
+ }
+ RollId.erase(rollI);
+ delete roll;
+}
+
+void Group::SetTargetIcon(uint8 id, uint64 guid)
+{
+ if(id >= TARGETICONCOUNT)
+ return;
+
+ // clean other icons
+ if( guid != 0 )
+ for(int i=0; inext())
+ {
+ Player* member = itr->getSource();
+ if(!member || !member->isAlive()) // only for alive
+ continue;
+
+ if(!member->IsAtGroupRewardDistance(victim)) // at req. distance
+ continue;
+
+ ++count;
+ sum_level += member->getLevel();
+ if(!member_with_max_level || member_with_max_level->getLevel() < member->getLevel())
+ member_with_max_level = member;
+ }
+}
+
+void Group::SendTargetIconList(WorldSession *session)
+{
+ if(!session)
+ return;
+
+ WorldPacket data(MSG_RAID_TARGET_UPDATE, (1+TARGETICONCOUNT*9));
+ data << (uint8)1;
+
+ for(int i=0; iSendPacket(&data);
+}
+
+void Group::SendUpdate()
+{
+ Player *player;
+
+ for(member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
+ {
+ player = objmgr.GetPlayer(citr->guid);
+ if(!player || !player->GetSession())
+ continue;
+ // guess size
+ WorldPacket data(SMSG_GROUP_LIST, (1+1+1+1+8+4+GetMembersCount()*20));
+ data << (uint8)m_groupType; // group type
+ data << (uint8)(isBGGroup() ? 1 : 0); // 2.0.x, isBattleGroundGroup?
+ data << (uint8)(citr->group); // groupid
+ data << (uint8)(citr->assistant?0x01:0); // 0x2 main assist, 0x4 main tank
+ data << uint64(0x50000000FFFFFFFELL); // related to voice chat?
+ data << uint32(GetMembersCount()-1);
+ for(member_citerator citr2 = m_memberSlots.begin(); citr2 != m_memberSlots.end(); ++citr2)
+ {
+ if(citr->guid == citr2->guid)
+ continue;
+
+ data << citr2->name;
+ data << (uint64)citr2->guid;
+ // online-state
+ data << (uint8)(objmgr.GetPlayer(citr2->guid) ? 1 : 0);
+ data << (uint8)(citr2->group); // groupid
+ data << (uint8)(citr2->assistant?0x01:0); // 0x2 main assist, 0x4 main tank
+ }
+
+ data << uint64(m_leaderGuid); // leader guid
+ if(GetMembersCount()-1)
+ {
+ data << (uint8)m_lootMethod; // loot method
+ data << (uint64)m_looterGuid; // looter guid
+ data << (uint8)m_lootThreshold; // loot threshold
+ data << (uint8)m_difficulty; // Heroic Mod Group
+
+ }
+ player->GetSession()->SendPacket( &data );
+ }
+}
+
+void Group::UpdatePlayerOutOfRange(Player* pPlayer)
+{
+ if(!pPlayer)
+ return;
+
+ Player *player;
+ WorldPacket data;
+ pPlayer->GetSession()->BuildPartyMemberStatsChangedPacket(pPlayer, &data);
+
+ for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ player = itr->getSource();
+ if (player && player != pPlayer && !pPlayer->isVisibleFor(player))
+ player->GetSession()->SendPacket(&data);
+ }
+}
+
+void Group::BroadcastPacket(WorldPacket *packet, int group, uint64 ignore)
+{
+ for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player *pl = itr->getSource();
+ if(!pl || (ignore != 0 && pl->GetGUID() == ignore))
+ continue;
+
+ if (pl->GetSession() && (group==-1 || itr->getSubGroup()==group))
+ pl->GetSession()->SendPacket(packet);
+ }
+}
+
+void Group::BroadcastReadyCheck(WorldPacket *packet)
+{
+ for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player *pl = itr->getSource();
+ if(pl && pl->GetSession())
+ if(IsLeader(pl->GetGUID()) || IsAssistant(pl->GetGUID()))
+ pl->GetSession()->SendPacket(packet);
+ }
+}
+
+void Group::OfflineReadyCheck()
+{
+ for(member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr)
+ {
+ Player *pl = objmgr.GetPlayer(citr->guid);
+ if (!pl || !pl->GetSession())
+ {
+ WorldPacket data(MSG_RAID_READY_CHECK_CONFIRM, 9);
+ data << citr->guid;
+ data << (uint8)0;
+ BroadcastReadyCheck(&data);
+ }
+ }
+}
+
+bool Group::_addMember(const uint64 &guid, const char* name, bool isAssistant)
+{
+ // get first not-full group
+ uint8 groupid = 0;
+ std::vector temp(MAXRAIDSIZE/MAXGROUPSIZE);
+ for(member_citerator itr = m_memberSlots.begin(); itr != m_memberSlots.end(); ++itr)
+ {
+ if (itr->group >= temp.size()) continue;
+ ++temp[itr->group];
+ if(temp[groupid] >= MAXGROUPSIZE)
+ ++groupid;
+ }
+
+ return _addMember(guid, name, isAssistant, groupid);
+}
+
+bool Group::_addMember(const uint64 &guid, const char* name, bool isAssistant, uint8 group)
+{
+ if(IsFull())
+ return false;
+
+ if(!guid)
+ return false;
+
+ Player *player = objmgr.GetPlayer(guid);
+
+ MemberSlot member;
+ member.guid = guid;
+ member.name = name;
+ member.group = group;
+ member.assistant = isAssistant;
+ m_memberSlots.push_back(member);
+
+ if(player)
+ {
+ player->SetGroupInvite(NULL);
+ player->SetGroup(this, group);
+ // if the same group invites the player back, cancel the homebind timer
+ InstanceGroupBind *bind = GetBoundInstance(player->GetMapId(), player->GetDifficulty());
+ if(bind && bind->save->GetInstanceId() == player->GetInstanceId())
+ player->m_InstanceValid = true;
+ }
+
+ if(!isRaidGroup()) // reset targetIcons for non-raid-groups
+ {
+ for(int i=0; iSetGroup(NULL);
+ }
+
+ _removeRolls(guid);
+
+ member_witerator slot = _getMemberWSlot(guid);
+ if (slot != m_memberSlots.end())
+ m_memberSlots.erase(slot);
+
+ if(!isBGGroup())
+ CharacterDatabase.PExecute("DELETE FROM group_member WHERE memberGuid='%u'", GUID_LOPART(guid));
+
+ if(m_leaderGuid == guid) // leader was removed
+ {
+ if(GetMembersCount() > 0)
+ _setLeader(m_memberSlots.front().guid);
+ return true;
+ }
+
+ return false;
+}
+
+void Group::_setLeader(const uint64 &guid)
+{
+ member_citerator slot = _getMemberCSlot(guid);
+ if(slot==m_memberSlots.end())
+ return;
+
+ if(!isBGGroup())
+ {
+ // TODO: set a time limit to have this function run rarely cause it can be slow
+ CharacterDatabase.BeginTransaction();
+
+ // update the group's bound instances when changing leaders
+
+ // remove all permanent binds from the group
+ // in the DB also remove solo binds that will be replaced with permbinds
+ // from the new leader
+ CharacterDatabase.PExecute(
+ "DELETE FROM group_instance WHERE leaderguid='%u' AND (permanent = 1 OR "
+ "instance IN (SELECT instance FROM character_instance WHERE guid = '%u')"
+ ")", GUID_LOPART(m_leaderGuid), GUID_LOPART(slot->guid)
+ );
+
+ Player *player = objmgr.GetPlayer(slot->guid);
+ if(player)
+ {
+ for(uint8 i = 0; i < TOTAL_DIFFICULTIES; i++)
+ {
+ for(BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end();)
+ {
+ if(itr->second.perm)
+ {
+ itr->second.save->RemoveGroup(this);
+ m_boundInstances[i].erase(itr++);
+ }
+ else
+ ++itr;
+ }
+ }
+ }
+
+ // update the group's solo binds to the new leader
+ CharacterDatabase.PExecute("UPDATE group_instance SET leaderGuid='%u' WHERE leaderGuid = '%u'", GUID_LOPART(slot->guid), GUID_LOPART(m_leaderGuid));
+
+ // copy the permanent binds from the new leader to the group
+ // overwriting the solo binds with permanent ones if necessary
+ // in the DB those have been deleted already
+ Player::ConvertInstancesToGroup(player, this, slot->guid);
+
+ // update the group leader
+ CharacterDatabase.PExecute("UPDATE groups SET leaderGuid='%u' WHERE leaderGuid='%u'", GUID_LOPART(slot->guid), GUID_LOPART(m_leaderGuid));
+ CharacterDatabase.PExecute("UPDATE group_member SET leaderGuid='%u' WHERE leaderGuid='%u'", GUID_LOPART(slot->guid), GUID_LOPART(m_leaderGuid));
+ CharacterDatabase.CommitTransaction();
+ }
+
+ m_leaderGuid = slot->guid;
+ m_leaderName = slot->name;
+}
+
+void Group::_removeRolls(const uint64 &guid)
+{
+ for (Rolls::iterator it = RollId.begin(); it < RollId.end(); it++)
+ {
+ Roll* roll = *it;
+ Roll::PlayerVote::iterator itr2 = roll->playerVote.find(guid);
+ if(itr2 == roll->playerVote.end())
+ continue;
+
+ if (itr2->second == GREED) --roll->totalGreed;
+ if (itr2->second == NEED) --roll->totalNeed;
+ if (itr2->second == PASS) --roll->totalPass;
+ if (itr2->second != NOT_VALID) --roll->totalPlayersRolling;
+
+ roll->playerVote.erase(itr2);
+
+ CountRollVote(guid, roll->itemGUID, GetMembersCount()-1, 3);
+ }
+}
+
+void Group::_convertToRaid()
+{
+ m_groupType = GROUPTYPE_RAID;
+
+ if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE groups SET isRaid = 1 WHERE leaderGuid='%u'", GUID_LOPART(m_leaderGuid));
+}
+
+bool Group::_setMembersGroup(const uint64 &guid, const uint8 &group)
+{
+ member_witerator slot = _getMemberWSlot(guid);
+ if(slot==m_memberSlots.end())
+ return false;
+
+ slot->group = group;
+ if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE group_member SET subgroup='%u' WHERE memberGuid='%u'", group, GUID_LOPART(guid));
+ return true;
+}
+
+bool Group::_setAssistantFlag(const uint64 &guid, const bool &state)
+{
+ member_witerator slot = _getMemberWSlot(guid);
+ if(slot==m_memberSlots.end())
+ return false;
+
+ slot->assistant = state;
+ if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE group_member SET assistant='%u' WHERE memberGuid='%u'", (state==true)?1:0, GUID_LOPART(guid));
+ return true;
+}
+
+bool Group::_setMainTank(const uint64 &guid)
+{
+ member_citerator slot = _getMemberCSlot(guid);
+ if(slot==m_memberSlots.end())
+ return false;
+
+ if(m_mainAssistant == guid)
+ _setMainAssistant(0);
+ m_mainTank = guid;
+ if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE groups SET mainTank='%u' WHERE leaderGuid='%u'", GUID_LOPART(m_mainTank), GUID_LOPART(m_leaderGuid));
+ return true;
+}
+
+bool Group::_setMainAssistant(const uint64 &guid)
+{
+ member_witerator slot = _getMemberWSlot(guid);
+ if(slot==m_memberSlots.end())
+ return false;
+
+ if(m_mainTank == guid)
+ _setMainTank(0);
+ m_mainAssistant = guid;
+ if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE groups SET mainAssistant='%u' WHERE leaderGuid='%u'", GUID_LOPART(m_mainAssistant), GUID_LOPART(m_leaderGuid));
+ return true;
+}
+
+bool Group::SameSubGroup(Player const* member1, Player const* member2) const
+{
+ if(!member1 || !member2) return false;
+ if (member1->GetGroup() != this || member2->GetGroup() != this) return false;
+ else return member1->GetSubGroup() == member2->GetSubGroup();
+}
+
+// allows setting subgroup for offline members
+void Group::ChangeMembersGroup(const uint64 &guid, const uint8 &group)
+{
+ if(!isRaidGroup())
+ return;
+ Player *player = objmgr.GetPlayer(guid);
+ if (!player)
+ {
+ if(_setMembersGroup(guid, group))
+ SendUpdate();
+ }
+ else ChangeMembersGroup(player, group);
+}
+
+// only for online members
+void Group::ChangeMembersGroup(Player *player, const uint8 &group)
+{
+ if(!player || !isRaidGroup())
+ return;
+ if(_setMembersGroup(player->GetGUID(), group))
+ {
+ player->GetGroupRef().setSubGroup(group);
+ SendUpdate();
+ }
+}
+
+void Group::UpdateLooterGuid( Creature* creature, bool ifneed )
+{
+ switch (GetLootMethod())
+ {
+ case MASTER_LOOT:
+ case FREE_FOR_ALL:
+ return;
+ default:
+ // round robin style looting applies for all low
+ // quality items in each loot method except free for all and master loot
+ break;
+ }
+
+ member_citerator guid_itr = _getMemberCSlot(GetLooterGuid());
+ if(guid_itr != m_memberSlots.end())
+ {
+ if(ifneed)
+ {
+ // not update if only update if need and ok
+ Player* looter = ObjectAccessor::FindPlayer(guid_itr->guid);
+ if(looter && looter->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
+ return;
+ }
+ ++guid_itr;
+ }
+
+ // search next after current
+ if(guid_itr != m_memberSlots.end())
+ {
+ for(member_citerator itr = guid_itr; itr != m_memberSlots.end(); ++itr)
+ {
+ if(Player* pl = ObjectAccessor::FindPlayer(itr->guid))
+ {
+ if (pl->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
+ {
+ bool refresh = pl->GetLootGUID()==creature->GetGUID();
+
+ //if(refresh) // update loot for new looter
+ // pl->GetSession()->DoLootRelease(pl->GetLootGUID());
+ SetLooterGuid(pl->GetGUID());
+ SendUpdate();
+ if(refresh) // update loot for new looter
+ pl->SendLoot(creature->GetGUID(),LOOT_CORPSE);
+ return;
+ }
+ }
+ }
+ }
+
+ // search from start
+ for(member_citerator itr = m_memberSlots.begin(); itr != guid_itr; ++itr)
+ {
+ if(Player* pl = ObjectAccessor::FindPlayer(itr->guid))
+ {
+ if (pl->GetDistance2d(creature) < sWorld.getConfig(CONFIG_GROUP_XP_DISTANCE))
+ {
+ bool refresh = pl->GetLootGUID()==creature->GetGUID();
+
+ //if(refresh) // update loot for new looter
+ // pl->GetSession()->DoLootRelease(pl->GetLootGUID());
+ SetLooterGuid(pl->GetGUID());
+ SendUpdate();
+ if(refresh) // update loot for new looter
+ pl->SendLoot(creature->GetGUID(),LOOT_CORPSE);
+ return;
+ }
+ }
+ }
+
+ SetLooterGuid(0);
+ SendUpdate();
+}
+
+uint32 Group::CanJoinBattleGroundQueue(uint32 bgTypeId, uint32 bgQueueType, uint32 MinPlayerCount, uint32 MaxPlayerCount, bool isRated, uint32 arenaSlot)
+{
+ // check for min / max count
+ uint32 memberscount = GetMembersCount();
+ if(memberscount < MinPlayerCount)
+ return BG_JOIN_ERR_GROUP_NOT_ENOUGH;
+ if(memberscount > MaxPlayerCount)
+ return BG_JOIN_ERR_GROUP_TOO_MANY;
+
+ // get a player as reference, to compare other players' stats to (arena team id, queue id based on level, etc.)
+ Player * reference = GetFirstMember()->getSource();
+ // no reference found, can't join this way
+ if(!reference)
+ return BG_JOIN_ERR_OFFLINE_MEMBER;
+
+ uint32 bgQueueId = reference->GetBattleGroundQueueIdFromLevel();
+ uint32 arenaTeamId = reference->GetArenaTeamId(arenaSlot);
+ uint32 team = reference->GetTeam();
+
+ // check every member of the group to be able to join
+ for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player *member = itr->getSource();
+ // offline member? don't let join
+ if(!member)
+ return BG_JOIN_ERR_OFFLINE_MEMBER;
+ // don't allow cross-faction join as group
+ if(member->GetTeam() != team)
+ return BG_JOIN_ERR_MIXED_FACTION;
+ // not in the same battleground level braket, don't let join
+ if(member->GetBattleGroundQueueIdFromLevel() != bgQueueId)
+ return BG_JOIN_ERR_MIXED_LEVELS;
+ // don't let join rated matches if the arena team id doesn't match
+ if(isRated && member->GetArenaTeamId(arenaSlot) != arenaTeamId)
+ return BG_JOIN_ERR_MIXED_ARENATEAM;
+ // don't let join if someone from the group is already in that bg queue
+ if(member->InBattleGroundQueueForBattleGroundQueueType(bgQueueType))
+ return BG_JOIN_ERR_GROUP_MEMBER_ALREADY_IN_QUEUE;
+ // check for deserter debuff in case not arena queue
+ if(bgTypeId != BATTLEGROUND_AA && !member->CanJoinToBattleground())
+ return BG_JOIN_ERR_GROUP_DESERTER;
+ // check if member can join any more battleground queues
+ if(!member->HasFreeBattleGroundQueueId())
+ return BG_JOIN_ERR_ALL_QUEUES_USED;
+ }
+ return BG_JOIN_ERR_OK;
+}
+
+//===================================================
+//============== Roll ===============================
+//===================================================
+
+void Roll::targetObjectBuildLink()
+{
+ // called from link()
+ this->getTarget()->addLootValidatorRef(this);
+}
+
+void Group::SetDifficulty(uint8 difficulty)
+{
+ m_difficulty = difficulty;
+ if(!isBGGroup()) CharacterDatabase.PExecute("UPDATE groups SET difficulty = %u WHERE leaderGuid ='%u'", m_difficulty, GUID_LOPART(m_leaderGuid));
+
+ for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player *player = itr->getSource();
+ if(!player->GetSession() || player->getLevel() < LEVELREQUIREMENT_HEROIC)
+ continue;
+ player->SetDifficulty(difficulty);
+ player->SendDungeonDifficulty(true);
+ }
+}
+
+bool Group::InCombatToInstance(uint32 instanceId)
+{
+ for(GroupReference *itr = GetFirstMember(); itr != NULL; itr = itr->next())
+ {
+ Player *pPlayer = itr->getSource();
+ if(pPlayer->getAttackers().size() && pPlayer->GetInstanceId() == instanceId)
+ return true;
+ }
+ return false;
+}
+
+void Group::ResetInstances(uint8 method, Player* SendMsgTo)
+{
+ if(isBGGroup())
+ return;
+
+ // method can be INSTANCE_RESET_ALL, INSTANCE_RESET_CHANGE_DIFFICULTY, INSTANCE_RESET_GROUP_DISBAND
+
+ // we assume that when the difficulty changes, all instances that can be reset will be
+ uint8 dif = GetDifficulty();
+
+ for(BoundInstancesMap::iterator itr = m_boundInstances[dif].begin(); itr != m_boundInstances[dif].end();)
+ {
+ InstanceSave *p = itr->second.save;
+ const MapEntry *entry = sMapStore.LookupEntry(itr->first);
+ if(!entry || (!p->CanReset() && method != INSTANCE_RESET_GROUP_DISBAND))
+ {
+ ++itr;
+ continue;
+ }
+
+ if(method == INSTANCE_RESET_ALL)
+ {
+ // the "reset all instances" method can only reset normal maps
+ if(dif == DIFFICULTY_HEROIC || entry->map_type == MAP_RAID)
+ {
+ ++itr;
+ continue;
+ }
+ }
+
+ bool isEmpty = true;
+ // if the map is loaded, reset it
+ Map *map = MapManager::Instance().FindMap(p->GetMapId(), p->GetInstanceId());
+ if(map && map->IsDungeon())
+ isEmpty = ((InstanceMap*)map)->Reset(method);
+
+ if(SendMsgTo)
+ {
+ if(isEmpty) SendMsgTo->SendResetInstanceSuccess(p->GetMapId());
+ else SendMsgTo->SendResetInstanceFailed(0, p->GetMapId());
+ }
+
+ if(isEmpty || method == INSTANCE_RESET_GROUP_DISBAND || method == INSTANCE_RESET_CHANGE_DIFFICULTY)
+ {
+ // do not reset the instance, just unbind if others are permanently bound to it
+ if(p->CanReset()) p->DeleteFromDB();
+ else CharacterDatabase.PExecute("DELETE FROM group_instance WHERE instance = '%u'", p->GetInstanceId());
+ // i don't know for sure if hash_map iterators
+ m_boundInstances[dif].erase(itr);
+ itr = m_boundInstances[dif].begin();
+ // this unloads the instance save unless online players are bound to it
+ // (eg. permanent binds or GM solo binds)
+ p->RemoveGroup(this);
+ }
+ else
+ ++itr;
+ }
+}
+
+InstanceGroupBind* Group::GetBoundInstance(uint32 mapid, uint8 difficulty)
+{
+ // some instances only have one difficulty
+ const MapEntry* entry = sMapStore.LookupEntry(mapid);
+ if(!entry || !entry->SupportsHeroicMode()) difficulty = DIFFICULTY_NORMAL;
+
+ BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid);
+ if(itr != m_boundInstances[difficulty].end())
+ return &itr->second;
+ else
+ return NULL;
+}
+
+InstanceGroupBind* Group::BindToInstance(InstanceSave *save, bool permanent, bool load)
+{
+ if(save && !isBGGroup())
+ {
+ InstanceGroupBind& bind = m_boundInstances[save->GetDifficulty()][save->GetMapId()];
+ if(bind.save)
+ {
+ // when a boss is killed or when copying the players's binds to the group
+ if(permanent != bind.perm || save != bind.save)
+ if(!load) CharacterDatabase.PExecute("UPDATE group_instance SET instance = '%u', permanent = '%u' WHERE leaderGuid = '%u' AND instance = '%u'", save->GetInstanceId(), permanent, GUID_LOPART(GetLeaderGUID()), bind.save->GetInstanceId());
+ }
+ else
+ if(!load) CharacterDatabase.PExecute("INSERT INTO group_instance (leaderGuid, instance, permanent) VALUES ('%u', '%u', '%u')", GUID_LOPART(GetLeaderGUID()), save->GetInstanceId(), permanent);
+
+ if(bind.save != save)
+ {
+ if(bind.save) bind.save->RemoveGroup(this);
+ save->AddGroup(this);
+ }
+
+ bind.save = save;
+ bind.perm = permanent;
+ if(!load) sLog.outDebug("Group::BindToInstance: %d is now bound to map %d, instance %d, difficulty %d", GUID_LOPART(GetLeaderGUID()), save->GetMapId(), save->GetInstanceId(), save->GetDifficulty());
+ return &bind;
+ }
+ else
+ return NULL;
+}
+
+void Group::UnbindInstance(uint32 mapid, uint8 difficulty, bool unload)
+{
+ BoundInstancesMap::iterator itr = m_boundInstances[difficulty].find(mapid);
+ if(itr != m_boundInstances[difficulty].end())
+ {
+ if(!unload) CharacterDatabase.PExecute("DELETE FROM group_instance WHERE leaderGuid = '%u' AND instance = '%u'", GUID_LOPART(GetLeaderGUID()), itr->second.save->GetInstanceId());
+ itr->second.save->RemoveGroup(this); // save can become invalid
+ m_boundInstances[difficulty].erase(itr);
+ }
+}
+
+void Group::_homebindIfInstance(Player *player)
+{
+ if(player && !player->isGameMaster() && sMapStore.LookupEntry(player->GetMapId())->IsDungeon())
+ {
+ // leaving the group in an instance, the homebind timer is started
+ // unless the player is permanently saved to the instance
+ InstanceSave *save = sInstanceSaveManager.GetInstanceSave(player->GetInstanceId());
+ InstancePlayerBind *playerBind = save ? player->GetBoundInstance(save->GetMapId(), save->GetDifficulty()) : NULL;
+ if(!playerBind || !playerBind->perm)
+ player->m_InstanceValid = false;
+ }
+}
diff --git a/src/game/HomeMovementGenerator.cpp b/src/game/HomeMovementGenerator.cpp
index 281909b68de..79f312d3b8b 100644
--- a/src/game/HomeMovementGenerator.cpp
+++ b/src/game/HomeMovementGenerator.cpp
@@ -1,86 +1,86 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS
- *
- * 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 "HomeMovementGenerator.h"
-#include "Creature.h"
-#include "Traveller.h"
-#include "MapManager.h"
-#include "ObjectAccessor.h"
-#include "DestinationHolderImp.h"
-#include "ObjectMgr.h"
-#include "WorldPacket.h"
-
-void
-HomeMovementGenerator::Initialize(Creature & owner)
-{
- owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
- _setTargetLocation(owner);
-}
-
-void
-HomeMovementGenerator::Reset(Creature &)
-{
-}
-
-void
-HomeMovementGenerator::_setTargetLocation(Creature & owner)
-{
- if( !&owner )
- return;
-
- if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED | UNIT_STAT_DISTRACTED) )
- return;
-
- float x, y, z;
- owner.GetRespawnCoord(x, y, z);
-
- CreatureTraveller traveller(owner);
-
- uint32 travel_time = i_destinationHolder.SetDestination(traveller, x, y, z);
- modifyTravelTime(travel_time);
- owner.clearUnitState(UNIT_STAT_ALL_STATE);
-}
-
-bool
-HomeMovementGenerator::Update(Creature &owner, const uint32& time_diff)
-{
- CreatureTraveller traveller( owner);
- i_destinationHolder.UpdateTraveller(traveller, time_diff, false);
-
- if (time_diff > i_travel_timer)
- {
- owner.AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
-
- // restore orientation of not moving creature at returning to home
- if(owner.GetDefaultMovementType()==IDLE_MOTION_TYPE)
- {
- if(CreatureData const* data = objmgr.GetCreatureData(owner.GetDBTableGUIDLow()))
- {
- owner.SetOrientation(data->orientation);
- WorldPacket packet;
- owner.BuildHeartBeatMsg(&packet);
- owner.SendMessageToSet(&packet, false);
- }
- }
- return false;
- }
-
- i_travel_timer -= time_diff;
-
- return true;
-}
+/*
+ * Copyright (C) 2005-2008 MaNGOS
+ *
+ * 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 "HomeMovementGenerator.h"
+#include "Creature.h"
+#include "Traveller.h"
+#include "MapManager.h"
+#include "ObjectAccessor.h"
+#include "DestinationHolderImp.h"
+#include "ObjectMgr.h"
+#include "WorldPacket.h"
+
+void
+HomeMovementGenerator::Initialize(Creature & owner)
+{
+ owner.RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
+ _setTargetLocation(owner);
+}
+
+void
+HomeMovementGenerator::Reset(Creature &)
+{
+}
+
+void
+HomeMovementGenerator::_setTargetLocation(Creature & owner)
+{
+ if( !&owner )
+ return;
+
+ if( owner.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED) )
+ return;
+
+ float x, y, z;
+ owner.GetRespawnCoord(x, y, z);
+
+ CreatureTraveller traveller(owner);
+
+ uint32 travel_time = i_destinationHolder.SetDestination(traveller, x, y, z);
+ modifyTravelTime(travel_time);
+ owner.clearUnitState(UNIT_STAT_ALL_STATE);
+}
+
+bool
+HomeMovementGenerator::Update(Creature &owner, const uint32& time_diff)
+{
+ CreatureTraveller traveller( owner);
+ i_destinationHolder.UpdateTraveller(traveller, time_diff, false);
+
+ if (time_diff > i_travel_timer)
+ {
+ owner.AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
+
+ // restore orientation of not moving creature at returning to home
+ if(owner.GetDefaultMovementType()==IDLE_MOTION_TYPE)
+ {
+ if(CreatureData const* data = objmgr.GetCreatureData(owner.GetDBTableGUIDLow()))
+ {
+ owner.SetOrientation(data->orientation);
+ WorldPacket packet;
+ owner.BuildHeartBeatMsg(&packet);
+ owner.SendMessageToSet(&packet, false);
+ }
+ }
+ return false;
+ }
+
+ i_travel_timer -= time_diff;
+
+ return true;
+}
diff --git a/src/game/Language.h b/src/game/Language.h
index dcd76059e2c..fc4f4039e51 100644
--- a/src/game/Language.h
+++ b/src/game/Language.h
@@ -75,7 +75,9 @@ enum MangosStrings
LANG_LEVEL_MINREQUIRED = 49,
LANG_LEVEL_MINREQUIRED_AND_ITEM = 50,
LANG_NPC_TAINER_HELLO = 51,
- // Room for more level 0
+ LANG_COMMAND_INVALID_ITEM_COUNT = 52,
+ LANG_COMMAND_MAIL_ITEMS_LIMIT = 53,
+ // Room for more level 0 54-99 not used
// level 1 chat
LANG_GLOBAL_NOTIFY = 100,
@@ -159,7 +161,7 @@ enum MangosStrings
LANG_MAIL_SENT = 169,
LANG_SOUND_NOT_EXIST = 170,
- // Room for more level 1
+ // Room for more level 1 171-199 not used
// level 2 chat
LANG_NO_SELECTION = 200,
@@ -304,8 +306,11 @@ enum MangosStrings
LANG_LOOKUP_PLAYER_CHARACTER = 329,
LANG_NO_PLAYERS_FOUND = 330,
LANG_EXTENDED_COST_NOT_EXIST = 331,
-
- // Room for more level 2
+ LANG_GM_ON = 332,
+ LANG_GM_OFF = 333,
+ LANG_GM_CHAT_ON = 334,
+ LANG_GM_CHAT_OFF = 335,
+ // Room for more level 2 336-399 not used
// level 3 chat
LANG_SCRIPTS_RELOADED = 400,
@@ -610,79 +615,49 @@ enum MangosStrings
LANG_BG_GROUP_TOO_LARGE = 711,
LANG_ARENA_GROUP_TOO_LARGE = 712,
- LANG_ARENA_YOUR_TEAM_ONLY = 713,
- LANG_ARENA_NOT_ENOUGH_PLAYERS = 714,
- LANG_ARENA_GOLD_WINS = 715,
- LANG_ARENA_GREEN_WINS = 716,
- LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING = 717,
- LANG_BG_GROUP_OFFLINE_MEMBER = 718,
- LANG_BG_GROUP_MIXED_FACTION = 719,
- LANG_BG_GROUP_MIXED_LEVELS = 720,
- LANG_BG_GROUP_MEMBER_ALREADY_IN_QUEUE = 721,
- LANG_BG_GROUP_MEMBER_DESERTER = 722,
- LANG_BG_GROUP_MEMBER_NO_FREE_QUEUE_SLOTS = 723,
+ LANG_YOUR_ARENA_LEVEL_REQ_ERROR = 713,
+ 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_CANNOT_TELE_TO_BG = 724,
- LANG_CANNOT_SUMMON_TO_BG = 725,
- LANG_CANNOT_GO_TO_BG_GM = 726,
- LANG_CANNOT_GO_TO_BG_FROM_BG = 727,
+ 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_ARENA_TESTING = 728
+ 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,
+
+ // in game strings
+ LANG_PET_INVALID_NAME = 800,
+ LANG_NOT_ENOUGH_GOLD = 801,
+ LANG_NOT_FREE_TRADE_SLOTS = 802,
+ LANG_NOT_PARTNER_FREE_TRADE_SLOTS = 803,
+ LANG_YOU_NOT_HAVE_PERMISSION = 804,
+ LANG_UNKNOWN_LANGUAGE = 805,
+ LANG_NOT_LEARNED_LANGUAGE = 806,
+ LANG_NEED_CHARACTER_NAME = 807,
+ LANG_PLAYER_NOT_EXIST_OR_OFFLINE = 808,
+ LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND = 809,
+ // Room for in-game strings 810-999 not used
+
+ // FREE IDS 1000-9999
+
+ // Use for not-in-svn patches 10000-10999
+ // Use for custom patches 11000-11999
+
+ // NOT RESERVED IDS 12000-
};
#endif
-
-/* NOT USED VALUES
-// alliance ranks
-#define LANG_ALI_PRIVATE "Private "
-#define LANG_ALI_CORPORAL "Corporal "
-#define LANG_ALI_SERGEANT "Sergeant "
-#define LANG_ALI_MASTER_SERGEANT "Master Sergeant "
-#define LANG_ALI_SERGEANT_MAJOR "Sergeant Major "
-#define LANG_ALI_KNIGHT "Knight "
-#define LANG_ALI_KNIGHT_LIEUTENANT "Knight-Lieutenant "
-#define LANG_ALI_KNIGHT_CAPTAIN "Knight-Captain "
-#define LANG_ALI_KNIGHT_CHAMPION "Knight-Champion "
-#define LANG_ALI_LIEUTENANT_COMMANDER "Lieutenant Commander "
-#define LANG_ALI_COMMANDER "Commander "
-#define LANG_ALI_MARSHAL "Marshal "
-#define LANG_ALI_FIELD_MARSHAL "Field Marshal "
-#define LANG_ALI_GRAND_MARSHAL "Grand Marshal "
-#define LANG_ALI_GAME_MASTER "Game Master "
-
-// horde ranks
-#define LANG_HRD_SCOUT "Scout "
-#define LANG_HRD_GRUNT "Grunt "
-#define LANG_HRD_SERGEANT "Sergeant "
-#define LANG_HRD_SENIOR_SERGEANT "Senior Sergeant "
-#define LANG_HRD_FIRST_SERGEANT "First Sergeant "
-#define LANG_HRD_STONE_GUARD "Stone Guard "
-#define LANG_HRD_BLOOD_GUARD "Blood Guard "
-#define LANG_HRD_LEGIONNARE "Legionnaire "
-#define LANG_HRD_CENTURION "Centurion "
-#define LANG_HRD_CHAMPION "Champion "
-#define LANG_HRD_LIEUTENANT_GENERAL "Lieutenant General "
-#define LANG_HRD_GENERAL "General "
-#define LANG_HRD_WARLORD "Warlord "
-#define LANG_HRD_HIGH_WARLORD "High Warlord "
-#define LANG_HRD_GAME_MASTER "Game Master "
-
-#define LANG_NO_RANK "No rank "
-#define LANG_RANK "%s (Rank %u)"
-#define LANG_HONOR_TODAY "Today: [Honorable kills: |c0000ff00%u|r] [Dishonorable kills: |c00ff0000%u|r]"
-#define LANG_HONOR_YESTERDAY "Yesterday: [Kills: |c0000ff00%u|r] [Honor: %u]"
-#define LANG_HONOR_THIS_WEEK "This week: [Kills: |c0000ff00%u|r] [Honor: %u]"
-#define LANG_HONOR_LAST_WEEK "Last week: [Kills: |c0000ff00%u|r] [Honor: %u] [Standing: %u]"
-#define LANG_HONOR_LIFE "Lifetime: [Honorable kills: |c0000ff00%u|r] [Dishonorable kills: |c00ff0000%u|r] [Highest rank %u: %s]"
-
-// level 2
-#define LANG_ADD_OBJ "AddObject at Chat.cpp" //log
-#define LANG_DEMORPHED "Demorphed %s" //log
-
-// level 3
-#define LANG_SPAWNING_SPIRIT_HEAL "Spawning spirit healers\n"
-#define LANG_NO_SPIRIT_HEAL_DB "No spirit healers in database, exiting."
-
-#define LANG_ADD_OBJ_LV3 "AddObject at Level3.cpp line 1176"
-
-*/
diff --git a/src/game/Level1.cpp b/src/game/Level1.cpp
index c1bca8b8b40..19dec5500bc 100644
--- a/src/game/Level1.cpp
+++ b/src/game/Level1.cpp
@@ -147,9 +147,11 @@ bool ChatHandler::HandleGMmodeCommand(const char* args)
{
if(!*args)
{
- SendSysMessage(LANG_USE_BOL);
- SetSentErrorMessage(true);
- return false;
+ if(m_session->GetPlayer()->isGameMaster())
+ m_session->SendNotification(LANG_GM_ON);
+ else
+ m_session->SendNotification(LANG_GM_OFF);
+ return true;
}
std::string argstr = (char*)args;
@@ -157,7 +159,7 @@ bool ChatHandler::HandleGMmodeCommand(const char* args)
if (argstr == "on")
{
m_session->GetPlayer()->SetGameMaster(true);
- m_session->SendNotification("GM mode is ON");
+ m_session->SendNotification(LANG_GM_ON);
#ifdef _DEBUG_VMAPS
VMAP::IVMapManager *vMapManager = VMAP::VMapFactory::createOrGetVMapManager();
vMapManager->processCommand("stoplog");
@@ -168,7 +170,7 @@ bool ChatHandler::HandleGMmodeCommand(const char* args)
if (argstr == "off")
{
m_session->GetPlayer()->SetGameMaster(false);
- m_session->SendNotification("GM mode is OFF");
+ m_session->SendNotification(LANG_GM_OFF);
#ifdef _DEBUG_VMAPS
VMAP::IVMapManager *vMapManager = VMAP::VMapFactory::createOrGetVMapManager();
vMapManager->processCommand("startlog");
@@ -181,6 +183,40 @@ bool ChatHandler::HandleGMmodeCommand(const char* args)
return false;
}
+// Enables or disables hiding of the staff badge
+bool ChatHandler::HandleGMChatCommand(const char* args)
+{
+ if(!*args)
+ {
+ if(m_session->GetPlayer()->isGMChat())
+ m_session->SendNotification(LANG_GM_CHAT_ON);
+ else
+ m_session->SendNotification(LANG_GM_CHAT_OFF);
+ return true;
+ }
+
+ std::string argstr = (char*)args;
+
+ if (argstr == "on")
+ {
+ m_session->GetPlayer()->SetGMChat(true);
+ m_session->SendNotification(LANG_GM_CHAT_ON);
+ return true;
+ }
+
+ if (argstr == "off")
+ {
+ m_session->GetPlayer()->SetGMChat(false);
+ m_session->SendNotification(LANG_GM_CHAT_OFF);
+ return true;
+ }
+
+ SendSysMessage(LANG_USE_BOL);
+ SetSentErrorMessage(true);
+ return false;
+}
+
+
//Enable\Dissable Invisible mode
bool ChatHandler::HandleVisibleCommand(const char* args)
{
@@ -195,13 +231,13 @@ bool ChatHandler::HandleVisibleCommand(const char* args)
if (argstr == "on")
{
m_session->GetPlayer()->SetGMVisible(true);
- m_session->SendNotification(GetMangosString(LANG_INVISIBLE_VISIBLE));
+ m_session->SendNotification(LANG_INVISIBLE_VISIBLE);
return true;
}
if (argstr == "off")
{
- m_session->SendNotification(GetMangosString(LANG_INVISIBLE_INVISIBLE));
+ m_session->SendNotification(LANG_INVISIBLE_INVISIBLE);
m_session->GetPlayer()->SetGMVisible(false);
return true;
}
@@ -1823,19 +1859,107 @@ bool ChatHandler::HandleSendMailCommand(const char* args)
if(!*args)
return false;
+ // format: name "subject text" "mail text" item1[:count1] item2[:count2] ... item12[:count12]
+
char* pName = strtok((char*)args, " ");
- char* msgSubject = strtok(NULL, " ");
- char* msgText = strtok(NULL, "");
+ if(!pName)
+ return false;
+
+ char* tail1 = strtok(NULL, "");
+ if(!tail1)
+ return false;
+
+ char* msgSubject;
+ if(*tail1=='"')
+ msgSubject = strtok(tail1+1, "\"");
+ else
+ {
+ char* space = strtok(tail1, "\"");
+ if(!space)
+ return false;
+ msgSubject = strtok(NULL, "\"");
+ }
+
+ if (!msgSubject)
+ return false;
+
+ char* tail2 = strtok(NULL, "");
+ if(!tail2)
+ return false;
+
+ char* msgText;
+ if(*tail2=='"')
+ msgText = strtok(tail2+1, "\"");
+ else
+ {
+ char* space = strtok(tail2, "\"");
+ if(!space)
+ return false;
+ msgText = strtok(NULL, "\"");
+ }
if (!msgText)
return false;
// pName, msgSubject, msgText isn't NUL after prev. check
-
std::string name = pName;
std::string subject = msgSubject;
std::string text = msgText;
+ // extract items
+ typedef std::pair ItemPair;
+ typedef std::list< ItemPair > ItemPairs;
+ ItemPairs items;
+
+ // get all tail string
+ char* tail = strtok(NULL, "");
+
+ // get from tail next item str
+ while(char* itemStr = strtok(tail, " "))
+ {
+ // and get new tail
+ tail = strtok(NULL, "");
+
+ // parse item str
+ char* itemIdStr = strtok(itemStr, ":");
+ char* itemCountStr = strtok(NULL, " ");
+
+ uint32 item_id = atoi(itemIdStr);
+ if(!item_id)
+ return false;
+
+ ItemPrototype const* item_proto = objmgr.GetItemPrototype(item_id);
+ if(!item_proto)
+ {
+ PSendSysMessage(LANG_COMMAND_ITEMIDINVALID, item_id);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ uint32 item_count = itemCountStr ? atoi(itemCountStr) : 1;
+ if(item_count < 1 || item_proto->MaxCount && item_count > item_proto->MaxCount)
+ {
+ PSendSysMessage(LANG_COMMAND_INVALID_ITEM_COUNT, item_count,item_id);
+ SetSentErrorMessage(true);
+ return false;
+ }
+
+ while(item_count > item_proto->Stackable)
+ {
+ items.push_back(ItemPair(item_id,item_proto->Stackable));
+ item_count -= item_proto->Stackable;
+ }
+
+ items.push_back(ItemPair(item_id,item_count));
+
+ if(items.size() > MAX_MAIL_ITEMS)
+ {
+ PSendSysMessage(LANG_COMMAND_MAIL_ITEMS_LIMIT, MAX_MAIL_ITEMS);
+ SetSentErrorMessage(true);
+ return false;
+ }
+ }
+
if(!normalizePlayerName(name))
{
SendSysMessage(LANG_PLAYER_NOT_FOUND);
@@ -1844,9 +1968,12 @@ bool ChatHandler::HandleSendMailCommand(const char* args)
}
uint64 receiver_guid = objmgr.GetPlayerGUIDByName(name);
-
if(!receiver_guid)
+ {
+ SendSysMessage(LANG_PLAYER_NOT_FOUND);
+ SetSentErrorMessage(true);
return false;
+ }
uint32 mailId = objmgr.GenerateMailID();
uint32 sender_guidlo = m_session->GetPlayer()->GetGUIDLow();
@@ -1860,7 +1987,19 @@ bool ChatHandler::HandleSendMailCommand(const char* args)
Player *receiver = objmgr.GetPlayer(receiver_guid);
- WorldSession::SendMailTo(receiver,messagetype, stationery, sender_guidlo, GUID_LOPART(receiver_guid), subject, itemTextId, NULL, 0, 0, MAIL_CHECK_MASK_NONE);
+ // fill mail
+ MailItemsInfo mi; // item list preparing
+
+ for(ItemPairs::const_iterator itr = items.begin(); itr != items.end(); ++itr)
+ {
+ if(Item* item = Item::CreateItem(itr->first,itr->second,m_session->GetPlayer()))
+ {
+ item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
+ mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item);
+ }
+ }
+
+ WorldSession::SendMailTo(receiver,messagetype, stationery, sender_guidlo, GUID_LOPART(receiver_guid), subject, itemTextId, &mi, 0, 0, MAIL_CHECK_MASK_NONE);
PSendSysMessage(LANG_MAIL_SENT, name.c_str());
return true;
diff --git a/src/game/MiscHandler.cpp b/src/game/MiscHandler.cpp
index 20d556fb9aa..cb9a7cd673f 100644
--- a/src/game/MiscHandler.cpp
+++ b/src/game/MiscHandler.cpp
@@ -1,1765 +1,1759 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS
- *
- * 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 "Database/DatabaseEnv.h"
-#include "WorldPacket.h"
-#include "Opcodes.h"
-#include "Log.h"
-#include "Player.h"
-#include "World.h"
-#include "ObjectMgr.h"
-#include "WorldSession.h"
-#include "Auth/BigNumber.h"
-#include "Auth/Sha1.h"
-#include "UpdateData.h"
-#include "LootMgr.h"
-#include "Chat.h"
-#include "ScriptCalls.h"
-#include
-#include "MapManager.h"
-#include "ObjectAccessor.h"
-#include "Object.h"
-#include "BattleGround.h"
-#include "SpellAuras.h"
-#include "Pet.h"
-#include "SocialMgr.h"
-
-void WorldSession::HandleRepopRequestOpcode( WorldPacket & /*recv_data*/ )
-{
- sLog.outDebug( "WORLD: Recvd CMSG_REPOP_REQUEST Message" );
-
- if(GetPlayer()->isAlive()||GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
- return;
-
- // the world update order is sessions, players, creatures
- // the netcode runs in parallel with all of these
- // creatures can kill players
- // so if the server is lagging enough the player can
- // release spirit after he's killed but before he is updated
- if(GetPlayer()->getDeathState() == JUST_DIED)
- {
- sLog.outDebug("HandleRepopRequestOpcode: got request after player %s(%d) was killed and before he was updated", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow());
- GetPlayer()->KillPlayer();
- }
-
- //this is spirit release confirm?
- GetPlayer()->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT, true);
- GetPlayer()->BuildPlayerRepop();
- GetPlayer()->RepopAtGraveyard();
-}
-
-void WorldSession::HandleWhoOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data,4+4+1+1+4+4+4+4);
-
- sLog.outDebug( "WORLD: Recvd CMSG_WHO Message" );
- //recv_data.hexlike();
-
- uint32 clientcount = 0;
-
- uint32 level_min, level_max, racemask, classmask, zones_count, str_count;
- uint32 zoneids[10]; // 10 is client limit
- std::string player_name, guild_name;
-
- recv_data >> level_min; // maximal player level, default 0
- recv_data >> level_max; // minimal player level, default 100
- recv_data >> player_name; // player name, case sensitive...
-
- // recheck
- CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+1+4+4+4+4);
-
- recv_data >> guild_name; // guild name, case sensitive...
-
- // recheck
- CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+(guild_name.size()+1)+4+4+4+4);
-
- recv_data >> racemask; // race mask
- recv_data >> classmask; // class mask
- recv_data >> zones_count; // zones count, client limit=10 (2.0.10)
-
- if(zones_count > 10)
- return; // can't be received from real client or broken packet
-
- // recheck
- CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+(guild_name.size()+1)+4+4+4+(4*zones_count)+4);
-
- for(uint32 i = 0; i < zones_count; i++)
- {
- uint32 temp;
- recv_data >> temp; // zone id, 0 if zone is unknown...
- zoneids[i] = temp;
- sLog.outDebug("Zone %u: %u", i, zoneids[i]);
- }
-
- recv_data >> str_count; // user entered strings count, client limit=4 (checked on 2.0.10)
-
- if(str_count > 4)
- return; // can't be received from real client or broken packet
-
- // recheck
- CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+(guild_name.size()+1)+4+4+4+(4*zones_count)+4+(1*str_count));
-
- sLog.outDebug("Minlvl %u, maxlvl %u, name %s, guild %s, racemask %u, classmask %u, zones %u, strings %u", level_min, level_max, player_name.c_str(), guild_name.c_str(), racemask, classmask, zones_count, str_count);
-
- std::wstring str[4]; // 4 is client limit
- for(uint32 i = 0; i < str_count; i++)
- {
- // recheck (have one more byte)
- CHECK_PACKET_SIZE(recv_data,recv_data.rpos());
-
- std::string temp;
- recv_data >> temp; // user entered string, it used as universal search pattern(guild+player name)?
-
- if(!Utf8toWStr(temp,str[i]))
- continue;
-
- wstrToLower(str[i]);
-
- sLog.outDebug("String %u: %s", i, str[i].c_str());
- }
-
- std::wstring wplayer_name;
- std::wstring wguild_name;
- if(!(Utf8toWStr(player_name, wplayer_name) && Utf8toWStr(guild_name, wguild_name)))
- return;
- wstrToLower(wplayer_name);
- wstrToLower(wguild_name);
-
- // client send in case not set max level value 100 but mangos support 255 max level,
- // update it to show GMs with characters after 100 level
- if(level_max >= 100)
- level_max = 255;
-
- uint32 team = _player->GetTeam();
- uint32 security = GetSecurity();
- bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
- bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST);
-
- WorldPacket data( SMSG_WHO, 50 ); // guess size
- data << clientcount; // clientcount place holder
- data << clientcount; // clientcount place holder
-
- //TODO: Guard Player map
- HashMapHolder::MapType& m = ObjectAccessor::Instance().GetPlayers();
- for(HashMapHolder::MapType::iterator itr = m.begin(); itr != m.end(); ++itr)
- {
- if (security == SEC_PLAYER)
- {
- // player can see member of other team only if CONFIG_ALLOW_TWO_SIDE_WHO_LIST
- if (itr->second->GetTeam() != team && !allowTwoSideWhoList )
- continue;
-
- // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST
- if ((itr->second->GetSession()->GetSecurity() > SEC_PLAYER && !gmInWhoList))
- continue;
- }
-
- // check if target is globally visible for player
- if (!(itr->second->IsVisibleGloballyFor(_player)))
- continue;
-
- // check if target's level is in level range
- uint32 lvl = itr->second->getLevel();
- if (lvl < level_min || lvl > level_max)
- continue;
-
- // check if class matches classmask
- uint32 class_ = itr->second->getClass();
- if (!(classmask & (1 << class_)))
- continue;
-
- // check if race matches racemask
- uint32 race = itr->second->getRace();
- if (!(racemask & (1 << race)))
- continue;
-
- uint32 pzoneid = itr->second->GetZoneId();
-
- bool z_show = true;
- for(uint32 i = 0; i < zones_count; i++)
- {
- if(zoneids[i] == pzoneid)
- {
- z_show = true;
- break;
- }
-
- z_show = false;
- }
- if (!z_show)
- continue;
-
- std::string pname = itr->second->GetName();
- std::wstring wpname;
- if(!Utf8toWStr(pname,wpname))
- continue;
- wstrToLower(wpname);
-
- if (!(wplayer_name.empty() || wpname.find(wplayer_name) != std::wstring::npos))
- continue;
-
- std::string gname = objmgr.GetGuildNameById(itr->second->GetGuildId());
- std::wstring wgname;
- if(!Utf8toWStr(gname,wgname))
- continue;
- wstrToLower(wgname);
-
- if (!(wguild_name.empty() || wgname.find(wguild_name) != std::wstring::npos))
- continue;
-
- std::string aname;
- if(AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(itr->second->GetZoneId()))
- aname = areaEntry->area_name[GetSessionDbcLocale()];
-
- bool s_show = true;
- for(uint32 i = 0; i < str_count; i++)
- {
- if (!str[i].empty())
- {
- if (wgname.find(str[i]) != std::wstring::npos ||
- wpname.find(str[i]) != std::wstring::npos ||
- Utf8FitTo(aname, str[i]) )
- {
- s_show = true;
- break;
- }
- s_show = false;
- }
- }
- if (!s_show)
- continue;
-
- data << pname; // player name
- data << gname; // guild name
- data << uint32( lvl ); // player level
- data << uint32( class_ ); // player class
- data << uint32( race ); // player race
- data << uint8(0); // new 2.4.0
- data << uint32( pzoneid ); // player zone id
-
- // 49 is maximum player count sent to client
- if ((++clientcount) == 49)
- break;
- }
-
- data.put( 0, clientcount ); //insert right count
- data.put( sizeof(uint32), clientcount ); //insert right count
-
- SendPacket(&data);
- sLog.outDebug( "WORLD: Send SMSG_WHO Message" );
-}
-
-void WorldSession::HandleLogoutRequestOpcode( WorldPacket & /*recv_data*/ )
-{
- sLog.outDebug( "WORLD: Recvd CMSG_LOGOUT_REQUEST Message, security - %u", GetSecurity() );
-
- 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
- //...is jumping ...is falling
- GetPlayer()->HasUnitMovementFlag(MOVEMENTFLAG_JUMPING | MOVEMENTFLAG_FALLING))
- {
- WorldPacket data( SMSG_LOGOUT_RESPONSE, (2+4) ) ;
- data << (uint8)0xC;
- data << uint32(0);
- data << uint8(0);
- SendPacket( &data );
- LogoutRequest(0);
- return;
- }
-
- //instant logout in taverns/cities or on taxi
- if(GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) || GetPlayer()->isInFlight())
- {
- LogoutPlayer(true);
- return;
- }
-
- // not set flags if player can't free move to prevent lost state at logout cancel
- if(GetPlayer()->CanFreeMove())
- {
- GetPlayer()->SetStandState(PLAYER_STATE_SIT);
-
- WorldPacket data( SMSG_FORCE_MOVE_ROOT, (8+4) ); // guess size
- data.append(GetPlayer()->GetPackGUID());
- data << (uint32)2;
- SendPacket( &data );
- GetPlayer()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
- }
-
- WorldPacket data( SMSG_LOGOUT_RESPONSE, 5 );
- data << uint32(0);
- data << uint8(0);
- SendPacket( &data );
- LogoutRequest(time(NULL));
-}
-
-void WorldSession::HandlePlayerLogoutOpcode( WorldPacket & /*recv_data*/ )
-{
- sLog.outDebug( "WORLD: Recvd CMSG_PLAYER_LOGOUT Message" );
-}
-
-void WorldSession::HandleLogoutCancelOpcode( WorldPacket & /*recv_data*/ )
-{
- sLog.outDebug( "WORLD: Recvd CMSG_LOGOUT_CANCEL Message" );
-
- LogoutRequest(0);
-
- WorldPacket data( SMSG_LOGOUT_CANCEL_ACK, 0 );
- SendPacket( &data );
-
- // not remove flags if can't free move - its not set in Logout request code.
- if(GetPlayer()->CanFreeMove())
- {
- //!we can move again
- data.Initialize( SMSG_FORCE_MOVE_UNROOT, 8 ); // guess size
- data.append(GetPlayer()->GetPackGUID());
- data << uint32(0);
- SendPacket( &data );
-
- //! Stand Up
- GetPlayer()->SetStandState(PLAYER_STATE_NONE);
-
- //! DISABLE_ROTATE
- GetPlayer()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
- }
-
- sLog.outDebug( "WORLD: sent SMSG_LOGOUT_CANCEL_ACK Message" );
-}
-
-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 );
-
- uint64 guid;
- Field *fields;
- guid = GetPlayer()->GetGUID();
-
- QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(ticket_id) FROM character_ticket WHERE guid = '%u'", GUID_LOPART(guid));
-
- if (result)
- {
- int cnt;
- fields = result->Fetch();
- cnt = fields[0].GetUInt32();
- delete result;
-
- if ( cnt > 0 )
- {
- QueryResult *result2 = CharacterDatabase.PQuery("SELECT ticket_text FROM character_ticket WHERE guid = '%u'", GUID_LOPART(guid));
- if(result2)
- {
- Field *fields2 = result2->Fetch();
- SendGMTicketGetTicket(0x06,fields2[0].GetString());
- delete result2;
- }
- }
- else
- SendGMTicketGetTicket(0x0A,0);
- }
-}
-
-void WorldSession::HandleGMTicketUpdateTextOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data,1);
-
- std::string ticketText;
- recv_data >> ticketText;
-
- CharacterDatabase.escape_string(ticketText);
- CharacterDatabase.PExecute("UPDATE character_ticket SET ticket_text = '%s' WHERE guid = '%u'", ticketText.c_str(), _player->GetGUIDLow());
-}
-
-void WorldSession::HandleGMTicketDeleteOpcode( WorldPacket & /*recv_data*/ )
-{
- uint32 guid = GetPlayer()->GetGUIDLow();
-
- CharacterDatabase.PExecute("DELETE FROM character_ticket WHERE guid = '%u' LIMIT 1",guid);
-
- 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);
-
- CharacterDatabase.escape_string(ticketText);
-
- QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(*) FROM character_ticket WHERE guid = '%u'", _player->GetGUIDLow());
-
- if (result)
- {
- int cnt;
- Field *fields = result->Fetch();
- cnt = fields[0].GetUInt32();
- delete result;
-
- if ( cnt > 0 )
- {
- WorldPacket data( SMSG_GMTICKET_CREATE, 4 );
- data << uint32(1);
- SendPacket( &data );
- }
- else
- {
- CharacterDatabase.PExecute("INSERT INTO character_ticket (guid,ticket_text) VALUES ('%u', '%s')", _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::MapType &m = ObjectAccessor::Instance().GetPlayers();
- for(HashMapHolder::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
-}
-
-void WorldSession::HandleTogglePvP( WorldPacket & recv_data )
-{
- // this opcode can be used in two ways: Either set explicit new status or toggle old status
- if(recv_data.size() == 1)
- {
- bool newPvPStatus;
- recv_data >> newPvPStatus;
- GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP, newPvPStatus);
- }
- else
- {
- GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP);
- }
-
- if(GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP))
- {
- if(!GetPlayer()->IsPvP() || GetPlayer()->pvpInfo.endTimer != 0)
- GetPlayer()->UpdatePvP(true, true);
- }
- else
- {
- if(!GetPlayer()->pvpInfo.inHostileArea && GetPlayer()->IsPvP())
- GetPlayer()->pvpInfo.endTimer = time(NULL); // start toggle-off
- }
-}
-
-void WorldSession::HandleZoneUpdateOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data,4);
-
- uint32 newZone;
- recv_data >> newZone;
-
- sLog.outDetail("WORLD: Recvd ZONE_UPDATE: %u", newZone);
-
- if(newZone != _player->GetZoneId())
- GetPlayer()->SendInitWorldStates(); // only if really enters to new zone, not just area change, works strange...
-
- GetPlayer()->UpdateZone(newZone);
-}
-
-void WorldSession::HandleSetTargetOpcode( WorldPacket & recv_data )
-{
- // When this packet send?
- CHECK_PACKET_SIZE(recv_data,8);
-
- uint64 guid ;
- recv_data >> guid;
-
- _player->SetUInt32Value(UNIT_FIELD_TARGET,guid);
-
- // update reputation list if need
- Unit* unit = ObjectAccessor::GetUnit(*_player, guid );
- if(!unit)
- return;
-
- _player->SetFactionVisibleForFactionTemplateId(unit->getFaction());
-}
-
-void WorldSession::HandleSetSelectionOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data,8);
-
- uint64 guid;
- recv_data >> guid;
-
- _player->SetSelection(guid);
-
- // update reputation list if need
- Unit* unit = ObjectAccessor::GetUnit(*_player, guid );
- if(!unit)
- return;
-
- _player->SetFactionVisibleForFactionTemplateId(unit->getFaction());
-}
-
-void WorldSession::HandleStandStateChangeOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data,1);
-
- sLog.outDebug( "WORLD: Received CMSG_STAND_STATE_CHANGE" );
- uint8 animstate;
- recv_data >> animstate;
-
- _player->SetStandState(animstate);
-}
-
-void WorldSession::HandleFriendListOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 4);
- sLog.outDebug( "WORLD: Received CMSG_CONTACT_LIST" );
- uint32 unk;
- recv_data >> unk;
- sLog.outDebug("unk value is %u", unk);
- _player->GetSocial()->SendSocialList();
-}
-
-void WorldSession::HandleAddFriendOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 1+1);
-
- sLog.outDebug( "WORLD: Received CMSG_ADD_FRIEND" );
-
- std::string friendName = GetMangosString(LANG_FRIEND_IGNORE_UNKNOWN);
- std::string friendNote;
- FriendsResult friendResult = FRIEND_NOT_FOUND;
- Player *pFriend = NULL;
- uint64 friendGuid = 0;
-
- recv_data >> friendName;
-
- // recheck
- CHECK_PACKET_SIZE(recv_data, (friendName.size()+1)+1);
-
- recv_data >> friendNote;
-
- if(!normalizePlayerName(friendName))
- return;
-
- CharacterDatabase.escape_string(friendName); // prevent SQL injection - normal name don't must changed by this call
-
- sLog.outDebug( "WORLD: %s asked to add friend : '%s'",
- GetPlayer()->GetName(), friendName.c_str() );
-
- friendGuid = objmgr.GetPlayerGUIDByName(friendName);
-
- if(friendGuid)
- {
- pFriend = ObjectAccessor::FindPlayer(friendGuid);
- if(pFriend==GetPlayer())
- friendResult = FRIEND_SELF;
- else if(GetPlayer()->GetTeam()!=objmgr.GetPlayerTeamByGUID(friendGuid) && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && GetSecurity() < SEC_MODERATOR)
- friendResult = FRIEND_ENEMY;
- else if(GetPlayer()->GetSocial()->HasFriend(GUID_LOPART(friendGuid)))
- friendResult = FRIEND_ALREADY;
- }
-
- if (friendGuid && friendResult==FRIEND_NOT_FOUND)
- {
- if( pFriend && pFriend->IsInWorld() && pFriend->IsVisibleGloballyFor(GetPlayer()))
- friendResult = FRIEND_ADDED_ONLINE;
- else
- friendResult = FRIEND_ADDED_OFFLINE;
-
- if(!_player->GetSocial()->AddToSocialList(GUID_LOPART(friendGuid), false))
- {
- friendResult = FRIEND_LIST_FULL;
- sLog.outDebug( "WORLD: %s's friend list is full.", GetPlayer()->GetName());
- }
-
- _player->GetSocial()->SetFriendNote(GUID_LOPART(friendGuid), friendNote);
-
- sLog.outDebug( "WORLD: %s Guid found '%u'.", friendName.c_str(), GUID_LOPART(friendGuid));
- }
- else if(friendResult==FRIEND_ALREADY)
- {
- sLog.outDebug( "WORLD: %s Guid Already a Friend.", friendName.c_str() );
- }
- else if(friendResult==FRIEND_SELF)
- {
- sLog.outDebug( "WORLD: %s Guid can't add himself.", friendName.c_str() );
- }
- else
- {
- sLog.outDebug( "WORLD: %s Guid not found.", friendName.c_str() );
- }
-
- sSocialMgr.SendFriendStatus(GetPlayer(), friendResult, GUID_LOPART(friendGuid), friendName, false);
-
- sLog.outDebug( "WORLD: Sent (SMSG_FRIEND_STATUS)" );
-}
-
-void WorldSession::HandleDelFriendOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 8);
-
- uint64 FriendGUID;
-
- sLog.outDebug( "WORLD: Received CMSG_DEL_FRIEND" );
-
- recv_data >> FriendGUID;
-
- _player->GetSocial()->RemoveFromSocialList(GUID_LOPART(FriendGUID), false);
-
- sSocialMgr.SendFriendStatus(GetPlayer(), FRIEND_REMOVED, GUID_LOPART(FriendGUID), "", false);
-
- sLog.outDebug( "WORLD: Sent motd (SMSG_FRIEND_STATUS)" );
-}
-
-void WorldSession::HandleAddIgnoreOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data,1);
-
- sLog.outDebug( "WORLD: Received CMSG_ADD_IGNORE" );
-
- std::string IgnoreName = GetMangosString(LANG_FRIEND_IGNORE_UNKNOWN);
- FriendsResult ignoreResult = FRIEND_IGNORE_NOT_FOUND;
- uint64 IgnoreGuid = 0;
-
- recv_data >> IgnoreName;
-
- if(!normalizePlayerName(IgnoreName))
- return;
-
- CharacterDatabase.escape_string(IgnoreName); // prevent SQL injection - normal name don't must changed by this call
-
- sLog.outDebug( "WORLD: %s asked to Ignore: '%s'",
- GetPlayer()->GetName(), IgnoreName.c_str() );
-
- IgnoreGuid = objmgr.GetPlayerGUIDByName(IgnoreName);
-
- if(IgnoreGuid)
- {
- if(IgnoreGuid==GetPlayer()->GetGUID())
- ignoreResult = FRIEND_IGNORE_SELF;
- else
- {
- if( GetPlayer()->GetSocial()->HasIgnore(GUID_LOPART(IgnoreGuid)) )
- ignoreResult = FRIEND_IGNORE_ALREADY;
- }
- }
-
- if (IgnoreGuid && ignoreResult == FRIEND_IGNORE_NOT_FOUND)
- {
- ignoreResult = FRIEND_IGNORE_ADDED;
-
- _player->GetSocial()->AddToSocialList(GUID_LOPART(IgnoreGuid), true);
- }
- else if(ignoreResult==FRIEND_IGNORE_ALREADY)
- {
- sLog.outDebug( "WORLD: %s Guid Already Ignored.", IgnoreName.c_str() );
- }
- else if(ignoreResult==FRIEND_IGNORE_SELF)
- {
- sLog.outDebug( "WORLD: %s Guid can't add himself.", IgnoreName.c_str() );
- }
- else
- {
- sLog.outDebug( "WORLD: %s Guid not found.", IgnoreName.c_str() );
- }
-
- sSocialMgr.SendFriendStatus(GetPlayer(), ignoreResult, GUID_LOPART(IgnoreGuid), "", false);
-
- sLog.outDebug( "WORLD: Sent (SMSG_FRIEND_STATUS)" );
-}
-
-void WorldSession::HandleDelIgnoreOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 8);
-
- uint64 IgnoreGUID;
-
- sLog.outDebug( "WORLD: Received CMSG_DEL_IGNORE" );
-
- recv_data >> IgnoreGUID;
-
- _player->GetSocial()->RemoveFromSocialList(GUID_LOPART(IgnoreGUID), true);
-
- sSocialMgr.SendFriendStatus(GetPlayer(), FRIEND_IGNORE_REMOVED, GUID_LOPART(IgnoreGUID), "", false);
-
- sLog.outDebug( "WORLD: Sent motd (SMSG_FRIEND_STATUS)" );
-}
-
-void WorldSession::HandleSetFriendNoteOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 8+1);
- uint64 guid;
- std::string note;
- recv_data >> guid >> note;
- _player->GetSocial()->SetFriendNote(guid, note);
-}
-
-void WorldSession::HandleBugOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data,4+4+1+4+1);
-
- uint32 suggestion, contentlen;
- std::string content;
- uint32 typelen;
- std::string type;
-
- recv_data >> suggestion >> contentlen >> content;
-
- //recheck
- CHECK_PACKET_SIZE(recv_data,4+4+(content.size()+1)+4+1);
-
- recv_data >> typelen >> type;
-
- if( suggestion == 0 )
- sLog.outDebug( "WORLD: Received CMSG_BUG [Bug Report]" );
- else
- sLog.outDebug( "WORLD: Received CMSG_BUG [Suggestion]" );
-
- sLog.outDebug( type.c_str( ) );
- sLog.outDebug( content.c_str( ) );
-
- CharacterDatabase.escape_string(type);
- CharacterDatabase.escape_string(content);
- CharacterDatabase.PExecute ("INSERT INTO bugreport (type,content) VALUES('%s', '%s')", type.c_str( ), content.c_str( ));
-}
-
-void WorldSession::HandleCorpseReclaimOpcode(WorldPacket &recv_data)
-{
- CHECK_PACKET_SIZE(recv_data,8);
-
- sLog.outDetail("WORLD: Received CMSG_RECLAIM_CORPSE");
- if (GetPlayer()->isAlive())
- return;
-
- if (BattleGround * bg = _player->GetBattleGround())
- if(bg->isArena())
- return;
-
- // body not released yet
- if(!GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
- return;
-
- Corpse *corpse = GetPlayer()->GetCorpse();
-
- if (!corpse )
- return;
-
- // prevent resurrect before 30-sec delay after body release not finished
- if(corpse->GetGhostTime() + GetPlayer()->GetCorpseReclaimDelay(corpse->GetType()==CORPSE_RESURRECTABLE_PVP) > time(NULL))
- return;
-
- float dist = corpse->GetDistance2d(GetPlayer());
- sLog.outDebug("Corpse 2D Distance: \t%f",dist);
- if (dist > CORPSE_RECLAIM_RADIUS)
- return;
-
- uint64 guid;
- recv_data >> guid;
-
- // resurrect
- GetPlayer()->ResurrectPlayer(GetPlayer()->InBattleGround() ? 1.0f : 0.5f);
-
- // spawn bones
- GetPlayer()->SpawnCorpseBones();
-
- GetPlayer()->SaveToDB();
-}
-
-void WorldSession::HandleResurrectResponseOpcode(WorldPacket & recv_data)
-{
- CHECK_PACKET_SIZE(recv_data,8+1);
-
- sLog.outDetail("WORLD: Received CMSG_RESURRECT_RESPONSE");
-
- if(GetPlayer()->isAlive())
- return;
-
- uint64 guid;
- uint8 status;
- recv_data >> guid;
- recv_data >> status;
-
- if(status == 0)
- {
- GetPlayer()->clearResurrectRequestData(); // reject
- return;
- }
-
- if(!GetPlayer()->isRessurectRequestedBy(guid))
- return;
-
- GetPlayer()->ResurectUsingRequestData();
- GetPlayer()->SaveToDB();
-}
-
-void WorldSession::HandleAreaTriggerOpcode(WorldPacket & recv_data)
-{
- CHECK_PACKET_SIZE(recv_data,4);
-
- sLog.outDebug("WORLD: Received CMSG_AREATRIGGER");
-
- uint32 Trigger_ID;
-
- recv_data >> Trigger_ID;
- sLog.outDebug("Trigger ID:%u",Trigger_ID);
-
- if(GetPlayer()->isInFlight())
- {
- sLog.outDebug("Player '%s' (GUID: %u) in flight, ignore Area Trigger ID:%u",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow(), Trigger_ID);
- return;
- }
-
- AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
- if(!atEntry)
- {
- sLog.outDebug("Player '%s' (GUID: %u) send unknown (by DBC) Area Trigger ID:%u",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow(), Trigger_ID);
- return;
- }
-
- if (GetPlayer()->GetMapId()!=atEntry->mapid)
- {
- sLog.outDebug("Player '%s' (GUID: %u) too far (trigger map: %u player map: %u), ignore Area Trigger ID: %u", GetPlayer()->GetName(), atEntry->mapid, GetPlayer()->GetMapId(), GetPlayer()->GetGUIDLow(), Trigger_ID);
- return;
- }
-
- // delta is safe radius
- const float delta = 5.0f;
- // check if player in the range of areatrigger
- Player* pl = GetPlayer();
-
- if (atEntry->radius > 0)
- {
- // if we have radius check it
- float dist = pl->GetDistance(atEntry->x,atEntry->y,atEntry->z);
- if(dist > atEntry->radius + delta)
- {
- sLog.outDebug("Player '%s' (GUID: %u) too far (radius: %f distance: %f), ignore Area Trigger ID: %u",
- pl->GetName(), pl->GetGUIDLow(), atEntry->radius, dist, Trigger_ID);
- return;
- }
- }
- else
- {
- // we have only extent
- float dx = pl->GetPositionX() - atEntry->x;
- float dy = pl->GetPositionY() - atEntry->y;
- float dz = pl->GetPositionZ() - atEntry->z;
- double es = sin(atEntry->box_orientation);
- double ec = cos(atEntry->box_orientation);
- // calc rotated vector based on extent axis
- double rotateDx = dx*ec - dy*es;
- double rotateDy = dx*es + dy*ec;
-
- if( (fabs(rotateDx) > atEntry->box_x/2 + delta) ||
- (fabs(rotateDy) > atEntry->box_y/2 + delta) ||
- (fabs(dz) > atEntry->box_z/2 + delta) )
- {
- sLog.outDebug("Player '%s' (GUID: %u) too far (1/2 box X: %f 1/2 box Y: %u 1/2 box Z: %u rotate dX: %f rotate dY: %f dZ:%f), ignore Area Trigger ID: %u",
- pl->GetName(), pl->GetGUIDLow(), atEntry->box_x/2, atEntry->box_y/2, atEntry->box_z/2, rotateDx, rotateDy, dz, Trigger_ID);
- return;
- }
- }
-
- if(Script->scriptAreaTrigger(GetPlayer(), atEntry))
- return;
-
- uint32 quest_id = objmgr.GetQuestForAreaTrigger( Trigger_ID );
- if( quest_id && GetPlayer()->isAlive() && GetPlayer()->IsActiveQuest(quest_id) )
- {
- Quest const* pQuest = objmgr.GetQuestTemplate(quest_id);
- if( pQuest )
- {
- if(GetPlayer()->GetQuestStatus(quest_id) == QUEST_STATUS_INCOMPLETE)
- GetPlayer()->AreaExploredOrEventHappens( quest_id );
- }
- }
-
- if(objmgr.IsTavernAreaTrigger(Trigger_ID))
- {
- // set resting flag we are in the inn
- GetPlayer()->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
- GetPlayer()->InnEnter(time(NULL), atEntry->mapid, atEntry->x, atEntry->y, atEntry->z);
- GetPlayer()->SetRestType(REST_TYPE_IN_TAVERN);
-
- if(sWorld.IsFFAPvPRealm())
- GetPlayer()->RemoveFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP);
-
- return;
- }
-
- if(GetPlayer()->InBattleGround())
- {
- BattleGround* bg = GetPlayer()->GetBattleGround();
- if(bg)
- if(bg->GetStatus() == STATUS_IN_PROGRESS)
- bg->HandleAreaTrigger(GetPlayer(), Trigger_ID);
-
- return;
- }
-
- // NULL if all values default (non teleport trigger)
- AreaTrigger const* at = objmgr.GetAreaTrigger(Trigger_ID);
- if(!at)
- return;
-
- if(!GetPlayer()->isGameMaster())
- {
- uint32 missingLevel = 0;
- if(GetPlayer()->getLevel() < at->requiredLevel && !sWorld.getConfig(CONFIG_INSTANCE_IGNORE_LEVEL))
- missingLevel = at->requiredLevel;
-
- // must have one or the other, report the first one that's missing
- uint32 missingItem = 0;
- if(at->requiredItem)
- {
- if(!GetPlayer()->HasItemCount(at->requiredItem, 1) &&
- (!at->requiredItem2 || !GetPlayer()->HasItemCount(at->requiredItem2, 1)))
- missingItem = at->requiredItem;
- }
- else if(at->requiredItem2 && !GetPlayer()->HasItemCount(at->requiredItem2, 1))
- missingItem = at->requiredItem2;
-
- uint32 missingKey = 0;
- if(GetPlayer()->GetDifficulty() == DIFFICULTY_HEROIC)
- {
- if(at->heroicKey)
- {
- if(!GetPlayer()->HasItemCount(at->heroicKey, 1) &&
- (!at->heroicKey2 || !GetPlayer()->HasItemCount(at->heroicKey2, 1)))
- missingKey = at->heroicKey;
- }
- else if(at->heroicKey2 && !GetPlayer()->HasItemCount(at->heroicKey2, 1))
- missingKey = at->heroicKey2;
- }
-
- uint32 missingQuest = 0;
- if(at->requiredQuest && !GetPlayer()->GetQuestRewardStatus(at->requiredQuest))
- missingQuest = at->requiredQuest;
-
- if(missingLevel || missingItem || missingKey || missingQuest)
- {
- // TODO: all this is probably wrong
- if(missingItem)
- SendAreaTriggerMessage(GetMangosString(LANG_LEVEL_MINREQUIRED_AND_ITEM), at->requiredLevel, objmgr.GetItemPrototype(missingItem)->Name1);
- else if(missingKey)
- GetPlayer()->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_DIFFICULTY2);
- else if(missingQuest)
- SendAreaTriggerMessage(at->requiredFailedText.c_str());
- else if(missingLevel)
- SendAreaTriggerMessage(GetMangosString(LANG_LEVEL_MINREQUIRED), missingLevel);
- return;
- }
- }
-
- GetPlayer()->TeleportTo(at->target_mapId,at->target_X,at->target_Y,at->target_Z,at->target_Orientation,TELE_TO_NOT_LEAVE_TRANSPORT);
-}
-
-void WorldSession::HandleUpdateAccountData(WorldPacket &/*recv_data*/)
-{
- sLog.outDetail("WORLD: Received CMSG_UPDATE_ACCOUNT_DATA");
- //recv_data.hexlike();
-}
-
-void WorldSession::HandleRequestAccountData(WorldPacket& /*recv_data*/)
-{
- sLog.outDetail("WORLD: Received CMSG_REQUEST_ACCOUNT_DATA");
- //recv_data.hexlike();
-}
-
-void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recv_data)
-{
- CHECK_PACKET_SIZE(recv_data,1+2+1+1);
-
- sLog.outDebug( "WORLD: Received CMSG_SET_ACTION_BUTTON" );
- uint8 button, misc, type;
- uint16 action;
- recv_data >> button >> action >> misc >> type;
- sLog.outDetail( "BUTTON: %u ACTION: %u TYPE: %u MISC: %u", button, action, type, misc );
- if(action==0)
- {
- sLog.outDetail( "MISC: Remove action from button %u", button );
-
- GetPlayer()->removeActionButton(button);
- }
- else
- {
- if(type==ACTION_BUTTON_MACRO || type==ACTION_BUTTON_CMACRO)
- {
- sLog.outDetail( "MISC: Added Macro %u into button %u", action, button );
- GetPlayer()->addActionButton(button,action,type,misc);
- }
- else if(type==ACTION_BUTTON_SPELL)
- {
- sLog.outDetail( "MISC: Added Action %u into button %u", action, button );
- GetPlayer()->addActionButton(button,action,type,misc);
- }
- else if(type==ACTION_BUTTON_ITEM)
- {
- sLog.outDetail( "MISC: Added Item %u into button %u", action, button );
- GetPlayer()->addActionButton(button,action,type,misc);
- }
- else
- sLog.outError( "MISC: Unknown action button type %u for action %u into button %u", type, action, button );
- }
-}
-
-void WorldSession::HandleCompleteCinema( WorldPacket & /*recv_data*/ )
-{
- DEBUG_LOG( "WORLD: Player is watching cinema" );
-}
-
-void WorldSession::HandleNextCinematicCamera( WorldPacket & /*recv_data*/ )
-{
- DEBUG_LOG( "WORLD: Which movie to play" );
-}
-
-void WorldSession::HandleMoveTimeSkippedOpcode( WorldPacket & /*recv_data*/ )
-{
- /* WorldSession::Update( getMSTime() );*/
- DEBUG_LOG( "WORLD: Time Lag/Synchronization Resent/Update" );
-
- /*
- CHECK_PACKET_SIZE(recv_data,8+4);
- uint64 guid;
- uint32 time_skipped;
- recv_data >> guid;
- recv_data >> time_skipped;
- sLog.outDebug( "WORLD: CMSG_MOVE_TIME_SKIPPED" );
-
- /// TODO
- must be need use in mangos
- We substract server Lags to move time ( AntiLags )
- for exmaple
- GetPlayer()->ModifyLastMoveTime( -int32(time_skipped) );
- */
-}
-
-void WorldSession::HandleFeatherFallAck(WorldPacket &/*recv_data*/)
-{
- DEBUG_LOG("WORLD: CMSG_MOVE_FEATHER_FALL_ACK");
-}
-
-void WorldSession::HandleMoveUnRootAck(WorldPacket&/* recv_data*/)
-{
- /*
- CHECK_PACKET_SIZE(recv_data,8+8+4+4+4+4+4);
-
- sLog.outDebug( "WORLD: CMSG_FORCE_MOVE_UNROOT_ACK" );
- recv_data.hexlike();
- uint64 guid;
- uint64 unknown1;
- uint32 unknown2;
- float PositionX;
- float PositionY;
- float PositionZ;
- float Orientation;
-
- recv_data >> guid;
- recv_data >> unknown1;
- recv_data >> unknown2;
- recv_data >> PositionX;
- recv_data >> PositionY;
- recv_data >> PositionZ;
- recv_data >> Orientation;
-
- // TODO for later may be we can use for anticheat
- DEBUG_LOG("Guid " I64FMTD,guid);
- DEBUG_LOG("unknown1 " I64FMTD,unknown1);
- DEBUG_LOG("unknown2 %u",unknown2);
- DEBUG_LOG("X %f",PositionX);
- DEBUG_LOG("Y %f",PositionY);
- DEBUG_LOG("Z %f",PositionZ);
- DEBUG_LOG("O %f",Orientation);
- */
-}
-
-void WorldSession::HandleMoveRootAck(WorldPacket&/* recv_data*/)
-{
- /*
- CHECK_PACKET_SIZE(recv_data,8+8+4+4+4+4+4);
-
- sLog.outDebug( "WORLD: CMSG_FORCE_MOVE_ROOT_ACK" );
- recv_data.hexlike();
- uint64 guid;
- uint64 unknown1;
- uint32 unknown2;
- float PositionX;
- float PositionY;
- float PositionZ;
- float Orientation;
-
- recv_data >> guid;
- recv_data >> unknown1;
- recv_data >> unknown2;
- recv_data >> PositionX;
- recv_data >> PositionY;
- recv_data >> PositionZ;
- recv_data >> Orientation;
-
- // for later may be we can use for anticheat
- DEBUG_LOG("Guid " I64FMTD,guid);
- DEBUG_LOG("unknown1 " I64FMTD,unknown1);
- DEBUG_LOG("unknown1 %u",unknown2);
- DEBUG_LOG("X %f",PositionX);
- DEBUG_LOG("Y %f",PositionY);
- DEBUG_LOG("Z %f",PositionZ);
- DEBUG_LOG("O %f",Orientation);
- */
-}
-
-void WorldSession::HandleMoveTeleportAck(WorldPacket&/* recv_data*/)
-{
- /*
- CHECK_PACKET_SIZE(recv_data,8+4);
-
- sLog.outDebug("MSG_MOVE_TELEPORT_ACK");
- uint64 guid;
- uint32 flags, time;
-
- recv_data >> guid;
- recv_data >> flags >> time;
- DEBUG_LOG("Guid " I64FMTD,guid);
- DEBUG_LOG("Flags %u, time %u",flags, time/1000);
- */
-}
-
-void WorldSession::HandleSetActionBar(WorldPacket& recv_data)
-{
- CHECK_PACKET_SIZE(recv_data,1);
-
- uint8 ActionBar;
-
- recv_data >> ActionBar;
-
- if(!GetPlayer()) // ignore until not logged (check needed because STATUS_AUTHED)
- {
- if(ActionBar!=0)
- sLog.outError("WorldSession::HandleSetActionBar in not logged state with value: %u, ignored",uint32(ActionBar));
- return;
- }
-
- GetPlayer()->SetByteValue(PLAYER_FIELD_BYTES, 2, ActionBar);
-}
-
-void WorldSession::HandleWardenDataOpcode(WorldPacket& /*recv_data*/)
-{
- /*
- CHECK_PACKET_SIZE(recv_data,1);
-
- uint8 tmp;
- recv_data >> tmp;
- sLog.outDebug("Received opcode CMSG_WARDEN_DATA, not resolve.uint8 = %u",tmp);
- */
-}
-
-void WorldSession::HandlePlayedTime(WorldPacket& /*recv_data*/)
-{
- uint32 TotalTimePlayed = GetPlayer()->GetTotalPlayedTime();
- uint32 LevelPlayedTime = GetPlayer()->GetLevelPlayedTime();
-
- WorldPacket data(SMSG_PLAYED_TIME, 8);
- data << TotalTimePlayed;
- data << LevelPlayedTime;
- SendPacket(&data);
-}
-
-void WorldSession::HandleInspectOpcode(WorldPacket& recv_data)
-{
- CHECK_PACKET_SIZE(recv_data, 8);
-
- uint64 guid;
- recv_data >> guid;
- DEBUG_LOG("Inspected guid is " I64FMTD, guid);
-
- _player->SetSelection(guid);
-
- Player *plr = objmgr.GetPlayer(guid);
- if(!plr) // wrong player
- return;
-
- uint32 talent_points = 0x3D;
- uint32 guid_size = plr->GetPackGUID().size();
- WorldPacket data(SMSG_INSPECT_TALENT, 4+talent_points);
- data.append(plr->GetPackGUID());
- data << uint32(talent_points);
-
- // fill by 0 talents array
- for(uint32 i = 0; i < talent_points; ++i)
- data << uint8(0);
-
- if(sWorld.getConfig(CONFIG_TALENTS_INSPECTING) || _player->isGameMaster())
- {
- // find class talent tabs (all players have 3 talent tabs)
- uint32 const* talentTabIds = GetTalentTabPages(plr->getClass());
-
- uint32 talentTabPos = 0; // pos of first talent rank in tab including all prev tabs
- for(uint32 i = 0; i < 3; ++i)
- {
- uint32 talentTabId = talentTabIds[i];
-
- // fill by real data
- for(uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
- {
- TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
- if(!talentInfo)
- continue;
-
- // skip another tab talents
- if(talentInfo->TalentTab != talentTabId)
- continue;
-
- // find talent rank
- uint32 curtalent_maxrank = 0;
- for(uint32 k = 5; k > 0; --k)
- {
- if(talentInfo->RankID[k-1] && plr->HasSpell(talentInfo->RankID[k-1]))
- {
- curtalent_maxrank = k;
- break;
- }
- }
-
- // not learned talent
- if(!curtalent_maxrank)
- continue;
-
- // 1 rank talent bit index
- uint32 curtalent_index = talentTabPos + GetTalentInspectBitPosInTab(talentId);
-
- uint32 curtalent_rank_index = curtalent_index+curtalent_maxrank-1;
-
- // slot/offset in 7-bit bytes
- uint32 curtalent_rank_slot7 = curtalent_rank_index / 7;
- uint32 curtalent_rank_offset7 = curtalent_rank_index % 7;
-
- // rank pos with skipped 8 bit
- uint32 curtalent_rank_index2 = curtalent_rank_slot7 * 8 + curtalent_rank_offset7;
-
- // slot/offset in 8-bit bytes with skipped high bit
- uint32 curtalent_rank_slot = curtalent_rank_index2 / 8;
- uint32 curtalent_rank_offset = curtalent_rank_index2 % 8;
-
- // apply mask
- uint32 val = data.read(guid_size + 4 + curtalent_rank_slot);
- val |= (1 << curtalent_rank_offset);
- data.put(guid_size + 4 + curtalent_rank_slot, val & 0xFF);
- }
-
- talentTabPos += GetTalentTabInspectBitSize(talentTabId);
- }
- }
-
- SendPacket(&data);
-}
-
-void WorldSession::HandleInspectHonorStatsOpcode(WorldPacket& recv_data)
-{
- CHECK_PACKET_SIZE(recv_data, 8);
-
- uint64 guid;
- recv_data >> guid;
-
- Player *player = objmgr.GetPlayer(guid);
-
- if(!player)
- {
- sLog.outError("InspectHonorStats: WTF, player not found...");
- return;
- }
-
- WorldPacket data(MSG_INSPECT_HONOR_STATS, 8+1+4*4);
- data << uint64(player->GetGUID());
- data << uint8(player->GetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY));
- data << uint32(player->GetUInt32Value(PLAYER_FIELD_KILLS));
- data << uint32(player->GetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION));
- data << uint32(player->GetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION));
- data << uint32(player->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORBALE_KILLS));
- SendPacket(&data);
-}
-
-void WorldSession::HandleWorldTeleportOpcode(WorldPacket& recv_data)
-{
- CHECK_PACKET_SIZE(recv_data,4+4+4+4+4+4);
-
- // write in client console: worldport 469 452 6454 2536 180 or /console worldport 469 452 6454 2536 180
- // Received opcode CMSG_WORLD_TELEPORT
- // Time is ***, map=469, x=452.000000, y=6454.000000, z=2536.000000, orient=3.141593
-
- //sLog.outDebug("Received opcode CMSG_WORLD_TELEPORT");
-
- if(GetPlayer()->isInFlight())
- {
- sLog.outDebug("Player '%s' (GUID: %u) in flight, ignore worldport command.",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow());
- return;
- }
-
- uint32 time;
- uint32 mapid;
- float PositionX;
- float PositionY;
- float PositionZ;
- float Orientation;
-
- recv_data >> time; // time in m.sec.
- recv_data >> mapid;
- recv_data >> PositionX;
- recv_data >> PositionY;
- recv_data >> PositionZ;
- recv_data >> Orientation; // o (3.141593 = 180 degrees)
- DEBUG_LOG("Time %u sec, map=%u, x=%f, y=%f, z=%f, orient=%f", time/1000, mapid, PositionX, PositionY, PositionZ, Orientation);
-
- if (GetSecurity() >= SEC_ADMINISTRATOR)
- GetPlayer()->TeleportTo(mapid,PositionX,PositionY,PositionZ,Orientation);
- else
- SendNotification("You do not have permission to perform that function");
- sLog.outDebug("Received worldport command from player %s", GetPlayer()->GetName());
-}
-
-void WorldSession::HandleWhoisOpcode(WorldPacket& recv_data)
-{
- CHECK_PACKET_SIZE(recv_data, 1);
-
- sLog.outDebug("Received opcode CMSG_WHOIS");
- std::string charname, acc, email, lastip, msg;
- recv_data >> charname;
-
- if (GetSecurity() < SEC_ADMINISTRATOR)
- {
- SendNotification("You do not have permission to perform that function");
- return;
- }
-
- if(charname.empty())
- {
- SendNotification("Please provide character name");
- return;
- }
-
- uint32 accid;
- Field *fields;
-
- Player *plr = objmgr.GetPlayer(charname.c_str());
-
- if(plr)
- accid = plr->GetSession()->GetAccountId();
- else
- {
- SendNotification("Player %s not found or offline", charname.c_str());
- return;
- }
-
- if(!accid)
- {
- SendNotification("Account for character %s not found", charname.c_str());
- return;
- }
-
- QueryResult *result = loginDatabase.PQuery("SELECT username,email,last_ip FROM account WHERE id=%u", accid);
- if(result)
- {
- fields = result->Fetch();
- acc = fields[0].GetCppString();
- if(acc.empty())
- acc = "Unknown";
- email = fields[1].GetCppString();
- if(email.empty())
- email = "Unknown";
- lastip = fields[2].GetCppString();
- if(lastip.empty())
- lastip = "Unknown";
- msg = charname + "'s " + "account is " + acc + ", e-mail: " + email + ", last ip: " + lastip;
-
- WorldPacket data(SMSG_WHOIS, msg.size()+1);
- data << msg;
- _player->GetSession()->SendPacket(&data);
- }
- else
- SendNotification("Account for character %s not found", charname.c_str());
-
- delete result;
- sLog.outDebug("Received whois command from player %s for character %s", GetPlayer()->GetName(), charname.c_str());
-}
-
-void WorldSession::HandleReportSpamOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 1+8);
- sLog.outDebug("WORLD: CMSG_REPORT_SPAM");
- recv_data.hexlike();
-
- uint8 spam_type; // 0 - mail, 1 - chat
- uint64 spammer_guid;
- uint32 unk1, unk2, unk3, unk4 = 0;
- std::string description = "";
- recv_data >> spam_type; // unk 0x01 const, may be spam type (mail/chat)
- recv_data >> spammer_guid; // player guid
- switch(spam_type)
- {
- case 0:
- CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4+4+4);
- recv_data >> unk1; // const 0
- recv_data >> unk2; // probably mail id
- recv_data >> unk3; // const 0
- break;
- case 1:
- CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4+4+4+4+1);
- recv_data >> unk1; // probably language
- recv_data >> unk2; // message type?
- recv_data >> unk3; // probably channel id
- recv_data >> unk4; // unk random value
- recv_data >> description; // spam description string (messagetype, channel name, player name, message)
- break;
- }
-
- // NOTE: all chat messages from this spammer automatically ignored by spam reporter until logout in case chat spam.
- // if it's mail spam - ALL mails from this spammer automatically removed by client
-
- // Complaint Received message
- WorldPacket data(SMSG_COMPLAIN_RESULT, 1);
- data << uint8(0);
- SendPacket(&data);
-
- sLog.outDebug("REPORT SPAM: type %u, guid %u, unk1 %u, unk2 %u, unk3 %u, unk4 %u, message %s", spam_type, GUID_LOPART(spammer_guid), unk1, unk2, unk3, unk4, description.c_str());
-}
-
-void WorldSession::HandleRealmStateRequestOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 4);
-
- sLog.outDebug("CMSG_REALM_SPLIT");
-
- uint32 unk;
- std::string split_date = "01/01/01";
- recv_data >> unk;
-
- WorldPacket data(SMSG_REALM_SPLIT, 4+4+split_date.size()+1);
- data << unk;
- data << uint32(0x00000000); // realm split state
- // split states:
- // 0x0 realm normal
- // 0x1 realm split
- // 0x2 realm split pending
- data << split_date;
- SendPacket(&data);
- //sLog.outDebug("response sent %u", unk);
-}
-
-void WorldSession::HandleFarSightOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 1);
-
- sLog.outDebug("WORLD: CMSG_FAR_SIGHT");
- //recv_data.hexlike();
-
- uint8 unk;
- recv_data >> unk;
-
- switch(unk)
- {
- case 0:
- //WorldPacket data(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, 0)
- //SendPacket(&data);
- //_player->SetUInt64Value(PLAYER_FARSIGHT, 0);
- sLog.outDebug("Removed FarSight from player %u", _player->GetGUIDLow());
- break;
- case 1:
- sLog.outDebug("Added FarSight " I64FMTD " to player %u", _player->GetUInt64Value(PLAYER_FARSIGHT), _player->GetGUIDLow());
- break;
- }
-}
-
-void WorldSession::HandleChooseTitleOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 4);
-
- sLog.outDebug("CMSG_SET_TITLE");
-
- int32 title;
- recv_data >> title;
-
- // -1 at none
- if(title > 0 && title < 64)
- {
- if(!GetPlayer()->HasFlag64(PLAYER__FIELD_KNOWN_TITLES,uint64(1) << title))
- return;
- }
- else
- title = 0;
-
- GetPlayer()->SetUInt32Value(PLAYER_CHOSEN_TITLE, title);
-}
-
-void WorldSession::HandleAllowMoveAckOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 4+4);
-
- sLog.outDebug("CMSG_ALLOW_MOVE_ACK");
-
- uint32 counter, time_;
- recv_data >> counter >> time_;
-
- // time_ seems always more than getMSTime()
- uint32 diff = getMSTimeDiff(getMSTime(),time_);
-
- sLog.outDebug("response sent: counter %u, time %u (HEX: %X), ms. time %u, diff %u", counter, time_, time_, getMSTime(), diff);
-}
-
-void WorldSession::HandleResetInstancesOpcode( WorldPacket & /*recv_data*/ )
-{
- sLog.outDebug("WORLD: CMSG_RESET_INSTANCES");
- Group *pGroup = _player->GetGroup();
- if(pGroup)
- {
- if(pGroup->IsLeader(_player->GetGUID()))
- pGroup->ResetInstances(INSTANCE_RESET_ALL, _player);
- }
- else
- _player->ResetInstances(INSTANCE_RESET_ALL);
-}
-
-void WorldSession::HandleDungeonDifficultyOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 4);
-
- sLog.outDebug("MSG_SET_DUNGEON_DIFFICULTY");
-
- uint32 mode;
- recv_data >> mode;
-
- if(mode == _player->GetDifficulty())
- return;
-
- if(mode > DIFFICULTY_HEROIC)
- {
- sLog.outError("WorldSession::HandleDungeonDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode);
- return;
- }
-
- // cannot reset while in an instance
- Map *map = _player->GetMap();
- if(map && map->IsDungeon())
- {
- sLog.outError("WorldSession::HandleDungeonDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow());
- return;
- }
-
- if(_player->getLevel() < LEVELREQUIREMENT_HEROIC)
- return;
- Group *pGroup = _player->GetGroup();
- if(pGroup)
- {
- if(pGroup->IsLeader(_player->GetGUID()))
- {
- // the difficulty is set even if the instances can't be reset
- //_player->SendDungeonDifficulty(true);
- pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, _player);
- pGroup->SetDifficulty(mode);
- }
- }
- else
- {
- _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY);
- _player->SetDifficulty(mode);
- }
-}
-
-void WorldSession::HandleNewUnknownOpcode( WorldPacket & recv_data )
-{
- sLog.outDebug("New Unknown Opcode %u", recv_data.GetOpcode());
- recv_data.hexlike();
- /*
- New Unknown Opcode 837
- STORAGE_SIZE: 60
- 02 00 00 00 00 00 00 00 | 00 00 00 00 01 20 00 00
- 89 EB 33 01 71 5C 24 C4 | 15 03 35 45 74 47 8B 42
- BA B8 1B 40 00 00 00 00 | 00 00 00 00 77 66 42 BF
- 23 91 26 3F 00 00 60 41 | 00 00 00 00
-
- New Unknown Opcode 837
- STORAGE_SIZE: 44
- 02 00 00 00 00 00 00 00 | 00 00 00 00 00 00 80 00
- 7B 80 34 01 84 EA 2B C4 | 5F A1 36 45 C9 39 1C 42
- BA B8 1B 40 CE 06 00 00 | 00 00 80 3F
- */
-}
-
-void WorldSession::HandleDismountOpcode( WorldPacket & /*recv_data*/ )
-{
- sLog.outDebug("WORLD: CMSG_CANCEL_MOUNT_AURA");
- //recv_data.hexlike();
-
- //If player is not mounted, so go out :)
- if (!_player->IsMounted()) // not blizz like; no any messages on blizz
- {
- ChatHandler(this).SendSysMessage(LANG_CHAR_NON_MOUNTED);
- return;
- }
-
- if(_player->isInFlight()) // not blizz like; no any messages on blizz
- {
- ChatHandler(this).SendSysMessage(LANG_YOU_IN_FLIGHT);
- return;
- }
-
- _player->Unmount();
- _player->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
-}
-
-void WorldSession::HandleMoveFlyModeChangeAckOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 8+4+4);
-
- // fly mode on/off
- sLog.outDebug("WORLD: CMSG_MOVE_SET_CAN_FLY_ACK");
- //recv_data.hexlike();
-
- uint64 guid;
- uint32 unk;
- uint32 flags;
-
- recv_data >> guid >> unk >> flags;
-
- _player->SetUnitMovementFlags(flags);
- /*
- on:
- 25 00 00 00 00 00 00 00 | 00 00 00 00 00 00 80 00
- 85 4E A9 01 19 BA 7A C3 | 42 0D 70 44 44 B0 A8 42
- 78 15 94 40 39 03 00 00 | 00 00 80 3F
- off:
- 25 00 00 00 00 00 00 00 | 00 00 00 00 00 00 00 00
- 10 FD A9 01 19 BA 7A C3 | 42 0D 70 44 44 B0 A8 42
- 78 15 94 40 39 03 00 00 | 00 00 00 00
- */
-}
-
-void WorldSession::HandleRequestPetInfoOpcode( WorldPacket & /*recv_data */)
-{
- /*
- sLog.outDebug("WORLD: CMSG_REQUEST_PET_INFO");
- recv_data.hexlike();
- */
-}
-
-void WorldSession::HandleSetTaxiBenchmarkOpcode( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data, 1);
-
- uint8 mode;
- recv_data >> mode;
-
- sLog.outDebug("Client used \"/timetest %d\" command", mode);
-}
+/*
+ * Copyright (C) 2005-2008 MaNGOS
+ *
+ * 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 "Database/DatabaseEnv.h"
+#include "WorldPacket.h"
+#include "Opcodes.h"
+#include "Log.h"
+#include "Player.h"
+#include "World.h"
+#include "ObjectMgr.h"
+#include "WorldSession.h"
+#include "Auth/BigNumber.h"
+#include "Auth/Sha1.h"
+#include "UpdateData.h"
+#include "LootMgr.h"
+#include "Chat.h"
+#include "ScriptCalls.h"
+#include
+#include "MapManager.h"
+#include "ObjectAccessor.h"
+#include "Object.h"
+#include "BattleGround.h"
+#include "SpellAuras.h"
+#include "Pet.h"
+#include "SocialMgr.h"
+
+void WorldSession::HandleRepopRequestOpcode( WorldPacket & /*recv_data*/ )
+{
+ sLog.outDebug( "WORLD: Recvd CMSG_REPOP_REQUEST Message" );
+
+ if(GetPlayer()->isAlive()||GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
+ return;
+
+ // the world update order is sessions, players, creatures
+ // the netcode runs in parallel with all of these
+ // creatures can kill players
+ // so if the server is lagging enough the player can
+ // release spirit after he's killed but before he is updated
+ if(GetPlayer()->getDeathState() == JUST_DIED)
+ {
+ sLog.outDebug("HandleRepopRequestOpcode: got request after player %s(%d) was killed and before he was updated", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow());
+ GetPlayer()->KillPlayer();
+ }
+
+ //this is spirit release confirm?
+ GetPlayer()->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT, true);
+ GetPlayer()->BuildPlayerRepop();
+ GetPlayer()->RepopAtGraveyard();
+}
+
+void WorldSession::HandleWhoOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data,4+4+1+1+4+4+4+4);
+
+ sLog.outDebug( "WORLD: Recvd CMSG_WHO Message" );
+ //recv_data.hexlike();
+
+ uint32 clientcount = 0;
+
+ uint32 level_min, level_max, racemask, classmask, zones_count, str_count;
+ uint32 zoneids[10]; // 10 is client limit
+ std::string player_name, guild_name;
+
+ recv_data >> level_min; // maximal player level, default 0
+ recv_data >> level_max; // minimal player level, default 100
+ recv_data >> player_name; // player name, case sensitive...
+
+ // recheck
+ CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+1+4+4+4+4);
+
+ recv_data >> guild_name; // guild name, case sensitive...
+
+ // recheck
+ CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+(guild_name.size()+1)+4+4+4+4);
+
+ recv_data >> racemask; // race mask
+ recv_data >> classmask; // class mask
+ recv_data >> zones_count; // zones count, client limit=10 (2.0.10)
+
+ if(zones_count > 10)
+ return; // can't be received from real client or broken packet
+
+ // recheck
+ CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+(guild_name.size()+1)+4+4+4+(4*zones_count)+4);
+
+ for(uint32 i = 0; i < zones_count; i++)
+ {
+ uint32 temp;
+ recv_data >> temp; // zone id, 0 if zone is unknown...
+ zoneids[i] = temp;
+ sLog.outDebug("Zone %u: %u", i, zoneids[i]);
+ }
+
+ recv_data >> str_count; // user entered strings count, client limit=4 (checked on 2.0.10)
+
+ if(str_count > 4)
+ return; // can't be received from real client or broken packet
+
+ // recheck
+ CHECK_PACKET_SIZE(recv_data,4+4+(player_name.size()+1)+(guild_name.size()+1)+4+4+4+(4*zones_count)+4+(1*str_count));
+
+ sLog.outDebug("Minlvl %u, maxlvl %u, name %s, guild %s, racemask %u, classmask %u, zones %u, strings %u", level_min, level_max, player_name.c_str(), guild_name.c_str(), racemask, classmask, zones_count, str_count);
+
+ std::wstring str[4]; // 4 is client limit
+ for(uint32 i = 0; i < str_count; i++)
+ {
+ // recheck (have one more byte)
+ CHECK_PACKET_SIZE(recv_data,recv_data.rpos());
+
+ std::string temp;
+ recv_data >> temp; // user entered string, it used as universal search pattern(guild+player name)?
+
+ if(!Utf8toWStr(temp,str[i]))
+ continue;
+
+ wstrToLower(str[i]);
+
+ sLog.outDebug("String %u: %s", i, str[i].c_str());
+ }
+
+ std::wstring wplayer_name;
+ std::wstring wguild_name;
+ if(!(Utf8toWStr(player_name, wplayer_name) && Utf8toWStr(guild_name, wguild_name)))
+ return;
+ wstrToLower(wplayer_name);
+ wstrToLower(wguild_name);
+
+ // client send in case not set max level value 100 but mangos support 255 max level,
+ // update it to show GMs with characters after 100 level
+ if(level_max >= 100)
+ level_max = 255;
+
+ uint32 team = _player->GetTeam();
+ uint32 security = GetSecurity();
+ bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
+ bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST);
+
+ WorldPacket data( SMSG_WHO, 50 ); // guess size
+ data << clientcount; // clientcount place holder
+ data << clientcount; // clientcount place holder
+
+ //TODO: Guard Player map
+ HashMapHolder::MapType& m = ObjectAccessor::Instance().GetPlayers();
+ for(HashMapHolder::MapType::iterator itr = m.begin(); itr != m.end(); ++itr)
+ {
+ if (security == SEC_PLAYER)
+ {
+ // player can see member of other team only if CONFIG_ALLOW_TWO_SIDE_WHO_LIST
+ if (itr->second->GetTeam() != team && !allowTwoSideWhoList )
+ continue;
+
+ // player can see MODERATOR, GAME MASTER, ADMINISTRATOR only if CONFIG_GM_IN_WHO_LIST
+ if ((itr->second->GetSession()->GetSecurity() > SEC_PLAYER && !gmInWhoList))
+ continue;
+ }
+
+ // check if target is globally visible for player
+ if (!(itr->second->IsVisibleGloballyFor(_player)))
+ continue;
+
+ // check if target's level is in level range
+ uint32 lvl = itr->second->getLevel();
+ if (lvl < level_min || lvl > level_max)
+ continue;
+
+ // check if class matches classmask
+ uint32 class_ = itr->second->getClass();
+ if (!(classmask & (1 << class_)))
+ continue;
+
+ // check if race matches racemask
+ uint32 race = itr->second->getRace();
+ if (!(racemask & (1 << race)))
+ continue;
+
+ uint32 pzoneid = itr->second->GetZoneId();
+
+ bool z_show = true;
+ for(uint32 i = 0; i < zones_count; i++)
+ {
+ if(zoneids[i] == pzoneid)
+ {
+ z_show = true;
+ break;
+ }
+
+ z_show = false;
+ }
+ if (!z_show)
+ continue;
+
+ std::string pname = itr->second->GetName();
+ std::wstring wpname;
+ if(!Utf8toWStr(pname,wpname))
+ continue;
+ wstrToLower(wpname);
+
+ if (!(wplayer_name.empty() || wpname.find(wplayer_name) != std::wstring::npos))
+ continue;
+
+ std::string gname = objmgr.GetGuildNameById(itr->second->GetGuildId());
+ std::wstring wgname;
+ if(!Utf8toWStr(gname,wgname))
+ continue;
+ wstrToLower(wgname);
+
+ if (!(wguild_name.empty() || wgname.find(wguild_name) != std::wstring::npos))
+ continue;
+
+ std::string aname;
+ if(AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(itr->second->GetZoneId()))
+ aname = areaEntry->area_name[GetSessionDbcLocale()];
+
+ bool s_show = true;
+ for(uint32 i = 0; i < str_count; i++)
+ {
+ if (!str[i].empty())
+ {
+ if (wgname.find(str[i]) != std::wstring::npos ||
+ wpname.find(str[i]) != std::wstring::npos ||
+ Utf8FitTo(aname, str[i]) )
+ {
+ s_show = true;
+ break;
+ }
+ s_show = false;
+ }
+ }
+ if (!s_show)
+ continue;
+
+ data << pname; // player name
+ data << gname; // guild name
+ data << uint32( lvl ); // player level
+ data << uint32( class_ ); // player class
+ data << uint32( race ); // player race
+ data << uint8(0); // new 2.4.0
+ data << uint32( pzoneid ); // player zone id
+
+ // 49 is maximum player count sent to client
+ if ((++clientcount) == 49)
+ break;
+ }
+
+ data.put( 0, clientcount ); //insert right count
+ data.put( sizeof(uint32), clientcount ); //insert right count
+
+ SendPacket(&data);
+ sLog.outDebug( "WORLD: Send SMSG_WHO Message" );
+}
+
+void WorldSession::HandleLogoutRequestOpcode( WorldPacket & /*recv_data*/ )
+{
+ sLog.outDebug( "WORLD: Recvd CMSG_LOGOUT_REQUEST Message, security - %u", GetSecurity() );
+
+ 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
+ //...is jumping ...is falling
+ GetPlayer()->HasUnitMovementFlag(MOVEMENTFLAG_JUMPING | MOVEMENTFLAG_FALLING))
+ {
+ WorldPacket data( SMSG_LOGOUT_RESPONSE, (2+4) ) ;
+ data << (uint8)0xC;
+ data << uint32(0);
+ data << uint8(0);
+ SendPacket( &data );
+ LogoutRequest(0);
+ return;
+ }
+
+ //instant logout in taverns/cities or on taxi
+ if(GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) || GetPlayer()->isInFlight())
+ {
+ LogoutPlayer(true);
+ return;
+ }
+
+ // not set flags if player can't free move to prevent lost state at logout cancel
+ if(GetPlayer()->CanFreeMove())
+ {
+ GetPlayer()->SetStandState(PLAYER_STATE_SIT);
+
+ WorldPacket data( SMSG_FORCE_MOVE_ROOT, (8+4) ); // guess size
+ data.append(GetPlayer()->GetPackGUID());
+ data << (uint32)2;
+ SendPacket( &data );
+ GetPlayer()->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
+ }
+
+ WorldPacket data( SMSG_LOGOUT_RESPONSE, 5 );
+ data << uint32(0);
+ data << uint8(0);
+ SendPacket( &data );
+ LogoutRequest(time(NULL));
+}
+
+void WorldSession::HandlePlayerLogoutOpcode( WorldPacket & /*recv_data*/ )
+{
+ sLog.outDebug( "WORLD: Recvd CMSG_PLAYER_LOGOUT Message" );
+}
+
+void WorldSession::HandleLogoutCancelOpcode( WorldPacket & /*recv_data*/ )
+{
+ sLog.outDebug( "WORLD: Recvd CMSG_LOGOUT_CANCEL Message" );
+
+ LogoutRequest(0);
+
+ WorldPacket data( SMSG_LOGOUT_CANCEL_ACK, 0 );
+ SendPacket( &data );
+
+ // not remove flags if can't free move - its not set in Logout request code.
+ if(GetPlayer()->CanFreeMove())
+ {
+ //!we can move again
+ data.Initialize( SMSG_FORCE_MOVE_UNROOT, 8 ); // guess size
+ data.append(GetPlayer()->GetPackGUID());
+ data << uint32(0);
+ SendPacket( &data );
+
+ //! Stand Up
+ GetPlayer()->SetStandState(PLAYER_STATE_NONE);
+
+ //! DISABLE_ROTATE
+ GetPlayer()->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE);
+ }
+
+ sLog.outDebug( "WORLD: sent SMSG_LOGOUT_CANCEL_ACK Message" );
+}
+
+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 );
+
+ uint64 guid;
+ Field *fields;
+ guid = GetPlayer()->GetGUID();
+
+ QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(ticket_id) FROM character_ticket WHERE guid = '%u'", GUID_LOPART(guid));
+
+ if (result)
+ {
+ int cnt;
+ fields = result->Fetch();
+ cnt = fields[0].GetUInt32();
+ delete result;
+
+ if ( cnt > 0 )
+ {
+ QueryResult *result2 = CharacterDatabase.PQuery("SELECT ticket_text FROM character_ticket WHERE guid = '%u'", GUID_LOPART(guid));
+ if(result2)
+ {
+ Field *fields2 = result2->Fetch();
+ SendGMTicketGetTicket(0x06,fields2[0].GetString());
+ delete result2;
+ }
+ }
+ else
+ SendGMTicketGetTicket(0x0A,0);
+ }
+}
+
+void WorldSession::HandleGMTicketUpdateTextOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data,1);
+
+ std::string ticketText;
+ recv_data >> ticketText;
+
+ CharacterDatabase.escape_string(ticketText);
+ CharacterDatabase.PExecute("UPDATE character_ticket SET ticket_text = '%s' WHERE guid = '%u'", ticketText.c_str(), _player->GetGUIDLow());
+}
+
+void WorldSession::HandleGMTicketDeleteOpcode( WorldPacket & /*recv_data*/ )
+{
+ uint32 guid = GetPlayer()->GetGUIDLow();
+
+ CharacterDatabase.PExecute("DELETE FROM character_ticket WHERE guid = '%u' LIMIT 1",guid);
+
+ 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);
+
+ CharacterDatabase.escape_string(ticketText);
+
+ QueryResult *result = CharacterDatabase.PQuery("SELECT COUNT(*) FROM character_ticket WHERE guid = '%u'", _player->GetGUIDLow());
+
+ if (result)
+ {
+ int cnt;
+ Field *fields = result->Fetch();
+ cnt = fields[0].GetUInt32();
+ delete result;
+
+ if ( cnt > 0 )
+ {
+ WorldPacket data( SMSG_GMTICKET_CREATE, 4 );
+ data << uint32(1);
+ SendPacket( &data );
+ }
+ else
+ {
+ CharacterDatabase.PExecute("INSERT INTO character_ticket (guid,ticket_text) VALUES ('%u', '%s')", _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::MapType &m = ObjectAccessor::Instance().GetPlayers();
+ for(HashMapHolder::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
+}
+
+void WorldSession::HandleTogglePvP( WorldPacket & recv_data )
+{
+ // this opcode can be used in two ways: Either set explicit new status or toggle old status
+ if(recv_data.size() == 1)
+ {
+ bool newPvPStatus;
+ recv_data >> newPvPStatus;
+ GetPlayer()->ApplyModFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP, newPvPStatus);
+ }
+ else
+ {
+ GetPlayer()->ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP);
+ }
+
+ if(GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP))
+ {
+ if(!GetPlayer()->IsPvP() || GetPlayer()->pvpInfo.endTimer != 0)
+ GetPlayer()->UpdatePvP(true, true);
+ }
+ else
+ {
+ if(!GetPlayer()->pvpInfo.inHostileArea && GetPlayer()->IsPvP())
+ GetPlayer()->pvpInfo.endTimer = time(NULL); // start toggle-off
+ }
+}
+
+void WorldSession::HandleZoneUpdateOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data,4);
+
+ uint32 newZone;
+ recv_data >> newZone;
+
+ sLog.outDetail("WORLD: Recvd ZONE_UPDATE: %u", newZone);
+
+ if(newZone != _player->GetZoneId())
+ GetPlayer()->SendInitWorldStates(); // only if really enters to new zone, not just area change, works strange...
+
+ GetPlayer()->UpdateZone(newZone);
+}
+
+void WorldSession::HandleSetTargetOpcode( WorldPacket & recv_data )
+{
+ // When this packet send?
+ CHECK_PACKET_SIZE(recv_data,8);
+
+ uint64 guid ;
+ recv_data >> guid;
+
+ _player->SetUInt32Value(UNIT_FIELD_TARGET,guid);
+
+ // update reputation list if need
+ Unit* unit = ObjectAccessor::GetUnit(*_player, guid );
+ if(!unit)
+ return;
+
+ _player->SetFactionVisibleForFactionTemplateId(unit->getFaction());
+}
+
+void WorldSession::HandleSetSelectionOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data,8);
+
+ uint64 guid;
+ recv_data >> guid;
+
+ _player->SetSelection(guid);
+
+ // update reputation list if need
+ Unit* unit = ObjectAccessor::GetUnit(*_player, guid );
+ if(!unit)
+ return;
+
+ _player->SetFactionVisibleForFactionTemplateId(unit->getFaction());
+}
+
+void WorldSession::HandleStandStateChangeOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data,1);
+
+ sLog.outDebug( "WORLD: Received CMSG_STAND_STATE_CHANGE" );
+ uint8 animstate;
+ recv_data >> animstate;
+
+ _player->SetStandState(animstate);
+}
+
+void WorldSession::HandleFriendListOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 4);
+ sLog.outDebug( "WORLD: Received CMSG_CONTACT_LIST" );
+ uint32 unk;
+ recv_data >> unk;
+ sLog.outDebug("unk value is %u", unk);
+ _player->GetSocial()->SendSocialList();
+}
+
+void WorldSession::HandleAddFriendOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 1+1);
+
+ sLog.outDebug( "WORLD: Received CMSG_ADD_FRIEND" );
+
+ std::string friendName = GetMangosString(LANG_FRIEND_IGNORE_UNKNOWN);
+ std::string friendNote;
+ FriendsResult friendResult = FRIEND_NOT_FOUND;
+ Player *pFriend = NULL;
+ uint64 friendGuid = 0;
+
+ recv_data >> friendName;
+
+ // recheck
+ CHECK_PACKET_SIZE(recv_data, (friendName.size()+1)+1);
+
+ recv_data >> friendNote;
+
+ if(!normalizePlayerName(friendName))
+ return;
+
+ CharacterDatabase.escape_string(friendName); // prevent SQL injection - normal name don't must changed by this call
+
+ sLog.outDebug( "WORLD: %s asked to add friend : '%s'",
+ GetPlayer()->GetName(), friendName.c_str() );
+
+ friendGuid = objmgr.GetPlayerGUIDByName(friendName);
+
+ if(friendGuid)
+ {
+ pFriend = ObjectAccessor::FindPlayer(friendGuid);
+ if(pFriend==GetPlayer())
+ friendResult = FRIEND_SELF;
+ else if(GetPlayer()->GetTeam()!=objmgr.GetPlayerTeamByGUID(friendGuid) && !sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_ADD_FRIEND) && GetSecurity() < SEC_MODERATOR)
+ friendResult = FRIEND_ENEMY;
+ else if(GetPlayer()->GetSocial()->HasFriend(GUID_LOPART(friendGuid)))
+ friendResult = FRIEND_ALREADY;
+ }
+
+ if (friendGuid && friendResult==FRIEND_NOT_FOUND)
+ {
+ if( pFriend && pFriend->IsInWorld() && pFriend->IsVisibleGloballyFor(GetPlayer()))
+ friendResult = FRIEND_ADDED_ONLINE;
+ else
+ friendResult = FRIEND_ADDED_OFFLINE;
+
+ if(!_player->GetSocial()->AddToSocialList(GUID_LOPART(friendGuid), false))
+ {
+ friendResult = FRIEND_LIST_FULL;
+ sLog.outDebug( "WORLD: %s's friend list is full.", GetPlayer()->GetName());
+ }
+
+ _player->GetSocial()->SetFriendNote(GUID_LOPART(friendGuid), friendNote);
+
+ sLog.outDebug( "WORLD: %s Guid found '%u'.", friendName.c_str(), GUID_LOPART(friendGuid));
+ }
+ else if(friendResult==FRIEND_ALREADY)
+ {
+ sLog.outDebug( "WORLD: %s Guid Already a Friend.", friendName.c_str() );
+ }
+ else if(friendResult==FRIEND_SELF)
+ {
+ sLog.outDebug( "WORLD: %s Guid can't add himself.", friendName.c_str() );
+ }
+ else
+ {
+ sLog.outDebug( "WORLD: %s Guid not found.", friendName.c_str() );
+ }
+
+ sSocialMgr.SendFriendStatus(GetPlayer(), friendResult, GUID_LOPART(friendGuid), friendName, false);
+
+ sLog.outDebug( "WORLD: Sent (SMSG_FRIEND_STATUS)" );
+}
+
+void WorldSession::HandleDelFriendOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 8);
+
+ uint64 FriendGUID;
+
+ sLog.outDebug( "WORLD: Received CMSG_DEL_FRIEND" );
+
+ recv_data >> FriendGUID;
+
+ _player->GetSocial()->RemoveFromSocialList(GUID_LOPART(FriendGUID), false);
+
+ sSocialMgr.SendFriendStatus(GetPlayer(), FRIEND_REMOVED, GUID_LOPART(FriendGUID), "", false);
+
+ sLog.outDebug( "WORLD: Sent motd (SMSG_FRIEND_STATUS)" );
+}
+
+void WorldSession::HandleAddIgnoreOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data,1);
+
+ sLog.outDebug( "WORLD: Received CMSG_ADD_IGNORE" );
+
+ std::string IgnoreName = GetMangosString(LANG_FRIEND_IGNORE_UNKNOWN);
+ FriendsResult ignoreResult = FRIEND_IGNORE_NOT_FOUND;
+ uint64 IgnoreGuid = 0;
+
+ recv_data >> IgnoreName;
+
+ if(!normalizePlayerName(IgnoreName))
+ return;
+
+ CharacterDatabase.escape_string(IgnoreName); // prevent SQL injection - normal name don't must changed by this call
+
+ sLog.outDebug( "WORLD: %s asked to Ignore: '%s'",
+ GetPlayer()->GetName(), IgnoreName.c_str() );
+
+ IgnoreGuid = objmgr.GetPlayerGUIDByName(IgnoreName);
+
+ if(IgnoreGuid)
+ {
+ if(IgnoreGuid==GetPlayer()->GetGUID())
+ ignoreResult = FRIEND_IGNORE_SELF;
+ else
+ {
+ if( GetPlayer()->GetSocial()->HasIgnore(GUID_LOPART(IgnoreGuid)) )
+ ignoreResult = FRIEND_IGNORE_ALREADY;
+ }
+ }
+
+ if (IgnoreGuid && ignoreResult == FRIEND_IGNORE_NOT_FOUND)
+ {
+ ignoreResult = FRIEND_IGNORE_ADDED;
+
+ _player->GetSocial()->AddToSocialList(GUID_LOPART(IgnoreGuid), true);
+ }
+ else if(ignoreResult==FRIEND_IGNORE_ALREADY)
+ {
+ sLog.outDebug( "WORLD: %s Guid Already Ignored.", IgnoreName.c_str() );
+ }
+ else if(ignoreResult==FRIEND_IGNORE_SELF)
+ {
+ sLog.outDebug( "WORLD: %s Guid can't add himself.", IgnoreName.c_str() );
+ }
+ else
+ {
+ sLog.outDebug( "WORLD: %s Guid not found.", IgnoreName.c_str() );
+ }
+
+ sSocialMgr.SendFriendStatus(GetPlayer(), ignoreResult, GUID_LOPART(IgnoreGuid), "", false);
+
+ sLog.outDebug( "WORLD: Sent (SMSG_FRIEND_STATUS)" );
+}
+
+void WorldSession::HandleDelIgnoreOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 8);
+
+ uint64 IgnoreGUID;
+
+ sLog.outDebug( "WORLD: Received CMSG_DEL_IGNORE" );
+
+ recv_data >> IgnoreGUID;
+
+ _player->GetSocial()->RemoveFromSocialList(GUID_LOPART(IgnoreGUID), true);
+
+ sSocialMgr.SendFriendStatus(GetPlayer(), FRIEND_IGNORE_REMOVED, GUID_LOPART(IgnoreGUID), "", false);
+
+ sLog.outDebug( "WORLD: Sent motd (SMSG_FRIEND_STATUS)" );
+}
+
+void WorldSession::HandleSetFriendNoteOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 8+1);
+ uint64 guid;
+ std::string note;
+ recv_data >> guid >> note;
+ _player->GetSocial()->SetFriendNote(guid, note);
+}
+
+void WorldSession::HandleBugOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data,4+4+1+4+1);
+
+ uint32 suggestion, contentlen;
+ std::string content;
+ uint32 typelen;
+ std::string type;
+
+ recv_data >> suggestion >> contentlen >> content;
+
+ //recheck
+ CHECK_PACKET_SIZE(recv_data,4+4+(content.size()+1)+4+1);
+
+ recv_data >> typelen >> type;
+
+ if( suggestion == 0 )
+ sLog.outDebug( "WORLD: Received CMSG_BUG [Bug Report]" );
+ else
+ sLog.outDebug( "WORLD: Received CMSG_BUG [Suggestion]" );
+
+ sLog.outDebug( type.c_str( ) );
+ sLog.outDebug( content.c_str( ) );
+
+ CharacterDatabase.escape_string(type);
+ CharacterDatabase.escape_string(content);
+ CharacterDatabase.PExecute ("INSERT INTO bugreport (type,content) VALUES('%s', '%s')", type.c_str( ), content.c_str( ));
+}
+
+void WorldSession::HandleCorpseReclaimOpcode(WorldPacket &recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data,8);
+
+ sLog.outDetail("WORLD: Received CMSG_RECLAIM_CORPSE");
+ if (GetPlayer()->isAlive())
+ return;
+
+ if (BattleGround * bg = _player->GetBattleGround())
+ if(bg->isArena())
+ return;
+
+ // body not released yet
+ if(!GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
+ return;
+
+ Corpse *corpse = GetPlayer()->GetCorpse();
+
+ if (!corpse )
+ return;
+
+ // prevent resurrect before 30-sec delay after body release not finished
+ if(corpse->GetGhostTime() + GetPlayer()->GetCorpseReclaimDelay(corpse->GetType()==CORPSE_RESURRECTABLE_PVP) > time(NULL))
+ return;
+
+ float dist = corpse->GetDistance2d(GetPlayer());
+ sLog.outDebug("Corpse 2D Distance: \t%f",dist);
+ if (dist > CORPSE_RECLAIM_RADIUS)
+ return;
+
+ uint64 guid;
+ recv_data >> guid;
+
+ // resurrect
+ GetPlayer()->ResurrectPlayer(GetPlayer()->InBattleGround() ? 1.0f : 0.5f);
+
+ // spawn bones
+ GetPlayer()->SpawnCorpseBones();
+
+ GetPlayer()->SaveToDB();
+}
+
+void WorldSession::HandleResurrectResponseOpcode(WorldPacket & recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data,8+1);
+
+ sLog.outDetail("WORLD: Received CMSG_RESURRECT_RESPONSE");
+
+ if(GetPlayer()->isAlive())
+ return;
+
+ uint64 guid;
+ uint8 status;
+ recv_data >> guid;
+ recv_data >> status;
+
+ if(status == 0)
+ {
+ GetPlayer()->clearResurrectRequestData(); // reject
+ return;
+ }
+
+ if(!GetPlayer()->isRessurectRequestedBy(guid))
+ return;
+
+ GetPlayer()->ResurectUsingRequestData();
+ GetPlayer()->SaveToDB();
+}
+
+void WorldSession::HandleAreaTriggerOpcode(WorldPacket & recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data,4);
+
+ sLog.outDebug("WORLD: Received CMSG_AREATRIGGER");
+
+ uint32 Trigger_ID;
+
+ recv_data >> Trigger_ID;
+ sLog.outDebug("Trigger ID:%u",Trigger_ID);
+
+ if(GetPlayer()->isInFlight())
+ {
+ sLog.outDebug("Player '%s' (GUID: %u) in flight, ignore Area Trigger ID:%u",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow(), Trigger_ID);
+ return;
+ }
+
+ AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(Trigger_ID);
+ if(!atEntry)
+ {
+ sLog.outDebug("Player '%s' (GUID: %u) send unknown (by DBC) Area Trigger ID:%u",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow(), Trigger_ID);
+ return;
+ }
+
+ if (GetPlayer()->GetMapId()!=atEntry->mapid)
+ {
+ sLog.outDebug("Player '%s' (GUID: %u) too far (trigger map: %u player map: %u), ignore Area Trigger ID: %u", GetPlayer()->GetName(), atEntry->mapid, GetPlayer()->GetMapId(), GetPlayer()->GetGUIDLow(), Trigger_ID);
+ return;
+ }
+
+ // delta is safe radius
+ const float delta = 5.0f;
+ // check if player in the range of areatrigger
+ Player* pl = GetPlayer();
+
+ if (atEntry->radius > 0)
+ {
+ // if we have radius check it
+ float dist = pl->GetDistance(atEntry->x,atEntry->y,atEntry->z);
+ if(dist > atEntry->radius + delta)
+ {
+ sLog.outDebug("Player '%s' (GUID: %u) too far (radius: %f distance: %f), ignore Area Trigger ID: %u",
+ pl->GetName(), pl->GetGUIDLow(), atEntry->radius, dist, Trigger_ID);
+ return;
+ }
+ }
+ else
+ {
+ // we have only extent
+ float dx = pl->GetPositionX() - atEntry->x;
+ float dy = pl->GetPositionY() - atEntry->y;
+ float dz = pl->GetPositionZ() - atEntry->z;
+ double es = sin(atEntry->box_orientation);
+ double ec = cos(atEntry->box_orientation);
+ // calc rotated vector based on extent axis
+ double rotateDx = dx*ec - dy*es;
+ double rotateDy = dx*es + dy*ec;
+
+ if( (fabs(rotateDx) > atEntry->box_x/2 + delta) ||
+ (fabs(rotateDy) > atEntry->box_y/2 + delta) ||
+ (fabs(dz) > atEntry->box_z/2 + delta) )
+ {
+ sLog.outDebug("Player '%s' (GUID: %u) too far (1/2 box X: %f 1/2 box Y: %u 1/2 box Z: %u rotate dX: %f rotate dY: %f dZ:%f), ignore Area Trigger ID: %u",
+ pl->GetName(), pl->GetGUIDLow(), atEntry->box_x/2, atEntry->box_y/2, atEntry->box_z/2, rotateDx, rotateDy, dz, Trigger_ID);
+ return;
+ }
+ }
+
+ if(Script->scriptAreaTrigger(GetPlayer(), atEntry))
+ return;
+
+ uint32 quest_id = objmgr.GetQuestForAreaTrigger( Trigger_ID );
+ if( quest_id && GetPlayer()->isAlive() && GetPlayer()->IsActiveQuest(quest_id) )
+ {
+ Quest const* pQuest = objmgr.GetQuestTemplate(quest_id);
+ if( pQuest )
+ {
+ if(GetPlayer()->GetQuestStatus(quest_id) == QUEST_STATUS_INCOMPLETE)
+ GetPlayer()->AreaExploredOrEventHappens( quest_id );
+ }
+ }
+
+ if(objmgr.IsTavernAreaTrigger(Trigger_ID))
+ {
+ // set resting flag we are in the inn
+ GetPlayer()->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING);
+ GetPlayer()->InnEnter(time(NULL), atEntry->mapid, atEntry->x, atEntry->y, atEntry->z);
+ GetPlayer()->SetRestType(REST_TYPE_IN_TAVERN);
+
+ if(sWorld.IsFFAPvPRealm())
+ GetPlayer()->RemoveFlag(PLAYER_FLAGS,PLAYER_FLAGS_FFA_PVP);
+
+ return;
+ }
+
+ if(GetPlayer()->InBattleGround())
+ {
+ BattleGround* bg = GetPlayer()->GetBattleGround();
+ if(bg)
+ if(bg->GetStatus() == STATUS_IN_PROGRESS)
+ bg->HandleAreaTrigger(GetPlayer(), Trigger_ID);
+
+ return;
+ }
+
+ // NULL if all values default (non teleport trigger)
+ AreaTrigger const* at = objmgr.GetAreaTrigger(Trigger_ID);
+ if(!at)
+ return;
+
+ if(!GetPlayer()->isGameMaster())
+ {
+ uint32 missingLevel = 0;
+ if(GetPlayer()->getLevel() < at->requiredLevel && !sWorld.getConfig(CONFIG_INSTANCE_IGNORE_LEVEL))
+ missingLevel = at->requiredLevel;
+
+ // must have one or the other, report the first one that's missing
+ uint32 missingItem = 0;
+ if(at->requiredItem)
+ {
+ if(!GetPlayer()->HasItemCount(at->requiredItem, 1) &&
+ (!at->requiredItem2 || !GetPlayer()->HasItemCount(at->requiredItem2, 1)))
+ missingItem = at->requiredItem;
+ }
+ else if(at->requiredItem2 && !GetPlayer()->HasItemCount(at->requiredItem2, 1))
+ missingItem = at->requiredItem2;
+
+ uint32 missingKey = 0;
+ if(GetPlayer()->GetDifficulty() == DIFFICULTY_HEROIC)
+ {
+ if(at->heroicKey)
+ {
+ if(!GetPlayer()->HasItemCount(at->heroicKey, 1) &&
+ (!at->heroicKey2 || !GetPlayer()->HasItemCount(at->heroicKey2, 1)))
+ missingKey = at->heroicKey;
+ }
+ else if(at->heroicKey2 && !GetPlayer()->HasItemCount(at->heroicKey2, 1))
+ missingKey = at->heroicKey2;
+ }
+
+ uint32 missingQuest = 0;
+ if(at->requiredQuest && !GetPlayer()->GetQuestRewardStatus(at->requiredQuest))
+ missingQuest = at->requiredQuest;
+
+ if(missingLevel || missingItem || missingKey || missingQuest)
+ {
+ // TODO: all this is probably wrong
+ if(missingItem)
+ SendAreaTriggerMessage(GetMangosString(LANG_LEVEL_MINREQUIRED_AND_ITEM), at->requiredLevel, objmgr.GetItemPrototype(missingItem)->Name1);
+ else if(missingKey)
+ GetPlayer()->SendTransferAborted(at->target_mapId, TRANSFER_ABORT_DIFFICULTY2);
+ else if(missingQuest)
+ SendAreaTriggerMessage(at->requiredFailedText.c_str());
+ else if(missingLevel)
+ SendAreaTriggerMessage(GetMangosString(LANG_LEVEL_MINREQUIRED), missingLevel);
+ return;
+ }
+ }
+
+ GetPlayer()->TeleportTo(at->target_mapId,at->target_X,at->target_Y,at->target_Z,at->target_Orientation,TELE_TO_NOT_LEAVE_TRANSPORT);
+}
+
+void WorldSession::HandleUpdateAccountData(WorldPacket &/*recv_data*/)
+{
+ sLog.outDetail("WORLD: Received CMSG_UPDATE_ACCOUNT_DATA");
+ //recv_data.hexlike();
+}
+
+void WorldSession::HandleRequestAccountData(WorldPacket& /*recv_data*/)
+{
+ sLog.outDetail("WORLD: Received CMSG_REQUEST_ACCOUNT_DATA");
+ //recv_data.hexlike();
+}
+
+void WorldSession::HandleSetActionButtonOpcode(WorldPacket& recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data,1+2+1+1);
+
+ sLog.outDebug( "WORLD: Received CMSG_SET_ACTION_BUTTON" );
+ uint8 button, misc, type;
+ uint16 action;
+ recv_data >> button >> action >> misc >> type;
+ sLog.outDetail( "BUTTON: %u ACTION: %u TYPE: %u MISC: %u", button, action, type, misc );
+ if(action==0)
+ {
+ sLog.outDetail( "MISC: Remove action from button %u", button );
+
+ GetPlayer()->removeActionButton(button);
+ }
+ else
+ {
+ if(type==ACTION_BUTTON_MACRO || type==ACTION_BUTTON_CMACRO)
+ {
+ sLog.outDetail( "MISC: Added Macro %u into button %u", action, button );
+ GetPlayer()->addActionButton(button,action,type,misc);
+ }
+ else if(type==ACTION_BUTTON_SPELL)
+ {
+ sLog.outDetail( "MISC: Added Action %u into button %u", action, button );
+ GetPlayer()->addActionButton(button,action,type,misc);
+ }
+ else if(type==ACTION_BUTTON_ITEM)
+ {
+ sLog.outDetail( "MISC: Added Item %u into button %u", action, button );
+ GetPlayer()->addActionButton(button,action,type,misc);
+ }
+ else
+ sLog.outError( "MISC: Unknown action button type %u for action %u into button %u", type, action, button );
+ }
+}
+
+void WorldSession::HandleCompleteCinema( WorldPacket & /*recv_data*/ )
+{
+ DEBUG_LOG( "WORLD: Player is watching cinema" );
+}
+
+void WorldSession::HandleNextCinematicCamera( WorldPacket & /*recv_data*/ )
+{
+ DEBUG_LOG( "WORLD: Which movie to play" );
+}
+
+void WorldSession::HandleMoveTimeSkippedOpcode( WorldPacket & /*recv_data*/ )
+{
+ /* WorldSession::Update( getMSTime() );*/
+ DEBUG_LOG( "WORLD: Time Lag/Synchronization Resent/Update" );
+
+ /*
+ CHECK_PACKET_SIZE(recv_data,8+4);
+ uint64 guid;
+ uint32 time_skipped;
+ recv_data >> guid;
+ recv_data >> time_skipped;
+ sLog.outDebug( "WORLD: CMSG_MOVE_TIME_SKIPPED" );
+
+ /// TODO
+ must be need use in mangos
+ We substract server Lags to move time ( AntiLags )
+ for exmaple
+ GetPlayer()->ModifyLastMoveTime( -int32(time_skipped) );
+ */
+}
+
+void WorldSession::HandleFeatherFallAck(WorldPacket &/*recv_data*/)
+{
+ DEBUG_LOG("WORLD: CMSG_MOVE_FEATHER_FALL_ACK");
+}
+
+void WorldSession::HandleMoveUnRootAck(WorldPacket&/* recv_data*/)
+{
+ /*
+ CHECK_PACKET_SIZE(recv_data,8+8+4+4+4+4+4);
+
+ sLog.outDebug( "WORLD: CMSG_FORCE_MOVE_UNROOT_ACK" );
+ recv_data.hexlike();
+ uint64 guid;
+ uint64 unknown1;
+ uint32 unknown2;
+ float PositionX;
+ float PositionY;
+ float PositionZ;
+ float Orientation;
+
+ recv_data >> guid;
+ recv_data >> unknown1;
+ recv_data >> unknown2;
+ recv_data >> PositionX;
+ recv_data >> PositionY;
+ recv_data >> PositionZ;
+ recv_data >> Orientation;
+
+ // TODO for later may be we can use for anticheat
+ DEBUG_LOG("Guid " I64FMTD,guid);
+ DEBUG_LOG("unknown1 " I64FMTD,unknown1);
+ DEBUG_LOG("unknown2 %u",unknown2);
+ DEBUG_LOG("X %f",PositionX);
+ DEBUG_LOG("Y %f",PositionY);
+ DEBUG_LOG("Z %f",PositionZ);
+ DEBUG_LOG("O %f",Orientation);
+ */
+}
+
+void WorldSession::HandleMoveRootAck(WorldPacket&/* recv_data*/)
+{
+ /*
+ CHECK_PACKET_SIZE(recv_data,8+8+4+4+4+4+4);
+
+ sLog.outDebug( "WORLD: CMSG_FORCE_MOVE_ROOT_ACK" );
+ recv_data.hexlike();
+ uint64 guid;
+ uint64 unknown1;
+ uint32 unknown2;
+ float PositionX;
+ float PositionY;
+ float PositionZ;
+ float Orientation;
+
+ recv_data >> guid;
+ recv_data >> unknown1;
+ recv_data >> unknown2;
+ recv_data >> PositionX;
+ recv_data >> PositionY;
+ recv_data >> PositionZ;
+ recv_data >> Orientation;
+
+ // for later may be we can use for anticheat
+ DEBUG_LOG("Guid " I64FMTD,guid);
+ DEBUG_LOG("unknown1 " I64FMTD,unknown1);
+ DEBUG_LOG("unknown1 %u",unknown2);
+ DEBUG_LOG("X %f",PositionX);
+ DEBUG_LOG("Y %f",PositionY);
+ DEBUG_LOG("Z %f",PositionZ);
+ DEBUG_LOG("O %f",Orientation);
+ */
+}
+
+void WorldSession::HandleMoveTeleportAck(WorldPacket&/* recv_data*/)
+{
+ /*
+ CHECK_PACKET_SIZE(recv_data,8+4);
+
+ sLog.outDebug("MSG_MOVE_TELEPORT_ACK");
+ uint64 guid;
+ uint32 flags, time;
+
+ recv_data >> guid;
+ recv_data >> flags >> time;
+ DEBUG_LOG("Guid " I64FMTD,guid);
+ DEBUG_LOG("Flags %u, time %u",flags, time/1000);
+ */
+}
+
+void WorldSession::HandleSetActionBar(WorldPacket& recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data,1);
+
+ uint8 ActionBar;
+
+ recv_data >> ActionBar;
+
+ if(!GetPlayer()) // ignore until not logged (check needed because STATUS_AUTHED)
+ {
+ if(ActionBar!=0)
+ sLog.outError("WorldSession::HandleSetActionBar in not logged state with value: %u, ignored",uint32(ActionBar));
+ return;
+ }
+
+ GetPlayer()->SetByteValue(PLAYER_FIELD_BYTES, 2, ActionBar);
+}
+
+void WorldSession::HandleWardenDataOpcode(WorldPacket& /*recv_data*/)
+{
+ /*
+ CHECK_PACKET_SIZE(recv_data,1);
+
+ uint8 tmp;
+ recv_data >> tmp;
+ sLog.outDebug("Received opcode CMSG_WARDEN_DATA, not resolve.uint8 = %u",tmp);
+ */
+}
+
+void WorldSession::HandlePlayedTime(WorldPacket& /*recv_data*/)
+{
+ uint32 TotalTimePlayed = GetPlayer()->GetTotalPlayedTime();
+ uint32 LevelPlayedTime = GetPlayer()->GetLevelPlayedTime();
+
+ WorldPacket data(SMSG_PLAYED_TIME, 8);
+ data << TotalTimePlayed;
+ data << LevelPlayedTime;
+ SendPacket(&data);
+}
+
+void WorldSession::HandleInspectOpcode(WorldPacket& recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data, 8);
+
+ uint64 guid;
+ recv_data >> guid;
+ DEBUG_LOG("Inspected guid is " I64FMTD, guid);
+
+ _player->SetSelection(guid);
+
+ Player *plr = objmgr.GetPlayer(guid);
+ if(!plr) // wrong player
+ return;
+
+ uint32 talent_points = 0x3D;
+ uint32 guid_size = plr->GetPackGUID().size();
+ WorldPacket data(SMSG_INSPECT_TALENT, 4+talent_points);
+ data.append(plr->GetPackGUID());
+ data << uint32(talent_points);
+
+ // fill by 0 talents array
+ for(uint32 i = 0; i < talent_points; ++i)
+ data << uint8(0);
+
+ if(sWorld.getConfig(CONFIG_TALENTS_INSPECTING) || _player->isGameMaster())
+ {
+ // find class talent tabs (all players have 3 talent tabs)
+ uint32 const* talentTabIds = GetTalentTabPages(plr->getClass());
+
+ uint32 talentTabPos = 0; // pos of first talent rank in tab including all prev tabs
+ for(uint32 i = 0; i < 3; ++i)
+ {
+ uint32 talentTabId = talentTabIds[i];
+
+ // fill by real data
+ for(uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
+ {
+ TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
+ if(!talentInfo)
+ continue;
+
+ // skip another tab talents
+ if(talentInfo->TalentTab != talentTabId)
+ continue;
+
+ // find talent rank
+ uint32 curtalent_maxrank = 0;
+ for(uint32 k = 5; k > 0; --k)
+ {
+ if(talentInfo->RankID[k-1] && plr->HasSpell(talentInfo->RankID[k-1]))
+ {
+ curtalent_maxrank = k;
+ break;
+ }
+ }
+
+ // not learned talent
+ if(!curtalent_maxrank)
+ continue;
+
+ // 1 rank talent bit index
+ uint32 curtalent_index = talentTabPos + GetTalentInspectBitPosInTab(talentId);
+
+ uint32 curtalent_rank_index = curtalent_index+curtalent_maxrank-1;
+
+ // slot/offset in 7-bit bytes
+ uint32 curtalent_rank_slot7 = curtalent_rank_index / 7;
+ uint32 curtalent_rank_offset7 = curtalent_rank_index % 7;
+
+ // rank pos with skipped 8 bit
+ uint32 curtalent_rank_index2 = curtalent_rank_slot7 * 8 + curtalent_rank_offset7;
+
+ // slot/offset in 8-bit bytes with skipped high bit
+ uint32 curtalent_rank_slot = curtalent_rank_index2 / 8;
+ uint32 curtalent_rank_offset = curtalent_rank_index2 % 8;
+
+ // apply mask
+ uint32 val = data.read(guid_size + 4 + curtalent_rank_slot);
+ val |= (1 << curtalent_rank_offset);
+ data.put(guid_size + 4 + curtalent_rank_slot, val & 0xFF);
+ }
+
+ talentTabPos += GetTalentTabInspectBitSize(talentTabId);
+ }
+ }
+
+ SendPacket(&data);
+}
+
+void WorldSession::HandleInspectHonorStatsOpcode(WorldPacket& recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data, 8);
+
+ uint64 guid;
+ recv_data >> guid;
+
+ Player *player = objmgr.GetPlayer(guid);
+
+ if(!player)
+ {
+ sLog.outError("InspectHonorStats: WTF, player not found...");
+ return;
+ }
+
+ WorldPacket data(MSG_INSPECT_HONOR_STATS, 8+1+4*4);
+ data << uint64(player->GetGUID());
+ data << uint8(player->GetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY));
+ data << uint32(player->GetUInt32Value(PLAYER_FIELD_KILLS));
+ data << uint32(player->GetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION));
+ data << uint32(player->GetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION));
+ data << uint32(player->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORBALE_KILLS));
+ SendPacket(&data);
+}
+
+void WorldSession::HandleWorldTeleportOpcode(WorldPacket& recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data,4+4+4+4+4+4);
+
+ // write in client console: worldport 469 452 6454 2536 180 or /console worldport 469 452 6454 2536 180
+ // Received opcode CMSG_WORLD_TELEPORT
+ // Time is ***, map=469, x=452.000000, y=6454.000000, z=2536.000000, orient=3.141593
+
+ //sLog.outDebug("Received opcode CMSG_WORLD_TELEPORT");
+
+ if(GetPlayer()->isInFlight())
+ {
+ sLog.outDebug("Player '%s' (GUID: %u) in flight, ignore worldport command.",GetPlayer()->GetName(),GetPlayer()->GetGUIDLow());
+ return;
+ }
+
+ uint32 time;
+ uint32 mapid;
+ float PositionX;
+ float PositionY;
+ float PositionZ;
+ float Orientation;
+
+ recv_data >> time; // time in m.sec.
+ recv_data >> mapid;
+ recv_data >> PositionX;
+ recv_data >> PositionY;
+ recv_data >> PositionZ;
+ recv_data >> Orientation; // o (3.141593 = 180 degrees)
+ DEBUG_LOG("Time %u sec, map=%u, x=%f, y=%f, z=%f, orient=%f", time/1000, mapid, PositionX, PositionY, PositionZ, Orientation);
+
+ if (GetSecurity() >= SEC_ADMINISTRATOR)
+ GetPlayer()->TeleportTo(mapid,PositionX,PositionY,PositionZ,Orientation);
+ else
+ SendNotification(LANG_YOU_NOT_HAVE_PERMISSION);
+ sLog.outDebug("Received worldport command from player %s", GetPlayer()->GetName());
+}
+
+void WorldSession::HandleWhoisOpcode(WorldPacket& recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data, 1);
+
+ sLog.outDebug("Received opcode CMSG_WHOIS");
+ std::string charname;
+ recv_data >> charname;
+
+ if (GetSecurity() < SEC_ADMINISTRATOR)
+ {
+ SendNotification(LANG_YOU_NOT_HAVE_PERMISSION);
+ return;
+ }
+
+ if(charname.empty())
+ {
+ SendNotification(LANG_NEED_CHARACTER_NAME);
+ return;
+ }
+
+ Player *plr = objmgr.GetPlayer(charname.c_str());
+
+ if(!plr)
+ {
+ SendNotification(LANG_PLAYER_NOT_EXIST_OR_OFFLINE, charname.c_str());
+ return;
+ }
+
+ uint32 accid = plr->GetSession()->GetAccountId();
+
+ QueryResult *result = loginDatabase.PQuery("SELECT username,email,last_ip FROM account WHERE id=%u", accid);
+ if(!result)
+ {
+ SendNotification(LANG_ACCOUNT_FOR_PLAYER_NOT_FOUND, charname.c_str());
+ return;
+ }
+
+ Field *fields = result->Fetch();
+ std::string acc = fields[0].GetCppString();
+ if(acc.empty())
+ acc = "Unknown";
+ std::string email = fields[1].GetCppString();
+ if(email.empty())
+ email = "Unknown";
+ std::string lastip = fields[2].GetCppString();
+ if(lastip.empty())
+ lastip = "Unknown";
+
+ std::string msg = charname + "'s " + "account is " + acc + ", e-mail: " + email + ", last ip: " + lastip;
+
+ WorldPacket data(SMSG_WHOIS, msg.size()+1);
+ data << msg;
+ _player->GetSession()->SendPacket(&data);
+
+ delete result;
+
+ sLog.outDebug("Received whois command from player %s for character %s", GetPlayer()->GetName(), charname.c_str());
+}
+
+void WorldSession::HandleReportSpamOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 1+8);
+ sLog.outDebug("WORLD: CMSG_REPORT_SPAM");
+ recv_data.hexlike();
+
+ uint8 spam_type; // 0 - mail, 1 - chat
+ uint64 spammer_guid;
+ uint32 unk1, unk2, unk3, unk4 = 0;
+ std::string description = "";
+ recv_data >> spam_type; // unk 0x01 const, may be spam type (mail/chat)
+ recv_data >> spammer_guid; // player guid
+ switch(spam_type)
+ {
+ case 0:
+ CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4+4+4);
+ recv_data >> unk1; // const 0
+ recv_data >> unk2; // probably mail id
+ recv_data >> unk3; // const 0
+ break;
+ case 1:
+ CHECK_PACKET_SIZE(recv_data, recv_data.rpos()+4+4+4+4+1);
+ recv_data >> unk1; // probably language
+ recv_data >> unk2; // message type?
+ recv_data >> unk3; // probably channel id
+ recv_data >> unk4; // unk random value
+ recv_data >> description; // spam description string (messagetype, channel name, player name, message)
+ break;
+ }
+
+ // NOTE: all chat messages from this spammer automatically ignored by spam reporter until logout in case chat spam.
+ // if it's mail spam - ALL mails from this spammer automatically removed by client
+
+ // Complaint Received message
+ WorldPacket data(SMSG_COMPLAIN_RESULT, 1);
+ data << uint8(0);
+ SendPacket(&data);
+
+ sLog.outDebug("REPORT SPAM: type %u, guid %u, unk1 %u, unk2 %u, unk3 %u, unk4 %u, message %s", spam_type, GUID_LOPART(spammer_guid), unk1, unk2, unk3, unk4, description.c_str());
+}
+
+void WorldSession::HandleRealmStateRequestOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 4);
+
+ sLog.outDebug("CMSG_REALM_SPLIT");
+
+ uint32 unk;
+ std::string split_date = "01/01/01";
+ recv_data >> unk;
+
+ WorldPacket data(SMSG_REALM_SPLIT, 4+4+split_date.size()+1);
+ data << unk;
+ data << uint32(0x00000000); // realm split state
+ // split states:
+ // 0x0 realm normal
+ // 0x1 realm split
+ // 0x2 realm split pending
+ data << split_date;
+ SendPacket(&data);
+ //sLog.outDebug("response sent %u", unk);
+}
+
+void WorldSession::HandleFarSightOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 1);
+
+ sLog.outDebug("WORLD: CMSG_FAR_SIGHT");
+ //recv_data.hexlike();
+
+ uint8 unk;
+ recv_data >> unk;
+
+ switch(unk)
+ {
+ case 0:
+ //WorldPacket data(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, 0)
+ //SendPacket(&data);
+ //_player->SetUInt64Value(PLAYER_FARSIGHT, 0);
+ sLog.outDebug("Removed FarSight from player %u", _player->GetGUIDLow());
+ break;
+ case 1:
+ sLog.outDebug("Added FarSight " I64FMTD " to player %u", _player->GetUInt64Value(PLAYER_FARSIGHT), _player->GetGUIDLow());
+ break;
+ }
+}
+
+void WorldSession::HandleChooseTitleOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 4);
+
+ sLog.outDebug("CMSG_SET_TITLE");
+
+ int32 title;
+ recv_data >> title;
+
+ // -1 at none
+ if(title > 0 && title < 64)
+ {
+ if(!GetPlayer()->HasFlag64(PLAYER__FIELD_KNOWN_TITLES,uint64(1) << title))
+ return;
+ }
+ else
+ title = 0;
+
+ GetPlayer()->SetUInt32Value(PLAYER_CHOSEN_TITLE, title);
+}
+
+void WorldSession::HandleAllowMoveAckOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 4+4);
+
+ sLog.outDebug("CMSG_ALLOW_MOVE_ACK");
+
+ uint32 counter, time_;
+ recv_data >> counter >> time_;
+
+ // time_ seems always more than getMSTime()
+ uint32 diff = getMSTimeDiff(getMSTime(),time_);
+
+ sLog.outDebug("response sent: counter %u, time %u (HEX: %X), ms. time %u, diff %u", counter, time_, time_, getMSTime(), diff);
+}
+
+void WorldSession::HandleResetInstancesOpcode( WorldPacket & /*recv_data*/ )
+{
+ sLog.outDebug("WORLD: CMSG_RESET_INSTANCES");
+ Group *pGroup = _player->GetGroup();
+ if(pGroup)
+ {
+ if(pGroup->IsLeader(_player->GetGUID()))
+ pGroup->ResetInstances(INSTANCE_RESET_ALL, _player);
+ }
+ else
+ _player->ResetInstances(INSTANCE_RESET_ALL);
+}
+
+void WorldSession::HandleDungeonDifficultyOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 4);
+
+ sLog.outDebug("MSG_SET_DUNGEON_DIFFICULTY");
+
+ uint32 mode;
+ recv_data >> mode;
+
+ if(mode == _player->GetDifficulty())
+ return;
+
+ if(mode > DIFFICULTY_HEROIC)
+ {
+ sLog.outError("WorldSession::HandleDungeonDifficultyOpcode: player %d sent an invalid instance mode %d!", _player->GetGUIDLow(), mode);
+ return;
+ }
+
+ // cannot reset while in an instance
+ Map *map = _player->GetMap();
+ if(map && map->IsDungeon())
+ {
+ sLog.outError("WorldSession::HandleDungeonDifficultyOpcode: player %d tried to reset the instance while inside!", _player->GetGUIDLow());
+ return;
+ }
+
+ if(_player->getLevel() < LEVELREQUIREMENT_HEROIC)
+ return;
+ Group *pGroup = _player->GetGroup();
+ if(pGroup)
+ {
+ if(pGroup->IsLeader(_player->GetGUID()))
+ {
+ // the difficulty is set even if the instances can't be reset
+ //_player->SendDungeonDifficulty(true);
+ pGroup->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY, _player);
+ pGroup->SetDifficulty(mode);
+ }
+ }
+ else
+ {
+ _player->ResetInstances(INSTANCE_RESET_CHANGE_DIFFICULTY);
+ _player->SetDifficulty(mode);
+ }
+}
+
+void WorldSession::HandleNewUnknownOpcode( WorldPacket & recv_data )
+{
+ sLog.outDebug("New Unknown Opcode %u", recv_data.GetOpcode());
+ recv_data.hexlike();
+ /*
+ New Unknown Opcode 837
+ STORAGE_SIZE: 60
+ 02 00 00 00 00 00 00 00 | 00 00 00 00 01 20 00 00
+ 89 EB 33 01 71 5C 24 C4 | 15 03 35 45 74 47 8B 42
+ BA B8 1B 40 00 00 00 00 | 00 00 00 00 77 66 42 BF
+ 23 91 26 3F 00 00 60 41 | 00 00 00 00
+
+ New Unknown Opcode 837
+ STORAGE_SIZE: 44
+ 02 00 00 00 00 00 00 00 | 00 00 00 00 00 00 80 00
+ 7B 80 34 01 84 EA 2B C4 | 5F A1 36 45 C9 39 1C 42
+ BA B8 1B 40 CE 06 00 00 | 00 00 80 3F
+ */
+}
+
+void WorldSession::HandleDismountOpcode( WorldPacket & /*recv_data*/ )
+{
+ sLog.outDebug("WORLD: CMSG_CANCEL_MOUNT_AURA");
+ //recv_data.hexlike();
+
+ //If player is not mounted, so go out :)
+ if (!_player->IsMounted()) // not blizz like; no any messages on blizz
+ {
+ ChatHandler(this).SendSysMessage(LANG_CHAR_NON_MOUNTED);
+ return;
+ }
+
+ if(_player->isInFlight()) // not blizz like; no any messages on blizz
+ {
+ ChatHandler(this).SendSysMessage(LANG_YOU_IN_FLIGHT);
+ return;
+ }
+
+ _player->Unmount();
+ _player->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
+}
+
+void WorldSession::HandleMoveFlyModeChangeAckOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 8+4+4);
+
+ // fly mode on/off
+ sLog.outDebug("WORLD: CMSG_MOVE_SET_CAN_FLY_ACK");
+ //recv_data.hexlike();
+
+ uint64 guid;
+ uint32 unk;
+ uint32 flags;
+
+ recv_data >> guid >> unk >> flags;
+
+ _player->SetUnitMovementFlags(flags);
+ /*
+ on:
+ 25 00 00 00 00 00 00 00 | 00 00 00 00 00 00 80 00
+ 85 4E A9 01 19 BA 7A C3 | 42 0D 70 44 44 B0 A8 42
+ 78 15 94 40 39 03 00 00 | 00 00 80 3F
+ off:
+ 25 00 00 00 00 00 00 00 | 00 00 00 00 00 00 00 00
+ 10 FD A9 01 19 BA 7A C3 | 42 0D 70 44 44 B0 A8 42
+ 78 15 94 40 39 03 00 00 | 00 00 00 00
+ */
+}
+
+void WorldSession::HandleRequestPetInfoOpcode( WorldPacket & /*recv_data */)
+{
+ /*
+ sLog.outDebug("WORLD: CMSG_REQUEST_PET_INFO");
+ recv_data.hexlike();
+ */
+}
+
+void WorldSession::HandleSetTaxiBenchmarkOpcode( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data, 1);
+
+ uint8 mode;
+ recv_data >> mode;
+
+ sLog.outDebug("Client used \"/timetest %d\" command", mode);
+}
diff --git a/src/game/MotionMaster.cpp b/src/game/MotionMaster.cpp
index cf910bf50b2..2a5cc05e986 100644
--- a/src/game/MotionMaster.cpp
+++ b/src/game/MotionMaster.cpp
@@ -1,342 +1,342 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS
- *
- * 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 "MotionMaster.h"
-#include "CreatureAISelector.h"
-#include "Creature.h"
-#include "Traveller.h"
-
-#include "ConfusedMovementGenerator.h"
-#include "FleeingMovementGenerator.h"
-#include "HomeMovementGenerator.h"
-#include "IdleMovementGenerator.h"
-#include "PointMovementGenerator.h"
-#include "TargetedMovementGenerator.h"
-#include "WaypointMovementGenerator.h"
-
-#include
-
-inline bool isStatic(MovementGenerator *mv)
-{
- return (mv == &si_idleMovement);
-}
-
-void
-MotionMaster::Initialize()
-{
- // clear ALL movement generators (including default)
- while(!empty())
- {
- MovementGenerator *curr = top();
- curr->Finalize(*i_owner);
- pop();
- if( !isStatic( curr ) )
- delete curr;
- }
-
- // set new default movement generator
- if(i_owner->GetTypeId() == TYPEID_UNIT)
- {
- MovementGenerator* movement = FactorySelector::selectMovementGenerator((Creature*)i_owner);
- push( movement == NULL ? &si_idleMovement : movement );
- top()->Initialize(*i_owner);
- }
- else
- push(&si_idleMovement);
-}
-
-MotionMaster::~MotionMaster()
-{
- // clear ALL movement generators (including default)
- while(!empty())
- {
- MovementGenerator *curr = top();
- curr->Finalize(*i_owner);
- pop();
- if( !isStatic( curr ) )
- delete curr;
- }
-}
-
-void
-MotionMaster::UpdateMotion(const uint32 &diff)
-{
- if( i_owner->hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED) )
- return;
- assert( !empty() );
- if (!top()->Update(*i_owner, diff))
- MovementExpired();
-}
-
-void
-MotionMaster::Clear(bool reset)
-{
- while( !empty() && size() > 1 )
- {
- MovementGenerator *curr = top();
- curr->Finalize(*i_owner);
- pop();
- if( !isStatic( curr ) )
- delete curr;
- }
-
- if (reset)
- {
- assert( !empty() );
- top()->Reset(*i_owner);
- }
-}
-
-void
-MotionMaster::MovementExpired(bool reset)
-{
- if( empty() || size() == 1 )
- return;
-
- MovementGenerator *curr = top();
- curr->Finalize(*i_owner);
- pop();
-
- if( !isStatic(curr) )
- delete curr;
-
- assert( !empty() );
- while( !empty() && top()->GetMovementGeneratorType() == TARGETED_MOTION_TYPE )
- {
- // Should check if target is still valid? If not valid it will crash.
- curr = top();
- curr->Finalize(*i_owner);
- pop();
- delete curr;
- }
- if( empty() )
- Initialize();
- if (reset) top()->Reset(*i_owner);
-}
-
-void MotionMaster::MoveIdle()
-{
- if( empty() || !isStatic( top() ) )
- push( &si_idleMovement );
-}
-
-void
-MotionMaster::MoveTargetedHome()
-{
- if(i_owner->hasUnitState(UNIT_STAT_FLEEING))
- return;
-
- Clear(false);
-
- if(i_owner->GetTypeId()==TYPEID_UNIT && !((Creature*)i_owner)->GetCharmerOrOwnerGUID())
- {
- DEBUG_LOG("Creature (Entry: %u GUID: %u) targeted home", i_owner->GetEntry(), i_owner->GetGUIDLow());
- Mutate(new HomeMovementGenerator());
- }
- else if(i_owner->GetTypeId()==TYPEID_UNIT && ((Creature*)i_owner)->GetCharmerOrOwnerGUID())
- {
- sLog.outError("Pet or controlled creature (Entry: %u GUID: %u) attempt targeted home",
- i_owner->GetEntry(), i_owner->GetGUIDLow() );
- }
- else
- {
- sLog.outError("Player (GUID: %u) attempt targeted home", i_owner->GetGUIDLow() );
- }
-}
-
-void
-MotionMaster::MoveConfused()
-{
- if(i_owner->GetTypeId()==TYPEID_PLAYER)
- {
- DEBUG_LOG("Player (GUID: %u) move confused", i_owner->GetGUIDLow() );
- Mutate(new ConfusedMovementGenerator());
- }
- else
- {
- DEBUG_LOG("Creature (Entry: %u GUID: %u) move confused",
- i_owner->GetEntry(), i_owner->GetGUIDLow() );
- Mutate(new ConfusedMovementGenerator());
- }
-}
-
-void
-MotionMaster::MoveChase(Unit* target, float dist, float angle)
-{
- // ignore movement request if target not exist
- if(!target)
- return;
-
- i_owner->clearUnitState(UNIT_STAT_FOLLOW);
- if(i_owner->GetTypeId()==TYPEID_PLAYER)
- {
- DEBUG_LOG("Player (GUID: %u) chase to %s (GUID: %u)",
- target->GetTypeId()==TYPEID_PLAYER ? "player" : "creature",
- target->GetTypeId()==TYPEID_PLAYER ? i_owner->GetGUIDLow() : ((Creature*)i_owner)->GetDBTableGUIDLow() );
- Mutate(new TargetedMovementGenerator(*target,dist,angle));
- }
- else
- {
- DEBUG_LOG("Creature (Entry: %u GUID: %u) chase to %s (GUID: %u)",
- i_owner->GetEntry(), i_owner->GetGUIDLow(),
- target->GetTypeId()==TYPEID_PLAYER ? "player" : "creature",
- target->GetTypeId()==TYPEID_PLAYER ? target->GetGUIDLow() : ((Creature*)target)->GetDBTableGUIDLow() );
- Mutate(new TargetedMovementGenerator(*target,dist,angle));
- }
-}
-
-void
-MotionMaster::MoveFollow(Unit* target, float dist, float angle)
-{
- Clear();
-
- // ignore movement request if target not exist
- if(!target)
- return;
-
- i_owner->addUnitState(UNIT_STAT_FOLLOW);
- if(i_owner->GetTypeId()==TYPEID_PLAYER)
- {
- DEBUG_LOG("Player (GUID: %u) follow to %s (GUID: %u)", i_owner->GetGUIDLow(),
- target->GetTypeId()==TYPEID_PLAYER ? "player" : "creature",
- target->GetTypeId()==TYPEID_PLAYER ? i_owner->GetGUIDLow() : ((Creature*)i_owner)->GetDBTableGUIDLow() );
- Mutate(new TargetedMovementGenerator(*target,dist,angle));
- }
- else
- {
- DEBUG_LOG("Creature (Entry: %u GUID: %u) follow to %s (GUID: %u)",
- i_owner->GetEntry(), i_owner->GetGUIDLow(),
- target->GetTypeId()==TYPEID_PLAYER ? "player" : "creature",
- target->GetTypeId()==TYPEID_PLAYER ? target->GetGUIDLow() : ((Creature*)target)->GetDBTableGUIDLow() );
- Mutate(new TargetedMovementGenerator(*target,dist,angle));
- }
-}
-
-void
-MotionMaster::MovePoint(uint32 id, float x, float y, float z)
-{
- if(i_owner->GetTypeId()==TYPEID_PLAYER)
- {
- DEBUG_LOG("Player (GUID: %u) targeted point (Id: %u X: %f Y: %f Z: %f)", i_owner->GetGUIDLow(), id, x, y, z );
- Mutate(new PointMovementGenerator(id,x,y,z));
- }
- else
- {
- DEBUG_LOG("Creature (Entry: %u GUID: %u) targeted point (ID: %u X: %f Y: %f Z: %f)",
- i_owner->GetEntry(), i_owner->GetGUIDLow(), id, x, y, z );
- Mutate(new PointMovementGenerator(id,x,y,z));
- }
-}
-
-void
-MotionMaster::MoveFleeing(Unit* enemy)
-{
- if(!enemy)
- return;
-
- if(i_owner->GetTypeId()==TYPEID_PLAYER)
- {
- DEBUG_LOG("Player (GUID: %u) flee from %s (GUID: %u)", i_owner->GetGUIDLow(),
- enemy->GetTypeId()==TYPEID_PLAYER ? "player" : "creature",
- enemy->GetTypeId()==TYPEID_PLAYER ? enemy->GetGUIDLow() : ((Creature*)enemy)->GetDBTableGUIDLow() );
- Mutate(new FleeingMovementGenerator(enemy->GetGUID()));
- }
- else
- {
- DEBUG_LOG("Creature (Entry: %u GUID: %u) flee from %s (GUID: %u)",
- i_owner->GetEntry(), i_owner->GetGUIDLow(),
- enemy->GetTypeId()==TYPEID_PLAYER ? "player" : "creature",
- enemy->GetTypeId()==TYPEID_PLAYER ? enemy->GetGUIDLow() : ((Creature*)enemy)->GetDBTableGUIDLow() );
- Mutate(new FleeingMovementGenerator(enemy->GetGUID()));
- }
-}
-
-void
-MotionMaster::MoveTaxiFlight(uint32 path, uint32 pathnode)
-{
- if(i_owner->GetTypeId()==TYPEID_PLAYER)
- {
- DEBUG_LOG("Player (GUID: %u) taxi to (Path %u node %u)", i_owner->GetGUIDLow(), path, pathnode);
- FlightPathMovementGenerator* mgen = new FlightPathMovementGenerator(path,pathnode);
- Mutate(mgen);
- }
- else
- {
- sLog.outError("Creature (Entry: %u GUID: %u) attempt taxi to (Path %u node %u)",
- i_owner->GetEntry(), i_owner->GetGUIDLow(), path, pathnode );
- }
-}
-
-void
-MotionMaster::MoveDistract(uint32 timer)
-{
- if(i_owner->GetTypeId()==TYPEID_PLAYER)
- {
- DEBUG_LOG("Player (GUID: %u) distracted (timer: %u)", i_owner->GetGUIDLow(), timer);
- }
- else
- {
- DEBUG_LOG("Creature (Entry: %u GUID: %u) (timer: %u)",
- i_owner->GetEntry(), i_owner->GetGUIDLow(), timer);
- }
-
- DistractMovementGenerator* mgen = new DistractMovementGenerator(timer);
- Mutate(mgen);
-}
-
-void MotionMaster::Mutate(MovementGenerator *m)
-{
- if (!empty())
- {
- switch(top()->GetMovementGeneratorType())
- {
- // HomeMovement is not that important, delete it if meanwhile a new comes
- case HOME_MOTION_TYPE:
- // DistractMovement interrupted by any other movement
- case DISTRACT_MOTION_TYPE:
- MovementExpired(false);
- }
- }
- m->Initialize(*i_owner);
- push(m);
-}
-
-void MotionMaster::propagateSpeedChange()
-{
- Impl::container_type::iterator it = Impl::c.begin();
- for ( ;it != end(); ++it)
- {
- (*it)->unitSpeedChanged();
- }
-}
-
-MovementGeneratorType MotionMaster::GetCurrentMovementGeneratorType() const
-{
- if(empty())
- return IDLE_MOTION_TYPE;
-
- return top()->GetMovementGeneratorType();
-}
-
-bool MotionMaster::GetDestination(float &x, float &y, float &z)
-{
- if(empty())
- return false;
-
- return top()->GetDestination(x,y,z);
-}
+/*
+ * Copyright (C) 2005-2008 MaNGOS
+ *
+ * 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 "MotionMaster.h"
+#include "CreatureAISelector.h"
+#include "Creature.h"
+#include "Traveller.h"
+
+#include "ConfusedMovementGenerator.h"
+#include "FleeingMovementGenerator.h"
+#include "HomeMovementGenerator.h"
+#include "IdleMovementGenerator.h"
+#include "PointMovementGenerator.h"
+#include "TargetedMovementGenerator.h"
+#include "WaypointMovementGenerator.h"
+
+#include
+
+inline bool isStatic(MovementGenerator *mv)
+{
+ return (mv == &si_idleMovement);
+}
+
+void
+MotionMaster::Initialize()
+{
+ // clear ALL movement generators (including default)
+ while(!empty())
+ {
+ MovementGenerator *curr = top();
+ curr->Finalize(*i_owner);
+ pop();
+ if( !isStatic( curr ) )
+ delete curr;
+ }
+
+ // set new default movement generator
+ if(i_owner->GetTypeId() == TYPEID_UNIT)
+ {
+ MovementGenerator* movement = FactorySelector::selectMovementGenerator((Creature*)i_owner);
+ push( movement == NULL ? &si_idleMovement : movement );
+ top()->Initialize(*i_owner);
+ }
+ else
+ push(&si_idleMovement);
+}
+
+MotionMaster::~MotionMaster()
+{
+ // clear ALL movement generators (including default)
+ while(!empty())
+ {
+ MovementGenerator *curr = top();
+ curr->Finalize(*i_owner);
+ pop();
+ if( !isStatic( curr ) )
+ delete curr;
+ }
+}
+
+void
+MotionMaster::UpdateMotion(const uint32 &diff)
+{
+ if( i_owner->hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED) )
+ return;
+ assert( !empty() );
+ if (!top()->Update(*i_owner, diff))
+ MovementExpired();
+}
+
+void
+MotionMaster::Clear(bool reset)
+{
+ while( !empty() && size() > 1 )
+ {
+ MovementGenerator *curr = top();
+ curr->Finalize(*i_owner);
+ pop();
+ if( !isStatic( curr ) )
+ delete curr;
+ }
+
+ if (reset)
+ {
+ assert( !empty() );
+ top()->Reset(*i_owner);
+ }
+}
+
+void
+MotionMaster::MovementExpired(bool reset)
+{
+ if( empty() || size() == 1 )
+ return;
+
+ MovementGenerator *curr = top();
+ curr->Finalize(*i_owner);
+ pop();
+
+ if( !isStatic(curr) )
+ delete curr;
+
+ assert( !empty() );
+ while( !empty() && top()->GetMovementGeneratorType() == TARGETED_MOTION_TYPE )
+ {
+ // Should check if target is still valid? If not valid it will crash.
+ curr = top();
+ curr->Finalize(*i_owner);
+ pop();
+ delete curr;
+ }
+ if( empty() )
+ Initialize();
+ if (reset) top()->Reset(*i_owner);
+}
+
+void MotionMaster::MoveIdle()
+{
+ if( empty() || !isStatic( top() ) )
+ push( &si_idleMovement );
+}
+
+void
+MotionMaster::MoveTargetedHome()
+{
+ if(i_owner->hasUnitState(UNIT_STAT_FLEEING))
+ return;
+
+ Clear(false);
+
+ if(i_owner->GetTypeId()==TYPEID_UNIT && !((Creature*)i_owner)->GetCharmerOrOwnerGUID())
+ {
+ DEBUG_LOG("Creature (Entry: %u GUID: %u) targeted home", i_owner->GetEntry(), i_owner->GetGUIDLow());
+ Mutate(new HomeMovementGenerator());
+ }
+ else if(i_owner->GetTypeId()==TYPEID_UNIT && ((Creature*)i_owner)->GetCharmerOrOwnerGUID())
+ {
+ sLog.outError("Pet or controlled creature (Entry: %u GUID: %u) attempt targeted home",
+ i_owner->GetEntry(), i_owner->GetGUIDLow() );
+ }
+ else
+ {
+ sLog.outError("Player (GUID: %u) attempt targeted home", i_owner->GetGUIDLow() );
+ }
+}
+
+void
+MotionMaster::MoveConfused()
+{
+ if(i_owner->GetTypeId()==TYPEID_PLAYER)
+ {
+ DEBUG_LOG("Player (GUID: %u) move confused", i_owner->GetGUIDLow() );
+ Mutate(new ConfusedMovementGenerator());
+ }
+ else
+ {
+ DEBUG_LOG("Creature (Entry: %u GUID: %u) move confused",
+ i_owner->GetEntry(), i_owner->GetGUIDLow() );
+ Mutate(new ConfusedMovementGenerator());
+ }
+}
+
+void
+MotionMaster::MoveChase(Unit* target, float dist, float angle)
+{
+ // ignore movement request if target not exist
+ if(!target)
+ return;
+
+ i_owner->clearUnitState(UNIT_STAT_FOLLOW);
+ if(i_owner->GetTypeId()==TYPEID_PLAYER)
+ {
+ DEBUG_LOG("Player (GUID: %u) chase to %s (GUID: %u)",
+ target->GetTypeId()==TYPEID_PLAYER ? "player" : "creature",
+ target->GetTypeId()==TYPEID_PLAYER ? i_owner->GetGUIDLow() : ((Creature*)i_owner)->GetDBTableGUIDLow() );
+ Mutate(new TargetedMovementGenerator(*target,dist,angle));
+ }
+ else
+ {
+ DEBUG_LOG("Creature (Entry: %u GUID: %u) chase to %s (GUID: %u)",
+ i_owner->GetEntry(), i_owner->GetGUIDLow(),
+ target->GetTypeId()==TYPEID_PLAYER ? "player" : "creature",
+ target->GetTypeId()==TYPEID_PLAYER ? target->GetGUIDLow() : ((Creature*)target)->GetDBTableGUIDLow() );
+ Mutate(new TargetedMovementGenerator(*target,dist,angle));
+ }
+}
+
+void
+MotionMaster::MoveFollow(Unit* target, float dist, float angle)
+{
+ Clear();
+
+ // ignore movement request if target not exist
+ if(!target)
+ return;
+
+ i_owner->addUnitState(UNIT_STAT_FOLLOW);
+ if(i_owner->GetTypeId()==TYPEID_PLAYER)
+ {
+ DEBUG_LOG("Player (GUID: %u) follow to %s (GUID: %u)", i_owner->GetGUIDLow(),
+ target->GetTypeId()==TYPEID_PLAYER ? "player" : "creature",
+ target->GetTypeId()==TYPEID_PLAYER ? i_owner->GetGUIDLow() : ((Creature*)i_owner)->GetDBTableGUIDLow() );
+ Mutate(new TargetedMovementGenerator(*target,dist,angle));
+ }
+ else
+ {
+ DEBUG_LOG("Creature (Entry: %u GUID: %u) follow to %s (GUID: %u)",
+ i_owner->GetEntry(), i_owner->GetGUIDLow(),
+ target->GetTypeId()==TYPEID_PLAYER ? "player" : "creature",
+ target->GetTypeId()==TYPEID_PLAYER ? target->GetGUIDLow() : ((Creature*)target)->GetDBTableGUIDLow() );
+ Mutate(new TargetedMovementGenerator(*target,dist,angle));
+ }
+}
+
+void
+MotionMaster::MovePoint(uint32 id, float x, float y, float z)
+{
+ if(i_owner->GetTypeId()==TYPEID_PLAYER)
+ {
+ DEBUG_LOG("Player (GUID: %u) targeted point (Id: %u X: %f Y: %f Z: %f)", i_owner->GetGUIDLow(), id, x, y, z );
+ Mutate(new PointMovementGenerator(id,x,y,z));
+ }
+ else
+ {
+ DEBUG_LOG("Creature (Entry: %u GUID: %u) targeted point (ID: %u X: %f Y: %f Z: %f)",
+ i_owner->GetEntry(), i_owner->GetGUIDLow(), id, x, y, z );
+ Mutate(new PointMovementGenerator(id,x,y,z));
+ }
+}
+
+void
+MotionMaster::MoveFleeing(Unit* enemy)
+{
+ if(!enemy)
+ return;
+
+ if(i_owner->GetTypeId()==TYPEID_PLAYER)
+ {
+ DEBUG_LOG("Player (GUID: %u) flee from %s (GUID: %u)", i_owner->GetGUIDLow(),
+ enemy->GetTypeId()==TYPEID_PLAYER ? "player" : "creature",
+ enemy->GetTypeId()==TYPEID_PLAYER ? enemy->GetGUIDLow() : ((Creature*)enemy)->GetDBTableGUIDLow() );
+ Mutate(new FleeingMovementGenerator(enemy->GetGUID()));
+ }
+ else
+ {
+ DEBUG_LOG("Creature (Entry: %u GUID: %u) flee from %s (GUID: %u)",
+ i_owner->GetEntry(), i_owner->GetGUIDLow(),
+ enemy->GetTypeId()==TYPEID_PLAYER ? "player" : "creature",
+ enemy->GetTypeId()==TYPEID_PLAYER ? enemy->GetGUIDLow() : ((Creature*)enemy)->GetDBTableGUIDLow() );
+ Mutate(new FleeingMovementGenerator(enemy->GetGUID()));
+ }
+}
+
+void
+MotionMaster::MoveTaxiFlight(uint32 path, uint32 pathnode)
+{
+ if(i_owner->GetTypeId()==TYPEID_PLAYER)
+ {
+ DEBUG_LOG("Player (GUID: %u) taxi to (Path %u node %u)", i_owner->GetGUIDLow(), path, pathnode);
+ FlightPathMovementGenerator* mgen = new FlightPathMovementGenerator(path,pathnode);
+ Mutate(mgen);
+ }
+ else
+ {
+ sLog.outError("Creature (Entry: %u GUID: %u) attempt taxi to (Path %u node %u)",
+ i_owner->GetEntry(), i_owner->GetGUIDLow(), path, pathnode );
+ }
+}
+
+void
+MotionMaster::MoveDistract(uint32 timer)
+{
+ if(i_owner->GetTypeId()==TYPEID_PLAYER)
+ {
+ DEBUG_LOG("Player (GUID: %u) distracted (timer: %u)", i_owner->GetGUIDLow(), timer);
+ }
+ else
+ {
+ DEBUG_LOG("Creature (Entry: %u GUID: %u) (timer: %u)",
+ i_owner->GetEntry(), i_owner->GetGUIDLow(), timer);
+ }
+
+ DistractMovementGenerator* mgen = new DistractMovementGenerator(timer);
+ Mutate(mgen);
+}
+
+void MotionMaster::Mutate(MovementGenerator *m)
+{
+ if (!empty())
+ {
+ switch(top()->GetMovementGeneratorType())
+ {
+ // HomeMovement is not that important, delete it if meanwhile a new comes
+ case HOME_MOTION_TYPE:
+ // DistractMovement interrupted by any other movement
+ case DISTRACT_MOTION_TYPE:
+ MovementExpired(false);
+ }
+ }
+ m->Initialize(*i_owner);
+ push(m);
+}
+
+void MotionMaster::propagateSpeedChange()
+{
+ Impl::container_type::iterator it = Impl::c.begin();
+ for ( ;it != end(); ++it)
+ {
+ (*it)->unitSpeedChanged();
+ }
+}
+
+MovementGeneratorType MotionMaster::GetCurrentMovementGeneratorType() const
+{
+ if(empty())
+ return IDLE_MOTION_TYPE;
+
+ return top()->GetMovementGeneratorType();
+}
+
+bool MotionMaster::GetDestination(float &x, float &y, float &z)
+{
+ if(empty())
+ return false;
+
+ return top()->GetDestination(x,y,z);
+}
diff --git a/src/game/Object.cpp b/src/game/Object.cpp
index 7266d5612e7..1b690902023 100644
--- a/src/game/Object.cpp
+++ b/src/game/Object.cpp
@@ -1,1447 +1,1447 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS
- *
- * 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 "SharedDefines.h"
-#include "WorldPacket.h"
-#include "Opcodes.h"
-#include "Log.h"
-#include "World.h"
-#include "Object.h"
-#include "Creature.h"
-#include "Player.h"
-#include "ObjectMgr.h"
-#include "WorldSession.h"
-#include "UpdateData.h"
-#include "UpdateMask.h"
-#include "Util.h"
-#include "MapManager.h"
-#include "ObjectAccessor.h"
-#include "Log.h"
-#include "Transports.h"
-#include "TargetedMovementGenerator.h"
-#include "WaypointMovementGenerator.h"
-#include "VMapFactory.h"
-#include "CellImpl.h"
-#include "GridNotifiers.h"
-#include "GridNotifiersImpl.h"
-
-#include "TemporarySummon.h"
-
-uint32 GuidHigh2TypeId(uint32 guid_hi)
-{
- switch(guid_hi)
- {
- case HIGHGUID_ITEM: return TYPEID_ITEM;
- //case HIGHGUID_CONTAINER: return TYPEID_CONTAINER; HIGHGUID_CONTAINER==HIGHGUID_ITEM currently
- case HIGHGUID_UNIT: return TYPEID_UNIT;
- case HIGHGUID_PET: return TYPEID_UNIT;
- case HIGHGUID_PLAYER: return TYPEID_PLAYER;
- case HIGHGUID_GAMEOBJECT: return TYPEID_GAMEOBJECT;
- case HIGHGUID_DYNAMICOBJECT:return TYPEID_DYNAMICOBJECT;
- case HIGHGUID_CORPSE: return TYPEID_CORPSE;
- case HIGHGUID_MO_TRANSPORT: return TYPEID_GAMEOBJECT;
- }
- return 10; // unknown
-}
-
-Object::Object( )
-{
- m_objectTypeId = TYPEID_OBJECT;
- m_objectType = TYPEMASK_OBJECT;
-
- m_uint32Values = 0;
- m_uint32Values_mirror = 0;
- m_valuesCount = 0;
-
- m_inWorld = false;
- m_objectUpdated = false;
-
- m_PackGUID.clear();
- m_PackGUID.appendPackGUID(0);
-}
-
-Object::~Object( )
-{
- if(m_objectUpdated)
- ObjectAccessor::Instance().RemoveUpdateObject(this);
-
- if(m_uint32Values)
- {
- if(IsInWorld())
- {
- ///- Do NOT call RemoveFromWorld here, if the object is a player it will crash
- sLog.outError("Object::~Object - guid="I64FMTD", typeid=%d deleted but still in world!!", GetGUID(), GetTypeId());
- //assert(0);
- }
-
- //DEBUG_LOG("Object desctr 1 check (%p)",(void*)this);
- delete [] m_uint32Values;
- delete [] m_uint32Values_mirror;
- //DEBUG_LOG("Object desctr 2 check (%p)",(void*)this);
- }
-}
-
-void Object::_InitValues()
-{
- m_uint32Values = new uint32[ m_valuesCount ];
- memset(m_uint32Values, 0, m_valuesCount*sizeof(uint32));
-
- m_uint32Values_mirror = new uint32[ m_valuesCount ];
- memset(m_uint32Values_mirror, 0, m_valuesCount*sizeof(uint32));
-
- m_objectUpdated = false;
-}
-
-void Object::_Create( uint32 guidlow, uint32 entry, HighGuid guidhigh )
-{
- if(!m_uint32Values) _InitValues();
-
- uint64 guid = MAKE_NEW_GUID(guidlow, entry, guidhigh); // required more changes to make it working
- SetUInt64Value( OBJECT_FIELD_GUID, guid );
- SetUInt32Value( OBJECT_FIELD_TYPE, m_objectType );
- m_PackGUID.clear();
- m_PackGUID.appendPackGUID(GetGUID());
-}
-
-void Object::BuildMovementUpdateBlock(UpdateData * data, uint32 flags ) const
-{
- ByteBuffer buf(500);
-
- buf << uint8( UPDATETYPE_MOVEMENT );
- buf << GetGUID();
-
- _BuildMovementUpdate(&buf, flags, 0x00000000);
-
- data->AddUpdateBlock(buf);
-}
-
-void Object::BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const
-{
- if(!target)
- {
- return;
- }
-
- uint8 updatetype = UPDATETYPE_CREATE_OBJECT;
- uint8 flags = m_updateFlag;
- uint32 flags2 = 0;
-
- /** lower flag1 **/
- if(target == this) // building packet for oneself
- {
- flags |= UPDATEFLAG_SELF;
-
- /*** temporary reverted - until real source of stack corruption will not found
- updatetype = UPDATETYPE_CREATE_OBJECT2;
- ****/
- }
-
- if(flags & UPDATEFLAG_HASPOSITION)
- {
- // UPDATETYPE_CREATE_OBJECT2 dynamic objects, corpses...
- if(isType(TYPEMASK_DYNAMICOBJECT) || isType(TYPEMASK_CORPSE) || isType(TYPEMASK_PLAYER))
- updatetype = UPDATETYPE_CREATE_OBJECT2;
-
- // UPDATETYPE_CREATE_OBJECT2 for pets...
- if(target->GetPetGUID() == GetGUID())
- updatetype = UPDATETYPE_CREATE_OBJECT2;
-
- // UPDATETYPE_CREATE_OBJECT2 for some gameobject types...
- if(isType(TYPEMASK_GAMEOBJECT))
- {
- switch(((GameObject*)this)->GetGoType())
- {
- case GAMEOBJECT_TYPE_TRAP:
- case GAMEOBJECT_TYPE_DUEL_ARBITER:
- case GAMEOBJECT_TYPE_FLAGSTAND:
- case GAMEOBJECT_TYPE_FLAGDROP:
- updatetype = UPDATETYPE_CREATE_OBJECT2;
- break;
- case GAMEOBJECT_TYPE_TRANSPORT:
- flags |= UPDATEFLAG_TRANSPORT;
- break;
- }
- }
- }
-
- //sLog.outDebug("BuildCreateUpdate: update-type: %u, object-type: %u got flags: %X, flags2: %X", updatetype, m_objectTypeId, flags, flags2);
-
- ByteBuffer buf(500);
- buf << (uint8)updatetype;
- //buf.append(GetPackGUID()); //client crashes when using this
- buf << (uint8)0xFF << GetGUID();
- buf << (uint8)m_objectTypeId;
-
- _BuildMovementUpdate(&buf, flags, flags2);
-
- UpdateMask updateMask;
- updateMask.SetCount( m_valuesCount );
- _SetCreateBits( &updateMask, target );
- _BuildValuesUpdate(updatetype, &buf, &updateMask, target );
- data->AddUpdateBlock(buf);
-}
-
-void Object::BuildUpdate(UpdateDataMapType &update_players)
-{
- ObjectAccessor::_buildUpdateObject(this,update_players);
- ClearUpdateMask(true);
-}
-
-void Object::SendUpdateToPlayer(Player* player)
-{
- // send update to another players
- SendUpdateObjectToAllExcept(player);
-
- // send create update to player
- UpdateData upd;
- WorldPacket packet;
-
- upd.Clear();
- BuildCreateUpdateBlockForPlayer(&upd, player);
- upd.BuildPacket(&packet);
- player->GetSession()->SendPacket(&packet);
-
- // now object updated/(create updated)
-}
-
-void Object::BuildValuesUpdateBlockForPlayer(UpdateData *data, Player *target) const
-{
- ByteBuffer buf(500);
-
- buf << (uint8) UPDATETYPE_VALUES;
- //buf.append(GetPackGUID()); //client crashes when using this. but not have crash in debug mode
- buf << (uint8)0xFF;
- buf << GetGUID();
-
- UpdateMask updateMask;
- updateMask.SetCount( m_valuesCount );
-
- _SetUpdateBits( &updateMask, target );
- _BuildValuesUpdate(UPDATETYPE_VALUES, &buf, &updateMask, target );
-
- data->AddUpdateBlock(buf);
-}
-
-void Object::BuildOutOfRangeUpdateBlock(UpdateData * data) const
-{
- data->AddOutOfRangeGUID(GetGUID());
-}
-
-void Object::DestroyForPlayer(Player *target) const
-{
- ASSERT(target);
-
- WorldPacket data(SMSG_DESTROY_OBJECT, 8);
- data << GetGUID();
- target->GetSession()->SendPacket( &data );
-}
-
-void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2 ) const
-{
- *data << (uint8)flags; // update flags
-
- // 0x20
- if (flags & UPDATEFLAG_LIVING)
- {
- switch(GetTypeId())
- {
- case TYPEID_UNIT:
- {
- flags2 = ((Unit*)this)->GetUnitMovementFlags();
- }
- break;
- case TYPEID_PLAYER:
- {
- flags2 = ((Player*)this)->GetUnitMovementFlags();
-
- if(((Player*)this)->GetTransport())
- flags2 |= MOVEMENTFLAG_ONTRANSPORT;
- else
- flags2 &= ~MOVEMENTFLAG_ONTRANSPORT;
-
- // remove unknown, unused etc flags for now
- flags2 &= ~MOVEMENTFLAG_SPLINE2; // will be set manually
-
- if(((Player*)this)->isInFlight())
- {
- WPAssert(((Player*)this)->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE);
- flags2 = (MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_SPLINE2);
- }
- }
- break;
- }
-
- *data << uint32(flags2); // movement flags
- *data << uint8(0); // unk 2.3.0
- *data << uint32(getMSTime()); // time (in milliseconds)
- }
-
- // 0x40
- if (flags & UPDATEFLAG_HASPOSITION)
- {
- // 0x02
- if(flags & UPDATEFLAG_TRANSPORT && ((GameObject*)this)->GetGoType() == GAMEOBJECT_TYPE_MO_TRANSPORT)
- {
- *data << (float)0;
- *data << (float)0;
- *data << (float)0;
- *data << ((WorldObject *)this)->GetOrientation();
- }
- else
- {
- *data << ((WorldObject *)this)->GetPositionX();
- *data << ((WorldObject *)this)->GetPositionY();
- *data << ((WorldObject *)this)->GetPositionZ();
- *data << ((WorldObject *)this)->GetOrientation();
- }
- }
-
- // 0x20
- if(flags & UPDATEFLAG_LIVING)
- {
- // 0x00000200
- if(flags2 & MOVEMENTFLAG_ONTRANSPORT)
- {
- if(GetTypeId() == TYPEID_PLAYER)
- {
- *data << (uint64)((Player*)this)->GetTransport()->GetGUID();
- *data << (float)((Player*)this)->GetTransOffsetX();
- *data << (float)((Player*)this)->GetTransOffsetY();
- *data << (float)((Player*)this)->GetTransOffsetZ();
- *data << (float)((Player*)this)->GetTransOffsetO();
- *data << (uint32)((Player*)this)->GetTransTime();
- }
- //MaNGOS currently not have support for other than player on transport
- }
-
- // 0x02200000
- if(flags2 & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING2))
- {
- if(GetTypeId() == TYPEID_PLAYER)
- *data << (float)((Player*)this)->m_movementInfo.s_pitch;
- else
- *data << (float)0; // is't part of movement packet, we must store and send it...
- }
-
- if(GetTypeId() == TYPEID_PLAYER)
- *data << (uint32)((Player*)this)->m_movementInfo.fallTime;
- else
- *data << (uint32)0; // last fall time
-
- // 0x00001000
- if(flags2 & MOVEMENTFLAG_JUMPING)
- {
- if(GetTypeId() == TYPEID_PLAYER)
- {
- *data << (float)((Player*)this)->m_movementInfo.j_unk;
- *data << (float)((Player*)this)->m_movementInfo.j_sinAngle;
- *data << (float)((Player*)this)->m_movementInfo.j_cosAngle;
- *data << (float)((Player*)this)->m_movementInfo.j_xyspeed;
- }
- else
- {
- *data << (float)0;
- *data << (float)0;
- *data << (float)0;
- *data << (float)0;
- }
- }
-
- // 0x04000000
- if(flags2 & MOVEMENTFLAG_SPLINE)
- {
- if(GetTypeId() == TYPEID_PLAYER)
- *data << (float)((Player*)this)->m_movementInfo.u_unk1;
- else
- *data << (float)0;
- }
-
- *data << ((Unit*)this)->GetSpeed( MOVE_WALK );
- *data << ((Unit*)this)->GetSpeed( MOVE_RUN );
- *data << ((Unit*)this)->GetSpeed( MOVE_SWIMBACK );
- *data << ((Unit*)this)->GetSpeed( MOVE_SWIM );
- *data << ((Unit*)this)->GetSpeed( MOVE_WALKBACK );
- *data << ((Unit*)this)->GetSpeed( MOVE_FLY );
- *data << ((Unit*)this)->GetSpeed( MOVE_FLYBACK );
- *data << ((Unit*)this)->GetSpeed( MOVE_TURN );
-
- // 0x08000000
- if(flags2 & MOVEMENTFLAG_SPLINE2)
- {
- if(GetTypeId() != TYPEID_PLAYER)
- {
- sLog.outDebug("_BuildMovementUpdate: MOVEMENTFLAG_SPLINE2 for non-player");
- return;
- }
-
- if(!((Player*)this)->isInFlight())
- {
- sLog.outDebug("_BuildMovementUpdate: MOVEMENTFLAG_SPLINE2 but not in flight");
- return;
- }
-
- WPAssert(((Player*)this)->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE);
-
- FlightPathMovementGenerator *fmg = (FlightPathMovementGenerator*)(((Player*)this)->GetMotionMaster()->top());
-
- uint32 flags3 = 0x00000300;
-
- *data << uint32(flags3); // splines flag?
-
- if(flags3 & 0x10000) // probably x,y,z coords there
- {
- *data << (float)0;
- *data << (float)0;
- *data << (float)0;
- }
-
- if(flags3 & 0x20000) // probably guid there
- {
- *data << uint64(0);
- }
-
- if(flags3 & 0x40000) // may be orientation
- {
- *data << (float)0;
- }
-
- Path &path = fmg->GetPath();
-
- float x, y, z;
- ((Player*)this)->GetPosition(x, y, z);
-
- uint32 inflighttime = uint32(path.GetPassedLength(fmg->GetCurrentNode(), x, y, z) * 32);
- uint32 traveltime = uint32(path.GetTotalLength() * 32);
-
- *data << uint32(inflighttime); // passed move time?
- *data << uint32(traveltime); // full move time?
- *data << uint32(0); // ticks count?
-
- uint32 poscount = uint32(path.Size());
-
- *data << uint32(poscount); // points count
-
- for(uint32 i = 0; i < poscount; ++i)
- {
- *data << path.GetNodes()[i].x;
- *data << path.GetNodes()[i].y;
- *data << path.GetNodes()[i].z;
- }
-
- /*for(uint32 i = 0; i < poscount; i++)
- {
- // path points
- *data << (float)0;
- *data << (float)0;
- *data << (float)0;
- }*/
-
- *data << path.GetNodes()[poscount-1].x;
- *data << path.GetNodes()[poscount-1].y;
- *data << path.GetNodes()[poscount-1].z;
-
- // target position (path end)
- /**data << ((Unit*)this)->GetPositionX();
- *data << ((Unit*)this)->GetPositionY();
- *data << ((Unit*)this)->GetPositionZ();*/
- }
- }
-
- // 0x8
- if(flags & UPDATEFLAG_LOWGUID)
- {
- switch(GetTypeId())
- {
- case TYPEID_OBJECT:
- case TYPEID_ITEM:
- case TYPEID_CONTAINER:
- case TYPEID_GAMEOBJECT:
- case TYPEID_DYNAMICOBJECT:
- case TYPEID_CORPSE:
- *data << uint32(GetGUIDLow()); // GetGUIDLow()
- break;
- case TYPEID_UNIT:
- *data << uint32(0x0000000B); // unk, can be 0xB or 0xC
- break;
- case TYPEID_PLAYER:
- if(flags & UPDATEFLAG_SELF)
- *data << uint32(0x00000015); // unk, can be 0x15 or 0x22
- else
- *data << uint32(0x00000008); // unk, can be 0x7 or 0x8
- break;
- default:
- *data << uint32(0x00000000); // unk
- break;
- }
- }
-
- // 0x10
- if(flags & UPDATEFLAG_HIGHGUID)
- {
- switch(GetTypeId())
- {
- case TYPEID_OBJECT:
- case TYPEID_ITEM:
- case TYPEID_CONTAINER:
- case TYPEID_GAMEOBJECT:
- case TYPEID_DYNAMICOBJECT:
- case TYPEID_CORPSE:
- *data << uint32(GetGUIDHigh()); // GetGUIDHigh()
- break;
- default:
- *data << uint32(0x00000000); // unk
- break;
- }
- }
-
- // 0x4
- if(flags & UPDATEFLAG_FULLGUID)
- {
- *data << uint8(0); // packed guid (probably target guid)
- }
-
- // 0x2
- if(flags & UPDATEFLAG_TRANSPORT)
- {
- *data << uint32(getMSTime()); // ms time
- }
-}
-
-void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask *updateMask, Player *target) const
-{
- if(!target)
- return;
-
- bool IsActivateToQuest = false;
- if (updatetype == UPDATETYPE_CREATE_OBJECT || updatetype == UPDATETYPE_CREATE_OBJECT2)
- {
- if (isType(TYPEMASK_GAMEOBJECT) && !((GameObject*)this)->IsTransport())
- {
- if ( ((GameObject*)this)->ActivateToQuest(target) || target->isGameMaster())
- {
- IsActivateToQuest = true;
- updateMask->SetBit(GAMEOBJECT_DYN_FLAGS);
- }
- }
- }
- else //case UPDATETYPE_VALUES
- {
- if (isType(TYPEMASK_GAMEOBJECT) && !((GameObject*)this)->IsTransport())
- {
- if ( ((GameObject*)this)->ActivateToQuest(target) || target->isGameMaster())
- {
- IsActivateToQuest = true;
- }
- updateMask->SetBit(GAMEOBJECT_DYN_FLAGS);
- updateMask->SetBit(GAMEOBJECT_ANIMPROGRESS);
- }
- }
-
- WPAssert(updateMask && updateMask->GetCount() == m_valuesCount);
-
- *data << (uint8)updateMask->GetBlockCount();
- data->append( updateMask->GetMask(), updateMask->GetLength() );
-
- // 2 specialized loops for speed optimization in non-unit case
- if(isType(TYPEMASK_UNIT)) // unit (creature/player) case
- {
- for( uint16 index = 0; index < m_valuesCount; index ++ )
- {
- if( updateMask->GetBit( index ) )
- {
- // remove custom flag before send
- if( index == UNIT_NPC_FLAGS )
- *data << uint32(m_uint32Values[ index ] & ~UNIT_NPC_FLAG_GUARD);
- // FIXME: Some values at server stored in float format but must be sent to client in uint32 format
- else if(index >= UNIT_FIELD_BASEATTACKTIME && index <= UNIT_FIELD_RANGEDATTACKTIME)
- {
- // convert from float to uint32 and send
- *data << uint32(m_floatValues[ index ] < 0 ? 0 : m_floatValues[ index ]);
- }
- // there are some float values which may be negative or can't get negative due to other checks
- else if(index >= UNIT_FIELD_NEGSTAT0 && index <= UNIT_FIELD_NEGSTAT4 ||
- index >= UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE && index <= (UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + 6) ||
- index >= UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE && index <= (UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + 6) ||
- index >= UNIT_FIELD_POSSTAT0 && index <= UNIT_FIELD_POSSTAT4)
- {
- *data << uint32(m_floatValues[ index ]);
- }
- // Gamemasters should be always able to select units - remove not selectable flag
- else if(index == UNIT_FIELD_FLAGS && target->isGameMaster())
- {
- *data << (m_uint32Values[ index ] & ~UNIT_FLAG_NOT_SELECTABLE);
- }
- // hide lootable animation for unallowed players
- else if(index == UNIT_DYNAMIC_FLAGS && GetTypeId() == TYPEID_UNIT)
- {
- if(!target->isAllowedToLoot((Creature*)this))
- *data << (m_uint32Values[ index ] & ~UNIT_DYNFLAG_LOOTABLE);
- else
- *data << (m_uint32Values[ index ] & ~UNIT_DYNFLAG_OTHER_TAGGER);
- }
- else
- {
- // send in current format (float as float, uint32 as uint32)
- *data << m_uint32Values[ index ];
- }
- }
- }
- }
- else if(isType(TYPEMASK_GAMEOBJECT)) // gameobject case
- {
- for( uint16 index = 0; index < m_valuesCount; index ++ )
- {
- if( updateMask->GetBit( index ) )
- {
- // send in current format (float as float, uint32 as uint32)
- if ( index == GAMEOBJECT_DYN_FLAGS )
- {
- if(IsActivateToQuest )
- {
- switch(((GameObject*)this)->GetGoType())
- {
- case GAMEOBJECT_TYPE_CHEST:
- *data << uint32(9); // enable quest object. Represent 9, but 1 for client before 2.3.0
- break;
- case GAMEOBJECT_TYPE_GOOBER:
- *data << uint32(1);
- break;
- default:
- *data << uint32(0); //unknown. not happen.
- break;
- }
- }
- else
- *data << uint32(0); // disable quest object
- }
- else
- *data << m_uint32Values[ index ]; // other cases
- }
- }
- }
- else // other objects case (no special index checks)
- {
- for( uint16 index = 0; index < m_valuesCount; index ++ )
- {
- if( updateMask->GetBit( index ) )
- {
- // send in current format (float as float, uint32 as uint32)
- *data << m_uint32Values[ index ];
- }
- }
- }
-}
-
-void Object::ClearUpdateMask(bool remove)
-{
- for( uint16 index = 0; index < m_valuesCount; index ++ )
- {
- if(m_uint32Values_mirror[index]!= m_uint32Values[index])
- m_uint32Values_mirror[index] = m_uint32Values[index];
- }
- if(m_objectUpdated)
- {
- if(remove)
- ObjectAccessor::Instance().RemoveUpdateObject(this);
- m_objectUpdated = false;
- }
-}
-
-// Send current value fields changes to all viewers
-void Object::SendUpdateObjectToAllExcept(Player* exceptPlayer)
-{
- // changes will be send in create packet
- if(!IsInWorld())
- return;
-
- // nothing do
- if(!m_objectUpdated)
- return;
-
- ObjectAccessor::UpdateObject(this,exceptPlayer);
-}
-
-bool Object::LoadValues(const char* data)
-{
- if(!m_uint32Values) _InitValues();
-
- Tokens tokens = StrSplit(data, " ");
-
- if(tokens.size() != m_valuesCount)
- return false;
-
- Tokens::iterator iter;
- int index;
- for (iter = tokens.begin(), index = 0; index < m_valuesCount; ++iter, ++index)
- {
- m_uint32Values[index] = atol((*iter).c_str());
- }
-
- return true;
-}
-
-void Object::_SetUpdateBits(UpdateMask *updateMask, Player* /*target*/) const
-{
- for( uint16 index = 0; index < m_valuesCount; index ++ )
- {
- if(m_uint32Values_mirror[index]!= m_uint32Values[index])
- updateMask->SetBit(index);
- }
-}
-
-void Object::_SetCreateBits(UpdateMask *updateMask, Player* /*target*/) const
-{
- for( uint16 index = 0; index < m_valuesCount; index++ )
- {
- if(GetUInt32Value(index) != 0)
- updateMask->SetBit(index);
- }
-}
-
-void Object::SetInt32Value( uint16 index, int32 value )
-{
- ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
-
- if(m_int32Values[ index ] != value)
- {
- m_int32Values[ index ] = value;
-
- if(m_inWorld)
- {
- if(!m_objectUpdated)
- {
- ObjectAccessor::Instance().AddUpdateObject(this);
- m_objectUpdated = true;
- }
- }
- }
-}
-
-void Object::SetUInt32Value( uint16 index, uint32 value )
-{
- ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
-
- if(m_uint32Values[ index ] != value)
- {
- m_uint32Values[ index ] = value;
-
- if(m_inWorld)
- {
- if(!m_objectUpdated)
- {
- ObjectAccessor::Instance().AddUpdateObject(this);
- m_objectUpdated = true;
- }
- }
- }
-}
-
-void Object::SetUInt64Value( uint16 index, const uint64 &value )
-{
- ASSERT( index + 1 < m_valuesCount || PrintIndexError( index , true ) );
- if(*((uint64*)&(m_uint32Values[ index ])) != value)
- {
- m_uint32Values[ index ] = *((uint32*)&value);
- m_uint32Values[ index + 1 ] = *(((uint32*)&value) + 1);
-
- if(m_inWorld)
- {
- if(!m_objectUpdated)
- {
- ObjectAccessor::Instance().AddUpdateObject(this);
- m_objectUpdated = true;
- }
- }
- }
-}
-
-void Object::SetFloatValue( uint16 index, float value )
-{
- ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
-
- if(m_floatValues[ index ] != value)
- {
- m_floatValues[ index ] = value;
-
- if(m_inWorld)
- {
- if(!m_objectUpdated)
- {
- ObjectAccessor::Instance().AddUpdateObject(this);
- m_objectUpdated = true;
- }
- }
- }
-}
-
-void Object::SetByteValue( uint16 index, uint8 offset, uint8 value )
-{
- ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
-
- if(offset > 4)
- {
- sLog.outError("Object::SetByteValue: wrong offset %u", offset);
- return;
- }
-
- if(uint8(m_uint32Values[ index ] >> (offset * 8)) != value)
- {
- m_uint32Values[ index ] &= ~uint32(uint32(0xFF) << (offset * 8));
- m_uint32Values[ index ] |= uint32(uint32(value) << (offset * 8));
-
- if(m_inWorld)
- {
- if(!m_objectUpdated)
- {
- ObjectAccessor::Instance().AddUpdateObject(this);
- m_objectUpdated = true;
- }
- }
- }
-}
-
-void Object::SetUInt16Value( uint16 index, uint8 offset, uint16 value )
-{
- ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
-
- if(offset > 2)
- {
- sLog.outError("Object::SetUInt16Value: wrong offset %u", offset);
- return;
- }
-
- if(uint8(m_uint32Values[ index ] >> (offset * 16)) != value)
- {
- m_uint32Values[ index ] &= ~uint32(uint32(0xFFFF) << (offset * 16));
- m_uint32Values[ index ] |= uint32(uint32(value) << (offset * 16));
-
- if(m_inWorld)
- {
- if(!m_objectUpdated)
- {
- ObjectAccessor::Instance().AddUpdateObject(this);
- m_objectUpdated = true;
- }
- }
- }
-}
-
-void Object::SetStatFloatValue( uint16 index, float value)
-{
- if(value < 0)
- value = 0.0f;
-
- SetFloatValue(index, value);
-}
-
-void Object::SetStatInt32Value( uint16 index, int32 value)
-{
- if(value < 0)
- value = 0;
-
- SetUInt32Value(index, uint32(value));
-}
-
-void Object::ApplyModUInt32Value(uint16 index, int32 val, bool apply)
-{
- int32 cur = GetUInt32Value(index);
- cur += (apply ? val : -val);
- if(cur < 0)
- cur = 0;
- SetUInt32Value(index,cur);
-}
-
-void Object::ApplyModInt32Value(uint16 index, int32 val, bool apply)
-{
- int32 cur = GetInt32Value(index);
- cur += (apply ? val : -val);
- SetInt32Value(index,cur);
-}
-
-void Object::ApplyModSignedFloatValue(uint16 index, float val, bool apply)
-{
- float cur = GetFloatValue(index);
- cur += (apply ? val : -val);
- SetFloatValue(index,cur);
-}
-
-void Object::ApplyModPositiveFloatValue(uint16 index, float val, bool apply)
-{
- float cur = GetFloatValue(index);
- cur += (apply ? val : -val);
- if(cur < 0)
- cur = 0;
- SetFloatValue(index,cur);
-}
-
-void Object::SetFlag( uint16 index, uint32 newFlag )
-{
- ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
- uint32 oldval = m_uint32Values[ index ];
- uint32 newval = oldval | newFlag;
-
- if(oldval != newval)
- {
- m_uint32Values[ index ] = newval;
-
- if(m_inWorld)
- {
- if(!m_objectUpdated)
- {
- ObjectAccessor::Instance().AddUpdateObject(this);
- m_objectUpdated = true;
- }
- }
- }
-}
-
-void Object::RemoveFlag( uint16 index, uint32 oldFlag )
-{
- ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
- uint32 oldval = m_uint32Values[ index ];
- uint32 newval = oldval & ~oldFlag;
-
- if(oldval != newval)
- {
- m_uint32Values[ index ] = newval;
-
- if(m_inWorld)
- {
- if(!m_objectUpdated)
- {
- ObjectAccessor::Instance().AddUpdateObject(this);
- m_objectUpdated = true;
- }
- }
- }
-}
-
-bool Object::PrintIndexError(uint32 index, bool set) const
-{
- sLog.outError("ERROR: Attempt %s non-existed value field: %u (count: %u) for object typeid: %u type mask: %u",(set ? "set value to" : "get value from"),index,m_valuesCount,GetTypeId(),m_objectType);
-
- // assert must fail after function call
- return false;
-}
-
-WorldObject::WorldObject()
-{
- m_positionX = 0.0f;
- m_positionY = 0.0f;
- m_positionZ = 0.0f;
- m_orientation = 0.0f;
-
- m_mapId = 0;
- m_InstanceId = 0;
-
- m_name = "";
-
- mSemaphoreTeleport = false;
-}
-
-void WorldObject::_Create( uint32 guidlow, HighGuid guidhigh, uint32 mapid )
-{
- Object::_Create(guidlow, 0, guidhigh);
-
- m_mapId = mapid;
-}
-
-uint32 WorldObject::GetZoneId() const
-{
- return MapManager::Instance().GetBaseMap(m_mapId)->GetZoneId(m_positionX,m_positionY);
-}
-
-uint32 WorldObject::GetAreaId() const
-{
- return MapManager::Instance().GetBaseMap(m_mapId)->GetAreaId(m_positionX,m_positionY);
-}
-
-InstanceData* WorldObject::GetInstanceData()
-{
- Map *map = MapManager::Instance().GetMap(m_mapId, this);
- return map->IsDungeon() ? ((InstanceMap*)map)->GetInstanceData() : NULL;
-}
-
- //slow
-float WorldObject::GetDistance(const WorldObject* obj) const
-{
- float dx = GetPositionX() - obj->GetPositionX();
- float dy = GetPositionY() - obj->GetPositionY();
- float dz = GetPositionZ() - obj->GetPositionZ();
- float sizefactor = GetObjectSize() + obj->GetObjectSize();
- float dist = sqrt((dx*dx) + (dy*dy) + (dz*dz)) - sizefactor;
- return ( dist > 0 ? dist : 0);
-}
-
-float WorldObject::GetDistance2d(float x, float y) const
-{
- float dx = GetPositionX() - x;
- float dy = GetPositionY() - y;
- float sizefactor = GetObjectSize();
- float dist = sqrt((dx*dx) + (dy*dy)) - sizefactor;
- return ( dist > 0 ? dist : 0);
-}
-
-float WorldObject::GetDistance(const float x, const float y, const float z) const
-{
- float dx = GetPositionX() - x;
- float dy = GetPositionY() - y;
- float dz = GetPositionZ() - z;
- float sizefactor = GetObjectSize();
- float dist = sqrt((dx*dx) + (dy*dy) + (dz*dz)) - sizefactor;
- return ( dist > 0 ? dist : 0);
-}
-
-float WorldObject::GetDistance2d(const WorldObject* obj) const
-{
- float dx = GetPositionX() - obj->GetPositionX();
- float dy = GetPositionY() - obj->GetPositionY();
- float sizefactor = GetObjectSize() + obj->GetObjectSize();
- float dist = sqrt((dx*dx) + (dy*dy)) - sizefactor;
- return ( dist > 0 ? dist : 0);
-}
-
-float WorldObject::GetDistanceZ(const WorldObject* obj) const
-{
- float dz = fabs(GetPositionZ() - obj->GetPositionZ());
- float sizefactor = GetObjectSize() + obj->GetObjectSize();
- float dist = dz - sizefactor;
- return ( dist > 0 ? dist : 0);
-}
-
-bool WorldObject::IsWithinDistInMap(const WorldObject* obj, const float dist2compare) const
-{
- if (!obj || !IsInMap(obj)) return false;
-
- float dx = GetPositionX() - obj->GetPositionX();
- float dy = GetPositionY() - obj->GetPositionY();
- float dz = GetPositionZ() - obj->GetPositionZ();
- float distsq = dx*dx + dy*dy + dz*dz;
- float sizefactor = GetObjectSize() + obj->GetObjectSize();
- float maxdist = dist2compare + sizefactor;
-
- return distsq < maxdist * maxdist;
-}
-
-bool WorldObject::IsWithinLOSInMap(const WorldObject* obj) const
-{
- if (!IsInMap(obj)) return false;
- float ox,oy,oz;
- obj->GetPosition(ox,oy,oz);
- return(IsWithinLOS(ox, oy, oz ));
-}
-
-bool WorldObject::IsWithinLOS(const float ox, const float oy, const float oz ) const
-{
- float x,y,z;
- GetPosition(x,y,z);
- VMAP::IVMapManager *vMapManager = VMAP::VMapFactory::createOrGetVMapManager();
- return vMapManager->isInLineOfSight(GetMapId(), x, y, z+2.0f, ox, oy, oz+2.0f);
-}
-
-float WorldObject::GetAngle(const WorldObject* obj) const
-{
- if(!obj) return 0;
- return GetAngle( obj->GetPositionX(), obj->GetPositionY() );
-}
-
-// Return angle in range 0..2*pi
-float WorldObject::GetAngle( const float x, const float y ) const
-{
- float dx = x - GetPositionX();
- float dy = y - GetPositionY();
-
- float ang = atan2(dy, dx);
- ang = (ang >= 0) ? ang : 2 * M_PI + ang;
- return ang;
-}
-
-bool WorldObject::HasInArc(const float arcangle, const WorldObject* obj) const
-{
- float arc = arcangle;
-
- // move arc to range 0.. 2*pi
- while( arc >= 2.0f * M_PI )
- arc -= 2.0f * M_PI;
- while( arc < 0 )
- arc += 2.0f * M_PI;
-
- float angle = GetAngle( obj );
- angle -= m_orientation;
-
- // move angle to range -pi ... +pi
- while( angle > M_PI)
- angle -= 2.0f * M_PI;
- while(angle < -M_PI)
- angle += 2.0f * M_PI;
-
- float lborder = -1 * (arc/2.0f); // in range -pi..0
- float rborder = (arc/2.0f); // in range 0..pi
- return (( angle >= lborder ) && ( angle <= rborder ));
-}
-
-void WorldObject::GetRandomPoint( float x, float y, float z, float distance, float &rand_x, float &rand_y, float &rand_z) const
-{
- if(distance==0)
- {
- rand_x = x;
- rand_y = y;
- rand_z = z;
- return;
- }
-
- // angle to face `obj` to `this`
- float angle = rand_norm()*2*M_PI;
- float new_dist = rand_norm()*distance;
-
- rand_x = x + new_dist * cos(angle);
- rand_y = y + new_dist * sin(angle);
- rand_z = z;
-
- MaNGOS::NormalizeMapCoord(rand_x);
- MaNGOS::NormalizeMapCoord(rand_y);
- UpdateGroundPositionZ(rand_x,rand_y,rand_z); // update to LOS height if available
-}
-
-void WorldObject::UpdateGroundPositionZ(float x, float y, float &z) const
-{
- float new_z = MapManager::Instance().GetBaseMap(GetMapId())->GetHeight(x,y,z,true);
- if(new_z > INVALID_HEIGHT)
- z = new_z+ 0.05f; // just to be sure that we are not a few pixel under the surface
-}
-
-bool WorldObject::IsPositionValid() const
-{
- return MaNGOS::IsValidMapCoord(m_positionX,m_positionY,m_positionZ,m_orientation);
-}
-
-void WorldObject::MonsterSay(const char* text, uint32 language, uint64 TargetGuid)
-{
- WorldPacket data(SMSG_MESSAGECHAT, 200);
- BuildMonsterChat(&data,CHAT_MSG_MONSTER_SAY,text,language,GetName(),TargetGuid);
- SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY),true);
-}
-
-void WorldObject::MonsterYell(const char* text, uint32 language, uint64 TargetGuid)
-{
- WorldPacket data(SMSG_MESSAGECHAT, 200);
- BuildMonsterChat(&data,CHAT_MSG_MONSTER_YELL,text,language,GetName(),TargetGuid);
- SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_YELL),true);
-}
-
-void WorldObject::MonsterTextEmote(const char* text, uint64 TargetGuid, bool IsBossEmote)
-{
- WorldPacket data(SMSG_MESSAGECHAT, 200);
- BuildMonsterChat(&data,IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE,text,LANG_UNIVERSAL,GetName(),TargetGuid);
- SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true);
-}
-
-void WorldObject::MonsterWhisper(const char* text, uint64 receiver, bool IsBossWhisper)
-{
- Player *player = objmgr.GetPlayer(receiver);
- if(!player || !player->GetSession())
- return;
-
- WorldPacket data(SMSG_MESSAGECHAT, 200);
- BuildMonsterChat(&data,IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER,text,LANG_UNIVERSAL,GetName(),receiver);
-
- player->GetSession()->SendPacket(&data);
-}
-
-void WorldObject::SendPlaySound(uint32 Sound, bool OnlySelf)
-{
- WorldPacket data(SMSG_PLAY_SOUND, 4);
- data << Sound;
- if (OnlySelf && GetTypeId() == TYPEID_PLAYER )
- ((Player*)this)->GetSession()->SendPacket( &data );
- else
- SendMessageToSet( &data, true ); // ToSelf ignored in this case
-}
-
-namespace MaNGOS
-{
- class MessageChatLocaleCacheDo
- {
- public:
- MessageChatLocaleCacheDo(WorldObject const& obj, ChatMsg msgtype, int32 textId, uint32 language, uint64 targetGUID, float dist)
- : i_object(obj), i_msgtype(msgtype), i_textId(textId), i_language(language),
- i_targetGUID(targetGUID), i_dist(dist)
- {
- }
-
- ~MessageChatLocaleCacheDo()
- {
- for(int i = 0; i < i_data_cache.size(); ++i)
- delete i_data_cache[i];
- }
-
- void operator()(Player* p)
- {
- // skip far away players
- if(p->GetDistance(&i_object) > i_dist)
- return;
-
- uint32 loc_idx = p->GetSession()->GetSessionDbLocaleIndex();
- uint32 cache_idx = loc_idx+1;
- WorldPacket* data;
-
- // create if not cached yet
- if(i_data_cache.size() < cache_idx+1 || !i_data_cache[cache_idx])
- {
- if(i_data_cache.size() < cache_idx+1)
- i_data_cache.resize(cache_idx+1);
-
- char const* text = objmgr.GetMangosString(i_textId,loc_idx);
-
- data = new WorldPacket(SMSG_MESSAGECHAT, 200);
-
- // TODO: i_object.GetName() also must be localized?
- i_object.BuildMonsterChat(data,i_msgtype,text,i_language,i_object.GetName(),i_targetGUID);
-
- i_data_cache[cache_idx] = data;
- }
- else
- data = i_data_cache[cache_idx];
-
- p->SendDirectMessage(data);
- }
-
- private:
- WorldObject const& i_object;
- ChatMsg i_msgtype;
- int32 i_textId;
- uint32 i_language;
- uint64 i_targetGUID;
- float i_dist;
- std::vector i_data_cache; // 0 = default, i => i-1 locale index
- };
-} // namespace MaNGOS
-
-void WorldObject::MonsterSay(int32 textId, uint32 language, uint64 TargetGuid)
-{
- CellPair p = MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY());
-
- Cell cell(p);
- cell.data.Part.reserved = ALL_DISTRICT;
- cell.SetNoCreate();
-
- MaNGOS::MessageChatLocaleCacheDo say_do(*this, CHAT_MSG_MONSTER_SAY, textId,language,TargetGuid,sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY));
- MaNGOS::PlayerWorker say_worker(say_do);
- TypeContainerVisitor, WorldTypeMapContainer > message(say_worker);
- CellLock cell_lock(cell, p);
- cell_lock->Visit(cell_lock, message, *GetMap());
-}
-
-void WorldObject::MonsterYell(int32 textId, uint32 language, uint64 TargetGuid)
-{
- CellPair p = MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY());
-
- Cell cell(p);
- cell.data.Part.reserved = ALL_DISTRICT;
- cell.SetNoCreate();
-
- MaNGOS::MessageChatLocaleCacheDo say_do(*this, CHAT_MSG_MONSTER_YELL, textId,language,TargetGuid,sWorld.getConfig(CONFIG_LISTEN_RANGE_YELL));
- MaNGOS::PlayerWorker say_worker(say_do);
- TypeContainerVisitor, WorldTypeMapContainer > message(say_worker);
- CellLock cell_lock(cell, p);
- cell_lock->Visit(cell_lock, message, *GetMap());
-}
-
-void WorldObject::MonsterTextEmote(int32 textId, uint64 TargetGuid, bool IsBossEmote)
-{
- CellPair p = MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY());
-
- Cell cell(p);
- cell.data.Part.reserved = ALL_DISTRICT;
- cell.SetNoCreate();
-
- MaNGOS::MessageChatLocaleCacheDo say_do(*this, IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, textId,LANG_UNIVERSAL,TargetGuid,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE));
- MaNGOS::PlayerWorker say_worker(say_do);
- TypeContainerVisitor, WorldTypeMapContainer > message(say_worker);
- CellLock cell_lock(cell, p);
- cell_lock->Visit(cell_lock, message, *GetMap());
-}
-
-void WorldObject::MonsterWhisper(int32 textId, uint64 receiver, bool IsBossWhisper)
-{
- Player *player = objmgr.GetPlayer(receiver);
- if(!player || !player->GetSession())
- return;
-
- uint32 loc_idx = player->GetSession()->GetSessionDbLocaleIndex();
- char const* text = objmgr.GetMangosString(textId,loc_idx);
-
- WorldPacket data(SMSG_MESSAGECHAT, 200);
- BuildMonsterChat(&data,IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER,text,LANG_UNIVERSAL,GetName(),receiver);
-
- player->GetSession()->SendPacket(&data);
-}
-
-void WorldObject::BuildMonsterChat(WorldPacket *data, uint8 msgtype, char const* text, uint32 language, char const* name, uint64 targetGuid) const
-{
- bool pre = (msgtype==CHAT_MSG_MONSTER_EMOTE || msgtype==CHAT_MSG_RAID_BOSS_EMOTE);
-
- *data << (uint8)msgtype;
- *data << (uint32)language;
- *data << (uint64)GetGUID();
- *data << (uint32)0; //2.1.0
- *data << (uint32)(strlen(name)+1);
- *data << name;
- *data << (uint64)targetGuid; //Unit Target
- if( targetGuid && !IS_PLAYER_GUID(targetGuid) )
- {
- *data << (uint32)1; // target name length
- *data << (uint8)0; // target name
- }
- *data << (uint32)(strlen(text)+1+(pre?3:0));
- if(pre)
- data->append("%s ",3);
- *data << text;
- *data << (uint8)0; // ChatTag
-}
-
-void WorldObject::BuildHeartBeatMsg(WorldPacket *data) const
-{
- //Heartbeat message cannot be used for non-units
- if (!isType(TYPEMASK_UNIT))
- return;
-
- data->Initialize(MSG_MOVE_HEARTBEAT, 32);
- data->append(GetPackGUID());
- *data << uint32(((Unit*)this)->GetUnitMovementFlags()); // movement flags
- *data << uint8(0); // 2.3.0
- *data << getMSTime(); // time
- *data << m_positionX;
- *data << m_positionY;
- *data << m_positionZ;
- *data << m_orientation;
- *data << uint32(0);
-}
-
-void WorldObject::BuildTeleportAckMsg(WorldPacket *data, float x, float y, float z, float ang) const
-{
- //TeleportAck message cannot be used for non-units
- if (!isType(TYPEMASK_UNIT))
- return;
-
- data->Initialize(MSG_MOVE_TELEPORT_ACK, 41);
- data->append(GetPackGUID());
- *data << uint32(0); // this value increments every time
- *data << uint32(((Unit*)this)->GetUnitMovementFlags()); // movement flags
- *data << uint8(0); // 2.3.0
- *data << getMSTime(); // time
- *data << x;
- *data << y;
- *data << z;
- *data << ang;
- *data << uint32(0);
-}
-
-void WorldObject::SendMessageToSet(WorldPacket *data, bool /*bToSelf*/)
-{
- MapManager::Instance().GetMap(m_mapId, this)->MessageBroadcast(this, data);
-}
-
-void WorldObject::SendMessageToSetInRange(WorldPacket *data, float dist, bool /*bToSelf*/)
-{
- MapManager::Instance().GetMap(m_mapId, this)->MessageDistBroadcast(this, data, dist);
-}
-
-void WorldObject::SendObjectDeSpawnAnim(uint64 guid)
-{
- WorldPacket data(SMSG_GAMEOBJECT_DESPAWN_ANIM, 8);
- data << guid;
- SendMessageToSet(&data, true);
-}
-
-Map* WorldObject::GetMap() const
-{
- return MapManager::Instance().GetMap(GetMapId(), this);
-}
-
-Map const* WorldObject::GetBaseMap() const
-{
- return MapManager::Instance().GetBaseMap(GetMapId());
-}
-
-void WorldObject::AddObjectToRemoveList()
-{
- Map* map = GetMap();
- if(!map)
- {
- sLog.outError("Object (TypeId: %u Entry: %u GUID: %u) at attempt add to move list not have valid map (Id: %u).",GetTypeId(),GetEntry(),GetGUIDLow(),GetMapId());
- return;
- }
-
- map->AddObjectToRemoveList(this);
-}
-
-Creature* WorldObject::SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime)
-{
- TemporarySummon* pCreature = new TemporarySummon(GetGUID());
-
- pCreature->SetInstanceId(GetInstanceId());
- uint32 team = 0;
- if (GetTypeId()==TYPEID_PLAYER)
- team = ((Player*)this)->GetTeam();
-
- if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), GetMap(), id, team))
- {
- delete pCreature;
- return NULL;
- }
-
- if (x == 0.0f && y == 0.0f && z == 0.0f)
- GetClosePoint(x, y, z, pCreature->GetObjectSize());
-
- pCreature->Relocate(x, y, z, ang);
-
- if(!pCreature->IsPositionValid())
- {
- sLog.outError("ERROR: Creature (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
- delete pCreature;
- return NULL;
- }
-
- pCreature->Summon(spwtype, despwtime);
-
- if(GetTypeId()==TYPEID_UNIT && ((Creature*)this)->AI())
- ((Creature*)this)->AI()->JustSummoned(pCreature);
-
- //return the creature therewith the summoner has access to it
- return pCreature;
-}
-
-void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float absAngle ) const
-{
- x = GetPositionX() + (GetObjectSize() + distance2d) * cos(absAngle);
- y = GetPositionY() + (GetObjectSize() + distance2d) * sin(absAngle);
-
- MaNGOS::NormalizeMapCoord(x);
- MaNGOS::NormalizeMapCoord(y);
-}
-
-void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y, float &z, float searcher_size, float distance2d, float absAngle ) const
-{
- GetNearPoint2D(x,y,distance2d+searcher_size,absAngle);
-
- z = GetPositionZ();
-
- UpdateGroundPositionZ(x,y,z);
-}
+/*
+ * Copyright (C) 2005-2008 MaNGOS
+ *
+ * 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 "SharedDefines.h"
+#include "WorldPacket.h"
+#include "Opcodes.h"
+#include "Log.h"
+#include "World.h"
+#include "Object.h"
+#include "Creature.h"
+#include "Player.h"
+#include "ObjectMgr.h"
+#include "WorldSession.h"
+#include "UpdateData.h"
+#include "UpdateMask.h"
+#include "Util.h"
+#include "MapManager.h"
+#include "ObjectAccessor.h"
+#include "Log.h"
+#include "Transports.h"
+#include "TargetedMovementGenerator.h"
+#include "WaypointMovementGenerator.h"
+#include "VMapFactory.h"
+#include "CellImpl.h"
+#include "GridNotifiers.h"
+#include "GridNotifiersImpl.h"
+
+#include "TemporarySummon.h"
+
+uint32 GuidHigh2TypeId(uint32 guid_hi)
+{
+ switch(guid_hi)
+ {
+ case HIGHGUID_ITEM: return TYPEID_ITEM;
+ //case HIGHGUID_CONTAINER: return TYPEID_CONTAINER; HIGHGUID_CONTAINER==HIGHGUID_ITEM currently
+ case HIGHGUID_UNIT: return TYPEID_UNIT;
+ case HIGHGUID_PET: return TYPEID_UNIT;
+ case HIGHGUID_PLAYER: return TYPEID_PLAYER;
+ case HIGHGUID_GAMEOBJECT: return TYPEID_GAMEOBJECT;
+ case HIGHGUID_DYNAMICOBJECT:return TYPEID_DYNAMICOBJECT;
+ case HIGHGUID_CORPSE: return TYPEID_CORPSE;
+ case HIGHGUID_MO_TRANSPORT: return TYPEID_GAMEOBJECT;
+ }
+ return 10; // unknown
+}
+
+Object::Object( )
+{
+ m_objectTypeId = TYPEID_OBJECT;
+ m_objectType = TYPEMASK_OBJECT;
+
+ m_uint32Values = 0;
+ m_uint32Values_mirror = 0;
+ m_valuesCount = 0;
+
+ m_inWorld = false;
+ m_objectUpdated = false;
+
+ m_PackGUID.clear();
+ m_PackGUID.appendPackGUID(0);
+}
+
+Object::~Object( )
+{
+ if(m_objectUpdated)
+ ObjectAccessor::Instance().RemoveUpdateObject(this);
+
+ if(m_uint32Values)
+ {
+ if(IsInWorld())
+ {
+ ///- Do NOT call RemoveFromWorld here, if the object is a player it will crash
+ sLog.outError("Object::~Object - guid="I64FMTD", typeid=%d deleted but still in world!!", GetGUID(), GetTypeId());
+ //assert(0);
+ }
+
+ //DEBUG_LOG("Object desctr 1 check (%p)",(void*)this);
+ delete [] m_uint32Values;
+ delete [] m_uint32Values_mirror;
+ //DEBUG_LOG("Object desctr 2 check (%p)",(void*)this);
+ }
+}
+
+void Object::_InitValues()
+{
+ m_uint32Values = new uint32[ m_valuesCount ];
+ memset(m_uint32Values, 0, m_valuesCount*sizeof(uint32));
+
+ m_uint32Values_mirror = new uint32[ m_valuesCount ];
+ memset(m_uint32Values_mirror, 0, m_valuesCount*sizeof(uint32));
+
+ m_objectUpdated = false;
+}
+
+void Object::_Create( uint32 guidlow, uint32 entry, HighGuid guidhigh )
+{
+ if(!m_uint32Values) _InitValues();
+
+ uint64 guid = MAKE_NEW_GUID(guidlow, entry, guidhigh); // required more changes to make it working
+ SetUInt64Value( OBJECT_FIELD_GUID, guid );
+ SetUInt32Value( OBJECT_FIELD_TYPE, m_objectType );
+ m_PackGUID.clear();
+ m_PackGUID.appendPackGUID(GetGUID());
+}
+
+void Object::BuildMovementUpdateBlock(UpdateData * data, uint32 flags ) const
+{
+ ByteBuffer buf(500);
+
+ buf << uint8( UPDATETYPE_MOVEMENT );
+ buf << GetGUID();
+
+ _BuildMovementUpdate(&buf, flags, 0x00000000);
+
+ data->AddUpdateBlock(buf);
+}
+
+void Object::BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const
+{
+ if(!target)
+ {
+ return;
+ }
+
+ uint8 updatetype = UPDATETYPE_CREATE_OBJECT;
+ uint8 flags = m_updateFlag;
+ uint32 flags2 = 0;
+
+ /** lower flag1 **/
+ if(target == this) // building packet for oneself
+ {
+ flags |= UPDATEFLAG_SELF;
+
+ /*** temporary reverted - until real source of stack corruption will not found
+ updatetype = UPDATETYPE_CREATE_OBJECT2;
+ ****/
+ }
+
+ if(flags & UPDATEFLAG_HASPOSITION)
+ {
+ // UPDATETYPE_CREATE_OBJECT2 dynamic objects, corpses...
+ if(isType(TYPEMASK_DYNAMICOBJECT) || isType(TYPEMASK_CORPSE) || isType(TYPEMASK_PLAYER))
+ updatetype = UPDATETYPE_CREATE_OBJECT2;
+
+ // UPDATETYPE_CREATE_OBJECT2 for pets...
+ if(target->GetPetGUID() == GetGUID())
+ updatetype = UPDATETYPE_CREATE_OBJECT2;
+
+ // UPDATETYPE_CREATE_OBJECT2 for some gameobject types...
+ if(isType(TYPEMASK_GAMEOBJECT))
+ {
+ switch(((GameObject*)this)->GetGoType())
+ {
+ case GAMEOBJECT_TYPE_TRAP:
+ case GAMEOBJECT_TYPE_DUEL_ARBITER:
+ case GAMEOBJECT_TYPE_FLAGSTAND:
+ case GAMEOBJECT_TYPE_FLAGDROP:
+ updatetype = UPDATETYPE_CREATE_OBJECT2;
+ break;
+ case GAMEOBJECT_TYPE_TRANSPORT:
+ flags |= UPDATEFLAG_TRANSPORT;
+ break;
+ }
+ }
+ }
+
+ //sLog.outDebug("BuildCreateUpdate: update-type: %u, object-type: %u got flags: %X, flags2: %X", updatetype, m_objectTypeId, flags, flags2);
+
+ ByteBuffer buf(500);
+ buf << (uint8)updatetype;
+ //buf.append(GetPackGUID()); //client crashes when using this
+ buf << (uint8)0xFF << GetGUID();
+ buf << (uint8)m_objectTypeId;
+
+ _BuildMovementUpdate(&buf, flags, flags2);
+
+ UpdateMask updateMask;
+ updateMask.SetCount( m_valuesCount );
+ _SetCreateBits( &updateMask, target );
+ _BuildValuesUpdate(updatetype, &buf, &updateMask, target );
+ data->AddUpdateBlock(buf);
+}
+
+void Object::BuildUpdate(UpdateDataMapType &update_players)
+{
+ ObjectAccessor::_buildUpdateObject(this,update_players);
+ ClearUpdateMask(true);
+}
+
+void Object::SendUpdateToPlayer(Player* player)
+{
+ // send update to another players
+ SendUpdateObjectToAllExcept(player);
+
+ // send create update to player
+ UpdateData upd;
+ WorldPacket packet;
+
+ upd.Clear();
+ BuildCreateUpdateBlockForPlayer(&upd, player);
+ upd.BuildPacket(&packet);
+ player->GetSession()->SendPacket(&packet);
+
+ // now object updated/(create updated)
+}
+
+void Object::BuildValuesUpdateBlockForPlayer(UpdateData *data, Player *target) const
+{
+ ByteBuffer buf(500);
+
+ buf << (uint8) UPDATETYPE_VALUES;
+ //buf.append(GetPackGUID()); //client crashes when using this. but not have crash in debug mode
+ buf << (uint8)0xFF;
+ buf << GetGUID();
+
+ UpdateMask updateMask;
+ updateMask.SetCount( m_valuesCount );
+
+ _SetUpdateBits( &updateMask, target );
+ _BuildValuesUpdate(UPDATETYPE_VALUES, &buf, &updateMask, target );
+
+ data->AddUpdateBlock(buf);
+}
+
+void Object::BuildOutOfRangeUpdateBlock(UpdateData * data) const
+{
+ data->AddOutOfRangeGUID(GetGUID());
+}
+
+void Object::DestroyForPlayer(Player *target) const
+{
+ ASSERT(target);
+
+ WorldPacket data(SMSG_DESTROY_OBJECT, 8);
+ data << GetGUID();
+ target->GetSession()->SendPacket( &data );
+}
+
+void Object::_BuildMovementUpdate(ByteBuffer * data, uint8 flags, uint32 flags2 ) const
+{
+ *data << (uint8)flags; // update flags
+
+ // 0x20
+ if (flags & UPDATEFLAG_LIVING)
+ {
+ switch(GetTypeId())
+ {
+ case TYPEID_UNIT:
+ {
+ flags2 = ((Unit*)this)->GetUnitMovementFlags();
+ }
+ break;
+ case TYPEID_PLAYER:
+ {
+ flags2 = ((Player*)this)->GetUnitMovementFlags();
+
+ if(((Player*)this)->GetTransport())
+ flags2 |= MOVEMENTFLAG_ONTRANSPORT;
+ else
+ flags2 &= ~MOVEMENTFLAG_ONTRANSPORT;
+
+ // remove unknown, unused etc flags for now
+ flags2 &= ~MOVEMENTFLAG_SPLINE2; // will be set manually
+
+ if(((Player*)this)->isInFlight())
+ {
+ WPAssert(((Player*)this)->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE);
+ flags2 = (MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_SPLINE2);
+ }
+ }
+ break;
+ }
+
+ *data << uint32(flags2); // movement flags
+ *data << uint8(0); // unk 2.3.0
+ *data << uint32(getMSTime()); // time (in milliseconds)
+ }
+
+ // 0x40
+ if (flags & UPDATEFLAG_HASPOSITION)
+ {
+ // 0x02
+ if(flags & UPDATEFLAG_TRANSPORT && ((GameObject*)this)->GetGoType() == GAMEOBJECT_TYPE_MO_TRANSPORT)
+ {
+ *data << (float)0;
+ *data << (float)0;
+ *data << (float)0;
+ *data << ((WorldObject *)this)->GetOrientation();
+ }
+ else
+ {
+ *data << ((WorldObject *)this)->GetPositionX();
+ *data << ((WorldObject *)this)->GetPositionY();
+ *data << ((WorldObject *)this)->GetPositionZ();
+ *data << ((WorldObject *)this)->GetOrientation();
+ }
+ }
+
+ // 0x20
+ if(flags & UPDATEFLAG_LIVING)
+ {
+ // 0x00000200
+ if(flags2 & MOVEMENTFLAG_ONTRANSPORT)
+ {
+ if(GetTypeId() == TYPEID_PLAYER)
+ {
+ *data << (uint64)((Player*)this)->GetTransport()->GetGUID();
+ *data << (float)((Player*)this)->GetTransOffsetX();
+ *data << (float)((Player*)this)->GetTransOffsetY();
+ *data << (float)((Player*)this)->GetTransOffsetZ();
+ *data << (float)((Player*)this)->GetTransOffsetO();
+ *data << (uint32)((Player*)this)->GetTransTime();
+ }
+ //MaNGOS currently not have support for other than player on transport
+ }
+
+ // 0x02200000
+ if(flags2 & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING2))
+ {
+ if(GetTypeId() == TYPEID_PLAYER)
+ *data << (float)((Player*)this)->m_movementInfo.s_pitch;
+ else
+ *data << (float)0; // is't part of movement packet, we must store and send it...
+ }
+
+ if(GetTypeId() == TYPEID_PLAYER)
+ *data << (uint32)((Player*)this)->m_movementInfo.fallTime;
+ else
+ *data << (uint32)0; // last fall time
+
+ // 0x00001000
+ if(flags2 & MOVEMENTFLAG_JUMPING)
+ {
+ if(GetTypeId() == TYPEID_PLAYER)
+ {
+ *data << (float)((Player*)this)->m_movementInfo.j_unk;
+ *data << (float)((Player*)this)->m_movementInfo.j_sinAngle;
+ *data << (float)((Player*)this)->m_movementInfo.j_cosAngle;
+ *data << (float)((Player*)this)->m_movementInfo.j_xyspeed;
+ }
+ else
+ {
+ *data << (float)0;
+ *data << (float)0;
+ *data << (float)0;
+ *data << (float)0;
+ }
+ }
+
+ // 0x04000000
+ if(flags2 & MOVEMENTFLAG_SPLINE)
+ {
+ if(GetTypeId() == TYPEID_PLAYER)
+ *data << (float)((Player*)this)->m_movementInfo.u_unk1;
+ else
+ *data << (float)0;
+ }
+
+ *data << ((Unit*)this)->GetSpeed( MOVE_WALK );
+ *data << ((Unit*)this)->GetSpeed( MOVE_RUN );
+ *data << ((Unit*)this)->GetSpeed( MOVE_SWIMBACK );
+ *data << ((Unit*)this)->GetSpeed( MOVE_SWIM );
+ *data << ((Unit*)this)->GetSpeed( MOVE_WALKBACK );
+ *data << ((Unit*)this)->GetSpeed( MOVE_FLY );
+ *data << ((Unit*)this)->GetSpeed( MOVE_FLYBACK );
+ *data << ((Unit*)this)->GetSpeed( MOVE_TURN );
+
+ // 0x08000000
+ if(flags2 & MOVEMENTFLAG_SPLINE2)
+ {
+ if(GetTypeId() != TYPEID_PLAYER)
+ {
+ sLog.outDebug("_BuildMovementUpdate: MOVEMENTFLAG_SPLINE2 for non-player");
+ return;
+ }
+
+ if(!((Player*)this)->isInFlight())
+ {
+ sLog.outDebug("_BuildMovementUpdate: MOVEMENTFLAG_SPLINE2 but not in flight");
+ return;
+ }
+
+ WPAssert(((Player*)this)->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE);
+
+ FlightPathMovementGenerator *fmg = (FlightPathMovementGenerator*)(((Player*)this)->GetMotionMaster()->top());
+
+ uint32 flags3 = 0x00000300;
+
+ *data << uint32(flags3); // splines flag?
+
+ if(flags3 & 0x10000) // probably x,y,z coords there
+ {
+ *data << (float)0;
+ *data << (float)0;
+ *data << (float)0;
+ }
+
+ if(flags3 & 0x20000) // probably guid there
+ {
+ *data << uint64(0);
+ }
+
+ if(flags3 & 0x40000) // may be orientation
+ {
+ *data << (float)0;
+ }
+
+ Path &path = fmg->GetPath();
+
+ float x, y, z;
+ ((Player*)this)->GetPosition(x, y, z);
+
+ uint32 inflighttime = uint32(path.GetPassedLength(fmg->GetCurrentNode(), x, y, z) * 32);
+ uint32 traveltime = uint32(path.GetTotalLength() * 32);
+
+ *data << uint32(inflighttime); // passed move time?
+ *data << uint32(traveltime); // full move time?
+ *data << uint32(0); // ticks count?
+
+ uint32 poscount = uint32(path.Size());
+
+ *data << uint32(poscount); // points count
+
+ for(uint32 i = 0; i < poscount; ++i)
+ {
+ *data << path.GetNodes()[i].x;
+ *data << path.GetNodes()[i].y;
+ *data << path.GetNodes()[i].z;
+ }
+
+ /*for(uint32 i = 0; i < poscount; i++)
+ {
+ // path points
+ *data << (float)0;
+ *data << (float)0;
+ *data << (float)0;
+ }*/
+
+ *data << path.GetNodes()[poscount-1].x;
+ *data << path.GetNodes()[poscount-1].y;
+ *data << path.GetNodes()[poscount-1].z;
+
+ // target position (path end)
+ /**data << ((Unit*)this)->GetPositionX();
+ *data << ((Unit*)this)->GetPositionY();
+ *data << ((Unit*)this)->GetPositionZ();*/
+ }
+ }
+
+ // 0x8
+ if(flags & UPDATEFLAG_LOWGUID)
+ {
+ switch(GetTypeId())
+ {
+ case TYPEID_OBJECT:
+ case TYPEID_ITEM:
+ case TYPEID_CONTAINER:
+ case TYPEID_GAMEOBJECT:
+ case TYPEID_DYNAMICOBJECT:
+ case TYPEID_CORPSE:
+ *data << uint32(GetGUIDLow()); // GetGUIDLow()
+ break;
+ case TYPEID_UNIT:
+ *data << uint32(0x0000000B); // unk, can be 0xB or 0xC
+ break;
+ case TYPEID_PLAYER:
+ if(flags & UPDATEFLAG_SELF)
+ *data << uint32(0x00000015); // unk, can be 0x15 or 0x22
+ else
+ *data << uint32(0x00000008); // unk, can be 0x7 or 0x8
+ break;
+ default:
+ *data << uint32(0x00000000); // unk
+ break;
+ }
+ }
+
+ // 0x10
+ if(flags & UPDATEFLAG_HIGHGUID)
+ {
+ switch(GetTypeId())
+ {
+ case TYPEID_OBJECT:
+ case TYPEID_ITEM:
+ case TYPEID_CONTAINER:
+ case TYPEID_GAMEOBJECT:
+ case TYPEID_DYNAMICOBJECT:
+ case TYPEID_CORPSE:
+ *data << uint32(GetGUIDHigh()); // GetGUIDHigh()
+ break;
+ default:
+ *data << uint32(0x00000000); // unk
+ break;
+ }
+ }
+
+ // 0x4
+ if(flags & UPDATEFLAG_FULLGUID)
+ {
+ *data << uint8(0); // packed guid (probably target guid)
+ }
+
+ // 0x2
+ if(flags & UPDATEFLAG_TRANSPORT)
+ {
+ *data << uint32(getMSTime()); // ms time
+ }
+}
+
+void Object::_BuildValuesUpdate(uint8 updatetype, ByteBuffer * data, UpdateMask *updateMask, Player *target) const
+{
+ if(!target)
+ return;
+
+ bool IsActivateToQuest = false;
+ if (updatetype == UPDATETYPE_CREATE_OBJECT || updatetype == UPDATETYPE_CREATE_OBJECT2)
+ {
+ if (isType(TYPEMASK_GAMEOBJECT) && !((GameObject*)this)->IsTransport())
+ {
+ if ( ((GameObject*)this)->ActivateToQuest(target) || target->isGameMaster())
+ {
+ IsActivateToQuest = true;
+ updateMask->SetBit(GAMEOBJECT_DYN_FLAGS);
+ }
+ }
+ }
+ else //case UPDATETYPE_VALUES
+ {
+ if (isType(TYPEMASK_GAMEOBJECT) && !((GameObject*)this)->IsTransport())
+ {
+ if ( ((GameObject*)this)->ActivateToQuest(target) || target->isGameMaster())
+ {
+ IsActivateToQuest = true;
+ }
+ updateMask->SetBit(GAMEOBJECT_DYN_FLAGS);
+ updateMask->SetBit(GAMEOBJECT_ANIMPROGRESS);
+ }
+ }
+
+ WPAssert(updateMask && updateMask->GetCount() == m_valuesCount);
+
+ *data << (uint8)updateMask->GetBlockCount();
+ data->append( updateMask->GetMask(), updateMask->GetLength() );
+
+ // 2 specialized loops for speed optimization in non-unit case
+ if(isType(TYPEMASK_UNIT)) // unit (creature/player) case
+ {
+ for( uint16 index = 0; index < m_valuesCount; index ++ )
+ {
+ if( updateMask->GetBit( index ) )
+ {
+ // remove custom flag before send
+ if( index == UNIT_NPC_FLAGS )
+ *data << uint32(m_uint32Values[ index ] & ~UNIT_NPC_FLAG_GUARD);
+ // FIXME: Some values at server stored in float format but must be sent to client in uint32 format
+ else if(index >= UNIT_FIELD_BASEATTACKTIME && index <= UNIT_FIELD_RANGEDATTACKTIME)
+ {
+ // convert from float to uint32 and send
+ *data << uint32(m_floatValues[ index ] < 0 ? 0 : m_floatValues[ index ]);
+ }
+ // there are some float values which may be negative or can't get negative due to other checks
+ else if(index >= UNIT_FIELD_NEGSTAT0 && index <= UNIT_FIELD_NEGSTAT4 ||
+ index >= UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE && index <= (UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + 6) ||
+ index >= UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE && index <= (UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + 6) ||
+ index >= UNIT_FIELD_POSSTAT0 && index <= UNIT_FIELD_POSSTAT4)
+ {
+ *data << uint32(m_floatValues[ index ]);
+ }
+ // Gamemasters should be always able to select units - remove not selectable flag
+ else if(index == UNIT_FIELD_FLAGS && target->isGameMaster())
+ {
+ *data << (m_uint32Values[ index ] & ~UNIT_FLAG_NOT_SELECTABLE);
+ }
+ // hide lootable animation for unallowed players
+ else if(index == UNIT_DYNAMIC_FLAGS && GetTypeId() == TYPEID_UNIT)
+ {
+ if(!target->isAllowedToLoot((Creature*)this))
+ *data << (m_uint32Values[ index ] & ~UNIT_DYNFLAG_LOOTABLE);
+ else
+ *data << (m_uint32Values[ index ] & ~UNIT_DYNFLAG_OTHER_TAGGER);
+ }
+ else
+ {
+ // send in current format (float as float, uint32 as uint32)
+ *data << m_uint32Values[ index ];
+ }
+ }
+ }
+ }
+ else if(isType(TYPEMASK_GAMEOBJECT)) // gameobject case
+ {
+ for( uint16 index = 0; index < m_valuesCount; index ++ )
+ {
+ if( updateMask->GetBit( index ) )
+ {
+ // send in current format (float as float, uint32 as uint32)
+ if ( index == GAMEOBJECT_DYN_FLAGS )
+ {
+ if(IsActivateToQuest )
+ {
+ switch(((GameObject*)this)->GetGoType())
+ {
+ case GAMEOBJECT_TYPE_CHEST:
+ *data << uint32(9); // enable quest object. Represent 9, but 1 for client before 2.3.0
+ break;
+ case GAMEOBJECT_TYPE_GOOBER:
+ *data << uint32(1);
+ break;
+ default:
+ *data << uint32(0); //unknown. not happen.
+ break;
+ }
+ }
+ else
+ *data << uint32(0); // disable quest object
+ }
+ else
+ *data << m_uint32Values[ index ]; // other cases
+ }
+ }
+ }
+ else // other objects case (no special index checks)
+ {
+ for( uint16 index = 0; index < m_valuesCount; index ++ )
+ {
+ if( updateMask->GetBit( index ) )
+ {
+ // send in current format (float as float, uint32 as uint32)
+ *data << m_uint32Values[ index ];
+ }
+ }
+ }
+}
+
+void Object::ClearUpdateMask(bool remove)
+{
+ for( uint16 index = 0; index < m_valuesCount; index ++ )
+ {
+ if(m_uint32Values_mirror[index]!= m_uint32Values[index])
+ m_uint32Values_mirror[index] = m_uint32Values[index];
+ }
+ if(m_objectUpdated)
+ {
+ if(remove)
+ ObjectAccessor::Instance().RemoveUpdateObject(this);
+ m_objectUpdated = false;
+ }
+}
+
+// Send current value fields changes to all viewers
+void Object::SendUpdateObjectToAllExcept(Player* exceptPlayer)
+{
+ // changes will be send in create packet
+ if(!IsInWorld())
+ return;
+
+ // nothing do
+ if(!m_objectUpdated)
+ return;
+
+ ObjectAccessor::UpdateObject(this,exceptPlayer);
+}
+
+bool Object::LoadValues(const char* data)
+{
+ if(!m_uint32Values) _InitValues();
+
+ Tokens tokens = StrSplit(data, " ");
+
+ if(tokens.size() != m_valuesCount)
+ return false;
+
+ Tokens::iterator iter;
+ int index;
+ for (iter = tokens.begin(), index = 0; index < m_valuesCount; ++iter, ++index)
+ {
+ m_uint32Values[index] = atol((*iter).c_str());
+ }
+
+ return true;
+}
+
+void Object::_SetUpdateBits(UpdateMask *updateMask, Player* /*target*/) const
+{
+ for( uint16 index = 0; index < m_valuesCount; index ++ )
+ {
+ if(m_uint32Values_mirror[index]!= m_uint32Values[index])
+ updateMask->SetBit(index);
+ }
+}
+
+void Object::_SetCreateBits(UpdateMask *updateMask, Player* /*target*/) const
+{
+ for( uint16 index = 0; index < m_valuesCount; index++ )
+ {
+ if(GetUInt32Value(index) != 0)
+ updateMask->SetBit(index);
+ }
+}
+
+void Object::SetInt32Value( uint16 index, int32 value )
+{
+ ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
+
+ if(m_int32Values[ index ] != value)
+ {
+ m_int32Values[ index ] = value;
+
+ if(m_inWorld)
+ {
+ if(!m_objectUpdated)
+ {
+ ObjectAccessor::Instance().AddUpdateObject(this);
+ m_objectUpdated = true;
+ }
+ }
+ }
+}
+
+void Object::SetUInt32Value( uint16 index, uint32 value )
+{
+ ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
+
+ if(m_uint32Values[ index ] != value)
+ {
+ m_uint32Values[ index ] = value;
+
+ if(m_inWorld)
+ {
+ if(!m_objectUpdated)
+ {
+ ObjectAccessor::Instance().AddUpdateObject(this);
+ m_objectUpdated = true;
+ }
+ }
+ }
+}
+
+void Object::SetUInt64Value( uint16 index, const uint64 &value )
+{
+ ASSERT( index + 1 < m_valuesCount || PrintIndexError( index , true ) );
+ if(*((uint64*)&(m_uint32Values[ index ])) != value)
+ {
+ m_uint32Values[ index ] = *((uint32*)&value);
+ m_uint32Values[ index + 1 ] = *(((uint32*)&value) + 1);
+
+ if(m_inWorld)
+ {
+ if(!m_objectUpdated)
+ {
+ ObjectAccessor::Instance().AddUpdateObject(this);
+ m_objectUpdated = true;
+ }
+ }
+ }
+}
+
+void Object::SetFloatValue( uint16 index, float value )
+{
+ ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
+
+ if(m_floatValues[ index ] != value)
+ {
+ m_floatValues[ index ] = value;
+
+ if(m_inWorld)
+ {
+ if(!m_objectUpdated)
+ {
+ ObjectAccessor::Instance().AddUpdateObject(this);
+ m_objectUpdated = true;
+ }
+ }
+ }
+}
+
+void Object::SetByteValue( uint16 index, uint8 offset, uint8 value )
+{
+ ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
+
+ if(offset > 4)
+ {
+ sLog.outError("Object::SetByteValue: wrong offset %u", offset);
+ return;
+ }
+
+ if(uint8(m_uint32Values[ index ] >> (offset * 8)) != value)
+ {
+ m_uint32Values[ index ] &= ~uint32(uint32(0xFF) << (offset * 8));
+ m_uint32Values[ index ] |= uint32(uint32(value) << (offset * 8));
+
+ if(m_inWorld)
+ {
+ if(!m_objectUpdated)
+ {
+ ObjectAccessor::Instance().AddUpdateObject(this);
+ m_objectUpdated = true;
+ }
+ }
+ }
+}
+
+void Object::SetUInt16Value( uint16 index, uint8 offset, uint16 value )
+{
+ ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
+
+ if(offset > 2)
+ {
+ sLog.outError("Object::SetUInt16Value: wrong offset %u", offset);
+ return;
+ }
+
+ if(uint8(m_uint32Values[ index ] >> (offset * 16)) != value)
+ {
+ m_uint32Values[ index ] &= ~uint32(uint32(0xFFFF) << (offset * 16));
+ m_uint32Values[ index ] |= uint32(uint32(value) << (offset * 16));
+
+ if(m_inWorld)
+ {
+ if(!m_objectUpdated)
+ {
+ ObjectAccessor::Instance().AddUpdateObject(this);
+ m_objectUpdated = true;
+ }
+ }
+ }
+}
+
+void Object::SetStatFloatValue( uint16 index, float value)
+{
+ if(value < 0)
+ value = 0.0f;
+
+ SetFloatValue(index, value);
+}
+
+void Object::SetStatInt32Value( uint16 index, int32 value)
+{
+ if(value < 0)
+ value = 0;
+
+ SetUInt32Value(index, uint32(value));
+}
+
+void Object::ApplyModUInt32Value(uint16 index, int32 val, bool apply)
+{
+ int32 cur = GetUInt32Value(index);
+ cur += (apply ? val : -val);
+ if(cur < 0)
+ cur = 0;
+ SetUInt32Value(index,cur);
+}
+
+void Object::ApplyModInt32Value(uint16 index, int32 val, bool apply)
+{
+ int32 cur = GetInt32Value(index);
+ cur += (apply ? val : -val);
+ SetInt32Value(index,cur);
+}
+
+void Object::ApplyModSignedFloatValue(uint16 index, float val, bool apply)
+{
+ float cur = GetFloatValue(index);
+ cur += (apply ? val : -val);
+ SetFloatValue(index,cur);
+}
+
+void Object::ApplyModPositiveFloatValue(uint16 index, float val, bool apply)
+{
+ float cur = GetFloatValue(index);
+ cur += (apply ? val : -val);
+ if(cur < 0)
+ cur = 0;
+ SetFloatValue(index,cur);
+}
+
+void Object::SetFlag( uint16 index, uint32 newFlag )
+{
+ ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
+ uint32 oldval = m_uint32Values[ index ];
+ uint32 newval = oldval | newFlag;
+
+ if(oldval != newval)
+ {
+ m_uint32Values[ index ] = newval;
+
+ if(m_inWorld)
+ {
+ if(!m_objectUpdated)
+ {
+ ObjectAccessor::Instance().AddUpdateObject(this);
+ m_objectUpdated = true;
+ }
+ }
+ }
+}
+
+void Object::RemoveFlag( uint16 index, uint32 oldFlag )
+{
+ ASSERT( index < m_valuesCount || PrintIndexError( index , true ) );
+ uint32 oldval = m_uint32Values[ index ];
+ uint32 newval = oldval & ~oldFlag;
+
+ if(oldval != newval)
+ {
+ m_uint32Values[ index ] = newval;
+
+ if(m_inWorld)
+ {
+ if(!m_objectUpdated)
+ {
+ ObjectAccessor::Instance().AddUpdateObject(this);
+ m_objectUpdated = true;
+ }
+ }
+ }
+}
+
+bool Object::PrintIndexError(uint32 index, bool set) const
+{
+ sLog.outError("ERROR: Attempt %s non-existed value field: %u (count: %u) for object typeid: %u type mask: %u",(set ? "set value to" : "get value from"),index,m_valuesCount,GetTypeId(),m_objectType);
+
+ // assert must fail after function call
+ return false;
+}
+
+WorldObject::WorldObject()
+{
+ m_positionX = 0.0f;
+ m_positionY = 0.0f;
+ m_positionZ = 0.0f;
+ m_orientation = 0.0f;
+
+ m_mapId = 0;
+ m_InstanceId = 0;
+
+ m_name = "";
+
+ mSemaphoreTeleport = false;
+}
+
+void WorldObject::_Create( uint32 guidlow, HighGuid guidhigh, uint32 mapid )
+{
+ Object::_Create(guidlow, 0, guidhigh);
+
+ m_mapId = mapid;
+}
+
+uint32 WorldObject::GetZoneId() const
+{
+ return MapManager::Instance().GetBaseMap(m_mapId)->GetZoneId(m_positionX,m_positionY);
+}
+
+uint32 WorldObject::GetAreaId() const
+{
+ return MapManager::Instance().GetBaseMap(m_mapId)->GetAreaId(m_positionX,m_positionY);
+}
+
+InstanceData* WorldObject::GetInstanceData()
+{
+ Map *map = MapManager::Instance().GetMap(m_mapId, this);
+ return map->IsDungeon() ? ((InstanceMap*)map)->GetInstanceData() : NULL;
+}
+
+ //slow
+float WorldObject::GetDistance(const WorldObject* obj) const
+{
+ float dx = GetPositionX() - obj->GetPositionX();
+ float dy = GetPositionY() - obj->GetPositionY();
+ float dz = GetPositionZ() - obj->GetPositionZ();
+ float sizefactor = GetObjectSize() + obj->GetObjectSize();
+ float dist = sqrt((dx*dx) + (dy*dy) + (dz*dz)) - sizefactor;
+ return ( dist > 0 ? dist : 0);
+}
+
+float WorldObject::GetDistance2d(float x, float y) const
+{
+ float dx = GetPositionX() - x;
+ float dy = GetPositionY() - y;
+ float sizefactor = GetObjectSize();
+ float dist = sqrt((dx*dx) + (dy*dy)) - sizefactor;
+ return ( dist > 0 ? dist : 0);
+}
+
+float WorldObject::GetDistance(const float x, const float y, const float z) const
+{
+ float dx = GetPositionX() - x;
+ float dy = GetPositionY() - y;
+ float dz = GetPositionZ() - z;
+ float sizefactor = GetObjectSize();
+ float dist = sqrt((dx*dx) + (dy*dy) + (dz*dz)) - sizefactor;
+ return ( dist > 0 ? dist : 0);
+}
+
+float WorldObject::GetDistance2d(const WorldObject* obj) const
+{
+ float dx = GetPositionX() - obj->GetPositionX();
+ float dy = GetPositionY() - obj->GetPositionY();
+ float sizefactor = GetObjectSize() + obj->GetObjectSize();
+ float dist = sqrt((dx*dx) + (dy*dy)) - sizefactor;
+ return ( dist > 0 ? dist : 0);
+}
+
+float WorldObject::GetDistanceZ(const WorldObject* obj) const
+{
+ float dz = fabs(GetPositionZ() - obj->GetPositionZ());
+ float sizefactor = GetObjectSize() + obj->GetObjectSize();
+ float dist = dz - sizefactor;
+ return ( dist > 0 ? dist : 0);
+}
+
+bool WorldObject::IsWithinDistInMap(const WorldObject* obj, const float dist2compare) const
+{
+ if (!obj || !IsInMap(obj)) return false;
+
+ float dx = GetPositionX() - obj->GetPositionX();
+ float dy = GetPositionY() - obj->GetPositionY();
+ float dz = GetPositionZ() - obj->GetPositionZ();
+ float distsq = dx*dx + dy*dy + dz*dz;
+ float sizefactor = GetObjectSize() + obj->GetObjectSize();
+ float maxdist = dist2compare + sizefactor;
+
+ return distsq < maxdist * maxdist;
+}
+
+bool WorldObject::IsWithinLOSInMap(const WorldObject* obj) const
+{
+ if (!IsInMap(obj)) return false;
+ float ox,oy,oz;
+ obj->GetPosition(ox,oy,oz);
+ return(IsWithinLOS(ox, oy, oz ));
+}
+
+bool WorldObject::IsWithinLOS(const float ox, const float oy, const float oz ) const
+{
+ float x,y,z;
+ GetPosition(x,y,z);
+ VMAP::IVMapManager *vMapManager = VMAP::VMapFactory::createOrGetVMapManager();
+ return vMapManager->isInLineOfSight(GetMapId(), x, y, z+2.0f, ox, oy, oz+2.0f);
+}
+
+float WorldObject::GetAngle(const WorldObject* obj) const
+{
+ if(!obj) return 0;
+ return GetAngle( obj->GetPositionX(), obj->GetPositionY() );
+}
+
+// Return angle in range 0..2*pi
+float WorldObject::GetAngle( const float x, const float y ) const
+{
+ float dx = x - GetPositionX();
+ float dy = y - GetPositionY();
+
+ float ang = atan2(dy, dx);
+ ang = (ang >= 0) ? ang : 2 * M_PI + ang;
+ return ang;
+}
+
+bool WorldObject::HasInArc(const float arcangle, const WorldObject* obj) const
+{
+ float arc = arcangle;
+
+ // move arc to range 0.. 2*pi
+ while( arc >= 2.0f * M_PI )
+ arc -= 2.0f * M_PI;
+ while( arc < 0 )
+ arc += 2.0f * M_PI;
+
+ float angle = GetAngle( obj );
+ angle -= m_orientation;
+
+ // move angle to range -pi ... +pi
+ while( angle > M_PI)
+ angle -= 2.0f * M_PI;
+ while(angle < -M_PI)
+ angle += 2.0f * M_PI;
+
+ float lborder = -1 * (arc/2.0f); // in range -pi..0
+ float rborder = (arc/2.0f); // in range 0..pi
+ return (( angle >= lborder ) && ( angle <= rborder ));
+}
+
+void WorldObject::GetRandomPoint( float x, float y, float z, float distance, float &rand_x, float &rand_y, float &rand_z) const
+{
+ if(distance==0)
+ {
+ rand_x = x;
+ rand_y = y;
+ rand_z = z;
+ return;
+ }
+
+ // angle to face `obj` to `this`
+ float angle = rand_norm()*2*M_PI;
+ float new_dist = rand_norm()*distance;
+
+ rand_x = x + new_dist * cos(angle);
+ rand_y = y + new_dist * sin(angle);
+ rand_z = z;
+
+ MaNGOS::NormalizeMapCoord(rand_x);
+ MaNGOS::NormalizeMapCoord(rand_y);
+ UpdateGroundPositionZ(rand_x,rand_y,rand_z); // update to LOS height if available
+}
+
+void WorldObject::UpdateGroundPositionZ(float x, float y, float &z) const
+{
+ float new_z = MapManager::Instance().GetBaseMap(GetMapId())->GetHeight(x,y,z,true);
+ if(new_z > INVALID_HEIGHT)
+ z = new_z+ 0.05f; // just to be sure that we are not a few pixel under the surface
+}
+
+bool WorldObject::IsPositionValid() const
+{
+ return MaNGOS::IsValidMapCoord(m_positionX,m_positionY,m_positionZ,m_orientation);
+}
+
+void WorldObject::MonsterSay(const char* text, uint32 language, uint64 TargetGuid)
+{
+ WorldPacket data(SMSG_MESSAGECHAT, 200);
+ BuildMonsterChat(&data,CHAT_MSG_MONSTER_SAY,text,language,GetName(),TargetGuid);
+ SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY),true);
+}
+
+void WorldObject::MonsterYell(const char* text, uint32 language, uint64 TargetGuid)
+{
+ WorldPacket data(SMSG_MESSAGECHAT, 200);
+ BuildMonsterChat(&data,CHAT_MSG_MONSTER_YELL,text,language,GetName(),TargetGuid);
+ SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_YELL),true);
+}
+
+void WorldObject::MonsterTextEmote(const char* text, uint64 TargetGuid, bool IsBossEmote)
+{
+ WorldPacket data(SMSG_MESSAGECHAT, 200);
+ BuildMonsterChat(&data,IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE,text,LANG_UNIVERSAL,GetName(),TargetGuid);
+ SendMessageToSetInRange(&data,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE),true);
+}
+
+void WorldObject::MonsterWhisper(const char* text, uint64 receiver, bool IsBossWhisper)
+{
+ Player *player = objmgr.GetPlayer(receiver);
+ if(!player || !player->GetSession())
+ return;
+
+ WorldPacket data(SMSG_MESSAGECHAT, 200);
+ BuildMonsterChat(&data,IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER,text,LANG_UNIVERSAL,GetName(),receiver);
+
+ player->GetSession()->SendPacket(&data);
+}
+
+void WorldObject::SendPlaySound(uint32 Sound, bool OnlySelf)
+{
+ WorldPacket data(SMSG_PLAY_SOUND, 4);
+ data << Sound;
+ if (OnlySelf && GetTypeId() == TYPEID_PLAYER )
+ ((Player*)this)->GetSession()->SendPacket( &data );
+ else
+ SendMessageToSet( &data, true ); // ToSelf ignored in this case
+}
+
+namespace MaNGOS
+{
+ class MessageChatLocaleCacheDo
+ {
+ public:
+ MessageChatLocaleCacheDo(WorldObject const& obj, ChatMsg msgtype, int32 textId, uint32 language, uint64 targetGUID, float dist)
+ : i_object(obj), i_msgtype(msgtype), i_textId(textId), i_language(language),
+ i_targetGUID(targetGUID), i_dist(dist)
+ {
+ }
+
+ ~MessageChatLocaleCacheDo()
+ {
+ for(int i = 0; i < i_data_cache.size(); ++i)
+ delete i_data_cache[i];
+ }
+
+ void operator()(Player* p)
+ {
+ // skip far away players
+ if(p->GetDistance(&i_object) > i_dist)
+ return;
+
+ uint32 loc_idx = p->GetSession()->GetSessionDbLocaleIndex();
+ uint32 cache_idx = loc_idx+1;
+ WorldPacket* data;
+
+ // create if not cached yet
+ if(i_data_cache.size() < cache_idx+1 || !i_data_cache[cache_idx])
+ {
+ if(i_data_cache.size() < cache_idx+1)
+ i_data_cache.resize(cache_idx+1);
+
+ char const* text = objmgr.GetMangosString(i_textId,loc_idx);
+
+ data = new WorldPacket(SMSG_MESSAGECHAT, 200);
+
+ // TODO: i_object.GetName() also must be localized?
+ i_object.BuildMonsterChat(data,i_msgtype,text,i_language,i_object.GetName(),i_targetGUID);
+
+ i_data_cache[cache_idx] = data;
+ }
+ else
+ data = i_data_cache[cache_idx];
+
+ p->SendDirectMessage(data);
+ }
+
+ private:
+ WorldObject const& i_object;
+ ChatMsg i_msgtype;
+ int32 i_textId;
+ uint32 i_language;
+ uint64 i_targetGUID;
+ float i_dist;
+ std::vector i_data_cache; // 0 = default, i => i-1 locale index
+ };
+} // namespace MaNGOS
+
+void WorldObject::MonsterSay(int32 textId, uint32 language, uint64 TargetGuid)
+{
+ CellPair p = MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY());
+
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+ cell.SetNoCreate();
+
+ MaNGOS::MessageChatLocaleCacheDo say_do(*this, CHAT_MSG_MONSTER_SAY, textId,language,TargetGuid,sWorld.getConfig(CONFIG_LISTEN_RANGE_SAY));
+ MaNGOS::PlayerWorker say_worker(say_do);
+ TypeContainerVisitor, WorldTypeMapContainer > message(say_worker);
+ CellLock cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, message, *GetMap());
+}
+
+void WorldObject::MonsterYell(int32 textId, uint32 language, uint64 TargetGuid)
+{
+ CellPair p = MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY());
+
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+ cell.SetNoCreate();
+
+ MaNGOS::MessageChatLocaleCacheDo say_do(*this, CHAT_MSG_MONSTER_YELL, textId,language,TargetGuid,sWorld.getConfig(CONFIG_LISTEN_RANGE_YELL));
+ MaNGOS::PlayerWorker say_worker(say_do);
+ TypeContainerVisitor, WorldTypeMapContainer > message(say_worker);
+ CellLock cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, message, *GetMap());
+}
+
+void WorldObject::MonsterTextEmote(int32 textId, uint64 TargetGuid, bool IsBossEmote)
+{
+ CellPair p = MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY());
+
+ Cell cell(p);
+ cell.data.Part.reserved = ALL_DISTRICT;
+ cell.SetNoCreate();
+
+ MaNGOS::MessageChatLocaleCacheDo say_do(*this, IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, textId,LANG_UNIVERSAL,TargetGuid,sWorld.getConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE));
+ MaNGOS::PlayerWorker say_worker(say_do);
+ TypeContainerVisitor, WorldTypeMapContainer > message(say_worker);
+ CellLock cell_lock(cell, p);
+ cell_lock->Visit(cell_lock, message, *GetMap());
+}
+
+void WorldObject::MonsterWhisper(int32 textId, uint64 receiver, bool IsBossWhisper)
+{
+ Player *player = objmgr.GetPlayer(receiver);
+ if(!player || !player->GetSession())
+ return;
+
+ uint32 loc_idx = player->GetSession()->GetSessionDbLocaleIndex();
+ char const* text = objmgr.GetMangosString(textId,loc_idx);
+
+ WorldPacket data(SMSG_MESSAGECHAT, 200);
+ BuildMonsterChat(&data,IsBossWhisper ? CHAT_MSG_RAID_BOSS_WHISPER : CHAT_MSG_MONSTER_WHISPER,text,LANG_UNIVERSAL,GetName(),receiver);
+
+ player->GetSession()->SendPacket(&data);
+}
+
+void WorldObject::BuildMonsterChat(WorldPacket *data, uint8 msgtype, char const* text, uint32 language, char const* name, uint64 targetGuid) const
+{
+ bool pre = (msgtype==CHAT_MSG_MONSTER_EMOTE || msgtype==CHAT_MSG_RAID_BOSS_EMOTE);
+
+ *data << (uint8)msgtype;
+ *data << (uint32)language;
+ *data << (uint64)GetGUID();
+ *data << (uint32)0; //2.1.0
+ *data << (uint32)(strlen(name)+1);
+ *data << name;
+ *data << (uint64)targetGuid; //Unit Target
+ if( targetGuid && !IS_PLAYER_GUID(targetGuid) )
+ {
+ *data << (uint32)1; // target name length
+ *data << (uint8)0; // target name
+ }
+ *data << (uint32)(strlen(text)+1+(pre?3:0));
+ if(pre)
+ data->append("%s ",3);
+ *data << text;
+ *data << (uint8)0; // ChatTag
+}
+
+void WorldObject::BuildHeartBeatMsg(WorldPacket *data) const
+{
+ //Heartbeat message cannot be used for non-units
+ if (!isType(TYPEMASK_UNIT))
+ return;
+
+ data->Initialize(MSG_MOVE_HEARTBEAT, 32);
+ data->append(GetPackGUID());
+ *data << uint32(((Unit*)this)->GetUnitMovementFlags()); // movement flags
+ *data << uint8(0); // 2.3.0
+ *data << getMSTime(); // time
+ *data << m_positionX;
+ *data << m_positionY;
+ *data << m_positionZ;
+ *data << m_orientation;
+ *data << uint32(0);
+}
+
+void WorldObject::BuildTeleportAckMsg(WorldPacket *data, float x, float y, float z, float ang) const
+{
+ //TeleportAck message cannot be used for non-units
+ if (!isType(TYPEMASK_UNIT))
+ return;
+
+ data->Initialize(MSG_MOVE_TELEPORT_ACK, 41);
+ data->append(GetPackGUID());
+ *data << uint32(0); // this value increments every time
+ *data << uint32(((Unit*)this)->GetUnitMovementFlags()); // movement flags
+ *data << uint8(0); // 2.3.0
+ *data << getMSTime(); // time
+ *data << x;
+ *data << y;
+ *data << z;
+ *data << ang;
+ *data << uint32(0);
+}
+
+void WorldObject::SendMessageToSet(WorldPacket *data, bool /*bToSelf*/)
+{
+ MapManager::Instance().GetMap(m_mapId, this)->MessageBroadcast(this, data);
+}
+
+void WorldObject::SendMessageToSetInRange(WorldPacket *data, float dist, bool /*bToSelf*/)
+{
+ MapManager::Instance().GetMap(m_mapId, this)->MessageDistBroadcast(this, data, dist);
+}
+
+void WorldObject::SendObjectDeSpawnAnim(uint64 guid)
+{
+ WorldPacket data(SMSG_GAMEOBJECT_DESPAWN_ANIM, 8);
+ data << guid;
+ SendMessageToSet(&data, true);
+}
+
+Map* WorldObject::GetMap() const
+{
+ return MapManager::Instance().GetMap(GetMapId(), this);
+}
+
+Map const* WorldObject::GetBaseMap() const
+{
+ return MapManager::Instance().GetBaseMap(GetMapId());
+}
+
+void WorldObject::AddObjectToRemoveList()
+{
+ Map* map = GetMap();
+ if(!map)
+ {
+ sLog.outError("Object (TypeId: %u Entry: %u GUID: %u) at attempt add to move list not have valid map (Id: %u).",GetTypeId(),GetEntry(),GetGUIDLow(),GetMapId());
+ return;
+ }
+
+ map->AddObjectToRemoveList(this);
+}
+
+Creature* WorldObject::SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime)
+{
+ TemporarySummon* pCreature = new TemporarySummon(GetGUID());
+
+ pCreature->SetInstanceId(GetInstanceId());
+ uint32 team = 0;
+ if (GetTypeId()==TYPEID_PLAYER)
+ team = ((Player*)this)->GetTeam();
+
+ if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), GetMap(), id, team))
+ {
+ delete pCreature;
+ return NULL;
+ }
+
+ if (x == 0.0f && y == 0.0f && z == 0.0f)
+ GetClosePoint(x, y, z, pCreature->GetObjectSize());
+
+ pCreature->Relocate(x, y, z, ang);
+
+ if(!pCreature->IsPositionValid())
+ {
+ sLog.outError("ERROR: Creature (guidlow %d, entry %d) not summoned. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
+ delete pCreature;
+ return NULL;
+ }
+
+ pCreature->Summon(spwtype, despwtime);
+
+ if(GetTypeId()==TYPEID_UNIT && ((Creature*)this)->AI())
+ ((Creature*)this)->AI()->JustSummoned(pCreature);
+
+ //return the creature therewith the summoner has access to it
+ return pCreature;
+}
+
+void WorldObject::GetNearPoint2D(float &x, float &y, float distance2d, float absAngle ) const
+{
+ x = GetPositionX() + (GetObjectSize() + distance2d) * cos(absAngle);
+ y = GetPositionY() + (GetObjectSize() + distance2d) * sin(absAngle);
+
+ MaNGOS::NormalizeMapCoord(x);
+ MaNGOS::NormalizeMapCoord(y);
+}
+
+void WorldObject::GetNearPoint(WorldObject const* searcher, float &x, float &y, float &z, float searcher_size, float distance2d, float absAngle ) const
+{
+ GetNearPoint2D(x,y,distance2d+searcher_size,absAngle);
+
+ z = GetPositionZ();
+
+ UpdateGroundPositionZ(x,y,z);
+}
diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp
index 1bbca47d3b5..74a6a3ef684 100644
--- a/src/game/ObjectMgr.cpp
+++ b/src/game/ObjectMgr.cpp
@@ -6679,6 +6679,8 @@ void ObjectMgr::LoadTrainerSpell()
itr->second.Clear();
m_mCacheTrainerSpellMap.clear();
+ std::set skip_trainers;
+
QueryResult *result = WorldDatabase.PQuery("SELECT entry, spell,spellcost,reqskill,reqskillvalue,reqlevel FROM npc_trainer");
if( !result )
@@ -6714,7 +6716,11 @@ void ObjectMgr::LoadTrainerSpell()
if(!(cInfo->npcflag & UNIT_NPC_FLAG_TRAINER))
{
- sLog.outErrorDb("Table `npc_trainer` have data for not creature template (Entry: %u) without trainer flag, ignore", entry);
+ 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;
}
@@ -6764,6 +6770,8 @@ void ObjectMgr::LoadVendors()
itr->second.Clear();
m_mCacheVendorItemMap.clear();
+ std::set skip_vendors;
+
QueryResult *result = WorldDatabase.PQuery("SELECT entry, item, maxcount, incrtime, ExtendedCost FROM npc_vendor");
if( !result )
{
@@ -6790,7 +6798,7 @@ void ObjectMgr::LoadVendors()
uint32 incrtime = fields[3].GetUInt32();
uint32 ExtendedCost = fields[4].GetUInt32();
- if(!IsVendorItemValid(entry,item_id,maxcount,incrtime,ExtendedCost))
+ if(!IsVendorItemValid(entry,item_id,maxcount,incrtime,ExtendedCost,NULL,&skip_vendors))
continue;
VendorItemData& vList = m_mCacheVendorItemMap[entry];
@@ -6878,7 +6886,7 @@ bool ObjectMgr::RemoveVendorItem( uint32 entry,uint32 item )
return true;
}
-bool ObjectMgr::IsVendorItemValid( uint32 vendor_entry, uint32 item_id, uint32 maxcount, uint32 incrtime, uint32 ExtendedCost, Player* pl ) const
+bool ObjectMgr::IsVendorItemValid( uint32 vendor_entry, uint32 item_id, uint32 maxcount, uint32 incrtime, uint32 ExtendedCost, Player* pl, std::set* skip_vendors ) const
{
CreatureInfo const* cInfo = GetCreatureTemplate(vendor_entry);
if(!cInfo)
@@ -6892,10 +6900,16 @@ bool ObjectMgr::IsVendorItemValid( uint32 vendor_entry, uint32 item_id, uint32 m
if(!(cInfo->npcflag & UNIT_NPC_FLAG_VENDOR))
{
- if(pl)
- ChatHandler(pl).SendSysMessage(LANG_COMMAND_VENDORSELECTION);
- else
- sLog.outErrorDb("Table `npc_vendor` have data for not creature template (Entry: %u) without vendor flag, ignore", vendor_entry);
+ if(!skip_vendors || skip_vendors->count(vendor_entry)==0)
+ {
+ if(pl)
+ ChatHandler(pl).SendSysMessage(LANG_COMMAND_VENDORSELECTION);
+ else
+ sLog.outErrorDb("Table `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;
}
diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h
index 5bb3aafde72..f5d35009307 100644
--- a/src/game/ObjectMgr.h
+++ b/src/game/ObjectMgr.h
@@ -742,7 +742,7 @@ class ObjectMgr
}
void AddVendorItem(uint32 entry,uint32 item, uint32 maxcount, uint32 incrtime, uint32 ExtendedCost);
bool RemoveVendorItem(uint32 entry,uint32 item);
- bool IsVendorItemValid( uint32 vendor_entry, uint32 item, uint32 maxcount, uint32 ptime, uint32 ExtendedCost, Player* pl = NULL ) const;
+ bool IsVendorItemValid( uint32 vendor_entry, uint32 item, uint32 maxcount, uint32 ptime, uint32 ExtendedCost, Player* pl = NULL, std::set* skip_vendors = NULL ) const;
protected:
uint32 m_auctionid;
uint32 m_mailid;
diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp
index 3251d02d5b9..9ac00048d49 100644
--- a/src/game/PetHandler.cpp
+++ b/src/game/PetHandler.cpp
@@ -1,648 +1,649 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS
- *
- * 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 "WorldPacket.h"
-#include "WorldSession.h"
-#include "World.h"
-#include "ObjectMgr.h"
-#include "SpellMgr.h"
-#include "Log.h"
-#include "Opcodes.h"
-#include "Spell.h"
-#include "ObjectAccessor.h"
-#include "MapManager.h"
-#include "CreatureAI.h"
-#include "Util.h"
-#include "Pet.h"
-
-void WorldSession::HandlePetAction( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data,8+2+2+8);
-
- uint64 guid1;
- uint16 spellid;
- uint16 flag;
- uint64 guid2;
- recv_data >> guid1; //pet guid
- recv_data >> spellid;
- recv_data >> flag; //delete = 0x0700 CastSpell = C100
- recv_data >> guid2; //tag guid
-
- // used also for charmed creature
- Unit* pet= ObjectAccessor::GetUnit(*_player,guid1);
- sLog.outDetail( "HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.\n", uint32(GUID_LOPART(guid1)), flag, spellid, uint32(GUID_LOPART(guid2)) );
- if(!pet)
- {
- sLog.outError( "Pet %u not exist.\n", uint32(GUID_LOPART(guid1)) );
- return;
- }
-
- if(pet != GetPlayer()->GetPet() && pet != GetPlayer()->GetCharm())
- {
- sLog.outError( "HandlePetAction.Pet %u isn't pet of player %s .\n", uint32(GUID_LOPART(guid1)),GetPlayer()->GetName() );
- return;
- }
-
- if(!pet->isAlive())
- return;
-
- if(pet->GetTypeId() == TYPEID_PLAYER && !(flag == ACT_COMMAND && spellid == COMMAND_ATTACK))
- return;
-
- CharmInfo *charmInfo = pet->GetCharmInfo();
- if(!charmInfo)
- {
- sLog.outError("WorldSession::HandlePetAction: object "I64FMTD" is considered pet-like but doesn't have a charminfo!", pet->GetGUID());
- return;
- }
-
- switch(flag)
- {
- case ACT_COMMAND: //0x0700
- switch(spellid)
- {
- case COMMAND_STAY: //flat=1792 //STAY
- pet->StopMoving();
- pet->GetMotionMaster()->Clear();
- pet->GetMotionMaster()->MoveIdle();
- charmInfo->SetCommandState( COMMAND_STAY );
- break;
- case COMMAND_FOLLOW: //spellid=1792 //FOLLOW
- pet->AttackStop();
- pet->GetMotionMaster()->MoveFollow(_player,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE);
- charmInfo->SetCommandState( COMMAND_FOLLOW );
- break;
- case COMMAND_ATTACK: //spellid=1792 //ATTACK
- {
- // only place where pet can be player
- pet->clearUnitState(UNIT_STAT_FOLLOW);
- uint64 selguid = _player->GetSelection();
- Unit *TargetUnit = ObjectAccessor::GetUnit(*_player, selguid);
- if(!TargetUnit)
- return;
-
- // not let attack friendly units.
- if( GetPlayer()->IsFriendlyTo(TargetUnit))
- return;
-
- if(pet->getVictim())
- pet->AttackStop();
-
- if(pet->GetTypeId() != TYPEID_PLAYER)
- {
- pet->GetMotionMaster()->Clear();
- if (((Creature*)pet)->AI())
- ((Creature*)pet)->AI()->AttackStart(TargetUnit);
-
- //10% chance to play special pet attack talk, else growl
- if(((Creature*)pet)->isPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != TargetUnit && urand(0, 100) < 10)
- pet->SendPetTalk((uint32)PET_TALK_ATTACK);
- else
- {
- // 90% chance for pet and 100% chance for charmed creature
- pet->SendPetAIReaction(guid1);
- }
- }
- else // charmed player
- {
- pet->Attack(TargetUnit,true);
- pet->SendPetAIReaction(guid1);
- }
- break;
- }
- case COMMAND_ABANDON: // abandon (hunter pet) or dismiss (summoned pet)
- if(((Creature*)pet)->isPet())
- {
- Pet* p = (Pet*)pet;
- if(p->getPetType() == HUNTER_PET)
- _player->RemovePet(p,PET_SAVE_AS_DELETED);
- else
- //dismissing a summoned pet is like killing them (this prevents returning a soulshard...)
- p->setDeathState(CORPSE);
- }
- else // charmed
- _player->Uncharm();
- break;
- default:
- sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.\n", flag, spellid);
- }
- break;
- case ACT_REACTION: // 0x600
- switch(spellid)
- {
- case REACT_PASSIVE: //passive
- case REACT_DEFENSIVE: //recovery
- case REACT_AGGRESSIVE: //activete
- charmInfo->SetReactState( ReactStates(spellid) );
- break;
- }
- break;
- case ACT_DISABLED: //0x8100 spell (disabled), ignore
- case ACT_CAST: //0x0100
- case ACT_ENABLED: //0xc100 spell
- {
- Unit* unit_target;
- if(guid2)
- unit_target = ObjectAccessor::GetUnit(*_player,guid2);
- else
- unit_target = NULL;
-
- // do not cast unknown spells
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid );
- if(!spellInfo)
- {
- sLog.outError("WORLD: unknown PET spell id %i\n", spellid);
- return;
- }
-
- for(uint32 i = 0; i < 3;i++)
- {
- if(spellInfo->EffectImplicitTargetA[i] == TARGET_ALL_ENEMY_IN_AREA || spellInfo->EffectImplicitTargetA[i] == TARGET_ALL_ENEMY_IN_AREA_INSTANT || spellInfo->EffectImplicitTargetA[i] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED)
- return;
- }
-
- // do not cast not learned spells
- if(!pet->HasSpell(spellid) || IsPassiveSpell(spellid))
- return;
-
- pet->clearUnitState(UNIT_STAT_FOLLOW);
-
- Spell *spell = new Spell(pet, spellInfo, false);
-
- int16 result = spell->PetCanCast(unit_target);
-
- //auto turn to target unless possessed
- if(result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->HasAuraType(SPELL_AURA_MOD_POSSESS))
- {
- pet->SetInFront(unit_target);
- if( unit_target->GetTypeId() == TYPEID_PLAYER )
- pet->SendUpdateToPlayer( (Player*)unit_target );
- if(Unit* powner = pet->GetCharmerOrOwner())
- if(powner->GetTypeId() == TYPEID_PLAYER)
- pet->SendUpdateToPlayer((Player*)powner);
- result = -1;
- }
-
- if(result == -1)
- {
- ((Creature*)pet)->AddCreatureSpellCooldown(spellid);
- if (((Creature*)pet)->isPet())
- ((Pet*)pet)->CheckLearning(spellid);
-
- unit_target = spell->m_targets.getUnitTarget();
-
- //10% chance to play special pet attack talk, else growl
- //actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
- if(((Creature*)pet)->isPet() && (((Pet*)pet)->getPetType() == SUMMON_PET) && (pet != unit_target) && (urand(0, 100) < 10))
- pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL);
- else
- {
- pet->SendPetAIReaction(guid1);
- }
-
- if( unit_target && !GetPlayer()->IsFriendlyTo(unit_target) && !pet->HasAuraType(SPELL_AURA_MOD_POSSESS))
- {
- pet->clearUnitState(UNIT_STAT_FOLLOW);
- if(pet->getVictim())
- pet->AttackStop();
- pet->GetMotionMaster()->Clear();
- if (((Creature*)pet)->AI())
- ((Creature*)pet)->AI()->AttackStart(unit_target);
- }
-
- spell->prepare(&(spell->m_targets));
- }
- else
- {
- if(pet->HasAuraType(SPELL_AURA_MOD_POSSESS))
- {
- WorldPacket data(SMSG_CAST_FAILED, (4+1+1));
- data << uint32(spellid) << uint8(2) << uint8(result);
- switch (result)
- {
- case SPELL_FAILED_REQUIRES_SPELL_FOCUS:
- data << uint32(spellInfo->RequiresSpellFocus);
- break;
- case SPELL_FAILED_REQUIRES_AREA:
- data << uint32(spellInfo->AreaId);
- break;
- }
- SendPacket(&data);
- }
- else
- pet->SendPetCastFail(spellid, result);
-
- if(!((Creature*)pet)->HasSpellCooldown(spellid))
- pet->SendPetClearCooldown(spellid);
-
- spell->finish(false);
- delete spell;
- }
- break;
- }
- default:
- sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.\n", flag, spellid);
- }
-}
-
-void WorldSession::HandlePetNameQuery( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data,4+8);
-
- sLog.outDetail( "HandlePetNameQuery. CMSG_PET_NAME_QUERY\n" );
-
- uint32 petnumber;
- uint64 petguid;
-
- recv_data >> petnumber;
- recv_data >> petguid;
-
- SendPetNameQuery(petguid,petnumber);
-}
-
-void WorldSession::SendPetNameQuery( uint64 petguid, uint32 petnumber)
-{
- Creature* pet = ObjectAccessor::GetCreatureOrPet(*_player, petguid);
- if(!pet || !pet->GetCharmInfo() || pet->GetCharmInfo()->GetPetNumber() != petnumber)
- return;
-
- std::string name = pet->GetName();
-
- WorldPacket data(SMSG_PET_NAME_QUERY_RESPONSE, (4+4+name.size()+1));
- data << uint32(petnumber);
- data << name.c_str();
- data << uint32(pet->GetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP));
-
- if( pet->isPet() && ((Pet*)pet)->GetDeclinedNames() )
- {
- data << uint8(1);
- for(int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
- data << ((Pet*)pet)->GetDeclinedNames()->name[i];
- }
- else
- data << uint8(0);
-
- _player->GetSession()->SendPacket(&data);
-}
-
-void WorldSession::HandlePetSetAction( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data,8+4+2+2);
-
- sLog.outDetail( "HandlePetSetAction. CMSG_PET_SET_ACTION\n" );
-
- uint64 petguid;
- uint32 position;
- uint16 spell_id;
- uint16 act_state;
- uint8 count;
-
- recv_data >> petguid;
-
- // FIXME: charmed case
- //Pet* pet = ObjectAccessor::Instance().GetPet(petguid);
- if(ObjectAccessor::FindPlayer(petguid))
- return;
-
- Creature* pet = ObjectAccessor::GetCreatureOrPet(*_player, petguid);
-
- if(!pet || (pet != _player->GetPet() && pet != _player->GetCharm()))
- {
- sLog.outError( "HandlePetSetAction: Unknown pet or pet owner.\n" );
- return;
- }
-
- CharmInfo *charmInfo = pet->GetCharmInfo();
- if(!charmInfo)
- {
- sLog.outError("WorldSession::HandlePetSetAction: object "I64FMTD" is considered pet-like but doesn't have a charminfo!", pet->GetGUID());
- return;
- }
-
- count = (recv_data.size() == 24) ? 2 : 1;
- for(uint8 i = 0; i < count; i++)
- {
- recv_data >> position;
- recv_data >> spell_id;
- recv_data >> act_state;
-
- sLog.outDetail( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X\n", _player->GetName(), position, spell_id, act_state);
-
- //if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add
- if(!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_CAST) && spell_id && !pet->HasSpell(spell_id)))
- {
- //sign for autocast
- if(act_state == ACT_ENABLED && spell_id)
- {
- if(pet->isCharmed())
- charmInfo->ToggleCreatureAutocast(spell_id, true);
- else
- ((Pet*)pet)->ToggleAutocast(spell_id, true);
- }
- //sign for no/turn off autocast
- else if(act_state == ACT_DISABLED && spell_id)
- {
- if(pet->isCharmed())
- charmInfo->ToggleCreatureAutocast(spell_id, false);
- else
- ((Pet*)pet)->ToggleAutocast(spell_id, false);
- }
-
- charmInfo->GetActionBarEntry(position)->Type = act_state;
- charmInfo->GetActionBarEntry(position)->SpellOrAction = spell_id;
- }
- }
-}
-
-void WorldSession::HandlePetRename( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data,8+1+1+1+1+1+1+1);
-
- sLog.outDetail( "HandlePetRename. CMSG_PET_RENAME\n" );
-
- uint64 petguid;
- uint8 isdeclined;
-
- std::string name;
- DeclinedName declinedname;
-
- recv_data >> petguid;
- recv_data >> name;
- recv_data >> isdeclined;
-
- Pet* pet = ObjectAccessor::GetPet(petguid);
- // check it!
- if( !pet || !pet->isPet() || ((Pet*)pet)->getPetType()!= HUNTER_PET ||
- pet->GetByteValue(UNIT_FIELD_BYTES_2, 2) != UNIT_RENAME_ALLOWED ||
- pet->GetOwnerGUID() != _player->GetGUID() || !pet->GetCharmInfo() )
- return;
-
- if((!ObjectMgr::IsValidPetName(name)) || (objmgr.IsReservedName(name)))
- {
- SendNotification("Invalid name");
- return;
- }
- pet->SetName(name);
-
- Unit *owner = pet->GetOwner();
- if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
- ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_NAME);
-
- pet->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED);
-
- if(isdeclined)
- {
- for(int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
- recv_data >> declinedname.name[i];
-
- std::wstring wname;
- Utf8toWStr(name,wname);
- if(!ObjectMgr::CheckDeclinedNames(GetMainPartOfName(wname,0),declinedname))
- {
- SendNotification("Invalid name");
- return;
- }
- }
-
- CharacterDatabase.BeginTransaction();
- if(isdeclined)
- {
- for(int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
- CharacterDatabase.escape_string(declinedname.name[i]);
- CharacterDatabase.PExecute("DELETE FROM character_pet_declinedname WHERE owner = '%u' AND id = '%u'", _player->GetGUIDLow(), pet->GetCharmInfo()->GetPetNumber());
- CharacterDatabase.PExecute("INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES ('%u','%u','%s','%s','%s','%s','%s')",
- pet->GetCharmInfo()->GetPetNumber(), _player->GetGUIDLow(), declinedname.name[0].c_str(),declinedname.name[1].c_str(),declinedname.name[2].c_str(),declinedname.name[3].c_str(),declinedname.name[4].c_str());
- }
-
- CharacterDatabase.escape_string(name);
- CharacterDatabase.PExecute("UPDATE character_pet SET name = '%s', renamed = '1' WHERE owner = '%u' AND id = '%u'", name.c_str(),_player->GetGUIDLow(),pet->GetCharmInfo()->GetPetNumber() );
- CharacterDatabase.CommitTransaction();
-
- pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
-}
-
-void WorldSession::HandlePetAbandon( WorldPacket & recv_data )
-{
- CHECK_PACKET_SIZE(recv_data,8);
-
- uint64 guid;
- recv_data >> guid; //pet guid
- sLog.outDetail( "HandlePetAbandon. CMSG_PET_ABANDON pet guid is %u", GUID_LOPART(guid) );
-
- // pet/charmed
- Creature* pet=ObjectAccessor::GetCreatureOrPet(*_player, guid);
- if(pet)
- {
- if(pet->isPet())
- {
- if(pet->GetGUID() == _player->GetPetGUID())
- {
- uint32 feelty = pet->GetPower(POWER_HAPPINESS);
- pet->SetPower(POWER_HAPPINESS ,(feelty-50000) > 0 ?(feelty-50000) : 0);
- }
-
- _player->RemovePet((Pet*)pet,PET_SAVE_AS_DELETED);
- }
- else if(pet->GetGUID() == _player->GetCharmGUID())
- {
- _player->Uncharm();
- }
- }
-}
-
-void WorldSession::HandlePetUnlearnOpcode(WorldPacket& recvPacket)
-{
- CHECK_PACKET_SIZE(recvPacket,8);
-
- sLog.outDetail("CMSG_PET_UNLEARN");
- uint64 guid;
- recvPacket >> guid;
-
- Pet* pet = _player->GetPet();
-
- if(!pet || pet->getPetType() != HUNTER_PET || pet->m_spells.size() <= 1)
- return;
-
- if(guid != pet->GetGUID())
- {
- sLog.outError( "HandlePetUnlearnOpcode.Pet %u isn't pet of player %s .\n", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() );
- return;
- }
-
- CharmInfo *charmInfo = pet->GetCharmInfo();
- if(!charmInfo)
- {
- sLog.outError("WorldSession::HandlePetUnlearnOpcode: object "I64FMTD" is considered pet-like but doesn't have a charminfo!", pet->GetGUID());
- return;
- }
-
- uint32 cost = pet->resetTalentsCost();
-
- if (GetPlayer()->GetMoney() < cost)
- {
- GetPlayer()->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, 0, 0, 0);
- return;
- }
-
- for(PetSpellMap::iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end();)
- {
- uint32 spell_id = itr->first; // Pet::removeSpell can invalidate iterator at erase NEW spell
- ++itr;
- pet->removeSpell(spell_id);
- }
-
- pet->SetTP(pet->getLevel() * (pet->GetLoyaltyLevel() - 1));
-
- for(uint8 i = 0; i < 10; i++)
- {
- if(charmInfo->GetActionBarEntry(i)->SpellOrAction && charmInfo->GetActionBarEntry(i)->Type == ACT_ENABLED || charmInfo->GetActionBarEntry(i)->Type == ACT_DISABLED)
- charmInfo->GetActionBarEntry(i)->SpellOrAction = 0;
- }
-
- // relearn pet passives
- pet->LearnPetPassives();
-
- pet->m_resetTalentsTime = time(NULL);
- pet->m_resetTalentsCost = cost;
- GetPlayer()->ModifyMoney(-(int32)cost);
-
- GetPlayer()->PetSpellInitialize();
-}
-
-void WorldSession::HandlePetSpellAutocastOpcode( WorldPacket& recvPacket )
-{
- CHECK_PACKET_SIZE(recvPacket,8+2+2+1);
-
- sLog.outDetail("CMSG_PET_SPELL_AUTOCAST");
- uint64 guid;
- uint16 spellid;
- uint16 spellid2; //maybe second spell, automatically toggled off when first toggled on?
- uint8 state; //1 for on, 0 for off
- recvPacket >> guid >> spellid >> spellid2 >> state;
-
- if(!_player->GetPet() && !_player->GetCharm())
- return;
-
- if(ObjectAccessor::FindPlayer(guid))
- return;
-
- Creature* pet=ObjectAccessor::GetCreatureOrPet(*_player,guid);
-
- if(!pet || (pet != _player->GetPet() && pet != _player->GetCharm()))
- {
- sLog.outError( "HandlePetSpellAutocastOpcode.Pet %u isn't pet of player %s .\n", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() );
- return;
- }
-
- // do not add not learned spells/ passive spells
- if(!pet->HasSpell(spellid) || IsPassiveSpell(spellid))
- return;
-
- CharmInfo *charmInfo = pet->GetCharmInfo();
- if(!charmInfo)
- {
- sLog.outError("WorldSession::HandlePetSpellAutocastOpcod: object "I64FMTD" is considered pet-like but doesn't have a charminfo!", pet->GetGUID());
- return;
- }
-
- if(pet->isCharmed())
- //state can be used as boolean
- pet->GetCharmInfo()->ToggleCreatureAutocast(spellid, state);
- else
- ((Pet*)pet)->ToggleAutocast(spellid, state);
-
- for(uint8 i = 0; i < 10; ++i)
- {
- if((charmInfo->GetActionBarEntry(i)->Type == ACT_ENABLED || charmInfo->GetActionBarEntry(i)->Type == ACT_DISABLED) && spellid == charmInfo->GetActionBarEntry(i)->SpellOrAction)
- charmInfo->GetActionBarEntry(i)->Type = state ? ACT_ENABLED : ACT_DISABLED;
- }
-}
-
-void WorldSession::HandleAddDynamicTargetObsoleteOpcode( WorldPacket& recvPacket )
-{
- sLog.outDetail("WORLD: CMSG_PET_CAST_SPELL");
-
- CHECK_PACKET_SIZE(recvPacket,8+4);
- uint64 guid;
- uint32 spellid;
-
- recvPacket >> guid >> spellid;
-
- if(!_player->GetPet() && !_player->GetCharm())
- return;
-
- if(ObjectAccessor::FindPlayer(guid))
- return;
-
- Creature* pet=ObjectAccessor::GetCreatureOrPet(*_player,guid);
-
- if(!pet || (pet != _player->GetPet() && pet!= _player->GetCharm()))
- {
- sLog.outError( "HandleAddDynamicTargetObsoleteOpcode.Pet %u isn't pet of player %s .\n", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() );
- return;
- }
-
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid);
- if(!spellInfo)
- {
- sLog.outError("WORLD: unknown PET spell id %i\n", spellid);
- return;
- }
-
- // do not cast not learned spells
- if(!pet->HasSpell(spellid) || IsPassiveSpell(spellid))
- return;
-
- SpellCastTargets targets;
- if(!targets.read(&recvPacket,pet))
- return;
-
- pet->clearUnitState(UNIT_STAT_FOLLOW);
-
- Spell *spell = new Spell(pet, spellInfo, false);
- spell->m_targets = targets;
-
- int16 result = spell->PetCanCast(NULL);
- if(result == -1)
- {
- pet->AddCreatureSpellCooldown(spellid);
- if(pet->isPet())
- {
- Pet* p = (Pet*)pet;
- p->CheckLearning(spellid);
- //10% chance to play special pet attack talk, else growl
- //actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
- if(p->getPetType() == SUMMON_PET && (urand(0, 100) < 10))
- pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL);
- else
- pet->SendPetAIReaction(guid);
- }
-
- spell->prepare(&(spell->m_targets));
- }
- else
- {
- pet->SendPetCastFail(spellid, result);
- if(!pet->HasSpellCooldown(spellid))
- pet->SendPetClearCooldown(spellid);
-
- spell->finish(false);
- delete spell;
- }
-}
+/*
+ * Copyright (C) 2005-2008 MaNGOS
+ *
+ * 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 "WorldPacket.h"
+#include "WorldSession.h"
+#include "World.h"
+#include "ObjectMgr.h"
+#include "SpellMgr.h"
+#include "Log.h"
+#include "Opcodes.h"
+#include "Spell.h"
+#include "ObjectAccessor.h"
+#include "MapManager.h"
+#include "CreatureAI.h"
+#include "Util.h"
+#include "Pet.h"
+#include "Language.h"
+
+void WorldSession::HandlePetAction( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data,8+2+2+8);
+
+ uint64 guid1;
+ uint16 spellid;
+ uint16 flag;
+ uint64 guid2;
+ recv_data >> guid1; //pet guid
+ recv_data >> spellid;
+ recv_data >> flag; //delete = 0x0700 CastSpell = C100
+ recv_data >> guid2; //tag guid
+
+ // used also for charmed creature
+ Unit* pet= ObjectAccessor::GetUnit(*_player,guid1);
+ sLog.outDetail( "HandlePetAction.Pet %u flag is %u, spellid is %u, target %u.\n", uint32(GUID_LOPART(guid1)), flag, spellid, uint32(GUID_LOPART(guid2)) );
+ if(!pet)
+ {
+ sLog.outError( "Pet %u not exist.\n", uint32(GUID_LOPART(guid1)) );
+ return;
+ }
+
+ if(pet != GetPlayer()->GetPet() && pet != GetPlayer()->GetCharm())
+ {
+ sLog.outError( "HandlePetAction.Pet %u isn't pet of player %s .\n", uint32(GUID_LOPART(guid1)),GetPlayer()->GetName() );
+ return;
+ }
+
+ if(!pet->isAlive())
+ return;
+
+ if(pet->GetTypeId() == TYPEID_PLAYER && !(flag == ACT_COMMAND && spellid == COMMAND_ATTACK))
+ return;
+
+ CharmInfo *charmInfo = pet->GetCharmInfo();
+ if(!charmInfo)
+ {
+ sLog.outError("WorldSession::HandlePetAction: object "I64FMTD" is considered pet-like but doesn't have a charminfo!", pet->GetGUID());
+ return;
+ }
+
+ switch(flag)
+ {
+ case ACT_COMMAND: //0x0700
+ switch(spellid)
+ {
+ case COMMAND_STAY: //flat=1792 //STAY
+ pet->StopMoving();
+ pet->GetMotionMaster()->Clear();
+ pet->GetMotionMaster()->MoveIdle();
+ charmInfo->SetCommandState( COMMAND_STAY );
+ break;
+ case COMMAND_FOLLOW: //spellid=1792 //FOLLOW
+ pet->AttackStop();
+ pet->GetMotionMaster()->MoveFollow(_player,PET_FOLLOW_DIST,PET_FOLLOW_ANGLE);
+ charmInfo->SetCommandState( COMMAND_FOLLOW );
+ break;
+ case COMMAND_ATTACK: //spellid=1792 //ATTACK
+ {
+ // only place where pet can be player
+ pet->clearUnitState(UNIT_STAT_FOLLOW);
+ uint64 selguid = _player->GetSelection();
+ Unit *TargetUnit = ObjectAccessor::GetUnit(*_player, selguid);
+ if(!TargetUnit)
+ return;
+
+ // not let attack friendly units.
+ if( GetPlayer()->IsFriendlyTo(TargetUnit))
+ return;
+
+ if(pet->getVictim())
+ pet->AttackStop();
+
+ if(pet->GetTypeId() != TYPEID_PLAYER)
+ {
+ pet->GetMotionMaster()->Clear();
+ if (((Creature*)pet)->AI())
+ ((Creature*)pet)->AI()->AttackStart(TargetUnit);
+
+ //10% chance to play special pet attack talk, else growl
+ if(((Creature*)pet)->isPet() && ((Pet*)pet)->getPetType() == SUMMON_PET && pet != TargetUnit && urand(0, 100) < 10)
+ pet->SendPetTalk((uint32)PET_TALK_ATTACK);
+ else
+ {
+ // 90% chance for pet and 100% chance for charmed creature
+ pet->SendPetAIReaction(guid1);
+ }
+ }
+ else // charmed player
+ {
+ pet->Attack(TargetUnit,true);
+ pet->SendPetAIReaction(guid1);
+ }
+ break;
+ }
+ case COMMAND_ABANDON: // abandon (hunter pet) or dismiss (summoned pet)
+ if(((Creature*)pet)->isPet())
+ {
+ Pet* p = (Pet*)pet;
+ if(p->getPetType() == HUNTER_PET)
+ _player->RemovePet(p,PET_SAVE_AS_DELETED);
+ else
+ //dismissing a summoned pet is like killing them (this prevents returning a soulshard...)
+ p->setDeathState(CORPSE);
+ }
+ else // charmed
+ _player->Uncharm();
+ break;
+ default:
+ sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.\n", flag, spellid);
+ }
+ break;
+ case ACT_REACTION: // 0x600
+ switch(spellid)
+ {
+ case REACT_PASSIVE: //passive
+ case REACT_DEFENSIVE: //recovery
+ case REACT_AGGRESSIVE: //activete
+ charmInfo->SetReactState( ReactStates(spellid) );
+ break;
+ }
+ break;
+ case ACT_DISABLED: //0x8100 spell (disabled), ignore
+ case ACT_CAST: //0x0100
+ case ACT_ENABLED: //0xc100 spell
+ {
+ Unit* unit_target;
+ if(guid2)
+ unit_target = ObjectAccessor::GetUnit(*_player,guid2);
+ else
+ unit_target = NULL;
+
+ // do not cast unknown spells
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid );
+ if(!spellInfo)
+ {
+ sLog.outError("WORLD: unknown PET spell id %i\n", spellid);
+ return;
+ }
+
+ for(uint32 i = 0; i < 3;i++)
+ {
+ if(spellInfo->EffectImplicitTargetA[i] == TARGET_ALL_ENEMY_IN_AREA || spellInfo->EffectImplicitTargetA[i] == TARGET_ALL_ENEMY_IN_AREA_INSTANT || spellInfo->EffectImplicitTargetA[i] == TARGET_ALL_ENEMY_IN_AREA_CHANNELED)
+ return;
+ }
+
+ // do not cast not learned spells
+ if(!pet->HasSpell(spellid) || IsPassiveSpell(spellid))
+ return;
+
+ pet->clearUnitState(UNIT_STAT_FOLLOW);
+
+ Spell *spell = new Spell(pet, spellInfo, false);
+
+ int16 result = spell->PetCanCast(unit_target);
+
+ //auto turn to target unless possessed
+ if(result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->HasAuraType(SPELL_AURA_MOD_POSSESS))
+ {
+ pet->SetInFront(unit_target);
+ if( unit_target->GetTypeId() == TYPEID_PLAYER )
+ pet->SendUpdateToPlayer( (Player*)unit_target );
+ if(Unit* powner = pet->GetCharmerOrOwner())
+ if(powner->GetTypeId() == TYPEID_PLAYER)
+ pet->SendUpdateToPlayer((Player*)powner);
+ result = -1;
+ }
+
+ if(result == -1)
+ {
+ ((Creature*)pet)->AddCreatureSpellCooldown(spellid);
+ if (((Creature*)pet)->isPet())
+ ((Pet*)pet)->CheckLearning(spellid);
+
+ unit_target = spell->m_targets.getUnitTarget();
+
+ //10% chance to play special pet attack talk, else growl
+ //actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
+ if(((Creature*)pet)->isPet() && (((Pet*)pet)->getPetType() == SUMMON_PET) && (pet != unit_target) && (urand(0, 100) < 10))
+ pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL);
+ else
+ {
+ pet->SendPetAIReaction(guid1);
+ }
+
+ if( unit_target && !GetPlayer()->IsFriendlyTo(unit_target) && !pet->HasAuraType(SPELL_AURA_MOD_POSSESS))
+ {
+ pet->clearUnitState(UNIT_STAT_FOLLOW);
+ if(pet->getVictim())
+ pet->AttackStop();
+ pet->GetMotionMaster()->Clear();
+ if (((Creature*)pet)->AI())
+ ((Creature*)pet)->AI()->AttackStart(unit_target);
+ }
+
+ spell->prepare(&(spell->m_targets));
+ }
+ else
+ {
+ if(pet->HasAuraType(SPELL_AURA_MOD_POSSESS))
+ {
+ WorldPacket data(SMSG_CAST_FAILED, (4+1+1));
+ data << uint32(spellid) << uint8(2) << uint8(result);
+ switch (result)
+ {
+ case SPELL_FAILED_REQUIRES_SPELL_FOCUS:
+ data << uint32(spellInfo->RequiresSpellFocus);
+ break;
+ case SPELL_FAILED_REQUIRES_AREA:
+ data << uint32(spellInfo->AreaId);
+ break;
+ }
+ SendPacket(&data);
+ }
+ else
+ pet->SendPetCastFail(spellid, result);
+
+ if(!((Creature*)pet)->HasSpellCooldown(spellid))
+ pet->SendPetClearCooldown(spellid);
+
+ spell->finish(false);
+ delete spell;
+ }
+ break;
+ }
+ default:
+ sLog.outError("WORLD: unknown PET flag Action %i and spellid %i.\n", flag, spellid);
+ }
+}
+
+void WorldSession::HandlePetNameQuery( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data,4+8);
+
+ sLog.outDetail( "HandlePetNameQuery. CMSG_PET_NAME_QUERY\n" );
+
+ uint32 petnumber;
+ uint64 petguid;
+
+ recv_data >> petnumber;
+ recv_data >> petguid;
+
+ SendPetNameQuery(petguid,petnumber);
+}
+
+void WorldSession::SendPetNameQuery( uint64 petguid, uint32 petnumber)
+{
+ Creature* pet = ObjectAccessor::GetCreatureOrPet(*_player, petguid);
+ if(!pet || !pet->GetCharmInfo() || pet->GetCharmInfo()->GetPetNumber() != petnumber)
+ return;
+
+ std::string name = pet->GetName();
+
+ WorldPacket data(SMSG_PET_NAME_QUERY_RESPONSE, (4+4+name.size()+1));
+ data << uint32(petnumber);
+ data << name.c_str();
+ data << uint32(pet->GetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP));
+
+ if( pet->isPet() && ((Pet*)pet)->GetDeclinedNames() )
+ {
+ data << uint8(1);
+ for(int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
+ data << ((Pet*)pet)->GetDeclinedNames()->name[i];
+ }
+ else
+ data << uint8(0);
+
+ _player->GetSession()->SendPacket(&data);
+}
+
+void WorldSession::HandlePetSetAction( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data,8+4+2+2);
+
+ sLog.outDetail( "HandlePetSetAction. CMSG_PET_SET_ACTION\n" );
+
+ uint64 petguid;
+ uint32 position;
+ uint16 spell_id;
+ uint16 act_state;
+ uint8 count;
+
+ recv_data >> petguid;
+
+ // FIXME: charmed case
+ //Pet* pet = ObjectAccessor::Instance().GetPet(petguid);
+ if(ObjectAccessor::FindPlayer(petguid))
+ return;
+
+ Creature* pet = ObjectAccessor::GetCreatureOrPet(*_player, petguid);
+
+ if(!pet || (pet != _player->GetPet() && pet != _player->GetCharm()))
+ {
+ sLog.outError( "HandlePetSetAction: Unknown pet or pet owner.\n" );
+ return;
+ }
+
+ CharmInfo *charmInfo = pet->GetCharmInfo();
+ if(!charmInfo)
+ {
+ sLog.outError("WorldSession::HandlePetSetAction: object "I64FMTD" is considered pet-like but doesn't have a charminfo!", pet->GetGUID());
+ return;
+ }
+
+ count = (recv_data.size() == 24) ? 2 : 1;
+ for(uint8 i = 0; i < count; i++)
+ {
+ recv_data >> position;
+ recv_data >> spell_id;
+ recv_data >> act_state;
+
+ sLog.outDetail( "Player %s has changed pet spell action. Position: %u, Spell: %u, State: 0x%X\n", _player->GetName(), position, spell_id, act_state);
+
+ //if it's act for spell (en/disable/cast) and there is a spell given (0 = remove spell) which pet doesn't know, don't add
+ if(!((act_state == ACT_ENABLED || act_state == ACT_DISABLED || act_state == ACT_CAST) && spell_id && !pet->HasSpell(spell_id)))
+ {
+ //sign for autocast
+ if(act_state == ACT_ENABLED && spell_id)
+ {
+ if(pet->isCharmed())
+ charmInfo->ToggleCreatureAutocast(spell_id, true);
+ else
+ ((Pet*)pet)->ToggleAutocast(spell_id, true);
+ }
+ //sign for no/turn off autocast
+ else if(act_state == ACT_DISABLED && spell_id)
+ {
+ if(pet->isCharmed())
+ charmInfo->ToggleCreatureAutocast(spell_id, false);
+ else
+ ((Pet*)pet)->ToggleAutocast(spell_id, false);
+ }
+
+ charmInfo->GetActionBarEntry(position)->Type = act_state;
+ charmInfo->GetActionBarEntry(position)->SpellOrAction = spell_id;
+ }
+ }
+}
+
+void WorldSession::HandlePetRename( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data,8+1+1+1+1+1+1+1);
+
+ sLog.outDetail( "HandlePetRename. CMSG_PET_RENAME\n" );
+
+ uint64 petguid;
+ uint8 isdeclined;
+
+ std::string name;
+ DeclinedName declinedname;
+
+ recv_data >> petguid;
+ recv_data >> name;
+ recv_data >> isdeclined;
+
+ Pet* pet = ObjectAccessor::GetPet(petguid);
+ // check it!
+ if( !pet || !pet->isPet() || ((Pet*)pet)->getPetType()!= HUNTER_PET ||
+ pet->GetByteValue(UNIT_FIELD_BYTES_2, 2) != UNIT_RENAME_ALLOWED ||
+ pet->GetOwnerGUID() != _player->GetGUID() || !pet->GetCharmInfo() )
+ return;
+
+ if((!ObjectMgr::IsValidPetName(name)) || (objmgr.IsReservedName(name)))
+ {
+ SendNotification(LANG_PET_INVALID_NAME);
+ return;
+ }
+ pet->SetName(name);
+
+ Unit *owner = pet->GetOwner();
+ if(owner && (owner->GetTypeId() == TYPEID_PLAYER) && ((Player*)owner)->GetGroup())
+ ((Player*)owner)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_PET_NAME);
+
+ pet->SetByteValue(UNIT_FIELD_BYTES_2, 2, UNIT_RENAME_NOT_ALLOWED);
+
+ if(isdeclined)
+ {
+ for(int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
+ recv_data >> declinedname.name[i];
+
+ std::wstring wname;
+ Utf8toWStr(name,wname);
+ if(!ObjectMgr::CheckDeclinedNames(GetMainPartOfName(wname,0),declinedname))
+ {
+ SendNotification(LANG_PET_INVALID_NAME);
+ return;
+ }
+ }
+
+ CharacterDatabase.BeginTransaction();
+ if(isdeclined)
+ {
+ for(int i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
+ CharacterDatabase.escape_string(declinedname.name[i]);
+ CharacterDatabase.PExecute("DELETE FROM character_pet_declinedname WHERE owner = '%u' AND id = '%u'", _player->GetGUIDLow(), pet->GetCharmInfo()->GetPetNumber());
+ CharacterDatabase.PExecute("INSERT INTO character_pet_declinedname (id, owner, genitive, dative, accusative, instrumental, prepositional) VALUES ('%u','%u','%s','%s','%s','%s','%s')",
+ pet->GetCharmInfo()->GetPetNumber(), _player->GetGUIDLow(), declinedname.name[0].c_str(),declinedname.name[1].c_str(),declinedname.name[2].c_str(),declinedname.name[3].c_str(),declinedname.name[4].c_str());
+ }
+
+ CharacterDatabase.escape_string(name);
+ CharacterDatabase.PExecute("UPDATE character_pet SET name = '%s', renamed = '1' WHERE owner = '%u' AND id = '%u'", name.c_str(),_player->GetGUIDLow(),pet->GetCharmInfo()->GetPetNumber() );
+ CharacterDatabase.CommitTransaction();
+
+ pet->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
+}
+
+void WorldSession::HandlePetAbandon( WorldPacket & recv_data )
+{
+ CHECK_PACKET_SIZE(recv_data,8);
+
+ uint64 guid;
+ recv_data >> guid; //pet guid
+ sLog.outDetail( "HandlePetAbandon. CMSG_PET_ABANDON pet guid is %u", GUID_LOPART(guid) );
+
+ // pet/charmed
+ Creature* pet=ObjectAccessor::GetCreatureOrPet(*_player, guid);
+ if(pet)
+ {
+ if(pet->isPet())
+ {
+ if(pet->GetGUID() == _player->GetPetGUID())
+ {
+ uint32 feelty = pet->GetPower(POWER_HAPPINESS);
+ pet->SetPower(POWER_HAPPINESS ,(feelty-50000) > 0 ?(feelty-50000) : 0);
+ }
+
+ _player->RemovePet((Pet*)pet,PET_SAVE_AS_DELETED);
+ }
+ else if(pet->GetGUID() == _player->GetCharmGUID())
+ {
+ _player->Uncharm();
+ }
+ }
+}
+
+void WorldSession::HandlePetUnlearnOpcode(WorldPacket& recvPacket)
+{
+ CHECK_PACKET_SIZE(recvPacket,8);
+
+ sLog.outDetail("CMSG_PET_UNLEARN");
+ uint64 guid;
+ recvPacket >> guid;
+
+ Pet* pet = _player->GetPet();
+
+ if(!pet || pet->getPetType() != HUNTER_PET || pet->m_spells.size() <= 1)
+ return;
+
+ if(guid != pet->GetGUID())
+ {
+ sLog.outError( "HandlePetUnlearnOpcode.Pet %u isn't pet of player %s .\n", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() );
+ return;
+ }
+
+ CharmInfo *charmInfo = pet->GetCharmInfo();
+ if(!charmInfo)
+ {
+ sLog.outError("WorldSession::HandlePetUnlearnOpcode: object "I64FMTD" is considered pet-like but doesn't have a charminfo!", pet->GetGUID());
+ return;
+ }
+
+ uint32 cost = pet->resetTalentsCost();
+
+ if (GetPlayer()->GetMoney() < cost)
+ {
+ GetPlayer()->SendBuyError( BUY_ERR_NOT_ENOUGHT_MONEY, 0, 0, 0);
+ return;
+ }
+
+ for(PetSpellMap::iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end();)
+ {
+ uint32 spell_id = itr->first; // Pet::removeSpell can invalidate iterator at erase NEW spell
+ ++itr;
+ pet->removeSpell(spell_id);
+ }
+
+ pet->SetTP(pet->getLevel() * (pet->GetLoyaltyLevel() - 1));
+
+ for(uint8 i = 0; i < 10; i++)
+ {
+ if(charmInfo->GetActionBarEntry(i)->SpellOrAction && charmInfo->GetActionBarEntry(i)->Type == ACT_ENABLED || charmInfo->GetActionBarEntry(i)->Type == ACT_DISABLED)
+ charmInfo->GetActionBarEntry(i)->SpellOrAction = 0;
+ }
+
+ // relearn pet passives
+ pet->LearnPetPassives();
+
+ pet->m_resetTalentsTime = time(NULL);
+ pet->m_resetTalentsCost = cost;
+ GetPlayer()->ModifyMoney(-(int32)cost);
+
+ GetPlayer()->PetSpellInitialize();
+}
+
+void WorldSession::HandlePetSpellAutocastOpcode( WorldPacket& recvPacket )
+{
+ CHECK_PACKET_SIZE(recvPacket,8+2+2+1);
+
+ sLog.outDetail("CMSG_PET_SPELL_AUTOCAST");
+ uint64 guid;
+ uint16 spellid;
+ uint16 spellid2; //maybe second spell, automatically toggled off when first toggled on?
+ uint8 state; //1 for on, 0 for off
+ recvPacket >> guid >> spellid >> spellid2 >> state;
+
+ if(!_player->GetPet() && !_player->GetCharm())
+ return;
+
+ if(ObjectAccessor::FindPlayer(guid))
+ return;
+
+ Creature* pet=ObjectAccessor::GetCreatureOrPet(*_player,guid);
+
+ if(!pet || (pet != _player->GetPet() && pet != _player->GetCharm()))
+ {
+ sLog.outError( "HandlePetSpellAutocastOpcode.Pet %u isn't pet of player %s .\n", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() );
+ return;
+ }
+
+ // do not add not learned spells/ passive spells
+ if(!pet->HasSpell(spellid) || IsPassiveSpell(spellid))
+ return;
+
+ CharmInfo *charmInfo = pet->GetCharmInfo();
+ if(!charmInfo)
+ {
+ sLog.outError("WorldSession::HandlePetSpellAutocastOpcod: object "I64FMTD" is considered pet-like but doesn't have a charminfo!", pet->GetGUID());
+ return;
+ }
+
+ if(pet->isCharmed())
+ //state can be used as boolean
+ pet->GetCharmInfo()->ToggleCreatureAutocast(spellid, state);
+ else
+ ((Pet*)pet)->ToggleAutocast(spellid, state);
+
+ for(uint8 i = 0; i < 10; ++i)
+ {
+ if((charmInfo->GetActionBarEntry(i)->Type == ACT_ENABLED || charmInfo->GetActionBarEntry(i)->Type == ACT_DISABLED) && spellid == charmInfo->GetActionBarEntry(i)->SpellOrAction)
+ charmInfo->GetActionBarEntry(i)->Type = state ? ACT_ENABLED : ACT_DISABLED;
+ }
+}
+
+void WorldSession::HandleAddDynamicTargetObsoleteOpcode( WorldPacket& recvPacket )
+{
+ sLog.outDetail("WORLD: CMSG_PET_CAST_SPELL");
+
+ CHECK_PACKET_SIZE(recvPacket,8+4);
+ uint64 guid;
+ uint32 spellid;
+
+ recvPacket >> guid >> spellid;
+
+ if(!_player->GetPet() && !_player->GetCharm())
+ return;
+
+ if(ObjectAccessor::FindPlayer(guid))
+ return;
+
+ Creature* pet=ObjectAccessor::GetCreatureOrPet(*_player,guid);
+
+ if(!pet || (pet != _player->GetPet() && pet!= _player->GetCharm()))
+ {
+ sLog.outError( "HandleAddDynamicTargetObsoleteOpcode.Pet %u isn't pet of player %s .\n", uint32(GUID_LOPART(guid)),GetPlayer()->GetName() );
+ return;
+ }
+
+ SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellid);
+ if(!spellInfo)
+ {
+ sLog.outError("WORLD: unknown PET spell id %i\n", spellid);
+ return;
+ }
+
+ // do not cast not learned spells
+ if(!pet->HasSpell(spellid) || IsPassiveSpell(spellid))
+ return;
+
+ SpellCastTargets targets;
+ if(!targets.read(&recvPacket,pet))
+ return;
+
+ pet->clearUnitState(UNIT_STAT_FOLLOW);
+
+ Spell *spell = new Spell(pet, spellInfo, false);
+ spell->m_targets = targets;
+
+ int16 result = spell->PetCanCast(NULL);
+ if(result == -1)
+ {
+ pet->AddCreatureSpellCooldown(spellid);
+ if(pet->isPet())
+ {
+ Pet* p = (Pet*)pet;
+ p->CheckLearning(spellid);
+ //10% chance to play special pet attack talk, else growl
+ //actually this only seems to happen on special spells, fire shield for imp, torment for voidwalker, but it's stupid to check every spell
+ if(p->getPetType() == SUMMON_PET && (urand(0, 100) < 10))
+ pet->SendPetTalk((uint32)PET_TALK_SPECIAL_SPELL);
+ else
+ pet->SendPetAIReaction(guid);
+ }
+
+ spell->prepare(&(spell->m_targets));
+ }
+ else
+ {
+ pet->SendPetCastFail(spellid, result);
+ if(!pet->HasSpellCooldown(spellid))
+ pet->SendPetClearCooldown(spellid);
+
+ spell->finish(false);
+ delete spell;
+ }
+}
diff --git a/src/game/PetitionsHandler.cpp b/src/game/PetitionsHandler.cpp
index 6957634dc9e..2c5c4493c10 100644
--- a/src/game/PetitionsHandler.cpp
+++ b/src/game/PetitionsHandler.cpp
@@ -1,936 +1,936 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS
- *
- * 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 "WorldSession.h"
-#include "World.h"
-#include "ObjectMgr.h"
-#include "Log.h"
-#include "Opcodes.h"
-#include "Guild.h"
-#include "ArenaTeam.h"
-#include "MapManager.h"
-#include "GossipDef.h"
-#include "SocialMgr.h"
-
-/*enum PetitionType // dbc data
-{
- PETITION_TYPE_GUILD = 1,
- PETITION_TYPE_ARENA_TEAM = 3
-};*/
-
-// Charters ID in item_template
-#define GUILD_CHARTER 5863
-#define GUILD_CHARTER_COST 1000 // 10 S
-#define ARENA_TEAM_CHARTER_2v2 23560
-#define ARENA_TEAM_CHARTER_2v2_COST 800000 // 80 G
-#define ARENA_TEAM_CHARTER_3v3 23561
-#define ARENA_TEAM_CHARTER_3v3_COST 1200000 // 120 G
-#define ARENA_TEAM_CHARTER_5v5 23562
-#define ARENA_TEAM_CHARTER_5v5_COST 2000000 // 200 G
-
-void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data)
-{
- CHECK_PACKET_SIZE(recv_data, 8+8+4+1+5*8+2+1+4+4);
-
- sLog.outDebug("Received opcode CMSG_PETITION_BUY");
- //recv_data.hexlike();
-
- uint64 guidNPC;
- uint64 unk1, unk3, unk4, unk5, unk6, unk7;
- uint32 unk2;
- std::string name;
- uint16 unk8;
- uint8 unk9;
- uint32 unk10; // selected index
- uint32 unk11;
- recv_data >> guidNPC; // NPC GUID
- recv_data >> unk1; // 0
- recv_data >> unk2; // 0
- recv_data >> name; // name
-
- // recheck
- CHECK_PACKET_SIZE(recv_data, 8+8+4+(name.size()+1)+5*8+2+1+4+4);
-
- recv_data >> unk3; // 0
- recv_data >> unk4; // 0
- recv_data >> unk5; // 0
- recv_data >> unk6; // 0
- recv_data >> unk7; // 0
- recv_data >> unk8; // 0
- recv_data >> unk9; // 0
- recv_data >> unk10; // index
- recv_data >> unk11; // 0
- sLog.outDebug("Petitioner with GUID %u tried sell petition: name %s", GUID_LOPART(guidNPC), name.c_str());
-
- // prevent cheating
- Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guidNPC,UNIT_NPC_FLAG_PETITIONER);
- if (!pCreature)
- {
- sLog.outDebug("WORLD: HandlePetitionBuyOpcode - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(guidNPC));
- return;
- }
-
- // remove fake death
- if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
-
- uint32 charterid = 0;
- uint32 cost = 0;
- uint32 type = 0;
- if(pCreature->isTabardDesigner())
- {
- // if tabard designer, then trying to buy a guild charter.
- // do not let if already in guild.
- if(_player->GetGuildId())
- return;
-
- charterid = GUILD_CHARTER;
- cost = GUILD_CHARTER_COST;
- type = 9;
- }
- else
- {
- // TODO: find correct opcode
- if(_player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
- {
- SendNotification(GetMangosString(LANG_ARENA_ONE_TOOLOW), 70);
- return;
- }
-
- for(uint8 i = 0; i < MAX_ARENA_SLOT; i++)
- {
- if(_player->GetArenaTeamId(i) && (i == (unk10-1)))
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM);
- return;
- }
- }
- switch(unk10)
- {
- case 1:
- charterid = ARENA_TEAM_CHARTER_2v2;
- cost = ARENA_TEAM_CHARTER_2v2_COST;
- type = 2; // 2v2
- break;
- case 2:
- charterid = ARENA_TEAM_CHARTER_3v3;
- cost = ARENA_TEAM_CHARTER_3v3_COST;
- type = 3; // 3v3
- break;
- case 3:
- charterid = ARENA_TEAM_CHARTER_5v5;
- cost = ARENA_TEAM_CHARTER_5v5_COST;
- type = 5; // 5v5
- break;
- default:
- sLog.outDebug("unknown selection at buy petition: %u", unk10);
- return;
- }
- }
-
- if(type == 9)
- {
- if(objmgr.GetGuildByName(name))
- {
- SendGuildCommandResult(GUILD_CREATE_S, name, GUILD_NAME_EXISTS);
- return;
- }
- if(objmgr.IsReservedName(name))
- {
- SendGuildCommandResult(GUILD_CREATE_S, name, GUILD_NAME_INVALID);
- return;
- }
- if(!ObjectMgr::IsValidCharterName(name))
- {
- SendGuildCommandResult(GUILD_CREATE_S, name, GUILD_NAME_INVALID);
- return;
- }
- }
- else
- {
- if(objmgr.GetArenaTeamByName(name))
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S);
- return;
- }
- if(objmgr.IsReservedName(name))
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_INVALID);
- return;
- }
- if(!ObjectMgr::IsValidCharterName(name))
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_INVALID);
- return;
- }
- }
-
- ItemPrototype const *pProto = objmgr.GetItemPrototype(charterid);
- if(!pProto)
- {
- _player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, NULL, charterid, 0);
- return;
- }
-
- if(_player->GetMoney() < cost)
- { //player hasn't got enough money
- _player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, charterid, 0);
- return;
- }
-
- ItemPosCountVec dest;
- uint8 msg = _player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, charterid, pProto->BuyCount );
- if(msg != EQUIP_ERR_OK)
- {
- _player->SendBuyError(msg, pCreature, charterid, 0);
- return;
- }
-
- _player->ModifyMoney(-(int32)cost);
- Item *charter = _player->StoreNewItem(dest, charterid, true);
- if(!charter)
- return;
-
- charter->SetUInt32Value(ITEM_FIELD_ENCHANTMENT, charter->GetGUIDLow());
- // ITEM_FIELD_ENCHANTMENT is guild/arenateam id
- // ITEM_FIELD_ENCHANTMENT+1 is current signatures count (showed on item)
- charter->SetState(ITEM_CHANGED, _player);
- _player->SendNewItem(charter, 1, true, false);
-
- // a petition is invalid, if both the owner and the type matches
- QueryResult *result = CharacterDatabase.PQuery("SELECT petitionguid FROM petition WHERE ownerguid = '%u' AND type = '%u'", _player->GetGUIDLow(), type);
-
- std::ostringstream ssInvalidPetitionGUIDs;
-
- if (result)
- {
-
- do
- {
- Field *fields = result->Fetch();
- ssInvalidPetitionGUIDs << "'" << fields[0].GetUInt32() << "' , ";
- } while (result->NextRow());
-
- delete result;
- }
-
- // delete petitions with the same guid as this one
- ssInvalidPetitionGUIDs << "'" << charter->GetGUIDLow() << "'";
-
- sLog.outDebug("Invalid petition GUIDs: %s", ssInvalidPetitionGUIDs.str().c_str());
- CharacterDatabase.escape_string(name);
- CharacterDatabase.BeginTransaction();
- CharacterDatabase.PExecute("DELETE FROM petition WHERE petitionguid IN ( %s )", ssInvalidPetitionGUIDs.str().c_str());
- CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE petitionguid IN ( %s )", ssInvalidPetitionGUIDs.str().c_str());
- CharacterDatabase.PExecute("INSERT INTO petition (ownerguid, petitionguid, name, type) VALUES ('%u', '%u', '%s', '%u')",
- _player->GetGUIDLow(), charter->GetGUIDLow(), name.c_str(), type);
- CharacterDatabase.CommitTransaction();
-}
-
-void WorldSession::HandlePetitionShowSignOpcode(WorldPacket & recv_data)
-{
- CHECK_PACKET_SIZE(recv_data, 8);
-
- // ok
- sLog.outDebug("Received opcode CMSG_PETITION_SHOW_SIGNATURES");
- //recv_data.hexlike();
-
- uint8 signs = 0;
- uint64 petitionguid;
- recv_data >> petitionguid; // petition guid
-
- // solve (possible) some strange compile problems with explicit use GUID_LOPART(petitionguid) at some GCC versions (wrong code optimization in compiler?)
- uint32 petitionguid_low = GUID_LOPART(petitionguid);
-
- QueryResult *result = CharacterDatabase.PQuery("SELECT petitionguid, type FROM petition WHERE petitionguid = '%u'", petitionguid_low);
- if(!result)
- {
- sLog.outError("any petition on server...");
- return;
- }
- Field *fields = result->Fetch();
- uint32 type = fields[1].GetUInt32();
- delete result;
- // if guild petition and has guild => error, return;
- if(type==9 && _player->GetGuildId())
- return;
-
- result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", petitionguid_low);
-
- // result==NULL also correct in case no sign yet
- if(result)
- signs = result->GetRowCount();
-
- sLog.outDebug("CMSG_PETITION_SHOW_SIGNATURES petition entry: '%u'", petitionguid_low);
-
- WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8+8+4+1+signs*12));
- data << petitionguid; // petition guid
- data << _player->GetGUID(); // owner guid
- data << petitionguid_low; // guild guid (in mangos always same as GUID_LOPART(petitionguid)
- data << signs; // sign's count
-
- for(uint8 i = 1; i <= signs; i++)
- {
- Field *fields = result->Fetch();
- uint64 plguid = fields[0].GetUInt64();
-
- data << plguid; // Player GUID
- data << (uint32)0; // there 0 ...
-
- result->NextRow();
- }
- delete result;
- SendPacket(&data);
-}
-
-void WorldSession::HandlePetitionQueryOpcode(WorldPacket & recv_data)
-{
- CHECK_PACKET_SIZE(recv_data, 4+8);
-
- sLog.outDebug("Received opcode CMSG_PETITION_QUERY"); // ok
- //recv_data.hexlike();
-
- uint32 guildguid;
- uint64 petitionguid;
- recv_data >> guildguid; // in mangos always same as GUID_LOPART(petitionguid)
- recv_data >> petitionguid; // petition guid
- sLog.outDebug("CMSG_PETITION_QUERY Petition GUID %u Guild GUID %u", GUID_LOPART(petitionguid), guildguid);
-
- SendPetitionQueryOpcode(petitionguid);
-}
-
-void WorldSession::SendPetitionQueryOpcode(uint64 petitionguid)
-{
- uint64 ownerguid = 0;
- uint32 type;
- std::string name = "NO_NAME_FOR_GUID";
- uint8 signs = 0;
-
- QueryResult *result = CharacterDatabase.PQuery(
- "SELECT ownerguid, name, "
- " (SELECT COUNT(playerguid) FROM petition_sign WHERE petition_sign.petitionguid = '%u') AS signs "
- "FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid), GUID_LOPART(petitionguid));
-
- if(result)
- {
- Field* fields = result->Fetch();
- ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
- name = fields[1].GetCppString();
- signs = fields[2].GetUInt8();
- delete result;
- }
- else
- {
- sLog.outDebug("CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid));
- return;
- }
-
- QueryResult *result2 = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
-
- if(result2)
- {
- Field* fields = result2->Fetch();
- type = fields[0].GetUInt32();
- delete result2;
- }
- else
- {
- sLog.outDebug("CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid));
- return;
- }
-
- WorldPacket data(SMSG_PETITION_QUERY_RESPONSE, (4+8+name.size()+1+1+4*13));
- data << GUID_LOPART(petitionguid); // guild/team guid (in mangos always same as GUID_LOPART(petition guid)
- data << ownerguid; // charter owner guid
- data << name; // name (guild/arena team)
- data << uint8(0); // 1
- if(type == 9)
- {
- data << uint32(9);
- data << uint32(9);
- data << uint32(0); // bypass client - side limitation, a different value is needed here for each petition
- }
- else
- {
- data << type-1;
- data << type-1;
- data << type; // bypass client - side limitation, a different value is needed here for each petition
- }
- data << uint32(0); // 5
- data << uint32(0); // 6
- data << uint32(0); // 7
- data << uint32(0); // 8
- data << uint16(0); // 9 2 bytes field
- data << uint32(0); // 10
- data << uint32(0); // 11
- data << uint32(0); // 13 count of next strings?
- data << uint32(0); // 14
- if(type == 9)
- data << uint32(0); // 15 0 - guild, 1 - arena team
- else
- data << uint32(1);
- SendPacket(&data);
-}
-
-void WorldSession::HandlePetitionRenameOpcode(WorldPacket & recv_data)
-{
- CHECK_PACKET_SIZE(recv_data, 8+1);
-
- sLog.outDebug("Received opcode MSG_PETITION_RENAME"); // ok
- //recv_data.hexlike();
-
- uint64 petitionguid;
- uint32 type;
- std::string newname;
-
- recv_data >> petitionguid; // guid
- recv_data >> newname; // new name
-
- Item *item = _player->GetItemByGuid(petitionguid);
- if(!item)
- return;
-
- QueryResult *result2 = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
-
- if(result2)
- {
- Field* fields = result2->Fetch();
- type = fields[0].GetUInt32();
- delete result2;
- }
- else
- {
- sLog.outDebug("CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid));
- return;
- }
-
- if(type == 9)
- {
- if(objmgr.GetGuildByName(newname))
- {
- SendGuildCommandResult(GUILD_CREATE_S, newname, GUILD_NAME_EXISTS);
- return;
- }
- if(objmgr.IsReservedName(newname))
- {
- SendGuildCommandResult(GUILD_CREATE_S, newname, GUILD_NAME_INVALID);
- return;
- }
- if(!ObjectMgr::IsValidCharterName(newname))
- {
- SendGuildCommandResult(GUILD_CREATE_S, newname, GUILD_NAME_INVALID);
- return;
- }
- }
- else
- {
- if(objmgr.GetArenaTeamByName(newname))
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_EXISTS_S);
- return;
- }
- if(objmgr.IsReservedName(newname))
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_INVALID);
- return;
- }
- if(!ObjectMgr::IsValidCharterName(newname))
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_INVALID);
- return;
- }
- }
-
- std::string db_newname = newname;
- CharacterDatabase.escape_string(db_newname);
- CharacterDatabase.PExecute("UPDATE petition SET name = '%s' WHERE petitionguid = '%u'",
- db_newname.c_str(), GUID_LOPART(petitionguid));
-
- sLog.outDebug("Petition (GUID: %u) renamed to '%s'", GUID_LOPART(petitionguid), newname.c_str());
- WorldPacket data(MSG_PETITION_RENAME, (8+newname.size()+1));
- data << petitionguid;
- data << newname;
- SendPacket(&data);
-}
-
-void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data)
-{
- CHECK_PACKET_SIZE(recv_data, 8+1);
-
- sLog.outDebug("Received opcode CMSG_PETITION_SIGN"); // ok
- //recv_data.hexlike();
-
- Field *fields;
- uint64 petitionguid;
- uint32 type;
- uint8 unk;
- uint64 ownerguid;
- recv_data >> petitionguid; // petition guid
- recv_data >> unk;
-
- uint8 signs = 0;
-
- QueryResult *result = CharacterDatabase.PQuery(
- "SELECT ownerguid, "
- " (SELECT COUNT(playerguid) FROM petition_sign WHERE petition_sign.petitionguid = '%u') AS signs "
- "FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid), GUID_LOPART(petitionguid));
-
- if(!result)
- {
- sLog.outError("any petition on server...");
- return;
- }
-
- fields = result->Fetch();
- ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
- signs = fields[1].GetUInt8();
-
- delete result;
-
- uint32 plguidlo = _player->GetGUIDLow();
- if(GUID_LOPART(ownerguid) == plguidlo)
- return;
-
- // not let enemies sign guild charter
- if(!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != objmgr.GetPlayerTeamByGUID(ownerguid))
- return;
-
- QueryResult *result2 = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
-
- if(result2)
- {
- Field* fields = result2->Fetch();
- type = fields[0].GetUInt32();
- delete result2;
- }
- else
- {
- sLog.outDebug("CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid));
- return;
- }
-
- if(type != 9 && _player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
- {
- // player is too low level to join an arena team
- SendNotification("You must be level %u to join an arena team!",sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL));
- return;
- }
-
- signs += 1;
- if(signs > type) // client signs maximum
- return;
-
- //client doesn't allow to sign petition two times by one character, but not check sign by another character from same account
- //not allow sign another player from already sign player account
- result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE player_account = '%u' AND petitionguid = '%u'", GetAccountId(), GUID_LOPART(petitionguid));
-
- if(result)
- {
- delete result;
- WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4));
- data << petitionguid;
- data << _player->GetGUID();
- data << (uint32)PETITION_SIGN_ALREADY_SIGNED;
-
- // close at signer side
- SendPacket(&data);
-
- // update for owner if online
- if(Player *owner = objmgr.GetPlayer(ownerguid))
- owner->GetSession()->SendPacket(&data);
- return;
- }
-
- CharacterDatabase.PExecute("INSERT INTO petition_sign (ownerguid,petitionguid, playerguid, player_account) VALUES ('%u', '%u', '%u','%u')", GUID_LOPART(ownerguid),GUID_LOPART(petitionguid), plguidlo,GetAccountId());
-
- sLog.outDebug("PETITION SIGN: GUID %u by player: %s (GUID: %u Account: %u)", GUID_LOPART(petitionguid), _player->GetName(),plguidlo,GetAccountId());
-
- WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4));
- data << petitionguid;
- data << _player->GetGUID();
- data << (uint32)PETITION_SIGN_OK;
-
- // close at signer side
- SendPacket(&data);
-
- // update signs count on charter, required testing...
- //Item *item = _player->GetItemByGuid(petitionguid));
- //if(item)
- // item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT+1, signs);
-
- // update for owner if online
- if(Player *owner = objmgr.GetPlayer(ownerguid))
- owner->GetSession()->SendPacket(&data);
-}
-
-void WorldSession::HandlePetitionDeclineOpcode(WorldPacket & recv_data)
-{
- CHECK_PACKET_SIZE(recv_data, 8);
-
- sLog.outDebug("Received opcode MSG_PETITION_DECLINE"); // ok
- //recv_data.hexlike();
-
- uint64 petitionguid;
- uint64 ownerguid;
- recv_data >> petitionguid; // petition guid
- sLog.outDebug("Petition %u declined by %u", GUID_LOPART(petitionguid), _player->GetGUIDLow());
-
- QueryResult *result = CharacterDatabase.PQuery("SELECT ownerguid FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
- if(!result)
- return;
-
- Field *fields = result->Fetch();
- ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
- delete result;
-
- Player *owner = objmgr.GetPlayer(ownerguid);
- if(owner) // petition owner online
- {
- WorldPacket data(MSG_PETITION_DECLINE, 8);
- data << _player->GetGUID();
- owner->GetSession()->SendPacket(&data);
- }
-}
-
-void WorldSession::HandleOfferPetitionOpcode(WorldPacket & recv_data)
-{
- CHECK_PACKET_SIZE(recv_data, 4+8+8);
-
- sLog.outDebug("Received opcode CMSG_OFFER_PETITION"); // ok
- //recv_data.hexlike();
-
- uint8 signs = 0;
- uint64 petitionguid, plguid;
- uint32 petitiontype;
- Player *player;
- recv_data >> petitiontype; // 2.0.8 - petition type?
- recv_data >> petitionguid; // petition guid
- recv_data >> plguid; // player guid
- sLog.outDebug("OFFER PETITION: type %u, GUID1 %u, to player id: %u", petitiontype, GUID_LOPART(petitionguid), GUID_LOPART(plguid));
-
- player = ObjectAccessor::FindPlayer(plguid);
- if(!player || player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow()))
- return;
-
- // not let offer to enemies
- if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != player->GetTeam() )
- return;
-
- QueryResult *result = CharacterDatabase.PQuery("SELECT petitionguid FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
- if(!result)
- {
- sLog.outError("any petition on server...");
- return;
- }
-
- delete result;
-
- result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
- // result==NULL also correct charter without signs
- if(result)
- signs = result->GetRowCount();
-
- WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8+8+4+signs+signs*12));
- data << petitionguid; // petition guid
- data << _player->GetGUID(); // owner guid
- data << GUID_LOPART(petitionguid); // guild guid (in mangos always same as GUID_LOPART(petition guid)
- data << signs; // sign's count
-
- for(uint8 i = 1; i <= signs; i++)
- {
- Field *fields = result->Fetch();
- uint64 plguid = fields[0].GetUInt64();
-
- data << plguid; // Player GUID
- data << (uint32)0; // there 0 ...
-
- result->NextRow();
- }
-
- delete result;
- player->GetSession()->SendPacket(&data);
-}
-
-void WorldSession::HandleTurnInPetitionOpcode(WorldPacket & recv_data)
-{
- CHECK_PACKET_SIZE(recv_data, 8);
-
- sLog.outDebug("Received opcode CMSG_TURN_IN_PETITION"); // ok
- //recv_data.hexlike();
-
- WorldPacket data;
- uint64 petitionguid;
-
- uint32 ownerguidlo;
- uint32 type;
- std::string name;
-
- recv_data >> petitionguid;
-
- sLog.outDebug("Petition %u turned in by %u", GUID_LOPART(petitionguid), _player->GetGUIDLow());
-
- // data
- QueryResult *result = CharacterDatabase.PQuery("SELECT ownerguid, name, type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
- if(result)
- {
- Field *fields = result->Fetch();
- ownerguidlo = fields[0].GetUInt32();
- name = fields[1].GetCppString();
- type = fields[2].GetUInt32();
- delete result;
- }
- else
- {
- sLog.outError("petition table has broken data!");
- return;
- }
-
- if(type == 9)
- {
- if(_player->GetGuildId())
- {
- data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4);
- data << (uint32)PETITION_TURN_ALREADY_IN_GUILD; // already in guild
- _player->GetSession()->SendPacket(&data);
- return;
- }
- }
- else
- {
- uint8 slot = ArenaTeam::GetSlotByType(type);
- if(slot >= MAX_ARENA_SLOT)
- return;
-
- if(_player->GetArenaTeamId(slot))
- {
- //data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4);
- //data << (uint32)PETITION_TURN_ALREADY_IN_GUILD; // already in guild
- //_player->GetSession()->SendPacket(&data);
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM);
- return;
- }
- }
-
- if(_player->GetGUIDLow() != ownerguidlo)
- return;
-
- // signs
- uint8 signs;
- result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
- if(result)
- signs = result->GetRowCount();
- else
- signs = 0;
-
- uint32 count;
- //if(signs < sWorld.getConfig(CONFIG_MIN_PETITION_SIGNS))
- if(type == 9)
- count = sWorld.getConfig(CONFIG_MIN_PETITION_SIGNS);
- else
- count = type-1;
- if(signs < count)
- {
- data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4);
- data << (uint32)PETITION_TURN_NEED_MORE_SIGNATURES; // need more signatures...
- SendPacket(&data);
- delete result;
- return;
- }
-
- if(type == 9)
- {
- if(objmgr.GetGuildByName(name))
- {
- SendGuildCommandResult(GUILD_CREATE_S, name, GUILD_NAME_EXISTS);
- delete result;
- return;
- }
- }
- else
- {
- if(objmgr.GetArenaTeamByName(name))
- {
- SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S);
- delete result;
- return;
- }
- }
-
- // and at last charter item check
- Item *item = _player->GetItemByGuid(petitionguid);
- if(!item)
- {
- delete result;
- return;
- }
-
- // OK!
-
- // delete charter item
- _player->DestroyItem(item->GetBagSlot(),item->GetSlot(), true);
-
- if(type == 9) // create guild
- {
- Guild* guild = new Guild;
- if(!guild->create(_player->GetGUID(), name))
- {
- delete guild;
- delete result;
- return;
- }
-
- // register guild and add guildmaster
- objmgr.AddGuild(guild);
-
- // add members
- for(uint8 i = 0; i < signs; ++i)
- {
- Field* fields = result->Fetch();
- guild->AddMember(fields[0].GetUInt64(), guild->GetLowestRank());
- result->NextRow();
- }
- }
- else // or arena team
- {
- ArenaTeam* at = new ArenaTeam;
- if(!at->create(_player->GetGUID(), type, name))
- {
- sLog.outError("PetitionsHandler: arena team create failed.");
- delete at;
- delete result;
- return;
- }
-
- CHECK_PACKET_SIZE(recv_data, 8+5*4);
- uint32 icon, iconcolor, border, bordercolor, backgroud;
- recv_data >> backgroud >> icon >> iconcolor >> border >> bordercolor;
-
- at->SetEmblem(backgroud, icon, iconcolor, border, bordercolor);
-
- // register team and add captain
- objmgr.AddArenaTeam(at);
- sLog.outDebug("PetitonsHandler: arena team added to objmrg");
-
- // add members
- for(uint8 i = 0; i < signs; ++i)
- {
- Field* fields = result->Fetch();
- sLog.outDebug("PetitionsHandler: adding arena member %u", fields[0].GetUInt64());
- at->AddMember(fields[0].GetUInt64());
- result->NextRow();
- }
- }
-
- delete result;
-
- CharacterDatabase.BeginTransaction();
- CharacterDatabase.PExecute("DELETE FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
- CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
- CharacterDatabase.CommitTransaction();
-
- // created
- sLog.outDebug("TURN IN PETITION GUID %u", GUID_LOPART(petitionguid));
-
- data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4);
- data << (uint32)PETITION_TURN_OK;
- SendPacket(&data);
-}
-
-void WorldSession::HandlePetitionShowListOpcode(WorldPacket & recv_data)
-{
- CHECK_PACKET_SIZE(recv_data, 8);
-
- sLog.outDebug("Received CMSG_PETITION_SHOWLIST"); // ok
- //recv_data.hexlike();
-
- uint64 guid;
- recv_data >> guid;
-
- SendPetitionShowList(guid);
-}
-
-void WorldSession::SendPetitionShowList(uint64 guid)
-{
- Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_PETITIONER);
- if (!pCreature)
- {
- sLog.outDebug("WORLD: HandlePetitionShowListOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)));
- return;
- }
-
- // remove fake death
- if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
- GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
-
- uint8 count = 0;
- if(pCreature->isTabardDesigner())
- count = 1;
- else
- count = 3;
-
- WorldPacket data(SMSG_PETITION_SHOWLIST, 8+1+4*6);
- data << guid; // npc guid
- data << count; // count
- if(count == 1)
- {
- data << uint32(1); // index
- data << uint32(GUILD_CHARTER); // charter entry
- data << uint32(16161); // charter display id
- data << uint32(GUILD_CHARTER_COST); // charter cost
- data << uint32(0); // unknown
- data << uint32(9); // required signs?
- }
- else
- {
- // 2v2
- data << uint32(1); // index
- data << uint32(ARENA_TEAM_CHARTER_2v2); // charter entry
- data << uint32(16161); // charter display id
- data << uint32(ARENA_TEAM_CHARTER_2v2_COST); // charter cost
- data << uint32(2); // unknown
- data << uint32(2); // required signs?
- // 3v3
- data << uint32(2); // index
- data << uint32(ARENA_TEAM_CHARTER_3v3); // charter entry
- data << uint32(16161); // charter display id
- data << uint32(ARENA_TEAM_CHARTER_3v3_COST); // charter cost
- data << uint32(3); // unknown
- data << uint32(3); // required signs?
- // 5v5
- data << uint32(3); // index
- data << uint32(ARENA_TEAM_CHARTER_5v5); // charter entry
- data << uint32(16161); // charter display id
- data << uint32(ARENA_TEAM_CHARTER_5v5_COST); // charter cost
- data << uint32(5); // unknown
- data << uint32(5); // required signs?
- }
- //for(uint8 i = 0; i < count; i++)
- //{
- // data << uint32(i); // index
- // data << uint32(GUILD_CHARTER); // charter entry
- // data << uint32(16161); // charter display id
- // data << uint32(GUILD_CHARTER_COST+i); // charter cost
- // data << uint32(0); // unknown
- // data << uint32(9); // required signs?
- //}
- SendPacket(&data);
- sLog.outDebug("Sent SMSG_PETITION_SHOWLIST");
-}
+/*
+ * Copyright (C) 2005-2008 MaNGOS
+ *
+ * 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 "WorldSession.h"
+#include "World.h"
+#include "ObjectMgr.h"
+#include "Log.h"
+#include "Opcodes.h"
+#include "Guild.h"
+#include "ArenaTeam.h"
+#include "MapManager.h"
+#include "GossipDef.h"
+#include "SocialMgr.h"
+
+/*enum PetitionType // dbc data
+{
+ PETITION_TYPE_GUILD = 1,
+ PETITION_TYPE_ARENA_TEAM = 3
+};*/
+
+// Charters ID in item_template
+#define GUILD_CHARTER 5863
+#define GUILD_CHARTER_COST 1000 // 10 S
+#define ARENA_TEAM_CHARTER_2v2 23560
+#define ARENA_TEAM_CHARTER_2v2_COST 800000 // 80 G
+#define ARENA_TEAM_CHARTER_3v3 23561
+#define ARENA_TEAM_CHARTER_3v3_COST 1200000 // 120 G
+#define ARENA_TEAM_CHARTER_5v5 23562
+#define ARENA_TEAM_CHARTER_5v5_COST 2000000 // 200 G
+
+void WorldSession::HandlePetitionBuyOpcode(WorldPacket & recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data, 8+8+4+1+5*8+2+1+4+4);
+
+ sLog.outDebug("Received opcode CMSG_PETITION_BUY");
+ //recv_data.hexlike();
+
+ uint64 guidNPC;
+ uint64 unk1, unk3, unk4, unk5, unk6, unk7;
+ uint32 unk2;
+ std::string name;
+ uint16 unk8;
+ uint8 unk9;
+ uint32 unk10; // selected index
+ uint32 unk11;
+ recv_data >> guidNPC; // NPC GUID
+ recv_data >> unk1; // 0
+ recv_data >> unk2; // 0
+ recv_data >> name; // name
+
+ // recheck
+ CHECK_PACKET_SIZE(recv_data, 8+8+4+(name.size()+1)+5*8+2+1+4+4);
+
+ recv_data >> unk3; // 0
+ recv_data >> unk4; // 0
+ recv_data >> unk5; // 0
+ recv_data >> unk6; // 0
+ recv_data >> unk7; // 0
+ recv_data >> unk8; // 0
+ recv_data >> unk9; // 0
+ recv_data >> unk10; // index
+ recv_data >> unk11; // 0
+ sLog.outDebug("Petitioner with GUID %u tried sell petition: name %s", GUID_LOPART(guidNPC), name.c_str());
+
+ // prevent cheating
+ Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guidNPC,UNIT_NPC_FLAG_PETITIONER);
+ if (!pCreature)
+ {
+ sLog.outDebug("WORLD: HandlePetitionBuyOpcode - Unit (GUID: %u) not found or you can't interact with him.", GUID_LOPART(guidNPC));
+ return;
+ }
+
+ // remove fake death
+ if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
+ GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+
+ uint32 charterid = 0;
+ uint32 cost = 0;
+ uint32 type = 0;
+ if(pCreature->isTabardDesigner())
+ {
+ // if tabard designer, then trying to buy a guild charter.
+ // do not let if already in guild.
+ if(_player->GetGuildId())
+ return;
+
+ charterid = GUILD_CHARTER;
+ cost = GUILD_CHARTER_COST;
+ type = 9;
+ }
+ else
+ {
+ // TODO: find correct opcode
+ if(_player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
+ {
+ SendNotification(LANG_ARENA_ONE_TOOLOW, 70);
+ return;
+ }
+
+ for(uint8 i = 0; i < MAX_ARENA_SLOT; i++)
+ {
+ if(_player->GetArenaTeamId(i) && (i == (unk10-1)))
+ {
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM);
+ return;
+ }
+ }
+ switch(unk10)
+ {
+ case 1:
+ charterid = ARENA_TEAM_CHARTER_2v2;
+ cost = ARENA_TEAM_CHARTER_2v2_COST;
+ type = 2; // 2v2
+ break;
+ case 2:
+ charterid = ARENA_TEAM_CHARTER_3v3;
+ cost = ARENA_TEAM_CHARTER_3v3_COST;
+ type = 3; // 3v3
+ break;
+ case 3:
+ charterid = ARENA_TEAM_CHARTER_5v5;
+ cost = ARENA_TEAM_CHARTER_5v5_COST;
+ type = 5; // 5v5
+ break;
+ default:
+ sLog.outDebug("unknown selection at buy petition: %u", unk10);
+ return;
+ }
+ }
+
+ if(type == 9)
+ {
+ if(objmgr.GetGuildByName(name))
+ {
+ SendGuildCommandResult(GUILD_CREATE_S, name, GUILD_NAME_EXISTS);
+ return;
+ }
+ if(objmgr.IsReservedName(name))
+ {
+ SendGuildCommandResult(GUILD_CREATE_S, name, GUILD_NAME_INVALID);
+ return;
+ }
+ if(!ObjectMgr::IsValidCharterName(name))
+ {
+ SendGuildCommandResult(GUILD_CREATE_S, name, GUILD_NAME_INVALID);
+ return;
+ }
+ }
+ else
+ {
+ if(objmgr.GetArenaTeamByName(name))
+ {
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S);
+ return;
+ }
+ if(objmgr.IsReservedName(name))
+ {
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_INVALID);
+ return;
+ }
+ if(!ObjectMgr::IsValidCharterName(name))
+ {
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_INVALID);
+ return;
+ }
+ }
+
+ ItemPrototype const *pProto = objmgr.GetItemPrototype(charterid);
+ if(!pProto)
+ {
+ _player->SendBuyError(BUY_ERR_CANT_FIND_ITEM, NULL, charterid, 0);
+ return;
+ }
+
+ if(_player->GetMoney() < cost)
+ { //player hasn't got enough money
+ _player->SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, pCreature, charterid, 0);
+ return;
+ }
+
+ ItemPosCountVec dest;
+ uint8 msg = _player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, charterid, pProto->BuyCount );
+ if(msg != EQUIP_ERR_OK)
+ {
+ _player->SendBuyError(msg, pCreature, charterid, 0);
+ return;
+ }
+
+ _player->ModifyMoney(-(int32)cost);
+ Item *charter = _player->StoreNewItem(dest, charterid, true);
+ if(!charter)
+ return;
+
+ charter->SetUInt32Value(ITEM_FIELD_ENCHANTMENT, charter->GetGUIDLow());
+ // ITEM_FIELD_ENCHANTMENT is guild/arenateam id
+ // ITEM_FIELD_ENCHANTMENT+1 is current signatures count (showed on item)
+ charter->SetState(ITEM_CHANGED, _player);
+ _player->SendNewItem(charter, 1, true, false);
+
+ // a petition is invalid, if both the owner and the type matches
+ QueryResult *result = CharacterDatabase.PQuery("SELECT petitionguid FROM petition WHERE ownerguid = '%u' AND type = '%u'", _player->GetGUIDLow(), type);
+
+ std::ostringstream ssInvalidPetitionGUIDs;
+
+ if (result)
+ {
+
+ do
+ {
+ Field *fields = result->Fetch();
+ ssInvalidPetitionGUIDs << "'" << fields[0].GetUInt32() << "' , ";
+ } while (result->NextRow());
+
+ delete result;
+ }
+
+ // delete petitions with the same guid as this one
+ ssInvalidPetitionGUIDs << "'" << charter->GetGUIDLow() << "'";
+
+ sLog.outDebug("Invalid petition GUIDs: %s", ssInvalidPetitionGUIDs.str().c_str());
+ CharacterDatabase.escape_string(name);
+ CharacterDatabase.BeginTransaction();
+ CharacterDatabase.PExecute("DELETE FROM petition WHERE petitionguid IN ( %s )", ssInvalidPetitionGUIDs.str().c_str());
+ CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE petitionguid IN ( %s )", ssInvalidPetitionGUIDs.str().c_str());
+ CharacterDatabase.PExecute("INSERT INTO petition (ownerguid, petitionguid, name, type) VALUES ('%u', '%u', '%s', '%u')",
+ _player->GetGUIDLow(), charter->GetGUIDLow(), name.c_str(), type);
+ CharacterDatabase.CommitTransaction();
+}
+
+void WorldSession::HandlePetitionShowSignOpcode(WorldPacket & recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data, 8);
+
+ // ok
+ sLog.outDebug("Received opcode CMSG_PETITION_SHOW_SIGNATURES");
+ //recv_data.hexlike();
+
+ uint8 signs = 0;
+ uint64 petitionguid;
+ recv_data >> petitionguid; // petition guid
+
+ // solve (possible) some strange compile problems with explicit use GUID_LOPART(petitionguid) at some GCC versions (wrong code optimization in compiler?)
+ uint32 petitionguid_low = GUID_LOPART(petitionguid);
+
+ QueryResult *result = CharacterDatabase.PQuery("SELECT petitionguid, type FROM petition WHERE petitionguid = '%u'", petitionguid_low);
+ if(!result)
+ {
+ sLog.outError("any petition on server...");
+ return;
+ }
+ Field *fields = result->Fetch();
+ uint32 type = fields[1].GetUInt32();
+ delete result;
+ // if guild petition and has guild => error, return;
+ if(type==9 && _player->GetGuildId())
+ return;
+
+ result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", petitionguid_low);
+
+ // result==NULL also correct in case no sign yet
+ if(result)
+ signs = result->GetRowCount();
+
+ sLog.outDebug("CMSG_PETITION_SHOW_SIGNATURES petition entry: '%u'", petitionguid_low);
+
+ WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8+8+4+1+signs*12));
+ data << petitionguid; // petition guid
+ data << _player->GetGUID(); // owner guid
+ data << petitionguid_low; // guild guid (in mangos always same as GUID_LOPART(petitionguid)
+ data << signs; // sign's count
+
+ for(uint8 i = 1; i <= signs; i++)
+ {
+ Field *fields = result->Fetch();
+ uint64 plguid = fields[0].GetUInt64();
+
+ data << plguid; // Player GUID
+ data << (uint32)0; // there 0 ...
+
+ result->NextRow();
+ }
+ delete result;
+ SendPacket(&data);
+}
+
+void WorldSession::HandlePetitionQueryOpcode(WorldPacket & recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data, 4+8);
+
+ sLog.outDebug("Received opcode CMSG_PETITION_QUERY"); // ok
+ //recv_data.hexlike();
+
+ uint32 guildguid;
+ uint64 petitionguid;
+ recv_data >> guildguid; // in mangos always same as GUID_LOPART(petitionguid)
+ recv_data >> petitionguid; // petition guid
+ sLog.outDebug("CMSG_PETITION_QUERY Petition GUID %u Guild GUID %u", GUID_LOPART(petitionguid), guildguid);
+
+ SendPetitionQueryOpcode(petitionguid);
+}
+
+void WorldSession::SendPetitionQueryOpcode(uint64 petitionguid)
+{
+ uint64 ownerguid = 0;
+ uint32 type;
+ std::string name = "NO_NAME_FOR_GUID";
+ uint8 signs = 0;
+
+ QueryResult *result = CharacterDatabase.PQuery(
+ "SELECT ownerguid, name, "
+ " (SELECT COUNT(playerguid) FROM petition_sign WHERE petition_sign.petitionguid = '%u') AS signs "
+ "FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid), GUID_LOPART(petitionguid));
+
+ if(result)
+ {
+ Field* fields = result->Fetch();
+ ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
+ name = fields[1].GetCppString();
+ signs = fields[2].GetUInt8();
+ delete result;
+ }
+ else
+ {
+ sLog.outDebug("CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid));
+ return;
+ }
+
+ QueryResult *result2 = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
+
+ if(result2)
+ {
+ Field* fields = result2->Fetch();
+ type = fields[0].GetUInt32();
+ delete result2;
+ }
+ else
+ {
+ sLog.outDebug("CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid));
+ return;
+ }
+
+ WorldPacket data(SMSG_PETITION_QUERY_RESPONSE, (4+8+name.size()+1+1+4*13));
+ data << GUID_LOPART(petitionguid); // guild/team guid (in mangos always same as GUID_LOPART(petition guid)
+ data << ownerguid; // charter owner guid
+ data << name; // name (guild/arena team)
+ data << uint8(0); // 1
+ if(type == 9)
+ {
+ data << uint32(9);
+ data << uint32(9);
+ data << uint32(0); // bypass client - side limitation, a different value is needed here for each petition
+ }
+ else
+ {
+ data << type-1;
+ data << type-1;
+ data << type; // bypass client - side limitation, a different value is needed here for each petition
+ }
+ data << uint32(0); // 5
+ data << uint32(0); // 6
+ data << uint32(0); // 7
+ data << uint32(0); // 8
+ data << uint16(0); // 9 2 bytes field
+ data << uint32(0); // 10
+ data << uint32(0); // 11
+ data << uint32(0); // 13 count of next strings?
+ data << uint32(0); // 14
+ if(type == 9)
+ data << uint32(0); // 15 0 - guild, 1 - arena team
+ else
+ data << uint32(1);
+ SendPacket(&data);
+}
+
+void WorldSession::HandlePetitionRenameOpcode(WorldPacket & recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data, 8+1);
+
+ sLog.outDebug("Received opcode MSG_PETITION_RENAME"); // ok
+ //recv_data.hexlike();
+
+ uint64 petitionguid;
+ uint32 type;
+ std::string newname;
+
+ recv_data >> petitionguid; // guid
+ recv_data >> newname; // new name
+
+ Item *item = _player->GetItemByGuid(petitionguid);
+ if(!item)
+ return;
+
+ QueryResult *result2 = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
+
+ if(result2)
+ {
+ Field* fields = result2->Fetch();
+ type = fields[0].GetUInt32();
+ delete result2;
+ }
+ else
+ {
+ sLog.outDebug("CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid));
+ return;
+ }
+
+ if(type == 9)
+ {
+ if(objmgr.GetGuildByName(newname))
+ {
+ SendGuildCommandResult(GUILD_CREATE_S, newname, GUILD_NAME_EXISTS);
+ return;
+ }
+ if(objmgr.IsReservedName(newname))
+ {
+ SendGuildCommandResult(GUILD_CREATE_S, newname, GUILD_NAME_INVALID);
+ return;
+ }
+ if(!ObjectMgr::IsValidCharterName(newname))
+ {
+ SendGuildCommandResult(GUILD_CREATE_S, newname, GUILD_NAME_INVALID);
+ return;
+ }
+ }
+ else
+ {
+ if(objmgr.GetArenaTeamByName(newname))
+ {
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_EXISTS_S);
+ return;
+ }
+ if(objmgr.IsReservedName(newname))
+ {
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_INVALID);
+ return;
+ }
+ if(!ObjectMgr::IsValidCharterName(newname))
+ {
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, newname, "", ERR_ARENA_TEAM_NAME_INVALID);
+ return;
+ }
+ }
+
+ std::string db_newname = newname;
+ CharacterDatabase.escape_string(db_newname);
+ CharacterDatabase.PExecute("UPDATE petition SET name = '%s' WHERE petitionguid = '%u'",
+ db_newname.c_str(), GUID_LOPART(petitionguid));
+
+ sLog.outDebug("Petition (GUID: %u) renamed to '%s'", GUID_LOPART(petitionguid), newname.c_str());
+ WorldPacket data(MSG_PETITION_RENAME, (8+newname.size()+1));
+ data << petitionguid;
+ data << newname;
+ SendPacket(&data);
+}
+
+void WorldSession::HandlePetitionSignOpcode(WorldPacket & recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data, 8+1);
+
+ sLog.outDebug("Received opcode CMSG_PETITION_SIGN"); // ok
+ //recv_data.hexlike();
+
+ Field *fields;
+ uint64 petitionguid;
+ uint32 type;
+ uint8 unk;
+ uint64 ownerguid;
+ recv_data >> petitionguid; // petition guid
+ recv_data >> unk;
+
+ uint8 signs = 0;
+
+ QueryResult *result = CharacterDatabase.PQuery(
+ "SELECT ownerguid, "
+ " (SELECT COUNT(playerguid) FROM petition_sign WHERE petition_sign.petitionguid = '%u') AS signs "
+ "FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid), GUID_LOPART(petitionguid));
+
+ if(!result)
+ {
+ sLog.outError("any petition on server...");
+ return;
+ }
+
+ fields = result->Fetch();
+ ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
+ signs = fields[1].GetUInt8();
+
+ delete result;
+
+ uint32 plguidlo = _player->GetGUIDLow();
+ if(GUID_LOPART(ownerguid) == plguidlo)
+ return;
+
+ // not let enemies sign guild charter
+ if(!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != objmgr.GetPlayerTeamByGUID(ownerguid))
+ return;
+
+ QueryResult *result2 = CharacterDatabase.PQuery("SELECT type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
+
+ if(result2)
+ {
+ Field* fields = result2->Fetch();
+ type = fields[0].GetUInt32();
+ delete result2;
+ }
+ else
+ {
+ sLog.outDebug("CMSG_PETITION_QUERY failed for petition (GUID: %u)", GUID_LOPART(petitionguid));
+ return;
+ }
+
+ if(type != 9 && _player->getLevel() < sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL))
+ {
+ // player is too low level to join an arena team
+ SendNotification(LANG_YOUR_ARENA_LEVEL_REQ_ERROR,sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL));
+ return;
+ }
+
+ signs += 1;
+ if(signs > type) // client signs maximum
+ return;
+
+ //client doesn't allow to sign petition two times by one character, but not check sign by another character from same account
+ //not allow sign another player from already sign player account
+ result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE player_account = '%u' AND petitionguid = '%u'", GetAccountId(), GUID_LOPART(petitionguid));
+
+ if(result)
+ {
+ delete result;
+ WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4));
+ data << petitionguid;
+ data << _player->GetGUID();
+ data << (uint32)PETITION_SIGN_ALREADY_SIGNED;
+
+ // close at signer side
+ SendPacket(&data);
+
+ // update for owner if online
+ if(Player *owner = objmgr.GetPlayer(ownerguid))
+ owner->GetSession()->SendPacket(&data);
+ return;
+ }
+
+ CharacterDatabase.PExecute("INSERT INTO petition_sign (ownerguid,petitionguid, playerguid, player_account) VALUES ('%u', '%u', '%u','%u')", GUID_LOPART(ownerguid),GUID_LOPART(petitionguid), plguidlo,GetAccountId());
+
+ sLog.outDebug("PETITION SIGN: GUID %u by player: %s (GUID: %u Account: %u)", GUID_LOPART(petitionguid), _player->GetName(),plguidlo,GetAccountId());
+
+ WorldPacket data(SMSG_PETITION_SIGN_RESULTS, (8+8+4));
+ data << petitionguid;
+ data << _player->GetGUID();
+ data << (uint32)PETITION_SIGN_OK;
+
+ // close at signer side
+ SendPacket(&data);
+
+ // update signs count on charter, required testing...
+ //Item *item = _player->GetItemByGuid(petitionguid));
+ //if(item)
+ // item->SetUInt32Value(ITEM_FIELD_ENCHANTMENT+1, signs);
+
+ // update for owner if online
+ if(Player *owner = objmgr.GetPlayer(ownerguid))
+ owner->GetSession()->SendPacket(&data);
+}
+
+void WorldSession::HandlePetitionDeclineOpcode(WorldPacket & recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data, 8);
+
+ sLog.outDebug("Received opcode MSG_PETITION_DECLINE"); // ok
+ //recv_data.hexlike();
+
+ uint64 petitionguid;
+ uint64 ownerguid;
+ recv_data >> petitionguid; // petition guid
+ sLog.outDebug("Petition %u declined by %u", GUID_LOPART(petitionguid), _player->GetGUIDLow());
+
+ QueryResult *result = CharacterDatabase.PQuery("SELECT ownerguid FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
+ if(!result)
+ return;
+
+ Field *fields = result->Fetch();
+ ownerguid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
+ delete result;
+
+ Player *owner = objmgr.GetPlayer(ownerguid);
+ if(owner) // petition owner online
+ {
+ WorldPacket data(MSG_PETITION_DECLINE, 8);
+ data << _player->GetGUID();
+ owner->GetSession()->SendPacket(&data);
+ }
+}
+
+void WorldSession::HandleOfferPetitionOpcode(WorldPacket & recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data, 4+8+8);
+
+ sLog.outDebug("Received opcode CMSG_OFFER_PETITION"); // ok
+ //recv_data.hexlike();
+
+ uint8 signs = 0;
+ uint64 petitionguid, plguid;
+ uint32 petitiontype;
+ Player *player;
+ recv_data >> petitiontype; // 2.0.8 - petition type?
+ recv_data >> petitionguid; // petition guid
+ recv_data >> plguid; // player guid
+ sLog.outDebug("OFFER PETITION: type %u, GUID1 %u, to player id: %u", petitiontype, GUID_LOPART(petitionguid), GUID_LOPART(plguid));
+
+ player = ObjectAccessor::FindPlayer(plguid);
+ if(!player || player->GetSocial()->HasIgnore(GetPlayer()->GetGUIDLow()))
+ return;
+
+ // not let offer to enemies
+ if (!sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD) && GetPlayer()->GetTeam() != player->GetTeam() )
+ return;
+
+ QueryResult *result = CharacterDatabase.PQuery("SELECT petitionguid FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
+ if(!result)
+ {
+ sLog.outError("any petition on server...");
+ return;
+ }
+
+ delete result;
+
+ result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
+ // result==NULL also correct charter without signs
+ if(result)
+ signs = result->GetRowCount();
+
+ WorldPacket data(SMSG_PETITION_SHOW_SIGNATURES, (8+8+4+signs+signs*12));
+ data << petitionguid; // petition guid
+ data << _player->GetGUID(); // owner guid
+ data << GUID_LOPART(petitionguid); // guild guid (in mangos always same as GUID_LOPART(petition guid)
+ data << signs; // sign's count
+
+ for(uint8 i = 1; i <= signs; i++)
+ {
+ Field *fields = result->Fetch();
+ uint64 plguid = fields[0].GetUInt64();
+
+ data << plguid; // Player GUID
+ data << (uint32)0; // there 0 ...
+
+ result->NextRow();
+ }
+
+ delete result;
+ player->GetSession()->SendPacket(&data);
+}
+
+void WorldSession::HandleTurnInPetitionOpcode(WorldPacket & recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data, 8);
+
+ sLog.outDebug("Received opcode CMSG_TURN_IN_PETITION"); // ok
+ //recv_data.hexlike();
+
+ WorldPacket data;
+ uint64 petitionguid;
+
+ uint32 ownerguidlo;
+ uint32 type;
+ std::string name;
+
+ recv_data >> petitionguid;
+
+ sLog.outDebug("Petition %u turned in by %u", GUID_LOPART(petitionguid), _player->GetGUIDLow());
+
+ // data
+ QueryResult *result = CharacterDatabase.PQuery("SELECT ownerguid, name, type FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
+ if(result)
+ {
+ Field *fields = result->Fetch();
+ ownerguidlo = fields[0].GetUInt32();
+ name = fields[1].GetCppString();
+ type = fields[2].GetUInt32();
+ delete result;
+ }
+ else
+ {
+ sLog.outError("petition table has broken data!");
+ return;
+ }
+
+ if(type == 9)
+ {
+ if(_player->GetGuildId())
+ {
+ data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4);
+ data << (uint32)PETITION_TURN_ALREADY_IN_GUILD; // already in guild
+ _player->GetSession()->SendPacket(&data);
+ return;
+ }
+ }
+ else
+ {
+ uint8 slot = ArenaTeam::GetSlotByType(type);
+ if(slot >= MAX_ARENA_SLOT)
+ return;
+
+ if(_player->GetArenaTeamId(slot))
+ {
+ //data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4);
+ //data << (uint32)PETITION_TURN_ALREADY_IN_GUILD; // already in guild
+ //_player->GetSession()->SendPacket(&data);
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM);
+ return;
+ }
+ }
+
+ if(_player->GetGUIDLow() != ownerguidlo)
+ return;
+
+ // signs
+ uint8 signs;
+ result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
+ if(result)
+ signs = result->GetRowCount();
+ else
+ signs = 0;
+
+ uint32 count;
+ //if(signs < sWorld.getConfig(CONFIG_MIN_PETITION_SIGNS))
+ if(type == 9)
+ count = sWorld.getConfig(CONFIG_MIN_PETITION_SIGNS);
+ else
+ count = type-1;
+ if(signs < count)
+ {
+ data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4);
+ data << (uint32)PETITION_TURN_NEED_MORE_SIGNATURES; // need more signatures...
+ SendPacket(&data);
+ delete result;
+ return;
+ }
+
+ if(type == 9)
+ {
+ if(objmgr.GetGuildByName(name))
+ {
+ SendGuildCommandResult(GUILD_CREATE_S, name, GUILD_NAME_EXISTS);
+ delete result;
+ return;
+ }
+ }
+ else
+ {
+ if(objmgr.GetArenaTeamByName(name))
+ {
+ SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ARENA_TEAM_NAME_EXISTS_S);
+ delete result;
+ return;
+ }
+ }
+
+ // and at last charter item check
+ Item *item = _player->GetItemByGuid(petitionguid);
+ if(!item)
+ {
+ delete result;
+ return;
+ }
+
+ // OK!
+
+ // delete charter item
+ _player->DestroyItem(item->GetBagSlot(),item->GetSlot(), true);
+
+ if(type == 9) // create guild
+ {
+ Guild* guild = new Guild;
+ if(!guild->create(_player->GetGUID(), name))
+ {
+ delete guild;
+ delete result;
+ return;
+ }
+
+ // register guild and add guildmaster
+ objmgr.AddGuild(guild);
+
+ // add members
+ for(uint8 i = 0; i < signs; ++i)
+ {
+ Field* fields = result->Fetch();
+ guild->AddMember(fields[0].GetUInt64(), guild->GetLowestRank());
+ result->NextRow();
+ }
+ }
+ else // or arena team
+ {
+ ArenaTeam* at = new ArenaTeam;
+ if(!at->create(_player->GetGUID(), type, name))
+ {
+ sLog.outError("PetitionsHandler: arena team create failed.");
+ delete at;
+ delete result;
+ return;
+ }
+
+ CHECK_PACKET_SIZE(recv_data, 8+5*4);
+ uint32 icon, iconcolor, border, bordercolor, backgroud;
+ recv_data >> backgroud >> icon >> iconcolor >> border >> bordercolor;
+
+ at->SetEmblem(backgroud, icon, iconcolor, border, bordercolor);
+
+ // register team and add captain
+ objmgr.AddArenaTeam(at);
+ sLog.outDebug("PetitonsHandler: arena team added to objmrg");
+
+ // add members
+ for(uint8 i = 0; i < signs; ++i)
+ {
+ Field* fields = result->Fetch();
+ sLog.outDebug("PetitionsHandler: adding arena member %u", fields[0].GetUInt64());
+ at->AddMember(fields[0].GetUInt64());
+ result->NextRow();
+ }
+ }
+
+ delete result;
+
+ CharacterDatabase.BeginTransaction();
+ CharacterDatabase.PExecute("DELETE FROM petition WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
+ CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE petitionguid = '%u'", GUID_LOPART(petitionguid));
+ CharacterDatabase.CommitTransaction();
+
+ // created
+ sLog.outDebug("TURN IN PETITION GUID %u", GUID_LOPART(petitionguid));
+
+ data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4);
+ data << (uint32)PETITION_TURN_OK;
+ SendPacket(&data);
+}
+
+void WorldSession::HandlePetitionShowListOpcode(WorldPacket & recv_data)
+{
+ CHECK_PACKET_SIZE(recv_data, 8);
+
+ sLog.outDebug("Received CMSG_PETITION_SHOWLIST"); // ok
+ //recv_data.hexlike();
+
+ uint64 guid;
+ recv_data >> guid;
+
+ SendPetitionShowList(guid);
+}
+
+void WorldSession::SendPetitionShowList(uint64 guid)
+{
+ Creature *pCreature = ObjectAccessor::GetNPCIfCanInteractWith(*_player, guid, UNIT_NPC_FLAG_PETITIONER);
+ if (!pCreature)
+ {
+ sLog.outDebug("WORLD: HandlePetitionShowListOpcode - Unit (GUID: %u) not found or you can't interact with him.", uint32(GUID_LOPART(guid)));
+ return;
+ }
+
+ // remove fake death
+ if(GetPlayer()->hasUnitState(UNIT_STAT_DIED))
+ GetPlayer()->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);
+
+ uint8 count = 0;
+ if(pCreature->isTabardDesigner())
+ count = 1;
+ else
+ count = 3;
+
+ WorldPacket data(SMSG_PETITION_SHOWLIST, 8+1+4*6);
+ data << guid; // npc guid
+ data << count; // count
+ if(count == 1)
+ {
+ data << uint32(1); // index
+ data << uint32(GUILD_CHARTER); // charter entry
+ data << uint32(16161); // charter display id
+ data << uint32(GUILD_CHARTER_COST); // charter cost
+ data << uint32(0); // unknown
+ data << uint32(9); // required signs?
+ }
+ else
+ {
+ // 2v2
+ data << uint32(1); // index
+ data << uint32(ARENA_TEAM_CHARTER_2v2); // charter entry
+ data << uint32(16161); // charter display id
+ data << uint32(ARENA_TEAM_CHARTER_2v2_COST); // charter cost
+ data << uint32(2); // unknown
+ data << uint32(2); // required signs?
+ // 3v3
+ data << uint32(2); // index
+ data << uint32(ARENA_TEAM_CHARTER_3v3); // charter entry
+ data << uint32(16161); // charter display id
+ data << uint32(ARENA_TEAM_CHARTER_3v3_COST); // charter cost
+ data << uint32(3); // unknown
+ data << uint32(3); // required signs?
+ // 5v5
+ data << uint32(3); // index
+ data << uint32(ARENA_TEAM_CHARTER_5v5); // charter entry
+ data << uint32(16161); // charter display id
+ data << uint32(ARENA_TEAM_CHARTER_5v5_COST); // charter cost
+ data << uint32(5); // unknown
+ data << uint32(5); // required signs?
+ }
+ //for(uint8 i = 0; i < count; i++)
+ //{
+ // data << uint32(i); // index
+ // data << uint32(GUILD_CHARTER); // charter entry
+ // data << uint32(16161); // charter display id
+ // data << uint32(GUILD_CHARTER_COST+i); // charter cost
+ // data << uint32(0); // unknown
+ // data << uint32(9); // required signs?
+ //}
+ SendPacket(&data);
+ sLog.outDebug("Sent SMSG_PETITION_SHOWLIST");
+}
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index 0da7f36c3eb..56e123f6e6f 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -265,8 +265,8 @@ Player::Player (WorldSession *session): Unit()
if(GetSession()->GetSecurity() >= SEC_GAMEMASTER)
SetAcceptTicket(true);
- // players always and GM if set in config accept whispers by default
- if(GetSession()->GetSecurity() == SEC_PLAYER || sWorld.getConfig(CONFIG_GM_WISPERING_TO))
+ // players always accept
+ if(GetSession()->GetSecurity() == SEC_PLAYER)
SetAcceptWhispers(true);
m_curSelection = 0;
@@ -1415,7 +1415,7 @@ uint8 Player::chatTag() const
// 0x4 - gm
// 0x2 - dnd
// 0x1 - afk
- if(isGameMaster())
+ if(isGMChat())
return 4;
else if(isDND())
return 3;
@@ -1555,10 +1555,13 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
}
}
- SetSemaphoreTeleport(false);
-
if(!GetSession()->PlayerLogout())
+ {
+ // don't reset teleport semaphore while logging out, otherwise m_teleport_dest won't be used in Player::SaveToDB
+ SetSemaphoreTeleport(false);
+
UpdateZone(GetZoneId());
+ }
// new zone
if(old_zone != GetZoneId())
@@ -9322,6 +9325,11 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo
ItemPrototype const *pProto = pItem->GetProto();
if( pProto )
{
+ // May be here should be more stronger checks; STUNNED checked
+ // ROOT, CONFUSED, DISTRACTED, FLEEING this needs to be checked.
+ if (not_loading && hasUnitState(UNIT_STAT_STUNNED))
+ return EQUIP_ERR_YOU_ARE_STUNNED;
+
if(pItem->IsBindedNotWith(GetGUID()))
return EQUIP_ERR_DONT_OWN_THAT_ITEM;
@@ -9346,6 +9354,9 @@ uint8 Player::CanEquipItem( uint8 slot, uint16 &dest, Item *pItem, bool swap, bo
if(isInCombat()&& pProto->Class == ITEM_CLASS_WEAPON && m_weaponChangeTimer != 0)
return EQUIP_ERR_CANT_DO_RIGHT_NOW; // maybe exist better err
+ if(IsNonMeleeSpellCasted(false))
+ return EQUIP_ERR_CANT_DO_RIGHT_NOW;
+
uint8 eslot = FindEquipSlot( pProto, slot, swap );
if( eslot == NULL_SLOT )
return EQUIP_ERR_ITEM_CANT_BE_EQUIPPED;
@@ -13798,16 +13809,45 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
{
switch(sWorld.getConfig(CONFIG_GM_LOGIN_STATE))
{
- case 0: // disable
- break;
- case 1: // enable
- SetGameMaster(true);
- break;
+ default:
+ case 0: break; // disable
+ case 1: SetGameMaster(true); break; // enable
case 2: // save state
- if(gmstate)
+ if(gmstate & PLAYER_EXTRA_GM_ON)
SetGameMaster(true);
break;
+ }
+
+ switch(sWorld.getConfig(CONFIG_GM_ACCEPT_TICKETS))
+ {
default:
+ case 0: break; // disable
+ case 1: SetAcceptTicket(true); break; // enable
+ case 2: // save state
+ if(gmstate & PLAYER_EXTRA_GM_ACCEPT_TICKETS)
+ SetAcceptTicket(true);
+ break;
+ }
+
+ switch(sWorld.getConfig(CONFIG_GM_CHAT))
+ {
+ default:
+ case 0: break; // disable
+ case 1: SetGMChat(true); break; // enable
+ case 2: // save state
+ if(gmstate & PLAYER_EXTRA_GM_CHAT)
+ SetGMChat(true);
+ break;
+ }
+
+ switch(sWorld.getConfig(CONFIG_GM_WISPERING_TO))
+ {
+ default:
+ case 0: break; // disable
+ case 1: SetAcceptWhispers(true); break; // enable
+ case 2: // save state
+ if(gmstate & PLAYER_EXTRA_ACCEPT_WHISPERS)
+ SetAcceptWhispers(true);
break;
}
}
@@ -14877,7 +14917,7 @@ void Player::SaveToDB()
ss << "0";
ss << ", ";
- ss << (isGameMaster()? 1 : 0);
+ ss << m_ExtraFlags;
ss << ", ";
ss << uint32(m_stableSlots); // to prevent save uint8 as char
@@ -16387,13 +16427,15 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
return false;
}
- VendorItem const* crItem = vItems->FindItem(item);
- if(!crItem)
+ size_t vendor_slot = vItems->FindItemSlot(item);
+ if(vendor_slot >= vItems->GetItemCount())
{
SendBuyError( BUY_ERR_CANT_FIND_ITEM, pCreature, item, 0);
return false;
}
+ VendorItem const* crItem = vItems->m_items[vendor_slot];
+
// check current item amount if it limited
if( crItem->maxcount != 0 )
{
@@ -16520,7 +16562,7 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
WorldPacket data(SMSG_BUY_ITEM, (8+4+4+4));
data << pCreature->GetGUID();
- data << (uint32)crItem->item;
+ data << (uint32)(vendor_slot+1); // numbered from 1 at client
data << (uint32)(crItem->maxcount > 0 ? new_count : 0xFFFFFFFF);
data << (uint32)count;
GetSession()->SendPacket(&data);
@@ -16559,7 +16601,7 @@ bool Player::BuyItemFromVendor(uint64 vendorguid, uint32 item, uint8 count, uint
WorldPacket data(SMSG_BUY_ITEM, (8+4+4+4));
data << pCreature->GetGUID();
- data << (uint32)crItem->item;
+ data << (uint32)(vendor_slot+1); // numbered from 1 at client
data << (uint32)(crItem->maxcount > 0 ? new_count : 0xFFFFFFFF);
data << (uint32)count;
GetSession()->SendPacket(&data);
diff --git a/src/game/Player.h b/src/game/Player.h
index 33ccc79e307..b8c35e941f7 100644
--- a/src/game/Player.h
+++ b/src/game/Player.h
@@ -496,6 +496,7 @@ enum PlayerExtraFlags
PLAYER_EXTRA_ACCEPT_WHISPERS = 0x0004,
PLAYER_EXTRA_TAXICHEAT = 0x0008,
PLAYER_EXTRA_GM_INVISIBLE = 0x0010,
+ PLAYER_EXTRA_GM_CHAT = 0x0020, // Show GM badge in chat messages
// other states
PLAYER_EXTRA_PVP_DEATH = 0x0100 // store PvP death status until corpse creating.
@@ -954,6 +955,8 @@ class MANGOS_DLL_SPEC Player : public Unit
void SetAcceptWhispers(bool on) { if(on) m_ExtraFlags |= PLAYER_EXTRA_ACCEPT_WHISPERS; else m_ExtraFlags &= ~PLAYER_EXTRA_ACCEPT_WHISPERS; }
bool isGameMaster() const { return m_ExtraFlags & PLAYER_EXTRA_GM_ON; }
void SetGameMaster(bool on);
+ bool isGMChat() const { return GetSession()->GetSecurity() >= SEC_MODERATOR && (m_ExtraFlags & PLAYER_EXTRA_GM_CHAT); }
+ void SetGMChat(bool on) { if(on) m_ExtraFlags |= PLAYER_EXTRA_GM_CHAT; else m_ExtraFlags &= ~PLAYER_EXTRA_GM_CHAT; }
bool isTaxiCheater() const { return m_ExtraFlags & PLAYER_EXTRA_TAXICHEAT; }
void SetTaxiCheater(bool on) { if(on) m_ExtraFlags |= PLAYER_EXTRA_TAXICHEAT; else m_ExtraFlags &= ~PLAYER_EXTRA_TAXICHEAT; }
bool isGMVisible() const { return !(m_ExtraFlags & PLAYER_EXTRA_GM_INVISIBLE); }
diff --git a/src/game/PointMovementGenerator.cpp b/src/game/PointMovementGenerator.cpp
index b03263c8bb6..b0e685fa412 100644
--- a/src/game/PointMovementGenerator.cpp
+++ b/src/game/PointMovementGenerator.cpp
@@ -41,7 +41,7 @@ bool PointMovementGenerator::Update(T &unit, const uint32 &diff)
if(!&unit)
return false;
- if(unit.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED))
+ if(unit.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED))
return true;
Traveller traveller(unit);
diff --git a/src/game/RandomMovementGenerator.cpp b/src/game/RandomMovementGenerator.cpp
index 15273843ffc..e27368c73f3 100644
--- a/src/game/RandomMovementGenerator.cpp
+++ b/src/game/RandomMovementGenerator.cpp
@@ -126,7 +126,7 @@ template<>
bool
RandomMovementGenerator::Update(Creature &creature, const uint32 &diff)
{
- if(creature.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNDED | UNIT_STAT_DISTRACTED))
+ if(creature.hasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED))
{
i_nextMoveTime.Update(i_nextMoveTime.GetExpiry()); // Expire the timer
creature.clearUnitState(UNIT_STAT_ROAMING);
diff --git a/src/game/SocialMgr.cpp b/src/game/SocialMgr.cpp
index 85afb48108a..858e6af6239 100644
--- a/src/game/SocialMgr.cpp
+++ b/src/game/SocialMgr.cpp
@@ -1,309 +1,311 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS
- *
- * 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 "SocialMgr.h"
-#include "Policies/SingletonImp.h"
-#include "Database/DatabaseEnv.h"
-#include "Opcodes.h"
-#include "WorldPacket.h"
-#include "WorldSession.h"
-#include "Player.h"
-#include "ObjectMgr.h"
-#include "World.h"
-#include "Util.h"
-
-INSTANTIATE_SINGLETON_1( SocialMgr );
-
-PlayerSocial::PlayerSocial()
-{
- m_playerGUID = 0;
-}
-
-PlayerSocial::~PlayerSocial()
-{
- m_playerSocialMap.clear();
-}
-
-bool PlayerSocial::AddToSocialList(uint32 friend_guid, bool ignore)
-{
- // prevent list (client-side) overflow
- if(m_playerSocialMap.size() >= (255-1))
- return false;
-
- uint32 flag = SOCIAL_FLAG_FRIEND;
- if(ignore)
- flag = SOCIAL_FLAG_IGNORED;
-
- PlayerSocialMap::iterator itr = m_playerSocialMap.find(friend_guid);
- if(itr != m_playerSocialMap.end())
- {
- CharacterDatabase.PExecute("UPDATE character_social SET flags = (flags | %u) WHERE guid = '%u' AND friend = '%u'", flag, GetPlayerGUID(), friend_guid);
- m_playerSocialMap[friend_guid].Flags |= flag;
- }
- else
- {
- CharacterDatabase.PExecute("INSERT INTO character_social (guid, friend, flags) VALUES ('%u', '%u', '%u')", GetPlayerGUID(), friend_guid, flag);
- FriendInfo fi;
- fi.Flags |= flag;
- m_playerSocialMap[friend_guid] = fi;
- }
- return true;
-}
-
-void PlayerSocial::RemoveFromSocialList(uint32 friend_guid, bool ignore)
-{
- PlayerSocialMap::iterator itr = m_playerSocialMap.find(friend_guid);
- if(itr == m_playerSocialMap.end()) // not exist
- return;
-
- uint32 flag = SOCIAL_FLAG_FRIEND;
- if(ignore)
- flag = SOCIAL_FLAG_IGNORED;
-
- itr->second.Flags &= ~flag;
- if(itr->second.Flags == 0)
- {
- CharacterDatabase.PExecute("DELETE FROM character_social WHERE guid = '%u' AND friend = '%u'", GetPlayerGUID(), friend_guid);
- m_playerSocialMap.erase(itr);
- }
- else
- {
- CharacterDatabase.PExecute("UPDATE character_social SET flags = (flags & ~%u) WHERE guid = '%u' AND friend = '%u'", flag, GetPlayerGUID(), friend_guid);
- }
-}
-
-void PlayerSocial::SetFriendNote(uint32 friend_guid, std::string note)
-{
- PlayerSocialMap::iterator itr = m_playerSocialMap.find(friend_guid);
- if(itr == m_playerSocialMap.end()) // not exist
- return;
-
- utf8truncate(note,48); // DB and client size limitation
-
- CharacterDatabase.escape_string(note);
- CharacterDatabase.PExecute("UPDATE character_social SET note = '%s' WHERE guid = '%u' AND friend = '%u'", note.c_str(), GetPlayerGUID(), friend_guid);
- m_playerSocialMap[friend_guid].Note = note;
-}
-
-void PlayerSocial::SendSocialList()
-{
- Player *plr = objmgr.GetPlayer(GetPlayerGUID());
- if(!plr)
- return;
-
- uint32 size = m_playerSocialMap.size();
-
- WorldPacket data(SMSG_CONTACT_LIST, (4+4+size*25)); // just can guess size
- data << uint32(7); // unk flag (0x1, 0x2, 0x4), 0x7 if it include ignore list
- data << uint32(size); // friends count
-
- for(PlayerSocialMap::iterator itr = m_playerSocialMap.begin(); itr != m_playerSocialMap.end(); ++itr)
- {
- sSocialMgr.GetFriendInfo(plr, itr->first, itr->second);
-
- data << uint64(itr->first); // player guid
- data << uint32(itr->second.Flags); // player flag (0x1-friend?, 0x2-ignored?, 0x4-muted?)
- data << itr->second.Note; // string note
- if(itr->second.Flags & SOCIAL_FLAG_FRIEND) // if IsFriend()
- {
- data << uint8(itr->second.Status); // online/offline/etc?
- if(itr->second.Status) // if online
- {
- data << uint32(itr->second.Area); // player area
- data << uint32(itr->second.Level); // player level
- data << uint32(itr->second.Class); // player class
- }
- }
- }
-
- plr->GetSession()->SendPacket(&data);
- sLog.outDebug("WORLD: Sent SMSG_CONTACT_LIST");
-}
-
-bool PlayerSocial::HasFriend(uint32 friend_guid)
-{
- PlayerSocialMap::iterator itr = m_playerSocialMap.find(friend_guid);
- if(itr != m_playerSocialMap.end())
- return itr->second.Flags & SOCIAL_FLAG_FRIEND;
- return false;
-}
-
-bool PlayerSocial::HasIgnore(uint32 ignore_guid)
-{
- PlayerSocialMap::iterator itr = m_playerSocialMap.find(ignore_guid);
- if(itr != m_playerSocialMap.end())
- return itr->second.Flags & SOCIAL_FLAG_IGNORED;
- return false;
-}
-
-SocialMgr::SocialMgr()
-{
-
-}
-
-SocialMgr::~SocialMgr()
-{
-
-}
-
-void SocialMgr::RemovePlayerSocial(uint32 guid)
-{
- SocialMap::iterator itr = m_socialMap.find(guid);
- if(itr != m_socialMap.end())
- m_socialMap.erase(itr);
-}
-
-void SocialMgr::GetFriendInfo(Player *player, uint32 friendGUID, FriendInfo &friendInfo)
-{
- if(!player)
- return;
-
- Player *pFriend = ObjectAccessor::FindPlayer(friendGUID);
-
- uint32 team = player->GetTeam();
- uint32 security = player->GetSession()->GetSecurity();
- bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
- bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST) || security > SEC_PLAYER;
-
- // PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
- // MODERATOR, GAME MASTER, ADMINISTRATOR can see all
- if( pFriend && pFriend->GetName() &&
- ( security > SEC_PLAYER ||
- ( pFriend->GetTeam() == team || allowTwoSideWhoList ) &&
- ( pFriend->GetSession()->GetSecurity() == SEC_PLAYER || gmInWhoList && pFriend->IsVisibleGloballyFor(player) )))
- {
- friendInfo.Status = FRIEND_STATUS_ONLINE;
- if(pFriend->isAFK())
- friendInfo.Status = FRIEND_STATUS_AFK;
- if(pFriend->isDND())
- friendInfo.Status = FRIEND_STATUS_DND;
- friendInfo.Area = pFriend->GetZoneId();
- friendInfo.Level = pFriend->getLevel();
- friendInfo.Class = pFriend->getClass();
- }
- else
- {
- friendInfo.Status = FRIEND_STATUS_OFFLINE;
- friendInfo.Area = 0;
- friendInfo.Level = 0;
- friendInfo.Class = 0;
- }
-}
-
-void SocialMgr::MakeFriendStatusPacket(FriendsResult result, uint32 guid, WorldPacket *data)
-{
- data->Initialize(SMSG_FRIEND_STATUS, 5);
- *data << uint8(result);
- *data << uint64(guid);
-}
-
-void SocialMgr::SendFriendStatus(Player *player, FriendsResult result, uint32 friend_guid, std::string name, bool broadcast)
-{
- FriendInfo fi;
-
- WorldPacket data;
- MakeFriendStatusPacket(result, friend_guid, &data);
- switch(result)
- {
- case FRIEND_ONLINE:
- GetFriendInfo(player, friend_guid, fi);
- data << uint8(fi.Status);
- data << uint32(fi.Area);
- data << uint32(fi.Level);
- data << uint32(fi.Class);
- break;
- case FRIEND_ADDED_ONLINE:
- GetFriendInfo(player, friend_guid, fi);
- data << name;
- data << uint8(fi.Status);
- data << uint32(fi.Area);
- data << uint32(fi.Level);
- data << uint32(fi.Class);
- break;
- case FRIEND_ADDED_OFFLINE:
- data << name;
- break;
- }
-
- if(broadcast)
- BroadcastToFriendListers(player, &data);
- else
- player->GetSession()->SendPacket(&data);
-}
-
-void SocialMgr::BroadcastToFriendListers(Player *player, WorldPacket *packet)
-{
- if(!player)
- return;
-
- uint32 team = player->GetTeam();
- uint32 security = player->GetSession()->GetSecurity();
- uint32 guid = player->GetGUIDLow();
- bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST);
- bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
-
- for(SocialMap::iterator itr = m_socialMap.begin(); itr != m_socialMap.end(); ++itr)
- {
- PlayerSocialMap::iterator itr2 = itr->second.m_playerSocialMap.find(guid);
- if(itr2 != itr->second.m_playerSocialMap.end() && (itr2->second.Flags & SOCIAL_FLAG_FRIEND))
- {
- Player *pFriend = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
-
- // PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
- // MODERATOR, GAME MASTER, ADMINISTRATOR can see all
- if( pFriend && pFriend->IsInWorld() &&
- ( pFriend->GetSession()->GetSecurity() > SEC_PLAYER ||
- ( pFriend->GetTeam() == team || allowTwoSideWhoList ) &&
- (security == SEC_PLAYER || gmInWhoList && player->IsVisibleGloballyFor(pFriend) )))
- {
- pFriend->GetSession()->SendPacket(packet);
- }
- }
- }
-}
-
-PlayerSocial *SocialMgr::LoadFromDB(QueryResult *result, uint32 guid)
-{
- PlayerSocial *social = &m_socialMap[guid];
- social->SetPlayerGUID(guid);
-
- if(!result)
- return social;
-
- uint32 friend_guid = 0;
- uint32 flags = 0;
- std::string note = "";
-
- do
- {
- Field *fields = result->Fetch();
-
- friend_guid = fields[0].GetUInt32();
- flags = fields[1].GetUInt32();
- note = fields[2].GetCppString();
-
- social->m_playerSocialMap[friend_guid] = FriendInfo(flags, note);
-
- // prevent list (client-side) overflow
- if(social->m_playerSocialMap.size() >= 255)
- break;
- }
- while( result->NextRow() );
- delete result;
- return social;
-}
+/*
+ * Copyright (C) 2005-2008 MaNGOS
+ *
+ * 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 "SocialMgr.h"
+#include "Policies/SingletonImp.h"
+#include "Database/DatabaseEnv.h"
+#include "Opcodes.h"
+#include "WorldPacket.h"
+#include "WorldSession.h"
+#include "Player.h"
+#include "ObjectMgr.h"
+#include "World.h"
+#include "Util.h"
+
+INSTANTIATE_SINGLETON_1( SocialMgr );
+
+PlayerSocial::PlayerSocial()
+{
+ m_playerGUID = 0;
+}
+
+PlayerSocial::~PlayerSocial()
+{
+ m_playerSocialMap.clear();
+}
+
+bool PlayerSocial::AddToSocialList(uint32 friend_guid, bool ignore)
+{
+ // client limit
+ if(m_playerSocialMap.size() >= 50)
+ return false;
+
+ uint32 flag = SOCIAL_FLAG_FRIEND;
+ if(ignore)
+ flag = SOCIAL_FLAG_IGNORED;
+
+ PlayerSocialMap::iterator itr = m_playerSocialMap.find(friend_guid);
+ if(itr != m_playerSocialMap.end())
+ {
+ CharacterDatabase.PExecute("UPDATE character_social SET flags = (flags | %u) WHERE guid = '%u' AND friend = '%u'", flag, GetPlayerGUID(), friend_guid);
+ m_playerSocialMap[friend_guid].Flags |= flag;
+ }
+ else
+ {
+ CharacterDatabase.PExecute("INSERT INTO character_social (guid, friend, flags) VALUES ('%u', '%u', '%u')", GetPlayerGUID(), friend_guid, flag);
+ FriendInfo fi;
+ fi.Flags |= flag;
+ m_playerSocialMap[friend_guid] = fi;
+ }
+ return true;
+}
+
+void PlayerSocial::RemoveFromSocialList(uint32 friend_guid, bool ignore)
+{
+ PlayerSocialMap::iterator itr = m_playerSocialMap.find(friend_guid);
+ if(itr == m_playerSocialMap.end()) // not exist
+ return;
+
+ uint32 flag = SOCIAL_FLAG_FRIEND;
+ if(ignore)
+ flag = SOCIAL_FLAG_IGNORED;
+
+ itr->second.Flags &= ~flag;
+ if(itr->second.Flags == 0)
+ {
+ CharacterDatabase.PExecute("DELETE FROM character_social WHERE guid = '%u' AND friend = '%u'", GetPlayerGUID(), friend_guid);
+ m_playerSocialMap.erase(itr);
+ }
+ else
+ {
+ CharacterDatabase.PExecute("UPDATE character_social SET flags = (flags & ~%u) WHERE guid = '%u' AND friend = '%u'", flag, GetPlayerGUID(), friend_guid);
+ }
+}
+
+void PlayerSocial::SetFriendNote(uint32 friend_guid, std::string note)
+{
+ PlayerSocialMap::iterator itr = m_playerSocialMap.find(friend_guid);
+ if(itr == m_playerSocialMap.end()) // not exist
+ return;
+
+ utf8truncate(note,48); // DB and client size limitation
+
+ CharacterDatabase.escape_string(note);
+ CharacterDatabase.PExecute("UPDATE character_social SET note = '%s' WHERE guid = '%u' AND friend = '%u'", note.c_str(), GetPlayerGUID(), friend_guid);
+ m_playerSocialMap[friend_guid].Note = note;
+}
+
+void PlayerSocial::SendSocialList()
+{
+ Player *plr = objmgr.GetPlayer(GetPlayerGUID());
+ if(!plr)
+ return;
+
+ uint32 size = m_playerSocialMap.size();
+
+ WorldPacket data(SMSG_CONTACT_LIST, (4+4+size*25)); // just can guess size
+ data << uint32(7); // unk flag (0x1, 0x2, 0x4), 0x7 if it include ignore list
+ data << uint32(size); // friends count
+
+ for(PlayerSocialMap::iterator itr = m_playerSocialMap.begin(); itr != m_playerSocialMap.end(); ++itr)
+ {
+ sSocialMgr.GetFriendInfo(plr, itr->first, itr->second);
+
+ data << uint64(itr->first); // player guid
+ data << uint32(itr->second.Flags); // player flag (0x1-friend?, 0x2-ignored?, 0x4-muted?)
+ data << itr->second.Note; // string note
+ if(itr->second.Flags & SOCIAL_FLAG_FRIEND) // if IsFriend()
+ {
+ data << uint8(itr->second.Status); // online/offline/etc?
+ if(itr->second.Status) // if online
+ {
+ data << uint32(itr->second.Area); // player area
+ data << uint32(itr->second.Level); // player level
+ data << uint32(itr->second.Class); // player class
+ }
+ }
+ }
+
+ plr->GetSession()->SendPacket(&data);
+ sLog.outDebug("WORLD: Sent SMSG_CONTACT_LIST");
+}
+
+bool PlayerSocial::HasFriend(uint32 friend_guid)
+{
+ PlayerSocialMap::iterator itr = m_playerSocialMap.find(friend_guid);
+ if(itr != m_playerSocialMap.end())
+ return itr->second.Flags & SOCIAL_FLAG_FRIEND;
+ return false;
+}
+
+bool PlayerSocial::HasIgnore(uint32 ignore_guid)
+{
+ PlayerSocialMap::iterator itr = m_playerSocialMap.find(ignore_guid);
+ if(itr != m_playerSocialMap.end())
+ return itr->second.Flags & SOCIAL_FLAG_IGNORED;
+ return false;
+}
+
+SocialMgr::SocialMgr()
+{
+
+}
+
+SocialMgr::~SocialMgr()
+{
+
+}
+
+void SocialMgr::RemovePlayerSocial(uint32 guid)
+{
+ SocialMap::iterator itr = m_socialMap.find(guid);
+ if(itr != m_socialMap.end())
+ m_socialMap.erase(itr);
+}
+
+void SocialMgr::GetFriendInfo(Player *player, uint32 friendGUID, FriendInfo &friendInfo)
+{
+ if(!player)
+ return;
+
+ Player *pFriend = ObjectAccessor::FindPlayer(friendGUID);
+
+ uint32 team = player->GetTeam();
+ uint32 security = player->GetSession()->GetSecurity();
+ bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
+ bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST) || security > SEC_PLAYER;
+
+ PlayerSocialMap::iterator itr = player->GetSocial()->m_playerSocialMap.find(friendGUID);
+ if(itr != player->GetSocial()->m_playerSocialMap.end())
+ friendInfo.Note = itr->second.Note;
+
+ // PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
+ // MODERATOR, GAME MASTER, ADMINISTRATOR can see all
+ if( pFriend && pFriend->GetName() &&
+ ( security > SEC_PLAYER ||
+ ( pFriend->GetTeam() == team || allowTwoSideWhoList ) &&
+ ( pFriend->GetSession()->GetSecurity() == SEC_PLAYER || gmInWhoList && pFriend->IsVisibleGloballyFor(player) )))
+ {
+ friendInfo.Status = FRIEND_STATUS_ONLINE;
+ if(pFriend->isAFK())
+ friendInfo.Status = FRIEND_STATUS_AFK;
+ if(pFriend->isDND())
+ friendInfo.Status = FRIEND_STATUS_DND;
+ friendInfo.Area = pFriend->GetZoneId();
+ friendInfo.Level = pFriend->getLevel();
+ friendInfo.Class = pFriend->getClass();
+ }
+ else
+ {
+ friendInfo.Status = FRIEND_STATUS_OFFLINE;
+ friendInfo.Area = 0;
+ friendInfo.Level = 0;
+ friendInfo.Class = 0;
+ }
+}
+
+void SocialMgr::MakeFriendStatusPacket(FriendsResult result, uint32 guid, WorldPacket *data)
+{
+ data->Initialize(SMSG_FRIEND_STATUS, 5);
+ *data << uint8(result);
+ *data << uint64(guid);
+}
+
+void SocialMgr::SendFriendStatus(Player *player, FriendsResult result, uint32 friend_guid, std::string name, bool broadcast)
+{
+ FriendInfo fi;
+
+ WorldPacket data;
+ MakeFriendStatusPacket(result, friend_guid, &data);
+ GetFriendInfo(player, friend_guid, fi);
+ switch(result)
+ {
+ case FRIEND_ADDED_OFFLINE:
+ case FRIEND_ADDED_ONLINE:
+ data << fi.Note;
+ break;
+ }
+
+ switch(result)
+ {
+ case FRIEND_ADDED_ONLINE:
+ case FRIEND_ONLINE:
+ data << uint8(fi.Status);
+ data << uint32(fi.Area);
+ data << uint32(fi.Level);
+ data << uint32(fi.Class);
+ break;
+ }
+
+ if(broadcast)
+ BroadcastToFriendListers(player, &data);
+ else
+ player->GetSession()->SendPacket(&data);
+}
+
+void SocialMgr::BroadcastToFriendListers(Player *player, WorldPacket *packet)
+{
+ if(!player)
+ return;
+
+ uint32 team = player->GetTeam();
+ uint32 security = player->GetSession()->GetSecurity();
+ uint32 guid = player->GetGUIDLow();
+ bool gmInWhoList = sWorld.getConfig(CONFIG_GM_IN_WHO_LIST);
+ bool allowTwoSideWhoList = sWorld.getConfig(CONFIG_ALLOW_TWO_SIDE_WHO_LIST);
+
+ for(SocialMap::iterator itr = m_socialMap.begin(); itr != m_socialMap.end(); ++itr)
+ {
+ PlayerSocialMap::iterator itr2 = itr->second.m_playerSocialMap.find(guid);
+ if(itr2 != itr->second.m_playerSocialMap.end() && (itr2->second.Flags & SOCIAL_FLAG_FRIEND))
+ {
+ Player *pFriend = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER));
+
+ // PLAYER see his team only and PLAYER can't see MODERATOR, GAME MASTER, ADMINISTRATOR characters
+ // MODERATOR, GAME MASTER, ADMINISTRATOR can see all
+ if( pFriend && pFriend->IsInWorld() &&
+ ( pFriend->GetSession()->GetSecurity() > SEC_PLAYER ||
+ ( pFriend->GetTeam() == team || allowTwoSideWhoList ) &&
+ (security == SEC_PLAYER || gmInWhoList && player->IsVisibleGloballyFor(pFriend) )))
+ {
+ pFriend->GetSession()->SendPacket(packet);
+ }
+ }
+ }
+}
+
+PlayerSocial *SocialMgr::LoadFromDB(QueryResult *result, uint32 guid)
+{
+ PlayerSocial *social = &m_socialMap[guid];
+ social->SetPlayerGUID(guid);
+
+ if(!result)
+ return social;
+
+ uint32 friend_guid = 0;
+ uint32 flags = 0;
+ std::string note = "";
+
+ do
+ {
+ Field *fields = result->Fetch();
+
+ friend_guid = fields[0].GetUInt32();
+ flags = fields[1].GetUInt32();
+ note = fields[2].GetCppString();
+
+ social->m_playerSocialMap[friend_guid] = FriendInfo(flags, note);
+
+ // client limit
+ if(social->m_playerSocialMap.size() >= 50)
+ break;
+ }
+ while( result->NextRow() );
+ delete result;
+ return social;
+}
diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp
index 3be0b6989b2..ba5b5d97b47 100644
--- a/src/game/Spell.cpp
+++ b/src/game/Spell.cpp
@@ -986,7 +986,7 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
if( !(m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_NO_INITIAL_AGGRO) )
{
- if(!unit->IsStandState() && !unit->hasUnitState(UNIT_STAT_STUNDED))
+ if(!unit->IsStandState() && !unit->hasUnitState(UNIT_STAT_STUNNED))
unit->SetStandState(PLAYER_STATE_NONE);
if(!unit->isInCombat() && unit->GetTypeId() != TYPEID_PLAYER && ((Creature*)unit)->AI())
@@ -2407,7 +2407,7 @@ void Spell::update(uint32 difftime)
cancel();
// check for incapacitating player states
- if( m_caster->hasUnitState(UNIT_STAT_STUNDED | UNIT_STAT_CONFUSED))
+ if( m_caster->hasUnitState(UNIT_STAT_STUNNED | UNIT_STAT_CONFUSED))
cancel();
// check if player has turned if flag is set
diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp
index e5abe4d842f..d8623a6ebe2 100644
--- a/src/game/SpellAuras.cpp
+++ b/src/game/SpellAuras.cpp
@@ -1,6360 +1,6360 @@
-/*
- * Copyright (C) 2005-2008 MaNGOS
- *
- * 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 "Opcodes.h"
-#include "Log.h"
-#include "UpdateMask.h"
-#include "World.h"
-#include "ObjectMgr.h"
-#include "SpellMgr.h"
-#include "Player.h"
-#include "Unit.h"
-#include "Spell.h"
-#include "SpellAuras.h"
-#include "DynamicObject.h"
-#include "Group.h"
-#include "UpdateData.h"
-#include "MapManager.h"
-#include "ObjectAccessor.h"
-#include "Policies/SingletonImp.h"
-#include "Totem.h"
-#include "Creature.h"
-#include "Formulas.h"
-#include "BattleGround.h"
-#include "CreatureAI.h"
-#include "Util.h"
-#include "GridNotifiers.h"
-#include "GridNotifiersImpl.h"
-#include "CellImpl.h"
-
-#define NULL_AURA_SLOT 0xFF
-
-pAuraHandler AuraHandler[TOTAL_AURAS]=
-{
- &Aura::HandleNULL, // 0 SPELL_AURA_NONE
- &Aura::HandleBindSight, // 1 SPELL_AURA_BIND_SIGHT
- &Aura::HandleModPossess, // 2 SPELL_AURA_MOD_POSSESS
- &Aura::HandlePeriodicDamage, // 3 SPELL_AURA_PERIODIC_DAMAGE
- &Aura::HandleAuraDummy, // 4 SPELL_AURA_DUMMY
- &Aura::HandleModConfuse, // 5 SPELL_AURA_MOD_CONFUSE
- &Aura::HandleModCharm, // 6 SPELL_AURA_MOD_CHARM
- &Aura::HandleModFear, // 7 SPELL_AURA_MOD_FEAR
- &Aura::HandlePeriodicHeal, // 8 SPELL_AURA_PERIODIC_HEAL
- &Aura::HandleModAttackSpeed, // 9 SPELL_AURA_MOD_ATTACKSPEED
- &Aura::HandleModThreat, // 10 SPELL_AURA_MOD_THREAT
- &Aura::HandleModTaunt, // 11 SPELL_AURA_MOD_TAUNT
- &Aura::HandleAuraModStun, // 12 SPELL_AURA_MOD_STUN
- &Aura::HandleModDamageDone, // 13 SPELL_AURA_MOD_DAMAGE_DONE
- &Aura::HandleNoImmediateEffect, // 14 SPELL_AURA_MOD_DAMAGE_TAKEN implemented in Unit::MeleeDamageBonus and Unit::SpellDamageBonus
- &Aura::HandleNoImmediateEffect, // 15 SPELL_AURA_DAMAGE_SHIELD implemented in Unit::DoAttackDamage
- &Aura::HandleModStealth, // 16 SPELL_AURA_MOD_STEALTH
- &Aura::HandleNoImmediateEffect, // 17 SPELL_AURA_MOD_STEALTH_DETECT
- &Aura::HandleInvisibility, // 18 SPELL_AURA_MOD_INVISIBILITY
- &Aura::HandleInvisibilityDetect, // 19 SPELL_AURA_MOD_INVISIBILITY_DETECTION
- &Aura::HandleAuraModTotalHealthPercentRegen, // 20 SPELL_AURA_OBS_MOD_HEALTH
- &Aura::HandleAuraModTotalManaPercentRegen, // 21 SPELL_AURA_OBS_MOD_MANA
- &Aura::HandleAuraModResistance, // 22 SPELL_AURA_MOD_RESISTANCE
- &Aura::HandlePeriodicTriggerSpell, // 23 SPELL_AURA_PERIODIC_TRIGGER_SPELL
- &Aura::HandlePeriodicEnergize, // 24 SPELL_AURA_PERIODIC_ENERGIZE
- &Aura::HandleAuraModPacify, // 25 SPELL_AURA_MOD_PACIFY
- &Aura::HandleAuraModRoot, // 26 SPELL_AURA_MOD_ROOT
- &Aura::HandleAuraModSilence, // 27 SPELL_AURA_MOD_SILENCE
- &Aura::HandleNoImmediateEffect, // 28 SPELL_AURA_REFLECT_SPELLS implement in Unit::SpellHitResult
- &Aura::HandleAuraModStat, // 29 SPELL_AURA_MOD_STAT
- &Aura::HandleAuraModSkill, // 30 SPELL_AURA_MOD_SKILL
- &Aura::HandleAuraModIncreaseSpeed, // 31 SPELL_AURA_MOD_INCREASE_SPEED
- &Aura::HandleAuraModIncreaseMountedSpeed, // 32 SPELL_AURA_MOD_INCREASE_MOUNTED_SPEED
- &Aura::HandleAuraModDecreaseSpeed, // 33 SPELL_AURA_MOD_DECREASE_SPEED
- &Aura::HandleAuraModIncreaseHealth, // 34 SPELL_AURA_MOD_INCREASE_HEALTH
- &Aura::HandleAuraModIncreaseEnergy, // 35 SPELL_AURA_MOD_INCREASE_ENERGY
- &Aura::HandleAuraModShapeshift, // 36 SPELL_AURA_MOD_SHAPESHIFT
- &Aura::HandleAuraModEffectImmunity, // 37 SPELL_AURA_EFFECT_IMMUNITY
- &Aura::HandleAuraModStateImmunity, // 38 SPELL_AURA_STATE_IMMUNITY
- &Aura::HandleAuraModSchoolImmunity, // 39 SPELL_AURA_SCHOOL_IMMUNITY
- &Aura::HandleAuraModDmgImmunity, // 40 SPELL_AURA_DAMAGE_IMMUNITY
- &Aura::HandleAuraModDispelImmunity, // 41 SPELL_AURA_DISPEL_IMMUNITY
- &Aura::HandleAuraProcTriggerSpell, // 42 SPELL_AURA_PROC_TRIGGER_SPELL implemented in Unit::ProcDamageAndSpellFor and Unit::HandleProcTriggerSpell
- &Aura::HandleNoImmediateEffect, // 43 SPELL_AURA_PROC_TRIGGER_DAMAGE implemented in Unit::ProcDamageAndSpellFor
- &Aura::HandleAuraTrackCreatures, // 44 SPELL_AURA_TRACK_CREATURES
- &Aura::HandleAuraTrackResources, // 45 SPELL_AURA_TRACK_RESOURCES
- &Aura::HandleUnused, // 46 SPELL_AURA_MOD_PARRY_SKILL obsolete?
- &Aura::HandleAuraModParryPercent, // 47 SPELL_AURA_MOD_PARRY_PERCENT
- &Aura::HandleUnused, // 48 SPELL_AURA_MOD_DODGE_SKILL obsolete?
- &Aura::HandleAuraModDodgePercent, // 49 SPELL_AURA_MOD_DODGE_PERCENT
- &Aura::HandleUnused, // 50 SPELL_AURA_MOD_BLOCK_SKILL obsolete?
- &Aura::HandleAuraModBlockPercent, // 51 SPELL_AURA_MOD_BLOCK_PERCENT
- &Aura::HandleAuraModCritPercent, // 52 SPELL_AURA_MOD_CRIT_PERCENT
- &Aura::HandlePeriodicLeech, // 53 SPELL_AURA_PERIODIC_LEECH
- &Aura::HandleModHitChance, // 54 SPELL_AURA_MOD_HIT_CHANCE
- &Aura::HandleModSpellHitChance, // 55 SPELL_AURA_MOD_SPELL_HIT_CHANCE
- &Aura::HandleAuraTransform, // 56 SPELL_AURA_TRANSFORM
- &Aura::HandleModSpellCritChance, // 57 SPELL_AURA_MOD_SPELL_CRIT_CHANCE
- &Aura::HandleAuraModIncreaseSwimSpeed, // 58 SPELL_AURA_MOD_INCREASE_SWIM_SPEED
- &Aura::HandleNoImmediateEffect, // 59 SPELL_AURA_MOD_DAMAGE_DONE_CREATURE implemented in Unit::MeleeDamageBonus and Unit::SpellDamageBonus
- &Aura::HandleAuraModPacifyAndSilence, // 60 SPELL_AURA_MOD_PACIFY_SILENCE
- &Aura::HandleAuraModScale, // 61 SPELL_AURA_MOD_SCALE
- &Aura::HandleNULL, // 62 SPELL_AURA_PERIODIC_HEALTH_FUNNEL
- &Aura::HandleUnused, // 63 SPELL_AURA_PERIODIC_MANA_FUNNEL obsolete?
- &Aura::HandlePeriodicManaLeech, // 64 SPELL_AURA_PERIODIC_MANA_LEECH
- &Aura::HandleModCastingSpeed, // 65 SPELL_AURA_MOD_CASTING_SPEED
- &Aura::HandleFeignDeath, // 66 SPELL_AURA_FEIGN_DEATH
- &Aura::HandleAuraModDisarm, // 67 SPELL_AURA_MOD_DISARM
- &Aura::HandleAuraModStalked, // 68 SPELL_AURA_MOD_STALKED
- &Aura::HandleSchoolAbsorb, // 69 SPELL_AURA_SCHOOL_ABSORB implemented in Unit::CalcAbsorbResist
- &Aura::HandleUnused, // 70 SPELL_AURA_EXTRA_ATTACKS Useless, used by only one spell that has only visual effect
- &Aura::HandleModSpellCritChanceShool, // 71 SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL
- &Aura::HandleModPowerCostPCT, // 72 SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT
- &Aura::HandleModPowerCost, // 73 SPELL_AURA_MOD_POWER_COST_SCHOOL
- &Aura::HandleNoImmediateEffect, // 74 SPELL_AURA_REFLECT_SPELLS_SCHOOL implemented in Unit::SpellHitResult
- &Aura::HandleNoImmediateEffect, // 75 SPELL_AURA_MOD_LANGUAGE
- &Aura::HandleFarSight, // 76 SPELL_AURA_FAR_SIGHT
- &Aura::HandleModMechanicImmunity, // 77 SPELL_AURA_MECHANIC_IMMUNITY
- &Aura::HandleAuraMounted, // 78 SPELL_AURA_MOUNTED
- &Aura::HandleModDamagePercentDone, // 79 SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
- &Aura::HandleModPercentStat, // 80 SPELL_AURA_MOD_PERCENT_STAT
- &Aura::HandleNoImmediateEffect, // 81 SPELL_AURA_SPLIT_DAMAGE_PCT
- &Aura::HandleWaterBreathing, // 82 SPELL_AURA_WATER_BREATHING
- &Aura::HandleModBaseResistance, // 83 SPELL_AURA_MOD_BASE_RESISTANCE
- &Aura::HandleModRegen, // 84 SPELL_AURA_MOD_REGEN
- &Aura::HandleModPowerRegen, // 85 SPELL_AURA_MOD_POWER_REGEN
- &Aura::HandleChannelDeathItem, // 86 SPELL_AURA_CHANNEL_DEATH_ITEM
- &Aura::HandleNoImmediateEffect, // 87 SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN implemented in Unit::MeleeDamageBonus and Unit::SpellDamageBonus
- &Aura::HandleNoImmediateEffect, // 88 SPELL_AURA_MOD_HEALTH_REGEN_PERCENT
- &Aura::HandlePeriodicDamagePCT, // 89 SPELL_AURA_PERIODIC_DAMAGE_PERCENT
- &Aura::HandleUnused, // 90 SPELL_AURA_MOD_RESIST_CHANCE Useless
- &Aura::HandleNoImmediateEffect, // 91 SPELL_AURA_MOD_DETECT_RANGE implemented in Creature::GetAttackDistance
- &Aura::HandlePreventFleeing, // 92 SPELL_AURA_PREVENTS_FLEEING
- &Aura::HandleModUnattackable, // 93 SPELL_AURA_MOD_UNATTACKABLE
- &Aura::HandleNoImmediateEffect, // 94 SPELL_AURA_INTERRUPT_REGEN implemented in Player::RegenerateAll
- &Aura::HandleAuraGhost, // 95 SPELL_AURA_GHOST
- &Aura::HandleNoImmediateEffect, // 96 SPELL_AURA_SPELL_MAGNET implemented in Spell::SelectMagnetTarget
- &Aura::HandleManaShield, // 97 SPELL_AURA_MANA_SHIELD implemented in Unit::CalcAbsorbResist
- &Aura::HandleAuraModSkill, // 98 SPELL_AURA_MOD_SKILL_TALENT
- &Aura::HandleAuraModAttackPower, // 99 SPELL_AURA_MOD_ATTACK_POWER
- &Aura::HandleUnused, //100 SPELL_AURA_AURAS_VISIBLE obsolete? all player can see all auras now
- &Aura::HandleModResistancePercent, //101 SPELL_AURA_MOD_RESISTANCE_PCT
- &Aura::HandleNoImmediateEffect, //102 SPELL_AURA_MOD_MELEE_ATTACK_POWER_VERSUS implemented in Unit::MeleeDamageBonus
- &Aura::HandleAuraModTotalThreat, //103 SPELL_AURA_MOD_TOTAL_THREAT
- &Aura::HandleAuraWaterWalk, //104 SPELL_AURA_WATER_WALK
- &Aura::HandleAuraFeatherFall, //105 SPELL_AURA_FEATHER_FALL
- &Aura::HandleAuraHover, //106 SPELL_AURA_HOVER
- &Aura::HandleAddModifier, //107 SPELL_AURA_ADD_FLAT_MODIFIER
- &Aura::HandleAddModifier, //108 SPELL_AURA_ADD_PCT_MODIFIER
- &Aura::HandleNoImmediateEffect, //109 SPELL_AURA_ADD_TARGET_TRIGGER
- &Aura::HandleModPowerRegenPCT, //110 SPELL_AURA_MOD_POWER_REGEN_PERCENT
- &Aura::HandleNULL, //111 SPELL_AURA_ADD_CASTER_HIT_TRIGGER
- &Aura::HandleNoImmediateEffect, //112 SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
- &Aura::HandleNoImmediateEffect, //113 SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN implemented in Unit::MeleeDamageBonus
- &Aura::HandleNoImmediateEffect, //114 SPELL_AURA_MOD_RANGED_DAMAGE_TAKEN_PCT implemented in Unit::MeleeDamageBonus
- &Aura::HandleAuraHealing, //115 SPELL_AURA_MOD_HEALING
- &Aura::HandleNoImmediateEffect, //116 SPELL_AURA_MOD_REGEN_DURING_COMBAT
- &Aura::HandleNoImmediateEffect, //117 SPELL_AURA_MOD_MECHANIC_RESISTANCE implemented in Unit::MagicSpellHitResult
- &Aura::HandleAuraHealingPct, //118 SPELL_AURA_MOD_HEALING_PCT
- &Aura::HandleUnused, //119 SPELL_AURA_SHARE_PET_TRACKING useless
- &Aura::HandleAuraUntrackable, //120 SPELL_AURA_UNTRACKABLE
- &Aura::HandleAuraEmpathy, //121 SPELL_AURA_EMPATHY
- &Aura::HandleModOffhandDamagePercent, //122 SPELL_AURA_MOD_OFFHAND_DAMAGE_PCT
- &Aura::HandleModTargetResistance, //123 SPELL_AURA_MOD_TARGET_RESISTANCE
- &Aura::HandleAuraModRangedAttackPower, //124 SPELL_AURA_MOD_RANGED_ATTACK_POWER
- &Aura::HandleNoImmediateEffect, //125 SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN implemented in Unit::MeleeDamageBonus
- &Aura::HandleNoImmediateEffect, //126 SPELL_AURA_MOD_MELEE_DAMAGE_TAKEN_PCT implemented in Unit::MeleeDamageBonus
- &Aura::HandleNoImmediateEffect, //127 SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS implemented in Unit::MeleeDamageBonus
- &Aura::HandleModPossessPet, //128 SPELL_AURA_MOD_POSSESS_PET
- &Aura::HandleAuraModIncreaseSpeed, //129 SPELL_AURA_MOD_SPEED_ALWAYS
- &Aura::HandleAuraModIncreaseMountedSpeed, //130 SPELL_AURA_MOD_MOUNTED_SPEED_ALWAYS
- &Aura::HandleNoImmediateEffect, //131 SPELL_AURA_MOD_RANGED_ATTACK_POWER_VERSUS implemented in Unit::MeleeDamageBonus
- &Aura::HandleAuraModIncreaseEnergyPercent, //132 SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT
- &Aura::HandleAuraModIncreaseHealthPercent, //133 SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT
- &Aura::HandleAuraModRegenInterrupt, //134 SPELL_AURA_MOD_MANA_REGEN_INTERRUPT
- &Aura::HandleModHealingDone, //135 SPELL_AURA_MOD_HEALING_DONE
- &Aura::HandleAuraHealingPct, //136 SPELL_AURA_MOD_HEALING_DONE_PERCENT implemented in Unit::SpellHealingBonus
- &Aura::HandleModTotalPercentStat, //137 SPELL_AURA_MOD_TOTAL_STAT_PERCENTAGE
- &Aura::HandleHaste, //138 SPELL_AURA_MOD_HASTE
- &Aura::HandleForceReaction, //139 SPELL_AURA_FORCE_REACTION
- &Aura::HandleAuraModRangedHaste, //140 SPELL_AURA_MOD_RANGED_HASTE
- &Aura::HandleRangedAmmoHaste, //141 SPELL_AURA_MOD_RANGED_AMMO_HASTE
- &Aura::HandleAuraModBaseResistancePCT, //142 SPELL_AURA_MOD_BASE_RESISTANCE_PCT
- &Aura::HandleAuraModResistanceExclusive, //143 SPELL_AURA_MOD_RESISTANCE_EXCLUSIVE
- &Aura::HandleNoImmediateEffect, //144 SPELL_AURA_SAFE_FALL implemented in WorldSession::HandleMovementOpcodes
- &Aura::HandleUnused, //145 SPELL_AURA_CHARISMA obsolete?
- &Aura::HandleUnused, //146 SPELL_AURA_PERSUADED obsolete?
- &Aura::HandleNULL, //147 SPELL_AURA_ADD_CREATURE_IMMUNITY
- &Aura::HandleAuraRetainComboPoints, //148 SPELL_AURA_RETAIN_COMBO_POINTS
- &Aura::HandleNoImmediateEffect, //149 SPELL_AURA_RESIST_PUSHBACK
- &Aura::HandleShieldBlockValue, //150 SPELL_AURA_MOD_SHIELD_BLOCKVALUE_PCT
- &Aura::HandleAuraTrackStealthed, //151 SPELL_AURA_TRACK_STEALTHED
- &Aura::HandleNoImmediateEffect, //152 SPELL_AURA_MOD_DETECTED_RANGE implemented in Creature::GetAttackDistance
- &Aura::HandleNoImmediateEffect, //153 SPELL_AURA_SPLIT_DAMAGE_FLAT
- &Aura::HandleNoImmediateEffect, //154 SPELL_AURA_MOD_STEALTH_LEVEL
- &Aura::HandleNoImmediateEffect, //155 SPELL_AURA_MOD_WATER_BREATHING
- &Aura::HandleNoImmediateEffect, //156 SPELL_AURA_MOD_REPUTATION_GAIN
- &Aura::HandleNULL, //157 SPELL_AURA_PET_DAMAGE_MULTI
- &Aura::HandleShieldBlockValue, //158 SPELL_AURA_MOD_SHIELD_BLOCKVALUE
- &Aura::HandleNoImmediateEffect, //159 SPELL_AURA_NO_PVP_CREDIT only for Honorless Target spell
- &Aura::HandleNoImmediateEffect, //160 SPELL_AURA_MOD_AOE_AVOIDANCE implemended in Unit::MagicSpellHitResult
- &Aura::HandleNoImmediateEffect, //161 SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT
- &Aura::HandleAuraPowerBurn, //162 SPELL_AURA_POWER_BURN_MANA
- &Aura::HandleNoImmediateEffect, //163 SPELL_AURA_MOD_CRIT_DAMAGE_BONUS_MELEE
- &Aura::HandleUnused, //164 useless, only one test spell
- &Aura::HandleAuraAttackPowerAttacker, //165 SPELL_AURA_MELEE_ATTACK_POWER_ATTACKER_BONUS implemented in Unit::MeleeDamageBonus
- &Aura::HandleAuraModAttackPowerPercent, //166 SPELL_AURA_MOD_ATTACK_POWER_PCT
- &Aura::HandleAuraModRangedAttackPowerPercent, //167 SPELL_AURA_MOD_RANGED_ATTACK_POWER_PCT
- &Aura::HandleNoImmediateEffect, //168 SPELL_AURA_MOD_DAMAGE_DONE_VERSUS implemented in Unit::SpellDamageBonus, Unit::MeleeDamageBonus
- &Aura::HandleNoImmediateEffect, //169 SPELL_AURA_MOD_CRIT_PERCENT_VERSUS implemented in Unit::DealDamageBySchool, Unit::DoAttackDamage, Unit::SpellCriticalBonus
- &Aura::HandleNULL, //170 SPELL_AURA_DETECT_AMORE only for Detect Amore spell
- &Aura::HandleAuraModIncreaseSpeed, //171 SPELL_AURA_MOD_SPEED_NOT_STACK
- &Aura::HandleAuraModIncreaseMountedSpeed, //172 SPELL_AURA_MOD_MOUNTED_SPEED_NOT_STACK
- &Aura::HandleUnused, //173 SPELL_AURA_ALLOW_CHAMPION_SPELLS only for Proclaim Champion spell
- &Aura::HandleModSpellDamagePercentFromStat, //174 SPELL_AURA_MOD_SPELL_DAMAGE_OF_STAT_PERCENT implemented in Unit::SpellBaseDamageBonus (by defeult intelect, dependent from SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT)
- &Aura::HandleModSpellHealingPercentFromStat, //175 SPELL_AURA_MOD_SPELL_HEALING_OF_STAT_PERCENT implemented in Unit::SpellBaseHealingBonus
- &Aura::HandleSpiritOfRedemption, //176 SPELL_AURA_SPIRIT_OF_REDEMPTION only for Spirit of Redemption spell, die at aura end
- &Aura::HandleNULL, //177 SPELL_AURA_AOE_CHARM
- &Aura::HandleNoImmediateEffect, //178 SPELL_AURA_MOD_DEBUFF_RESISTANCE implemented in Unit::MagicSpellHitResult
- &Aura::HandleNoImmediateEffect, //179 SPELL_AURA_MOD_ATTACKER_SPELL_CRIT_CHANCE implemented in Unit::SpellCriticalBonus
- &Aura::HandleNoImmediateEffect, //180 SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS implemented in Unit::SpellDamageBonus
- &Aura::HandleUnused, //181 SPELL_AURA_MOD_FLAT_SPELL_CRIT_DAMAGE_VERSUS unused
- &Aura::HandleAuraModResistenceOfStatPercent, //182 SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT
- &Aura::HandleNULL, //183 SPELL_AURA_MOD_CRITICAL_THREAT
- &Aura::HandleNoImmediateEffect, //184 SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
- &Aura::HandleNoImmediateEffect, //185 SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
- &Aura::HandleNoImmediateEffect, //186 SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE implemented in Unit::MagicSpellHitResult
- &Aura::HandleNoImmediateEffect, //187 SPELL_AURA_MOD_ATTACKER_MELEE_CRIT_CHANCE implemended in Unit::GetUnitCriticalChance
- &Aura::HandleNoImmediateEffect, //188 SPELL_AURA_MOD_ATTACKER_RANGED_CRIT_CHANCE implemented in Unit::GetUnitCriticalChance
- &Aura::HandleModRating, //189 SPELL_AURA_MOD_RATING
- &Aura::HandleNULL, //190 SPELL_AURA_MOD_FACTION_REPUTATION_GAIN
- &Aura::HandleAuraModUseNormalSpeed, //191 SPELL_AURA_USE_NORMAL_MOVEMENT_SPEED
- &Aura::HandleModMeleeRangedSpeedPct, //192 SPELL_AURA_HASTE_MELEE
- &Aura::HandleModCombatSpeedPct, //193 SPELL_AURA_MELEE_SLOW (in fact combat (any type attack) speed pct)
- &Aura::HandleUnused, //194 SPELL_AURA_MOD_DEPRICATED_1 not used now (old SPELL_AURA_MOD_SPELL_DAMAGE_OF_INTELLECT)
- &Aura::HandleUnused, //195 SPELL_AURA_MOD_DEPRICATED_2 not used now (old SPELL_AURA_MOD_SPELL_HEALING_OF_INTELLECT)
- &Aura::HandleNULL, //196 SPELL_AURA_MOD_COOLDOWN
- &Aura::HandleNoImmediateEffect, //197 SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE implemented in Unit::SpellCriticalBonus Unit::GetUnitCriticalChance
- &Aura::HandleUnused, //198 SPELL_AURA_MOD_ALL_WEAPON_SKILLS
- &Aura::HandleNoImmediateEffect, //199 SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT implemented in Unit::MagicSpellHitResult
- &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::HandleNULL, //205 vulnerable to school dmg?
- &Aura::HandleNULL, //206 SPELL_AURA_MOD_SPEED_MOUNTED
- &Aura::HandleAuraModIncreaseFlightSpeed, //207 SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED
- &Aura::HandleAuraModIncreaseFlightSpeed, //208 SPELL_AURA_MOD_SPEED_FLIGHT, used only in spell: Flight Form (Passive)
- &Aura::HandleAuraModIncreaseFlightSpeed, //209 SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS
- &Aura::HandleNULL, //210 Commentator's Command
- &Aura::HandleAuraModIncreaseFlightSpeed, //211 SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK
- &Aura::HandleAuraModRangedAttackPowerOfStatPercent, //212 SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT
- &Aura::HandleNoImmediateEffect, //213 SPELL_AURA_MOD_RAGE_FROM_DAMAGE_DEALT implemented in Player::RewardRage
- &Aura::HandleNULL, //214 Tamed Pet Passive
- &Aura::HandleArenaPreparation, //215 SPELL_AURA_ARENA_PREPARATION
- &Aura::HandleModCastingSpeed, //216 SPELL_AURA_HASTE_SPELLS
- &Aura::HandleUnused, //217 unused
- &Aura::HandleAuraModRangedHaste, //218 SPELL_AURA_HASTE_RANGED
- &Aura::HandleModManaRegen, //219 SPELL_AURA_MOD_MANA_REGEN_FROM_STAT
- &Aura::HandleNULL, //220 SPELL_AURA_MOD_RATING_FROM_STAT
- &Aura::HandleNULL, //221 ignored
- &Aura::HandleUnused, //222 unused
- &Aura::HandleNULL, //223 Cold Stare
- &Aura::HandleUnused, //224 unused
- &Aura::HandleNoImmediateEffect, //225 SPELL_AURA_PRAYER_OF_MENDING
- &Aura::HandleAuraPeriodicDummy, //226 SPELL_AURA_PERIODIC_DUMMY
- &Aura::HandleNULL, //227 periodic trigger spell
- &Aura::HandleNoImmediateEffect, //228 stealth detection
- &Aura::HandleNULL, //229 SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE
- &Aura::HandleAuraModIncreaseMaxHealth, //230 Commanding Shout
- &Aura::HandleNULL, //231
- &Aura::HandleNoImmediateEffect, //232 SPELL_AURA_MECHANIC_DURATION_MOD implement in Unit::CalculateSpellDuration
- &Aura::HandleNULL, //233 set model id to the one of the creature with id m_modifier.m_miscvalue
- &Aura::HandleNoImmediateEffect, //234 SPELL_AURA_MECHANIC_DURATION_MOD_NOT_STACK implement in Unit::CalculateSpellDuration
- &Aura::HandleAuraModDispelResist, //235 SPELL_AURA_MOD_DISPEL_RESIST implement in Unit::MagicSpellHitResult
- &Aura::HandleUnused, //236 unused
- &Aura::HandleModSpellDamagePercentFromAttackPower, //237 SPELL_AURA_MOD_SPELL_DAMAGE_OF_ATTACK_POWER implemented in Unit::SpellBaseDamageBonus
- &Aura::HandleModSpellHealingPercentFromAttackPower, //238 SPELL_AURA_MOD_SPELL_HEALING_OF_ATTACK_POWER implemented in Unit::SpellBaseHealingBonus
- &Aura::HandleAuraModScale, //239 SPELL_AURA_MOD_SCALE_2 only in Noggenfogger Elixir (16595) before 2.3.0 aura 61
- &Aura::HandleAuraModExpertise, //240 SPELL_AURA_MOD_EXPERTISE
- &Aura::HandleForceMoveForward, //241 Forces the player to move forward
- &Aura::HandleUnused, //242 SPELL_AURA_MOD_SPELL_DAMAGE_FROM_HEALING
- &Aura::HandleUnused, //243 used by two test spells
- &Aura::HandleComprehendLanguage, //244 Comprehend language
- &Aura::HandleUnused, //245 SPELL_AURA_MOD_DURATION_OF_MAGIC_EFFECTS
- &Aura::HandleUnused, //246 unused
- &Aura::HandleUnused, //247 unused
- &Aura::HandleNoImmediateEffect, //248 SPELL_AURA_MOD_COMBAT_RESULT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
- &Aura::HandleNULL, //249
- &Aura::HandleAuraModIncreaseHealth, //250 SPELL_AURA_MOD_INCREASE_HEALTH_2
- &Aura::HandleNULL, //251 SPELL_AURA_MOD_ENEMY_DODGE
- &Aura::HandleUnused, //252 unused
- &Aura::HandleUnused, //253 unused
- &Aura::HandleUnused, //254 unused
- &Aura::HandleUnused, //255 unused
- &Aura::HandleUnused, //256 unused
- &Aura::HandleUnused, //257 unused
- &Aura::HandleUnused, //258 unused
- &Aura::HandleUnused, //259 unused
- &Aura::HandleUnused, //260 unused
- &Aura::HandleNULL //261 SPELL_AURA_261 some phased state (44856 spell)
-};
-
-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_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),
-m_periodicTimer(0), m_PeriodicEventId(0), m_AuraDRGroup(DIMINISHING_NONE)
-{
- assert(target);
-
- assert(spellproto && spellproto == sSpellStore.LookupEntry( spellproto->Id ) && "`info` must be pointer to sSpellStore element");
-
- m_spellProto = spellproto;
-
- m_currentBasePoints = currentBasePoints ? *currentBasePoints : m_spellProto->EffectBasePoints[eff];
-
- m_isPassive = IsPassiveSpell(GetId());
- m_positive = IsPositiveEffect(GetId(), m_effIndex);
-
- m_applyTime = time(NULL);
-
- int32 damage;
- if(!caster)
- {
- m_caster_guid = target->GetGUID();
- damage = m_currentBasePoints+1; // stored value-1
- m_maxduration = target->CalculateSpellDuration(m_spellProto, m_effIndex, target);
- }
- else
- {
- m_caster_guid = caster->GetGUID();
-
- damage = caster->CalculateSpellDamage(m_spellProto,m_effIndex,m_currentBasePoints,target);
- m_maxduration = caster->CalculateSpellDuration(m_spellProto, m_effIndex, target);
-
- if (!damage && castItem && castItem->GetItemSuffixFactor())
- {
- ItemRandomSuffixEntry const *item_rand_suffix = sItemRandomSuffixStore.LookupEntry(abs(castItem->GetItemRandomPropertyId()));
- if(item_rand_suffix)
- {
- for (int k=0; k<3; k++)
- {
- SpellItemEnchantmentEntry const *pEnchant = sSpellItemEnchantmentStore.LookupEntry(item_rand_suffix->enchant_id[k]);
- if(pEnchant)
- {
- for (int t=0; t<3; t++)
- if(pEnchant->spellid[t] == m_spellProto->Id)
- {
- damage = uint32((item_rand_suffix->prefix[k]*castItem->GetItemSuffixFactor()) / 10000 );
- break;
- }
- }
-
- if(damage)
- break;
- }
- }
- }
- }
-
- if(m_maxduration == -1 || m_isPassive && m_spellProto->DurationIndex == 0)
- m_permanent = true;
-
- Player* modOwner = caster ? caster->GetSpellModOwner() : NULL;
-
- if(!m_permanent && modOwner)
- modOwner->ApplySpellMod(GetId(), SPELLMOD_DURATION, m_maxduration);
-
- m_duration = m_maxduration;
-
- if(modOwner)
- modOwner->ApplySpellMod(GetId(), SPELLMOD_ACTIVATION_TIME, m_periodicTimer);
-
- sLog.outDebug("Aura: construct Spellid : %u, Aura : %u Duration : %d Target : %d Damage : %d", m_spellProto->Id, m_spellProto->EffectApplyAuraName[eff], m_maxduration, m_spellProto->EffectImplicitTargetA[eff],damage);
-
- m_effIndex = eff;
- SetModifier(AuraType(m_spellProto->EffectApplyAuraName[eff]), damage, m_spellProto->EffectAmplitude[eff], m_spellProto->EffectMiscValue[eff]);
-
- m_isDeathPersist = IsDeathPersistentSpell(m_spellProto);
-
- if(m_spellProto->procCharges)
- {
- m_procCharges = m_spellProto->procCharges;
-
- if(modOwner)
- modOwner->ApplySpellMod(GetId(), SPELLMOD_CHARGES, m_procCharges);
- }
- else
- m_procCharges = -1;
-
- m_isRemovedOnShapeLost = (m_caster_guid==m_target->GetGUID() && m_spellProto->Stances &&
- !(m_spellProto->AttributesEx2 & 0x80000) && !(m_spellProto->Attributes & 0x10000));
-}
-
-Aura::~Aura()
-{
-}
-
-AreaAura::AreaAura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target,
-Unit *caster, Item* castItem) : Aura(spellproto, eff, currentBasePoints, target, caster, castItem)
-{
- m_isAreaAura = true;
-
- // caster==NULL in constructor args if target==caster in fact
- Unit* caster_ptr = caster ? caster : target;
-
- m_radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(GetSpellProto()->EffectRadiusIndex[m_effIndex]));
- if(Player* modOwner = caster_ptr->GetSpellModOwner())
- modOwner->ApplySpellMod(GetId(), SPELLMOD_RADIUS, m_radius);
-
- switch(spellproto->Effect[eff])
- {
- case SPELL_EFFECT_APPLY_AREA_AURA_PARTY:
- m_areaAuraType = AREA_AURA_PARTY;
- if(target->GetTypeId() == TYPEID_UNIT && ((Creature*)target)->isTotem())
- m_modifier.m_auraname = SPELL_AURA_NONE;
- break;
- case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND:
- m_areaAuraType = AREA_AURA_FRIEND;
- break;
- case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY:
- m_areaAuraType = AREA_AURA_ENEMY;
- if(target == caster_ptr)
- m_modifier.m_auraname = SPELL_AURA_NONE; // Do not do any effect on self
- break;
- case SPELL_EFFECT_APPLY_AREA_AURA_PET:
- m_areaAuraType = AREA_AURA_PET;
- break;
- case SPELL_EFFECT_APPLY_AREA_AURA_OWNER:
- m_areaAuraType = AREA_AURA_OWNER;
- if(target == caster_ptr)
- m_modifier.m_auraname = SPELL_AURA_NONE;
- break;
- default:
- sLog.outError("Wrong spell effect in AreaAura constructor");
- ASSERT(false);
- break;
- }
-}
-
-AreaAura::~AreaAura()
-{
-}
-
-PersistentAreaAura::PersistentAreaAura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target,
-Unit *caster, Item* castItem) : Aura(spellproto, eff, currentBasePoints, target, caster, castItem)
-{
- m_isPersistent = true;
-}
-
-PersistentAreaAura::~PersistentAreaAura()
-{
-}
-
-SingleEnemyTargetAura::SingleEnemyTargetAura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target,
-Unit *caster, Item* castItem) : Aura(spellproto, eff, currentBasePoints, target, caster, castItem)
-{
- if (caster)
- m_casters_target_guid = caster->GetTypeId()==TYPEID_PLAYER ? ((Player*)caster)->GetSelection() : caster->GetUInt64Value(UNIT_FIELD_TARGET);
- else
- m_casters_target_guid = 0;
-}
-
-SingleEnemyTargetAura::~SingleEnemyTargetAura()
-{
-}
-
-Unit* SingleEnemyTargetAura::GetTriggerTarget() const
-{
- return ObjectAccessor::GetUnit(*m_target, m_casters_target_guid);
-}
-
-Aura* CreateAura(SpellEntry const* spellproto, uint32 eff, int32 *currentBasePoints, Unit *target, Unit *caster, Item* castItem)
-{
- if (IsAreaAuraEffect(spellproto->Effect[eff]))
- return new AreaAura(spellproto, eff, currentBasePoints, target, caster, castItem);
-
- uint32 triggeredSpellId = spellproto->EffectTriggerSpell[eff];
-
- SpellEntry const* triggredSpellInfo = sSpellStore.LookupEntry(triggeredSpellId);
- if (triggredSpellInfo)
- for (int i = 0; i < 3; ++i)
- if (triggredSpellInfo->EffectImplicitTargetA[i] == TARGET_SINGLE_ENEMY)
- return new SingleEnemyTargetAura(spellproto, eff, currentBasePoints, target, caster, castItem);
-
- return new Aura(spellproto, eff, currentBasePoints, target, caster, castItem);
-}
-
-Unit* Aura::GetCaster() const
-{
- if(m_caster_guid==m_target->GetGUID())
- return m_target;
-
- //return ObjectAccessor::GetUnit(*m_target,m_caster_guid);
- //must return caster even if it's in another grid/map
- Unit *unit = ObjectAccessor::GetObjectInWorld(m_caster_guid, (Unit*)NULL);
- return unit && unit->IsInWorld() ? unit : NULL;
-}
-
-void Aura::SetModifier(AuraType t, int32 a, uint32 pt, int32 miscValue)
-{
- m_modifier.m_auraname = t;
- m_modifier.m_amount = a;
- m_modifier.m_miscvalue = miscValue;
- m_modifier.periodictime = pt;
-}
-
-void Aura::Update(uint32 diff)
-{
- if (m_duration > 0)
- {
- m_duration -= diff;
- if (m_duration < 0)
- m_duration = 0;
- m_timeCla -= diff;
-
- // GetEffIndex()==0 prevent double/triple apply manaPerSecond/manaPerSecondPerLevel to same spell with many auras
- // all spells with manaPerSecond/manaPerSecondPerLevel have aura in effect 0
- if(GetEffIndex()==0 && m_timeCla <= 0)
- {
- if(Unit* caster = GetCaster())
- {
- Powers powertype = Powers(m_spellProto->powerType);
- int32 manaPerSecond = m_spellProto->manaPerSecond + m_spellProto->manaPerSecondPerLevel * caster->getLevel();
- m_timeCla = 1000;
- if (manaPerSecond)
- {
- if(powertype==POWER_HEALTH)
- caster->ModifyHealth(-manaPerSecond);
- else
- caster->ModifyPower(powertype,-manaPerSecond);
- }
- }
- }
- }
-
- // Channeled aura required check distance from caster
- if(IsChanneledSpell(m_spellProto) && m_caster_guid != m_target->GetGUID())
- {
- Unit* caster = GetCaster();
- if(!caster)
- {
- m_target->RemoveAura(GetId(),GetEffIndex());
- return;
- }
-
- // Get spell range
- float radius;
- SpellModOp mod;
- if (m_spellProto->EffectRadiusIndex[GetEffIndex()])
- {
- radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(m_spellProto->EffectRadiusIndex[GetEffIndex()]));
- mod = SPELLMOD_RADIUS;
- }
- else
- {
- radius = GetSpellMaxRange(sSpellRangeStore.LookupEntry(m_spellProto->rangeIndex));
- mod = SPELLMOD_RANGE;
- }
-
- if(Player* modOwner = caster->GetSpellModOwner())
- modOwner->ApplySpellMod(GetId(), mod, radius,NULL);
-
- if(!caster->IsWithinDistInMap(m_target,radius))
- {
- m_target->RemoveAura(GetId(),GetEffIndex());
- return;
- }
- }
-
- if(m_isPeriodic && (m_duration >= 0 || m_isPassive || m_permanent))
- {
- m_periodicTimer -= diff;
- if(m_periodicTimer <= 0) // tick also at m_periodicTimer==0 to prevent lost last tick in case max m_duration == (max m_periodicTimer)*N
- {
- if( m_modifier.m_auraname == SPELL_AURA_MOD_REGEN ||
- m_modifier.m_auraname == SPELL_AURA_MOD_POWER_REGEN ||
- // Cannibalize, eating items and other spells
- m_modifier.m_auraname == SPELL_AURA_OBS_MOD_HEALTH ||
- // Eating items and other spells
- m_modifier.m_auraname == SPELL_AURA_OBS_MOD_MANA )
- {
- ApplyModifier(true);
- return;
- }
- // update before applying (aura can be removed in TriggerSpell or PeriodicTick calls)
- m_periodicTimer += m_modifier.periodictime;
-
- if(m_isTrigger)
- TriggerSpell();
- else
- PeriodicTick();
- }
- }
-}
-
-void AreaAura::Update(uint32 diff)
-{
- // update for the caster of the aura
- if(m_caster_guid == m_target->GetGUID())
- {
- Unit* caster = m_target;
-
- if( !caster->hasUnitState(UNIT_STAT_ISOLATED) )
- {
- Unit* owner = caster->GetCharmerOrOwner();
- if (!owner)
- owner = caster;
- std::list targets;
-
- switch(m_areaAuraType)
- {
- case AREA_AURA_PARTY:
- {
- Group *pGroup = NULL;
-
- if (owner->GetTypeId() == TYPEID_PLAYER)
- pGroup = ((Player*)owner)->GetGroup();
-
- if( pGroup)
- {
- uint8 subgroup = ((Player*)owner)->GetSubGroup();
- for(GroupReference *itr = pGroup->GetFirstMember(); itr != NULL; itr = itr->next())
- {
- Player* Target = itr->getSource();
- if(Target && Target->isAlive() && Target->GetSubGroup()==subgroup && caster->IsFriendlyTo(Target))
- {
- if(caster->IsWithinDistInMap(Target, m_radius))
- targets.push_back(Target);
- Pet *pet = Target->GetPet();
- if(pet && pet->isAlive() && caster->IsWithinDistInMap(pet, m_radius))
- targets.push_back(pet);
- }
- }
- }
- else
- {
- // add owner
- if( owner != caster && caster->IsWithinDistInMap(owner, m_radius) )
- targets.push_back(owner);
- // add caster's pet
- Unit* pet = caster->GetPet();
- if( pet && caster->IsWithinDistInMap(pet, m_radius))
- targets.push_back(pet);
- }
- break;
- }
- case AREA_AURA_FRIEND:
- {
- CellPair p(MaNGOS::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY()));
- Cell cell(p);
- cell.data.Part.reserved = ALL_DISTRICT;
- cell.SetNoCreate();
-
- MaNGOS::AnyFriendlyUnitInObjectRangeCheck u_check(caster, owner, m_radius);
- MaNGOS::UnitListSearcher searcher(targets, u_check);
- TypeContainerVisitor, WorldTypeMapContainer > world_unit_searcher(searcher);
- TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher);
- CellLock cell_lock(cell, p);
- cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(caster->GetMapId(), caster));
- cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(caster->GetMapId(), caster));
- break;
- }
- case AREA_AURA_ENEMY:
- {
- CellPair p(MaNGOS::ComputeCellPair(caster->GetPositionX(), caster->GetPositionY()));
- Cell cell(p);
- cell.data.Part.reserved = ALL_DISTRICT;
- cell.SetNoCreate();
-
- MaNGOS::AnyAoETargetUnitInObjectRangeCheck u_check(caster, owner, m_radius); // No GetCharmer in searcher
- MaNGOS::UnitListSearcher searcher(targets, u_check);
- TypeContainerVisitor, WorldTypeMapContainer > world_unit_searcher(searcher);
- TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher);
- CellLock cell_lock(cell, p);
- cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(caster->GetMapId(), caster));
- cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(caster->GetMapId(), caster));
- break;
- }
- case AREA_AURA_OWNER:
- case AREA_AURA_PET:
- {
- if(owner != caster)
- targets.push_back(owner);
- break;
- }
- }
-
- for(std::list::iterator tIter = targets.begin(); tIter != targets.end(); tIter++)
- {
- if((*tIter)->HasAura(GetId(), m_effIndex))
- continue;
-
- if(SpellEntry const *actualSpellInfo = spellmgr.SelectAuraRankForPlayerLevel(GetSpellProto(), (*tIter)->getLevel()))
- {
- int32 actualBasePoints = m_currentBasePoints;
- // recalculate basepoints for lower rank (all AreaAura spell not use custom basepoints?)
- if(actualSpellInfo != GetSpellProto())
- actualBasePoints = actualSpellInfo->EffectBasePoints[m_effIndex];
- AreaAura *aur = new AreaAura(actualSpellInfo, m_effIndex, &actualBasePoints, (*tIter), caster, NULL);
- (*tIter)->AddAura(aur);
- }
- }
- }
- Aura::Update(diff);
- }
- else // aura at non-caster
- {
- Unit * tmp_target = m_target;
- Unit* caster = GetCaster();
- uint32 tmp_spellId = GetId(), tmp_effIndex = m_effIndex;
-
- // WARNING: the aura may get deleted during the update
- // DO NOT access its members after update!
- Aura::Update(diff);
-
- // remove aura if out-of-range from caster (after teleport for example)
- // or caster is isolated or caster no longer has the aura
- // or caster is (no longer) friendly
- bool needFriendly = (m_areaAuraType == AREA_AURA_ENEMY ? false : true);
- if( !caster || caster->hasUnitState(UNIT_STAT_ISOLATED) ||
- !caster->IsWithinDistInMap(tmp_target, m_radius) ||
- !caster->HasAura(tmp_spellId, tmp_effIndex) ||
- caster->IsFriendlyTo(tmp_target) != needFriendly
- )
- {
- tmp_target->RemoveAura(tmp_spellId, tmp_effIndex);
- }
- else if( m_areaAuraType == AREA_AURA_PARTY) // check if in same sub group
- {
- // not check group if target == owner or target == pet
- if (caster->GetCharmerOrOwnerGUID() != tmp_target->GetGUID() && caster->GetGUID() != tmp_target->GetCharmerOrOwnerGUID())
- {
- Player* check = caster->GetCharmerOrOwnerPlayerOrPlayerItself();
-
- Group *pGroup = check ? check->GetGroup() : NULL;
- if( pGroup )
- {
- Player* checkTarget = tmp_target->GetCharmerOrOwnerPlayerOrPlayerItself();
- if(!checkTarget || !pGroup->SameSubGroup(check, checkTarget))
- tmp_target->RemoveAura(tmp_spellId, tmp_effIndex);
- }
- else
- tmp_target->RemoveAura(tmp_spellId, tmp_effIndex);
- }
- }
- else if( m_areaAuraType == AREA_AURA_PET || m_areaAuraType == AREA_AURA_OWNER )
- {
- if( tmp_target->GetGUID() != caster->GetCharmerOrOwnerGUID() )
- tmp_target->RemoveAura(tmp_spellId, tmp_effIndex);
- }
- }
-}
-
-void PersistentAreaAura::Update(uint32 diff)
-{
- bool remove = false;
-
- // remove the aura if its caster or the dynamic object causing it was removed
- // or if the target moves too far from the dynamic object
- Unit *caster = GetCaster();
- if (caster)
- {
- DynamicObject *dynObj = caster->GetDynObject(GetId(), GetEffIndex());
- if (dynObj)
- {
- if (!m_target->IsWithinDistInMap(dynObj, dynObj->GetRadius()))
- remove = true;
- }
- else
- remove = true;
- }
- else
- remove = true;
-
- Unit *tmp_target = m_target;
- uint32 tmp_id = GetId(), tmp_index = GetEffIndex();
-
- // WARNING: the aura may get deleted during the update
- // DO NOT access its members after update!
- Aura::Update(diff);
-
- if(remove)
- tmp_target->RemoveAura(tmp_id, tmp_index);
-}
-
-void Aura::ApplyModifier(bool apply, bool Real)
-{
- AuraType aura = m_modifier.m_auraname;
-
- m_in_use = true;
- if(aura= MAX_AURAS || m_isPassive)
- return;
-
- if( m_target->GetTypeId() == TYPEID_PLAYER)
- {
- WorldPacket data(SMSG_UPDATE_AURA_DURATION, 5);
- data << (uint8)m_auraSlot << (uint32)m_duration;
- ((Player*)m_target)->SendDirectMessage(&data);
-
- data.Initialize(SMSG_SET_EXTRA_AURA_INFO, (8+1+4+4+4));
- data.append(m_target->GetPackGUID());
- data << uint8(m_auraSlot);
- data << uint32(GetId());
- data << uint32(GetAuraMaxDuration());
- data << uint32(GetAuraDuration());
- ((Player*)m_target)->SendDirectMessage(&data);
- }
-
- // not send in case player loading (will not work anyway until player not added to map), sent in visibility change code
- if(m_target->GetTypeId() == TYPEID_PLAYER && ((Player*)m_target)->GetSession()->PlayerLoading())
- return;
-
- Unit* caster = GetCaster();
-
- if(caster && caster->GetTypeId() == TYPEID_PLAYER && caster != m_target)
- SendAuraDurationForCaster((Player*)caster);
-}
-
-void Aura::SendAuraDurationForCaster(Player* caster)
-{
- WorldPacket data(SMSG_SET_EXTRA_AURA_INFO_NEED_UPDATE, (8+1+4+4+4));
- data.append(m_target->GetPackGUID());
- data << uint8(m_auraSlot);
- data << uint32(GetId());
- data << uint32(GetAuraMaxDuration()); // full
- data << uint32(GetAuraDuration()); // remain
- caster->GetSession()->SendPacket(&data);
-}
-
-void Aura::_AddAura()
-{
- if (!GetId())
- return;
- if(!m_target)
- 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;
-
- for(uint8 i = 0; i < 3; i++)
- {
- Unit::spellEffectPair spair = Unit::spellEffectPair(GetId(), i);
- for(Unit::AuraMap::const_iterator itr = m_target->GetAuras().lower_bound(spair); itr != m_target->GetAuras().upper_bound(spair); ++itr)
- {
- // 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;
- slot = itr->second->GetAuraSlot();
- break;
- }
- }
-
- if(samespell)
- break;
- }
-
- // not call total regen auras at adding
- switch (m_modifier.m_auraname)
- {
- case SPELL_AURA_OBS_MOD_HEALTH:
- case SPELL_AURA_OBS_MOD_MANA:
- m_periodicTimer = m_modifier.periodictime;
- break;
- case SPELL_AURA_MOD_REGEN:
- case SPELL_AURA_MOD_POWER_REGEN:
- case SPELL_AURA_MOD_MANA_REGEN_FROM_STAT:
- m_periodicTimer = 5000;
- break;
- }
-
- // register aura
- if (getDiminishGroup() != DIMINISHING_NONE )
- m_target->ApplyDiminishingAura(getDiminishGroup(),true);
-
- Unit* caster = GetCaster();
-
- // passive auras (except totem auras) do not get placed in the slots
- // area auras with SPELL_AURA_NONE are not shown on target
- 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 (IsPositive()) // empty positive slot
- {
- for (uint8 i = 0; i < MAX_POSITIVE_AURAS; i++)
- {
- if (m_target->GetUInt32Value((uint16)(UNIT_FIELD_AURA + i)) == 0)
- {
- slot = i;
- break;
- }
- }
- }
- else // empty negative slot
- {
- for (uint8 i = MAX_POSITIVE_AURAS; i < MAX_AURAS; i++)
- {
- if (m_target->GetUInt32Value((uint16)(UNIT_FIELD_AURA + i)) == 0)
- {
- slot = i;
- break;
- }
- }
- }
-
- SetAuraSlot( slot );
-
- // Not update fields for not first spell's aura, all data already in fields
- if(!secondaura)
- {
- 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();
- }
- }
- else // use found slot
- {
- SetAuraSlot( slot );
- // Not recalculate stack count for second aura of the same spell
- if (!secondaura)
- UpdateSlotCounterAndDuration(true);
- }
-
- // Update Seals information
- if( IsSealSpell(GetSpellProto()) )
- m_target->ModifyAuraState(AURA_STATE_JUDGEMENT, true);
-
- // Conflagrate aura state
- if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellProto()->SpellFamilyFlags & 4))
- m_target->ModifyAuraState(AURA_STATE_IMMOLATE, true);
-
- if(GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
- && (GetSpellProto()->SpellFamilyFlags == 0x40 || GetSpellProto()->SpellFamilyFlags == 0x10))
- {
- m_target->ModifyAuraState(AURA_STATE_SWIFTMEND, true);
- }
- }
-}
-
-void Aura::_RemoveAura()
-{
- // Remove all triggered by aura spells vs unlimited duration
- // except same aura replace case
- if(m_removeMode!=AURA_REMOVE_BY_STACK)
- CleanupTriggeredSpells();
-
- Unit* caster = GetCaster();
-
- if(caster && IsPersistent())
- {
- DynamicObject *dynObj = caster->GetDynObject(GetId(), GetEffIndex());
- if (dynObj)
- dynObj->RemoveAffected(m_target);
- }
-
- // unregister aura
- if (getDiminishGroup() != DIMINISHING_NONE )
- m_target->ApplyDiminishingAura(getDiminishGroup(),false);
-
- //passive auras do not get put in slots
- // Note: but totem can be not accessible for aura target in time remove (to far for find in grid)
- //if(m_isPassive && !(caster && caster->GetTypeId() == TYPEID_UNIT && ((Creature*)caster)->isTotem()))
- // return;
-
- uint8 slot = GetAuraSlot();
-
- if(slot >= MAX_AURAS) // slot not set
- return;
-
- if(m_target->GetUInt32Value((uint16)(UNIT_FIELD_AURA + slot)) == 0)
- 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++)
- {
- Unit::spellEffectPair spair = Unit::spellEffectPair(GetId(), i);
- for(Unit::AuraMap::const_iterator itr = m_target->GetAuras().lower_bound(spair); itr != m_target->GetAuras().upper_bound(spair); ++itr)
- {
- if(itr->second->GetAuraSlot()==slot)
- {
- samespell = true;
-
- if(GetEffIndex()==i)
- sameaura = true;
-
- break;
- }
- }
- if(samespell)
- break;
- }
-
- // only remove icon when the last aura of the spell is removed (current aura already removed from list)
- if (!samespell)
- {
- SetAura(slot, true);
- SetAuraFlag(slot, false);
- SetAuraLevel(slot,caster ? caster->getLevel() : sWorld.getConfig(CONFIG_MAX_PLAYER_LEVEL));
-
- SetAuraApplication(slot, 0);
- // update for out of range group members
- m_target->UpdateAuraForGroup(slot);
-
- if( IsSealSpell(GetSpellProto()) )
- m_target->ModifyAuraState(AURA_STATE_JUDGEMENT,false);
-
- // Conflagrate aura state
- if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_WARLOCK && (GetSpellProto()->SpellFamilyFlags & 4))
- m_target->ModifyAuraState(AURA_STATE_IMMOLATE, false);
-
- // Swiftmend aura state
- if(GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
- && (GetSpellProto()->SpellFamilyFlags == 0x40 || GetSpellProto()->SpellFamilyFlags == 0x10))
- {
- bool found = false;
- Unit::AuraList const& RejorRegr = m_target->GetAurasByType(SPELL_AURA_PERIODIC_HEAL);
- for(Unit::AuraList::const_iterator i = RejorRegr.begin(); i != RejorRegr.end(); ++i)
- {
- if((*i)->GetSpellProto()->SpellFamilyName == SPELLFAMILY_DRUID
- && ((*i)->GetSpellProto()->SpellFamilyFlags == 0x40 || (*i)->GetSpellProto()->SpellFamilyFlags == 0x10) )
- {
- found = true;
- break;
- }
- }
- if(!found)
- m_target->ModifyAuraState(AURA_STATE_SWIFTMEND, false);
- }
-
- // reset cooldown state for spells
- if(caster && caster->GetTypeId() == TYPEID_PLAYER)
- {
- if ( GetSpellProto()->Attributes & SPELL_ATTR_DISABLED_WHILE_ACTIVE )
- ((Player*)caster)->SendCooldownEvent(GetSpellProto());
- }
- }
- else if(sameaura) // decrease count for spell, only for same aura effect, or this spell auras in remove proccess.
- UpdateSlotCounterAndDuration(false);
-}
-
-void Aura::SetAuraFlag(uint32 slot, bool add)
-{
- uint32 index = slot / 4;
- uint32 byte = (slot % 4) * 8;
- uint32 val = m_target->GetUInt32Value(UNIT_FIELD_AURAFLAGS + index);
- val &= ~((uint32)AFLAG_MASK << byte);
- if(add)
- {
- if (IsPositive())
- val |= ((uint32)AFLAG_POSITIVE << byte);
- else
- val |= ((uint32)AFLAG_NEGATIVE << byte);
- }
- m_target->SetUInt32Value(UNIT_FIELD_AURAFLAGS + index, val);
-}
-
-void Aura::SetAuraLevel(uint32 slot,uint32 level)
-{
- uint32 index = slot / 4;
- uint32 byte = (slot % 4) * 8;
- uint32 val = m_target->GetUInt32Value(UNIT_FIELD_AURALEVELS + index);
- val &= ~(0xFF << byte);
- val |= (level << byte);
- m_target->SetUInt32Value(UNIT_FIELD_AURALEVELS + index, val);
-}
-
-void Aura::SetAuraApplication(uint32 slot, int8 count)
-{
- uint32 index = slot / 4;
- uint32 byte = (slot % 4) * 8;
- uint32 val = m_target->GetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS + index);
- val &= ~(0xFF << byte);
- val |= ((uint8(count)) << byte);
- m_target->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS + index, val);
-}
-
-void Aura::UpdateSlotCounterAndDuration(bool add)
-{
- 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);
-
- UpdateAuraDuration();
-}
-
-/*********************************************************/
-/*** BASIC AURA FUNCTION ***/
-/*********************************************************/
-void Aura::HandleAddModifier(bool apply, bool Real)
-{
- if(m_target->GetTypeId() != TYPEID_PLAYER || !Real)
- return;
-
- SpellEntry const *spellInfo = GetSpellProto();
- if(!spellInfo)
- return;
-
- if(m_modifier.m_miscvalue >= MAX_SPELLMOD)
- return;
-
- if (apply)
- {
- // Add custom charges for some mod aura
- switch (m_spellProto->Id)
- {
- case 17941: // Shadow Trance
- case 22008: // Netherwind Focus
- case 34936: // Backlash
- m_procCharges = 1;
- break;
- }
-
- SpellModifier *mod = new SpellModifier;
- mod->op = SpellModOp(m_modifier.m_miscvalue);
- mod->value = m_modifier.m_amount;
- mod->type = SpellModType(m_modifier.m_auraname); // SpellModType value == spell aura types
- mod->spellId = GetId();
- mod->effectId = m_effIndex;
- mod->lastAffected = NULL;
-
- uint64 spellAffectMask = spellmgr.GetSpellAffectMask(GetId(), m_effIndex);
-
- if (spellAffectMask)
- mod->mask = spellAffectMask;
- else
- mod->mask = spellInfo->EffectItemType[m_effIndex];
-
- if (m_procCharges > 0)
- mod->charges = m_procCharges;
- else
- mod->charges = 0;
-
- m_spellmod = mod;
- }
-
- uint64 spellFamilyMask = m_spellmod->mask;
-
- ((Player*)m_target)->AddSpellMod(m_spellmod, apply);
-
- // reapply some passive spells after add/remove related spellmods
- if(spellInfo->SpellFamilyName==SPELLFAMILY_WARRIOR && (spellFamilyMask & 0x0000100000000000LL))
- {
- m_target->RemoveAurasDueToSpell(45471);
-
- if(apply)
- m_target->CastSpell(m_target,45471,true);
- }
-}
-
-void Aura::TriggerSpell()
-{
- Unit* caster = GetCaster();
- Unit* target = GetTriggerTarget();
-
- if(!caster || !target)
- return;
-
- // generic casting code with custom spells and target/caster customs
- uint32 trigger_spell_id = GetSpellProto()->EffectTriggerSpell[m_effIndex];
-
- uint64 originalCasterGUID = GetCasterGUID();
-
- SpellEntry const *triggredSpellInfo = sSpellStore.LookupEntry(trigger_spell_id);
- SpellEntry const *auraSpellInfo = GetSpellProto();
- uint32 auraId = auraSpellInfo->Id;
-
- // specific code for cases with no trigger spell provided in field
- if (triggredSpellInfo == NULL)
- {
- switch(auraSpellInfo->SpellFamilyName)
- {
- case SPELLFAMILY_GENERIC:
- {
- switch(auraId)
- {
- // Firestone Passive (1-5 rangs)
- case 758:
- case 17945:
- case 17947:
- case 17949:
- case 27252:
- {
- if (caster->GetTypeId()!=TYPEID_PLAYER)
- return;
- Item* item = ((Player*)caster)->GetWeaponForAttack(BASE_ATTACK);
- if (!item)
- return;
- uint32 enchant_id = 0;
- switch (GetId())
- {
- case 758: enchant_id = 1803; break; // Rank 1
- case 17945: enchant_id = 1823; break; // Rank 2
- case 17947: enchant_id = 1824; break; // Rank 3
- case 17949: enchant_id = 1825; break; // Rank 4
- case 27252: enchant_id = 2645; break; // Rank 5
- default:
- return;
- }
- // remove old enchanting before applying new
- ((Player*)caster)->ApplyEnchantment(item,TEMP_ENCHANTMENT_SLOT,false);
- item->SetEnchantment(TEMP_ENCHANTMENT_SLOT, enchant_id, m_modifier.periodictime+1000, 0);
- // add new enchanting
- ((Player*)caster)->ApplyEnchantment(item,TEMP_ENCHANTMENT_SLOT,true);
- return;
- }
-// // Periodic Mana Burn
-// case 812: break;
-// // Polymorphic Ray
-// case 6965: break;
-// // Fire Nova (1-7 Rangs)
-// case 8350:
-// case 8508:
-// case 8509:
-// case 11312:
-// case 11313:
-// case 25540:
-// case 25544:
-// break;
- // Thaumaturgy Channel
- case 9712: trigger_spell_id = 21029; break;
-// // Egan's Blaster
-// case 17368: break;
-// // Haunted
-// case 18347: break;
-// // Ranshalla Waiting
-// case 18953: break;
-// // Inferno
-// case 19695: break;
-// // Frostwolf Muzzle DND
-// case 21794: break;
-// // Alterac Ram Collar DND
-// case 21866: break;
-// // Celebras Waiting
-// case 21916: break;
- // Brood Affliction: Bronze
- case 23170:
- {
- m_target->CastSpell(m_target, 23171, true, 0, this);
- return;
- }
-// // Mark of Frost
-// case 23184: break;
- // Restoration
- case 23493:
- {
- int32 heal = caster->GetMaxHealth() / 10;
- caster->ModifyHealth( heal );
- caster->SendHealSpellLog(caster, 23493, heal);
-
- int32 mana = caster->GetMaxPower(POWER_MANA);
- if (mana)
- {
- mana /= 10;
- caster->ModifyPower( POWER_MANA, mana );
- caster->SendEnergizeSpellLog(caster, 23493, mana, POWER_MANA);
- }
- break;
- }
-// // Stoneclaw Totem Passive TEST
-// case 23792: break;
-// // Axe Flurry
-// case 24018: break;
-// // Mark of Arlokk
-// case 24210: break;
-// // Restoration
-// case 24379: break;
-// // Happy Pet
-// case 24716: break;
-// // Dream Fog
-// case 24780: break;
-// // Cannon Prep
-// case 24832: break;
-// // Shadow Bolt Whirl
-// case 24834: break;
-// // Stink Trap
-// case 24918: break;
-// // Mark of Nature
-// case 25041: break;
-// // Agro Drones
-// case 25152: break;
-// // Consume
-// case 25371: break;
-// // Pain Spike
-// case 25572: break;
-// // Rotate 360
-// case 26009: break;
-// // Rotate -360
-// case 26136: break;
-// // Consume
-// case 26196: break;
-// // Berserk
-// case 26615: break;
-// // Defile
-// case 27177: break;
-// // Teleport: IF/UC
-// case 27601: break;
-// // Five Fat Finger Exploding Heart Technique
-// case 27673: break;
-// // Nitrous Boost
-// case 27746: break;
-// // Steam Tank Passive
-// case 27747: break;
-// // Frost Blast
-// case 27808: break;
-// // Detonate Mana
-// case 27819: break;
-// // Controller Timer
-// case 28095: break;
-// // Stalagg Chain
-// case 28096: break;
-// // Stalagg Tesla Passive
-// case 28097: break;
-// // Feugen Tesla Passive
-// case 28109: break;
-// // Feugen Chain
-// case 28111: break;
-// // Mark of Didier
-// case 28114: break;
-// // Communique Timer, camp
-// case 28346: break;
-// // Icebolt
-// case 28522: break;
-// // Silithyst
-// case 29519: break;
-// // Inoculate Nestlewood Owlkin
- case 29528: trigger_spell_id = 28713; break;
-// // Overload
-// case 29768: break;
-// // Return Fire
-// case 29788: break;
-// // Return Fire
-// case 29793: break;
-// // Return Fire
-// case 29794: break;
-// // Guardian of Icecrown Passive
-// case 29897: break;
- // Feed Captured Animal
- case 29917: trigger_spell_id = 29916; break;
-// // Flame Wreath
-// case 29946: break;
-// // Flame Wreath
-// case 29947: break;
-// // Mind Exhaustion Passive
-// case 30025: break;
-// // Nether Beam - Serenity
-// case 30401: break;
- // Extract Gas
- case 30427:
- {
- // move loot to player inventory and despawn target
- if(caster->GetTypeId() ==TYPEID_PLAYER &&
- target->GetTypeId() == TYPEID_UNIT &&
- ((Creature*)target)->GetCreatureInfo()->type == CREATURE_TYPE_GAS_CLOUD)
- {
- Player* player = (Player*)caster;
- Creature* creature = (Creature*)target;
- // missing lootid has been reported on startup - just return
- if (!creature->GetCreatureInfo()->SkinLootId)
- {
- return;
- }
- Loot *loot = &creature->loot;
- loot->clear();
- loot->FillLoot(creature->GetCreatureInfo()->SkinLootId, LootTemplates_Skinning, NULL);
- for(uint8 i=0;iitems.size();i++)
- {
- LootItem *item = loot->LootItemInSlot(i,player);
- ItemPosCountVec dest;
- uint8 msg = player->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, item->itemid, item->count );
- if ( msg == EQUIP_ERR_OK )
- {
- Item * newitem = player->StoreNewItem( dest, item->itemid, true, item->randomPropertyId);
-
- player->SendNewItem(newitem, uint32(item->count), false, false, true);
- }
- else
- player->SendEquipError( msg, NULL, NULL );
- }
- creature->setDeathState(JUST_DIED);
- creature->RemoveCorpse();
- creature->SetHealth(0); // just for nice GM-mode view
- }
- return;
- break;
- }
- // Quake
- case 30576: trigger_spell_id = 30571; break;
-// // Burning Maul
-// case 30598: break;
-// // Regeneration
-// case 30799:
-// case 30800:
-// case 30801:
-// break;
-// // Despawn Self - Smoke cloud
-// case 31269: break;
-// // Time Rift Periodic
-// case 31320: break;
-// // Corrupt Medivh
-// case 31326: break;
- // Doom
- case 31347:
- {
- m_target->CastSpell(m_target,31350,true);
- m_target->DealDamage(m_target, m_target->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
- return;
- }
- // Spellcloth
- case 31373:
- {
- // Summon Elemental after create item
- caster->SummonCreature(17870, 0, 0, 0, caster->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 0);
- return;
- }
-// // Bloodmyst Tesla
-// case 31611: break;
-// // Doomfire
-// case 31944: break;
-// // Teleport Test
-// case 32236: break;
-// // Earthquake
-// case 32686: break;
-// // Possess
-// case 33401: break;
-// // Draw Shadows
-// case 33563: break;
-// // Murmur's Touch
-// case 33711: break;
- // Flame Quills
- case 34229:
- {
- // cast 24 spells 34269-34289, 34314-34316
- for(uint32 spell_id = 34269; spell_id != 34290; ++spell_id)
- caster->CastSpell(m_target,spell_id,true);
- for(uint32 spell_id = 34314; spell_id != 34317; ++spell_id)
- caster->CastSpell(m_target,spell_id,true);
- return;
- }
-// // Gravity Lapse
-// case 34480: break;
-// // Tornado
-// case 34683: break;
-// // Frostbite Rotate
-// case 34748: break;
-// // Arcane Flurry
-// case 34821: break;
-// // Interrupt Shutdown
-// case 35016: break;
-// // Interrupt Shutdown
-// case 35176: break;
-// // Inferno
-// case 35268: break;
-// // Salaadin's Tesla
-// case 35515: break;
-// // Ethereal Channel (Red)
-// case 35518: break;
-// // Nether Vapor
-// case 35879: break;
-// // Dark Portal Storm
-// case 36018: break;
-// // Burning Maul
-// case 36056: break;
-// // Living Grove Defender Lifespan
-// case 36061: break;
-// // Professor Dabiri Talks
-// case 36064: break;
-// // Kael Gaining Power
-// case 36091: break;
-// // They Must Burn Bomb Aura
-// case 36344: break;
-// // They Must Burn Bomb Aura (self)
-// case 36350: break;
-// // Stolen Ravenous Ravager Egg
-// case 36401: break;
-// // Activated Cannon
-// case 36410: break;
-// // Stolen Ravenous Ravager Egg
-// case 36418: break;
-// // Enchanted Weapons
-// case 36510: break;
-// // Cursed Scarab Periodic
-// case 36556: break;
-// // Cursed Scarab Despawn Periodic
-// case 36561: break;
-// // Vision Guide
-// case 36573: break;
-// // Cannon Charging (platform)
-// case 36785: break;
-// // Cannon Charging (self)
-// case 36860: break;
- // Remote Toy
- case 37027: trigger_spell_id = 37029; break;
-// // Mark of Death
-// case 37125: break;
-// // Arcane Flurry
-// case 37268: break;
-// // Spout
-// case 37429: break;
-// // Spout
-// case 37430: break;
-// // Karazhan - Chess NPC AI, Snapshot timer
-// case 37440: break;
-// // Karazhan - Chess NPC AI, action timer
-// case 37504: break;
-// // Karazhan - Chess: Is Square OCCUPIED aura (DND)
-// case 39400: break;
-// // Banish
-// case 37546: break;
-// // Shriveling Gaze
-// case 37589: break;
-// // Fake Aggro Radius (2 yd)
-// case 37815: break;
-// // Corrupt Medivh
-// case 37853: break;
- // Eye of Grillok
- case 38495:
- {
- m_target->CastSpell(m_target, 38530, true);
- return;
- }
- // Absorb Eye of Grillok (Zezzak's Shard)
- case 38554:
- {
- if(m_target->GetTypeId() != TYPEID_UNIT)
- return;
-
- caster->CastSpell(caster, 38495, true);
-
- Creature* creatureTarget = (Creature*)m_target;
-
- creatureTarget->setDeathState(JUST_DIED);
- creatureTarget->RemoveCorpse();
- creatureTarget->SetHealth(0); // just for nice GM-mode view
- return;
- }
-// // Magic Sucker Device timer
-// case 38672: break;
-// // Tomb Guarding Charging
-// case 38751: break;
-// // Murmur's Touch
-// case 38794: break;
-// // Activate Nether-wraith Beacon (31742 Nether-wraith Beacon item)
-// case 39105: break;
-// // Drain World Tree Visual
-// case 39140: break;
-// // Quest - Dustin's Undead Dragon Visual aura
-// case 39259: break;
-// // Hellfire - The Exorcism, Jules releases darkness, aura
-// case 39306: break;
-// // Inferno
-// case 39346: break;
-// // Enchanted Weapons
-// case 39489: break;
-// // Shadow Bolt Whirl
-// case 39630: break;
-// // Shadow Bolt Whirl
-// case 39634: break;
-// // Shadow Inferno
-// case 39645: break;
- // Tear of Azzinoth Summon Channel - it's not really supposed to do anything,and this only prevents the console spam
- case 39857: trigger_spell_id = 39856; break;
-// // Soulgrinder Ritual Visual (Smashed)
-// case 39974: break;
-// // Simon Game Pre-game timer
-// case 40041: break;
-// // Knockdown Fel Cannon: The Aggro Check Aura
-// case 40113: break;
-// // Spirit Lance
-// case 40157: break;
-// // Demon Transform 2
-// case 40398: break;
-// // Demon Transform 1
-// case 40511: break;
-// // Ancient Flames
-// case 40657: break;
-// // Ethereal Ring Cannon: Cannon Aura
-// case 40734: break;
-// // Cage Trap
-// case 40760: break;
-// // Random Periodic
-// case 40867: break;
-// // Prismatic Shield
-// case 40879: break;
-// // Aura of Desire
-// case 41350: break;
-// // Dementia
-// case 41404: break;
-// // Chaos Form
-// case 41629: break;
-// // Alert Drums
-// case 42177: break;
-// // Spout
-// case 42581: break;
-// // Spout
-// case 42582: break;
-// // Return to the Spirit Realm
-// case 44035: break;
-// // Curse of Boundless Agony
-// case 45050: break;
-// // Earthquake
-// case 46240: break;
- // Personalized Weather
- case 46736: trigger_spell_id = 46737; break;
-// // Stay Submerged
-// case 46981: break;
-// // Dragonblight Ram
-// case 47015: break;
-// // Party G.R.E.N.A.D.E.
-// case 51510: break;
- default:
- break;
- }
- break;
- }
- case SPELLFAMILY_MAGE:
- {
- switch(auraId)
- {
- // Invisibility
- case 66:
- {
- if(!m_duration)
- m_target->CastSpell(m_target, 32612, true, NULL, this);
- return;
- }
- default:
- break;
- }
- break;
- }
-// case SPELLFAMILY_WARRIOR:
-// {
-// switch(auraId)
-// {
-// // Wild Magic
-// case 23410: break;
-// // Corrupted Totems
-// case 23425: break;
-// default:
-// break;
-// }
-// break;
-// }
-// case SPELLFAMILY_PRIEST:
-// {
-// switch(auraId)
-// {
-// // Blue Beam
-// case 32930: break;
-// // Fury of the Dreghood Elders
-// case 35460: break;
-// default:
-// break;
-// }
- // break;
- // }
- case SPELLFAMILY_DRUID:
- {
- switch(auraId)
- {
- // Cat Form
- // trigger_spell_id not set and unknown effect triggered in this case, ignoring for while
- case 768:
- return;
- // Frenzied Regeneration
- case 22842:
- case 22895:
- case 22896:
- case 26999:
- {
- int32 LifePerRage = GetModifier()->m_amount;
-
- int32 lRage = m_target->GetPower(POWER_RAGE);
- if(lRage > 100) // rage stored as rage*10
- lRage = 100;
- m_target->ModifyPower(POWER_RAGE, -lRage);
- int32 FRTriggerBasePoints = int32(lRage*LifePerRage/10);
- m_target->CastCustomSpell(m_target,22845,&FRTriggerBasePoints,NULL,NULL,true,NULL,this);
- return;
- }
- default:
- break;
- }
- break;
- }
-
-// case SPELLFAMILY_HUNTER:
-// {
-// switch(auraId)
-// {
-// //Frost Trap Aura
-// case 13810:
-// return;
-// //Rizzle's Frost Trap
-// case 39900:
-// return;
-// // Tame spells
-// case 19597: // Tame Ice Claw Bear
-// case 19676: // Tame Snow Leopard
-// case 19677: // Tame Large Crag Boar
-// case 19678: // Tame Adult Plainstrider
-// case 19679: // Tame Prairie Stalker
-// case 19680: // Tame Swoop
-// case 19681: // Tame Dire Mottled Boar
-// case 19682: // Tame Surf Crawler
-// case 19683: // Tame Armored Scorpid
-// case 19684: // Tame Webwood Lurker
-// case 19685: // Tame Nightsaber Stalker
-// case 19686: // Tame Strigid Screecher
-// case 30100: // Tame Crazed Dragonhawk
-// case 30103: // Tame Elder Springpaw
-// case 30104: // Tame Mistbat
-// case 30647: // Tame Barbed Crawler
-// case 30648: // Tame Greater Timberstrider
-// case 30652: // Tame Nightstalker
-// return;
-// default:
-// break;
-// }
-// break;
-// }
- case SPELLFAMILY_SHAMAN:
- {
- switch(auraId)
- {
- // Lightning Shield (The Earthshatterer set trigger after cast Lighting Shield)
- case 28820:
- {
- // Need remove self if Lightning Shield not active
- Unit::AuraMap const& auras = target->GetAuras();
- for(Unit::AuraMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
- {
- SpellEntry const* spell = itr->second->GetSpellProto();
- if( spell->SpellFamilyName == SPELLFAMILY_SHAMAN &&
- spell->SpellFamilyFlags & 0x0000000000000400L)
- return;
- }
- target->RemoveAurasDueToSpell(28820);
- return;
- }
- // Totemic Mastery (Skyshatter Regalia (Shaman Tier 6) - bonus)
- case 38443:
- {
- bool all = true;
- for(int i = 0; i < MAX_TOTEM; ++i)
- {
- if(!caster->m_TotemSlot[i])
- {
- all = false;
- break;
- }
- }
-
- if(all)
- caster->CastSpell(caster,38437,true);
- else
- caster->RemoveAurasDueToSpell(38437);
- return;
- }
- default:
- break;
- }
- break;
- }
- default:
- break;
- }
- // Reget trigger spell proto
- triggredSpellInfo = sSpellStore.LookupEntry(trigger_spell_id);
- if(triggredSpellInfo == NULL)
- {
- sLog.outError("Aura::TriggerSpell: Spell %u have 0 in EffectTriggered[%d], not handled custom case?",GetId(),GetEffIndex());
- return;
- }
- }
- else
- {
- // Spell exist but require costum code
- switch(auraId)
- {
- // Curse of Idiocy
- case 1010:
- {
- // TODO: spell casted by result in correct way mostly
- // BUT:
- // 1) target show casting at each triggered cast: target don't must show casting animation for any triggered spell
- // but must show affect apply like item casting
- // 2) maybe aura must be replace by new with accumulative stat mods insteed stacking
-
- // prevent cast by triggered auras
- if(m_caster_guid == m_target->GetGUID())
- return;
-
- // stop triggering after each affected stats lost > 90
- int32 intelectLoss = 0;
- int32 spiritLoss = 0;
-
- Unit::AuraList const& mModStat = m_target->GetAurasByType(SPELL_AURA_MOD_STAT);
- for(Unit::AuraList::const_iterator i = mModStat.begin(); i != mModStat.end(); ++i)
- {
- if ((*i)->GetId() == 1010)
- {
- switch((*i)->GetModifier()->m_miscvalue)
- {
- case STAT_INTELLECT: intelectLoss += (*i)->GetModifier()->m_amount; break;
- case STAT_SPIRIT: spiritLoss += (*i)->GetModifier()->m_amount; break;
- default: break;
- }
- }
- }
-
- if(intelectLoss <= -90 && spiritLoss <= -90)
- return;
-
- caster = target;
- originalCasterGUID = 0;
- break;
- }
- // Mana Tide
- case 16191:
- {
- caster->CastCustomSpell(target, trigger_spell_id, &m_modifier.m_amount, NULL, NULL, true, NULL, this, originalCasterGUID);
- return;
- }
- }
- }
- // All ok cast by default case
- Spell *spell = new Spell(caster, triggredSpellInfo, true, originalCasterGUID );
-
- SpellCastTargets targets;
- targets.setUnitTarget( target );
-
- // if spell create dynamic object extract area from it
- if(DynamicObject* dynObj = caster->GetDynObject(GetId()))
- targets.setDestination(dynObj->GetPositionX(),dynObj->GetPositionY(),dynObj->GetPositionZ());
-
- spell->prepare(&targets, this);
-}
-
-/*********************************************************/
-/*** AURA EFFECTS ***/
-/*********************************************************/
-
-void Aura::HandleAuraDummy(bool apply, bool Real)
-{
- // spells required only Real aura add/remove
- if(!Real)
- return;
-
- Unit* caster = GetCaster();
-
- // AT APPLY
- if(apply)
- {
- switch(GetId())
- {
- case 1515: // Tame beast
- // FIX_ME: this is 2.0.12 threat effect replaced in 2.1.x by dummy aura, must be checked for correctness
- if( caster && m_target->CanHaveThreatList())
- m_target->AddThreat(caster, 10.0f);
- return;
- case 13139: // net-o-matic
- // root to self part of (root_target->charge->root_self sequence
- if(caster)
- caster->CastSpell(caster,13138,true,NULL,this);
- return;
- case 39850: // Rocket Blast
- if(roll_chance_i(20)) // backfire stun
- m_target->CastSpell(m_target, 51581, true, NULL, this);
- return;
- case 46354: // Blood Elf Illusion
- if(caster)
- {
- switch(caster->getGender())
- {
- case GENDER_FEMALE:
- caster->CastSpell(m_target,46356,true,NULL,this);
- break;
- case GENDER_MALE:
- caster->CastSpell(m_target,46355,true,NULL,this);
- break;
- default:
- break;
- }
- }
- return;
- case 46699: // Requires No Ammo
- if(m_target->GetTypeId()==TYPEID_PLAYER)
- ((Player*)m_target)->RemoveAmmo(); // not use ammo and not allow use
- return;
- }
-
- // Earth Shield
- if ( caster && GetSpellProto()->SpellFamilyName == SPELLFAMILY_SHAMAN && (GetSpellProto()->SpellFamilyFlags & 0x40000000000LL))
- {
- // prevent double apply bonuses
- 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);
- return;
- }
- }
- // AT REMOVE
- else
- {
- if( m_target->GetTypeId() == TYPEID_PLAYER &&
- ( GetSpellProto()->Effect[0]==72 || GetSpellProto()->Effect[0]==6 &&
- ( GetSpellProto()->EffectApplyAuraName[0]==1 || GetSpellProto()->EffectApplyAuraName[0]==128 ) ) )
- {
- // spells with SpellEffect=72 and aura=4: 6196, 6197, 21171, 21425
- m_target->SetUInt64Value(PLAYER_FARSIGHT, 0);
- WorldPacket data(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, 0);
- ((Player*)m_target)->GetSession()->SendPacket(&data);
- return;
- }
-
- if( (IsQuestTameSpell(GetId())) && caster && caster->isAlive() && m_target->isAlive())
- {
- uint32 finalSpelId = 0;
- switch(GetId())
- {
- case 19548: finalSpelId = 19597; break;
- case 19674: finalSpelId = 19677; break;
- case 19687: finalSpelId = 19676; break;
- case 19688: finalSpelId = 19678; break;
- case 19689: finalSpelId = 19679; break;
- case 19692: finalSpelId = 19680; break;
- case 19693: finalSpelId = 19684; break;
- case 19694: finalSpelId = 19681; break;
- case 19696: finalSpelId = 19682; break;
- case 19697: finalSpelId = 19683; break;
- case 19699: finalSpelId = 19685; break;
- case 19700: finalSpelId = 19686; break;
- case 30646: finalSpelId = 30647; break;
- case 30653: finalSpelId = 30648; break;
- case 30654: finalSpelId = 30652; break;
- case 30099: finalSpelId = 30100; break;
- case 30102: finalSpelId = 30103; break;
- case 30105: finalSpelId = 30104; break;
- }
-
- if(finalSpelId)
- caster->CastSpell(m_target,finalSpelId,true,NULL,this);
- return;
- }
- // Dark Fiend
- if(GetId()==45934)
- {
- // Kill target if dispeled
- if (m_removeMode==AURA_REMOVE_BY_DISPEL)
- m_target->DealDamage(m_target, m_target->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
- return;
- }
-
- // Burning Winds
- if(GetId()==46308) // casted only at creatures at spawn
- {
- m_target->CastSpell(m_target,47287,true,NULL,this);
- return;
- }
- }
-
- // AT APPLY & REMOVE
-
- switch(m_spellProto->SpellFamilyName)
- {
- case SPELLFAMILY_GENERIC:
- {
- // Unstable Power
- if( GetId()==24658 )
- {
- uint32 spellId = 24659;
- if (apply)
- {
- const SpellEntry *spell = sSpellStore.LookupEntry(spellId);
- if (!spell)
- return;
- for (int i=0; i < spell->StackAmount; ++i)
- caster->CastSpell(m_target, spell->Id, true, NULL, NULL, GetCasterGUID());
- return;
- }
- m_target->RemoveAurasDueToSpell(spellId);
- return;
- }
- // Restless Strength
- if( GetId()==24661 )
- {
- uint32 spellId = 24662;
- if (apply)
- {
- const SpellEntry *spell = sSpellStore.LookupEntry(spellId);
- if (!spell)
- return;
- for (int i=0; i < spell->StackAmount; ++i)
- caster->CastSpell(m_target, spell->Id, true, NULL, NULL, GetCasterGUID());
- return;
- }
- m_target->RemoveAurasDueToSpell(spellId);
- return;
- }
- // Victorious
- if(GetId()==32216 && m_target->getClass()==CLASS_WARRIOR)
- {
- m_target->ModifyAuraState(AURA_STATE_WARRIOR_VICTORY_RUSH, apply);
- return;
- }
- //Summon Fire Elemental
- if (GetId() == 40133 && caster)
- {
- Unit *owner = caster->GetOwner();
- if (owner && owner->GetTypeId() == TYPEID_PLAYER)
- {
- if(apply)
- owner->CastSpell(owner,8985,true);
- else
- ((Player*)owner)->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true);
- }
- return;
- }
-
- //Summon Earth Elemental
- if (GetId() == 40132 && caster)
- {
- Unit *owner = caster->GetOwner();
- if (owner && owner->GetTypeId() == TYPEID_PLAYER)
- {
- if(apply)
- owner->CastSpell(owner,19704,true);
- else
- ((Player*)owner)->RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true);
- }
- return;
- }
- break;
- }
- case SPELLFAMILY_MAGE:
- {
- // Hypothermia
- if( GetId()==41425 )
- {
- m_target->ModifyAuraState(AURA_STATE_HYPOTHERMIA,apply);
- return;
- }
- break;
- }
- case SPELLFAMILY_DRUID:
- {
- // Lifebloom
- if ( GetSpellProto()->SpellFamilyFlags & 0x1000000000LL )
- {
- if ( apply )
- {
- if ( caster )
- // prevent double apply bonuses
- 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
- {
- // 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());
- }
- return;
- }
-
- // Predatory Strikes
- if(m_target->GetTypeId()==TYPEID_PLAYER && GetSpellProto()->SpellIconID == 1563)
- {
- ((Player*)m_target)->UpdateAttackPowerAndDamage();
- return;
- }
- // Idol of the Emerald Queen
- if ( GetId() == 34246 && m_target->GetTypeId()==TYPEID_PLAYER )
- {
- if(apply)
- {
- SpellModifier *mod = new SpellModifier;
- mod->op = SPELLMOD_DOT;
- mod->value = m_modifier.m_amount/7;
- mod->type = SPELLMOD_FLAT;
- mod->spellId = GetId();
- mod->effectId = m_effIndex;
- mod->lastAffected = NULL;
- mod->mask = 0x001000000000LL;
- mod->charges = 0;
-
- m_spellmod = mod;
- }
-
- ((Player*)m_target)->AddSpellMod(m_spellmod, apply);
- return;
- }
- break;
- }
- case SPELLFAMILY_HUNTER:
- {
- // Improved Aspect of the Viper
- if( GetId()==38390 && m_target->GetTypeId()==TYPEID_PLAYER )
- {
- if(apply)
- {
- // + effect value for Aspect of the Viper
- SpellModifier *mod = new SpellModifier;
- mod->op = SPELLMOD_EFFECT1;
- mod->value = m_modifier.m_amount;
- mod->type = SPELLMOD_FLAT;
- mod->spellId = GetId();
- mod->effectId = m_effIndex;
- mod->lastAffected = NULL;
- mod->mask = 0x4000000000000LL;
- mod->charges = 0;
-
- m_spellmod = mod;
- }
-
- ((Player*)m_target)->AddSpellMod(m_spellmod, apply);
- return;
- }
- break;
- }
- case SPELLFAMILY_SHAMAN:
- {
- // Improved Weapon Totems
- if( GetSpellProto()->SpellIconID == 57 && m_target->GetTypeId()==TYPEID_PLAYER )
- {
- if(apply)
- {
- SpellModifier *mod = new SpellModifier;
- mod->op = SPELLMOD_EFFECT1;
- mod->value = m_modifier.m_amount;
- mod->type = SPELLMOD_PCT;
- mod->spellId = GetId();
- mod->effectId = m_effIndex;
- mod->lastAffected = NULL;
- switch (m_effIndex)
- {
- case 0:
- mod->mask = 0x00200000000LL; // Windfury Totem
- break;
- case 1:
- mod->mask = 0x00400000000LL; // Flametongue Totem
- break;
- }
- mod->charges = 0;
-
- m_spellmod = mod;
- }
-
- ((Player*)m_target)->AddSpellMod(m_spellmod, apply);
- return;
- }
- break;
- }
- }
-
- // pet auras
- if(PetAura const* petSpell = spellmgr.GetPetAura(GetId()))
- {
- if(apply)
- m_target->AddPetAura(petSpell);
- else
- m_target->RemovePetAura(petSpell);
- return;
- }
-}
-
-void Aura::HandleAuraPeriodicDummy(bool apply, bool Real)
-{
- // spells required only Real aura add/remove
- if(!Real)
- return;
-
- SpellEntry const*spell = GetSpellProto();
- switch( spell->SpellFamilyName)
- {
- case SPELLFAMILY_ROGUE:
- {
- // Master of Subtlety
- if (spell->Id==31666 && !apply && Real)
- {
- m_target->RemoveAurasDueToSpell(31665);
- break;
- }
- break;
- }
- case SPELLFAMILY_HUNTER:
- {
- // Aspect of the Viper
- if (spell->SpellFamilyFlags&0x0004000000000000LL)
- {
- // Update regen on remove
- if (!apply && m_target->GetTypeId() == TYPEID_PLAYER)
- ((Player*)m_target)->UpdateManaRegen();
- break;
- }
- break;
- }
- }
-
- m_isPeriodic = apply;
-}
-
-void Aura::HandleAuraMounted(bool apply, bool Real)
-{
- if(apply)
- {
- CreatureInfo const* ci = objmgr.GetCreatureTemplate(m_modifier.m_miscvalue);
- if(!ci)
- {
- sLog.outErrorDb("AuraMounted: `creature_template`='%u' not found in database (only need it modelid)", m_modifier.m_miscvalue);
- return;
- }
-
- uint32 team = 0;
- if (m_target->GetTypeId()==TYPEID_PLAYER)
- team = ((Player*)m_target)->GetTeam();
-
- uint32 display_id = objmgr.ChooseDisplayId(team,ci);
- CreatureModelInfo const *minfo = objmgr.GetCreatureModelRandomGender(display_id);
- if (minfo)
- display_id = minfo->modelid;
-
- m_target->Mount(display_id);
- }
- else
- {
- m_target->Unmount();
- }
-}
-
-void Aura::HandleAuraWaterWalk(bool apply, bool Real)
-{
- // only at real add/remove aura
- if(!Real)
- return;
-
- WorldPacket data;
- if(apply)
- data.Initialize(SMSG_MOVE_WATER_WALK, 8+4);
- else
- data.Initialize(SMSG_MOVE_LAND_WALK, 8+4);
- data.append(m_target->GetPackGUID());
- data << uint32(0);
- m_target->SendMessageToSet(&data,true);
-}
-
-void Aura::HandleAuraFeatherFall(bool apply, bool Real)
-{
- // only at real add/remove aura
- if(!Real)
- return;
-
- WorldPacket data;
- if(apply)
- data.Initialize(SMSG_MOVE_FEATHER_FALL, 8+4);
- else
- data.Initialize(SMSG_MOVE_NORMAL_FALL, 8+4);
- data.append(m_target->GetPackGUID());
- data << (uint32)0;
- m_target->SendMessageToSet(&data,true);
-}
-
-void Aura::HandleAuraHover(bool apply, bool Real)
-{
- // only at real add/remove aura
- if(!Real)
- return;
-
- WorldPacket data;
- if(apply)
- data.Initialize(SMSG_MOVE_SET_HOVER, 8+4);
- else
- data.Initialize(SMSG_MOVE_UNSET_HOVER, 8+4);
- data.append(m_target->GetPackGUID());
- data << uint32(0);
- m_target->SendMessageToSet(&data,true);
-}
-
-void Aura::HandleWaterBreathing(bool apply, bool Real)
-{
- if(apply)
- m_target->waterbreath = true;
- else if(m_target->GetAurasByType(SPELL_AURA_WATER_BREATHING).empty())
- {
- m_target->waterbreath = false;
-
- // update for enable timer in case not moving target
- if(m_target->GetTypeId()==TYPEID_PLAYER && m_target->IsInWorld())
- {
- ((Player*)m_target)->UpdateUnderwaterState(m_target->GetMap(),m_target->GetPositionX(),m_target->GetPositionY(),m_target->GetPositionZ());
- ((Player*)m_target)->HandleDrowning();
- }
- }
-}
-
-void Aura::HandleAuraModShapeshift(bool apply, bool Real)
-{
- if(!Real)
- return;
-
- uint32 modelid = 0;
- Powers PowerType = POWER_MANA;
- ShapeshiftForm form = ShapeshiftForm(m_modifier.m_miscvalue);
- switch(form)
- {
- case FORM_CAT:
- if(Player::TeamForRace(m_target->getRace())==ALLIANCE)
- modelid = 892;
- else
- modelid = 8571;
- PowerType = POWER_ENERGY;
- break;
- case FORM_TRAVEL:
- modelid = 632;
- break;
- case FORM_AQUA:
- if(Player::TeamForRace(m_target->getRace())==ALLIANCE)
- modelid = 2428;
- else
- modelid = 2428;
- break;
- case FORM_BEAR:
- if(Player::TeamForRace(m_target->getRace())==ALLIANCE)
- modelid = 2281;
- else
- modelid = 2289;
- PowerType = POWER_RAGE;
- break;
- case FORM_GHOUL:
- if(Player::TeamForRace(m_target->getRace())==ALLIANCE)
- modelid = 10045;
- break;
- case FORM_DIREBEAR:
- if(Player::TeamForRace(m_target->getRace())==ALLIANCE)
- modelid = 2281;
- else
- modelid = 2289;
- PowerType = POWER_RAGE;
- break;
- case FORM_CREATUREBEAR:
- modelid = 902;
- break;
- case FORM_GHOSTWOLF:
- modelid = 4613;
- break;
- case FORM_FLIGHT:
- if(Player::TeamForRace(m_target->getRace())==ALLIANCE)
- modelid = 20857;
- else
- modelid = 20872;
- break;
- case FORM_MOONKIN:
- if(Player::TeamForRace(m_target->getRace())==ALLIANCE)
- modelid = 15374;
- else
- modelid = 15375;
- break;
- case FORM_FLIGHT_EPIC:
- if(Player::TeamForRace(m_target->getRace())==ALLIANCE)
- modelid = 21243;
- else
- modelid = 21244;
- break;
- case FORM_AMBIENT:
- case FORM_SHADOW:
- case FORM_STEALTH:
- break;
- case FORM_TREE:
- modelid = 864;
- break;
- case FORM_BATTLESTANCE:
- case FORM_BERSERKERSTANCE:
- case FORM_DEFENSIVESTANCE:
- PowerType = POWER_RAGE;
- break;
- case FORM_SPIRITOFREDEMPTION:
- modelid = 16031;
- break;
- default:
- sLog.outError("Auras: Unknown Shapeshift Type: %u", m_modifier.m_miscvalue);
- }
-
- // remove polymorph before changing display id to keep new display id
- switch ( form )
- {
- case FORM_CAT:
- case FORM_TREE:
- case FORM_TRAVEL:
- case FORM_AQUA:
- case FORM_BEAR:
- case FORM_DIREBEAR:
- case FORM_FLIGHT_EPIC:
- case FORM_FLIGHT:
- case FORM_MOONKIN:
- // remove movement affects
- m_target->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT);
- m_target->RemoveSpellsCausingAura(SPELL_AURA_MOD_DECREASE_SPEED);
-
- // and polymorphic affects
- if(m_target->IsPolymorphed())
- m_target->RemoveAurasDueToSpell(m_target->getTransForm());
- break;
- default:
- break;
- }
-
- if(apply)
- {
- // remove other shapeshift before applying a new one
- if(m_target->m_ShapeShiftFormSpellId)
- {
- m_target->RemoveAurasDueToSpell(m_target->m_ShapeShiftFormSpellId,this);
- }
-
- m_target->SetByteValue(UNIT_FIELD_BYTES_2, 3, form);
-
- if(modelid > 0)
- {
- m_target->SetDisplayId(modelid);
- }
-
- if(PowerType != POWER_MANA)
- {
- // reset power to default values only at power change
- if(m_target->getPowerType()!=PowerType)
- m_target->setPowerType(PowerType);
-
- switch(form)
- {
- case FORM_CAT:
- case FORM_BEAR:
- case FORM_DIREBEAR:
- {
- // get furor proc chance
- uint32 FurorChance = 0;
- Unit::AuraList const& mDummy = m_target->GetAurasByType(SPELL_AURA_DUMMY);
- for(Unit::AuraList::const_iterator i = mDummy.begin(); i != mDummy.end(); ++i)
- {
- if ((*i)->GetSpellProto()->SpellIconID == 238)
- {
- FurorChance = (*i)->GetModifier()->m_amount;
- break;
- }
- }
-
- if (m_modifier.m_miscvalue == FORM_CAT)
- {
- m_target->SetPower(POWER_ENERGY,0);
- if(urand(1,100) <= FurorChance)
- {
- m_target->CastSpell(m_target,17099,true,NULL,this);
- }
- }
- else
- {
- m_target->SetPower(POWER_RAGE,0);
- if(urand(1,100) <= FurorChance)
- {
- m_target->CastSpell(m_target,17057,true,NULL,this);
- }
- }
- break;
- }
- case FORM_BATTLESTANCE:
- case FORM_DEFENSIVESTANCE:
- case FORM_BERSERKERSTANCE:
- {
- uint32 Rage_val = 0;
- // Stance mastery + Tactical mastery (both passive, and last have aura only in defense stance, but need apply at any stance switch)
- if(m_target->GetTypeId() == TYPEID_PLAYER)
- {
- PlayerSpellMap const& sp_list = ((Player *)m_target)->GetSpellMap();
- for (PlayerSpellMap::const_iterator itr = sp_list.begin(); itr != sp_list.end(); ++itr)
- {
- if(itr->second->state == PLAYERSPELL_REMOVED) continue;
- SpellEntry const *spellInfo = sSpellStore.LookupEntry(itr->first);
- if (spellInfo && spellInfo->SpellFamilyName == SPELLFAMILY_WARRIOR && spellInfo->SpellIconID == 139)
- Rage_val += m_target->CalculateSpellDamage(spellInfo,0,spellInfo->EffectBasePoints[0],m_target) * 10;
- }
- }
-
- if (m_target->GetPower(POWER_RAGE) > Rage_val)
- m_target->SetPower(POWER_RAGE,Rage_val);
- break;
- }
- default:
- break;
- }
- }
-
- m_target->m_ShapeShiftFormSpellId = GetId();
- m_target->m_form = form;
- }
- else
- {
- m_target->SetDisplayId(m_target->GetNativeDisplayId());
- m_target->SetByteValue(UNIT_FIELD_BYTES_2, 3, FORM_NONE);
- if(m_target->getClass() == CLASS_DRUID)
- m_target->setPowerType(POWER_MANA);
- m_target->m_ShapeShiftFormSpellId = 0;
- m_target->m_form = FORM_NONE;
-
- switch(form)
- {
- // Nordrassil Harness - bonus
- case FORM_BEAR:
- case FORM_DIREBEAR:
- case FORM_CAT:
- {
- if(Aura* dummy = m_target->GetDummyAura(37315) )
- m_target->CastSpell(m_target,37316,true,NULL,dummy);
- break;
- }
- // Nordrassil Regalia - bonus
- case FORM_MOONKIN:
- {
- if(Aura* dummy = m_target->GetDummyAura(37324) )
- m_target->CastSpell(m_target,37325,true,NULL,dummy);
- break;
- }
- }
- }
-
- // adding/removing linked auras
- // add/remove the shapeshift aura's boosts
- HandleShapeshiftBoosts(apply);
-
- if(m_target->GetTypeId()==TYPEID_PLAYER)
- ((Player*)m_target)->InitDataForForm();
-}
-
-void Aura::HandleAuraTransform(bool apply, bool Real)
-{
- if (apply)
- {
- // special case (spell specific functionality)
- if(m_modifier.m_miscvalue==0)
- {
- // player applied only
- if(m_target->GetTypeId()!=TYPEID_PLAYER)
- return;
-
- switch(GetId())
- {
- // Orb of Deception
- case 16739:
- {
- uint32 orb_model = m_target->GetNativeDisplayId();
- switch(orb_model)
- {
- // Troll Female
- case 1479: m_target->SetDisplayId(10134); break;
- // Troll Male
- case 1478: m_target->SetDisplayId(10135); break;
- // Tauren Male
- case 59: m_target->SetDisplayId(10136); break;
- // Human Male
- case 49: m_target->SetDisplayId(10137); break;
- // Human Female
- case 50: m_target->SetDisplayId(10138); break;
- // Orc Male
- case 51: m_target->SetDisplayId(10139); break;
- // Orc Female
- case 52: m_target->SetDisplayId(10140); break;
- // Dwarf Male
- case 53: m_target->SetDisplayId(10141); break;
- // Dwarf Female
- case 54: m_target->SetDisplayId(10142); break;
- // NightElf Male
- case 55: m_target->SetDisplayId(10143); break;
- // NightElf Female
- case 56: m_target->SetDisplayId(10144); break;
- // Undead Female
- case 58: m_target->SetDisplayId(10145); break;
- // Undead Male
- case 57: m_target->SetDisplayId(10146); break;
- // Tauren Female
- case 60: m_target->SetDisplayId(10147); break;
- // Gnome Male
- case 1563: m_target->SetDisplayId(10148); break;
- // Gnome Female
- case 1564: m_target->SetDisplayId(10149); break;
- // BloodElf Female
- case 15475: m_target->SetDisplayId(17830); break;
- // BloodElf Male
- case 15476: m_target->SetDisplayId(17829); break;
- // Dranei Female
- case 16126: m_target->SetDisplayId(17828); break;
- // Dranei Male
- case 16125: m_target->SetDisplayId(17827); break;
- default: break;
- }
- break;
- }
- // Murloc costume
- case 42365: m_target->SetDisplayId(21723); break;
- default: break;
- }
- }
- else
- {
- CreatureInfo const * ci = objmgr.GetCreatureTemplate(m_modifier.m_miscvalue);
- if(!ci)
- {
- //pig pink ^_^
- m_target->SetDisplayId(16358);
- sLog.outError("Auras: unknown creature id = %d (only need its modelid) Form Spell Aura Transform in Spell ID = %d", m_modifier.m_miscvalue, GetId());
- }
- else
- {
- // Will use the default model here
- m_target->SetDisplayId(ci->DisplayID_A);
-
- // Dragonmaw Illusion (set mount model also)
- if(GetId()==42016 && m_target->GetMountID() && !m_target->GetAurasByType(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED).empty())
- m_target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID,16314);
- }
- m_target->setTransForm(GetId());
- }
-
- // polymorph case
- if( Real && m_target->GetTypeId() == TYPEID_PLAYER && m_target->IsPolymorphed())
- {
- // for players, start regeneration after 1s (in polymorph fast regeneration case)
- // only if caster is Player (after patch 2.4.2)
- if(IS_PLAYER_GUID(GetCasterGUID()) )
- ((Player*)m_target)->setRegenTimer(1000);
-
- //dismount polymorphed target (after patch 2.4.2)
- if (m_target->IsMounted())
- m_target->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED);
- }
- }
- else
- {
- Unit::AuraList const& otherTransforms = m_target->GetAurasByType(SPELL_AURA_TRANSFORM);
- if(otherTransforms.empty())
- {
- m_target->SetDisplayId(m_target->GetNativeDisplayId());
- m_target->setTransForm(0);
- }
- else
- {
- // look for other transform auras
- Aura* handledAura = *otherTransforms.begin();
- for(Unit::AuraList::const_iterator i = otherTransforms.begin();i != otherTransforms.end(); ++i)
- {
- // negative auras are prefered
- if(!IsPositiveSpell((*i)->GetSpellProto()->Id))
- {
- handledAura = *i;
- break;
- }
- }
- handledAura->ApplyModifier(true);
- }
-
- // Dragonmaw Illusion (restore mount model)
- if(GetId()==42016 && m_target->GetMountID()==16314)
- {
- if(!m_target->GetAurasByType(SPELL_AURA_MOUNTED).empty())
- {
- uint32 cr_id = m_target->GetAurasByType(SPELL_AURA_MOUNTED).front()->GetModifier()->m_miscvalue;
- if(CreatureInfo const* ci = objmgr.GetCreatureTemplate(cr_id))
- {
- uint32 team = 0;
- if (m_target->GetTypeId()==TYPEID_PLAYER)
- team = ((Player*)m_target)->GetTeam();
-
- uint32 display_id = objmgr.ChooseDisplayId(team,ci);
- CreatureModelInfo const *minfo = objmgr.GetCreatureModelRandomGender(display_id);
- if (minfo)
- display_id = minfo->modelid;
-
- m_target->SetUInt32Value(UNIT_FIELD_MOUNTDISPLAYID,display_id);
- }
- }
- }
- }
-}
-
-void Aura::HandleForceReaction(bool apply, bool Real)
-{
- if(m_target->GetTypeId() != TYPEID_PLAYER)
- return;
-
- if(!Real)
- return;
-
- Player* player = (Player*)m_target;
-
- uint32 faction_id = m_modifier.m_miscvalue;
- uint32 faction_rank = m_modifier.m_amount;
-
- if(apply)
- player->m_forcedReactions[faction_id] = ReputationRank(faction_rank);
- else
- player->m_forcedReactions.erase(faction_id);
-
- WorldPacket data;
- data.Initialize(SMSG_SET_FORCED_REACTIONS, 4+player->m_forcedReactions.size()*(4+4));
- data << uint32(player->m_forcedReactions.size());
- for(ForcedReactions::const_iterator itr = player->m_forcedReactions.begin(); itr != player->m_forcedReactions.end(); ++itr)
- {
- data << uint32(itr->first); // faction_id (Faction.dbc)
- data << uint32(itr->second); // reputation rank
- }
- player->SendDirectMessage(&data);
-}
-
-void Aura::HandleAuraModSkill(bool apply, bool Real)
-{
- if(m_target->GetTypeId() != TYPEID_PLAYER)
- return;
-
- uint32 prot=GetSpellProto()->EffectMiscValue[m_effIndex];
- int32 points = GetModifier()->m_amount;
-
- ((Player*)m_target)->ModifySkillBonus(prot,(apply ? points: -points),m_modifier.m_auraname==SPELL_AURA_MOD_SKILL_TALENT);
- if(prot == SKILL_DEFENSE)
- ((Player*)m_target)->UpdateDefenseBonusesMod();
-}
-
-void Aura::HandleChannelDeathItem(bool apply, bool Real)
-{
- if(Real && !apply)
- {
- Unit* caster = GetCaster();
- Unit* victim = GetTarget();
- if(!caster || caster->GetTypeId() != TYPEID_PLAYER || !victim || m_removeMode!=AURA_REMOVE_BY_DEATH)
- return;
-
- SpellEntry const *spellInfo = GetSpellProto();
- if(spellInfo->EffectItemType[m_effIndex] == 0)
- return;
-
- // Soul Shard only from non-grey units
- if( spellInfo->EffectItemType[m_effIndex] == 6265 &&
- (victim->getLevel() <= MaNGOS::XP::GetGrayLevel(caster->getLevel()) ||
- victim->GetTypeId()==TYPEID_UNIT && !((Player*)caster)->isAllowedToLoot((Creature*)victim)) )
- return;
- ItemPosCountVec dest;
- uint8 msg = ((Player*)caster)->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, spellInfo->EffectItemType[m_effIndex], 1 );
- if( msg != EQUIP_ERR_OK )
- {
- ((Player*)caster)->SendEquipError( msg, NULL, NULL );
- return;
- }
-
- Item* newitem = ((Player*)caster)->StoreNewItem(dest, spellInfo->EffectItemType[m_effIndex], true);
- ((Player*)caster)->SendNewItem(newitem, 1, true, false);
- }
-}
-
-void Aura::HandleBindSight(bool apply, bool Real)
-{
- Unit* caster = GetCaster();
- if(!caster || caster->GetTypeId() != TYPEID_PLAYER)
- return;
-
- caster->SetUInt64Value(PLAYER_FARSIGHT,apply ? m_target->GetGUID() : 0);
-}
-
-void Aura::HandleFarSight(bool apply, bool Real)
-{
- Unit* caster = GetCaster();
- if(!caster || caster->GetTypeId() != TYPEID_PLAYER)
- return;
-
- caster->SetUInt64Value(PLAYER_FARSIGHT,apply ? m_modifier.m_miscvalue : 0);
-}
-
-void Aura::HandleAuraTrackCreatures(bool apply, bool Real)
-{
- if(m_target->GetTypeId()!=TYPEID_PLAYER)
- return;
-
- if(apply)
- m_target->RemoveNoStackAurasDueToAura(this);
- m_target->SetUInt32Value(PLAYER_TRACK_CREATURES, apply ? ((uint32)1)<<(m_modifier.m_miscvalue-1) : 0 );
-}
-
-void Aura::HandleAuraTrackResources(bool apply, bool Real)
-{
- if(m_target->GetTypeId()!=TYPEID_PLAYER)
- return;
-
- if(apply)
- m_target->RemoveNoStackAurasDueToAura(this);
- m_target->SetUInt32Value(PLAYER_TRACK_RESOURCES, apply ? ((uint32)1)<<(m_modifier.m_miscvalue-1): 0 );
-}
-
-void Aura::HandleAuraTrackStealthed(bool apply, bool Real)
-{
- if(m_target->GetTypeId()!=TYPEID_PLAYER)
- return;
-
- if(apply)
- m_target->RemoveNoStackAurasDueToAura(this);
-
- m_target->ApplyModFlag(PLAYER_FIELD_BYTES,PLAYER_FIELD_BYTE_TRACK_STEALTHED,apply);
-}
-
-void Aura::HandleAuraModScale(bool apply, bool Real)
-{
- m_target->ApplyPercentModFloatValue(OBJECT_FIELD_SCALE_X,m_modifier.m_amount,apply);
-}
-
-void Aura::HandleModPossess(bool apply, bool Real)
-{
- if(!Real)
- return;
-
- if(m_target->getLevel() > m_modifier.m_amount)
- return;
-
- // not possess yourself
- if(GetCasterGUID() == m_target->GetGUID())
- return;
-
- Unit* caster = GetCaster();
- if(!caster)
- return;
-
- if( apply )
- {
- m_target->SetCharmerGUID(GetCasterGUID());
- m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,caster->getFaction());
- caster->SetCharm(m_target);
-
- m_target->CombatStop();
- m_target->DeleteThreatList();
- if(m_target->GetTypeId() == TYPEID_UNIT)
- {
- m_target->StopMoving();
- m_target->GetMotionMaster()->Clear();
- m_target->GetMotionMaster()->MoveIdle();
- CharmInfo *charmInfo = ((Creature*)m_target)->InitCharmInfo(m_target);
- charmInfo->InitPossessCreateSpells();
- }
-
- if(caster->GetTypeId() == TYPEID_PLAYER)
- {
- ((Player*)caster)->PossessSpellInitialize();
- }
- }
- else
- {
- m_target->SetCharmerGUID(0);
-
- if(m_target->GetTypeId() == TYPEID_PLAYER)
- {
- ((Player*)m_target)->setFactionForRace(m_target->getRace());
- }
- else if(m_target->GetTypeId() == TYPEID_UNIT)
- {
- CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo();
- m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,cinfo->faction_A);
- }
-
- caster->SetCharm(0);
-
- if(caster->GetTypeId() == TYPEID_PLAYER)
- {
- WorldPacket data(SMSG_PET_SPELLS, 8);
- data << uint64(0);
- ((Player*)caster)->GetSession()->SendPacket(&data);
- }
- if(m_target->GetTypeId() == TYPEID_UNIT)
- {
- ((Creature*)m_target)->AIM_Initialize();
-
- if (((Creature*)m_target)->AI())
- ((Creature*)m_target)->AI()->AttackStart(caster);
- }
- }
- if(caster->GetTypeId() == TYPEID_PLAYER)
- caster->SetUInt64Value(PLAYER_FARSIGHT,apply ? m_target->GetGUID() : 0);
-}
-
-void Aura::HandleModPossessPet(bool apply, bool Real)
-{
- if(!Real)
- return;
-
- Unit* caster = GetCaster();
- if(!caster || caster->GetTypeId() != TYPEID_PLAYER)
- return;
- if(caster->GetPet() != m_target)
- return;
-
- if(apply)
- {
- caster->SetUInt64Value(PLAYER_FARSIGHT, m_target->GetGUID());
- m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN5);
- }
- else
- {
- caster->SetUInt64Value(PLAYER_FARSIGHT, 0);
- m_target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN5);
- }
-}
-
-void Aura::HandleModCharm(bool apply, bool Real)
-{
- if(!Real)
- return;
-
- // not charm yourself
- if(GetCasterGUID() == m_target->GetGUID())
- return;
-
- Unit* caster = GetCaster();
- if(!caster)
- return;
-
- if(int32(m_target->getLevel()) <= m_modifier.m_amount)
- {
- if( apply )
- {
- m_target->SetCharmerGUID(GetCasterGUID());
- m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,caster->getFaction());
- m_target->CastStop(m_target==caster ? GetId() : 0);
- caster->SetCharm(m_target);
-
- m_target->CombatStop();
- m_target->DeleteThreatList();
-
- if(m_target->GetTypeId() == TYPEID_UNIT)
- {
- ((Creature*)m_target)->AIM_Initialize();
- CharmInfo *charmInfo = ((Creature*)m_target)->InitCharmInfo(m_target);
- charmInfo->InitCharmCreateSpells();
- charmInfo->SetReactState( REACT_DEFENSIVE );
-
- if(caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK)
- {
- CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo();
- if(cinfo && cinfo->type == CREATURE_TYPE_DEMON)
- {
- //to prevent client crash
- m_target->SetFlag(UNIT_FIELD_BYTES_0, 2048);
- //just to enable stat window
- charmInfo->SetPetNumber(objmgr.GeneratePetNumber(), true);
- //if charmed two demons the same session, the 2nd gets the 1st one's name
- m_target->SetUInt32Value(UNIT_FIELD_PET_NAME_TIMESTAMP, time(NULL));
- }
- }
- }
-
- if(caster->GetTypeId() == TYPEID_PLAYER)
- {
- ((Player*)caster)->CharmSpellInitialize();
- }
- }
- else
- {
- m_target->SetCharmerGUID(0);
-
- if(m_target->GetTypeId() == TYPEID_PLAYER)
- {
- ((Player*)m_target)->setFactionForRace(m_target->getRace());
- }
- else
- {
- CreatureInfo const *cinfo = ((Creature*)m_target)->GetCreatureInfo();
-
- // restore faction
- if(((Creature*)m_target)->isPet())
- {
- if(Unit* owner = m_target->GetOwner())
- m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,owner->getFaction());
- else if(cinfo)
- m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,cinfo->faction_A);
- }
- else if(cinfo) // normal creature
- m_target->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE,cinfo->faction_A);
-
- // restore UNIT_FIELD_BYTES_0
- if(cinfo && caster->GetTypeId() == TYPEID_PLAYER && caster->getClass() == CLASS_WARLOCK && cinfo->type == CREATURE_TYPE_DEMON)
- {
- CreatureDataAddon const *cainfo = ((Creature*)m_target)->GetCreatureAddon();
- if(cainfo && cainfo->bytes0 != 0)
- m_target->SetUInt32Value(UNIT_FIELD_BYTES_0, cainfo->bytes0);
- else
- m_target->RemoveFlag(UNIT_FIELD_BYTES_0, 2048);
-
- if(m_target->GetCharmInfo())
- m_target->GetCharmInfo()->SetPetNumber(0, true);
- else
- sLog.outError("Aura::HandleModCharm: target="I64FMTD" with typeid=%d has a charm aura but no charm info!", m_target->GetGUID(), m_target->GetTypeId());
- }
- }
-
- caster->SetCharm(0);
-
- if(caster->GetTypeId() == TYPEID_PLAYER)
- {
- WorldPacket data(SMSG_PET_SPELLS, 8);
- data << uint64(0);
- ((Player*)caster)->GetSession()->SendPacket(&data);
- }
- if(m_target->GetTypeId() == TYPEID_UNIT)
- {
- ((Creature*)m_target)->AIM_Initialize();
- if (((Creature*)m_target)->AI())
- ((Creature*)m_target)->AI()->AttackStart(caster);
- }
- }
- }
-}
-
-void Aura::HandleModConfuse(bool apply, bool Real)
-{
- if(!Real)
- return;
-
- m_target->SetConfused(apply, GetCasterGUID(), GetId());
-}
-
-void Aura::HandleModFear(bool apply, bool Real)
-{
- if (!Real)
- return;
-
- m_target->SetFeared(apply, GetCasterGUID(), GetId());
-}
-
-void Aura::HandleFeignDeath(bool apply, bool Real)
-{
- if(!Real)
- return;
-
- if(m_target->GetTypeId() != TYPEID_PLAYER)
- return;
-
- if( apply )
- {
- /*
- WorldPacket data(SMSG_FEIGN_DEATH_RESISTED, 9);
- data<GetGUID();
- data<SendMessageToSet(&data,true);
- */
- // blizz like 2.0.x
- m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_UNKNOWN6);
- // blizz like 2.0.x
- m_target->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_FEIGN_DEATH);
- // blizz like 2.0.x
- m_target->SetFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_DEAD);
-
- m_target->addUnitState(UNIT_STAT_DIED);
- m_target->CombatStop();
-
- // prevent interrupt message
- if(m_caster_guid==m_target->GetGUID() && m_target->m_currentSpells[CURRENT_GENERIC_SPELL])
- m_target->m_currentSpells[CURRENT_GENERIC_SPELL]->finish();
- m_target->InterruptNonMeleeSpells(true);
- m_target->getHostilRefManager().deleteReferences();
- }
- else
- {
- /*
- WorldPacket data(SMSG_FEIGN_DEATH_RESISTED, 9);
- data<