[7622] Added creatureAI with related database tables. Author: AlexDereka

*Note: three tables are renamed.

--HG--
branch : trunk
This commit is contained in:
megamage
2009-04-07 19:38:09 -05:00
parent 24dede78d3
commit f59c4debf6
28 changed files with 3190 additions and 2490 deletions

View File

@@ -22,7 +22,7 @@
DROP TABLE IF EXISTS `db_version`;
CREATE TABLE `db_version` (
`version` varchar(120) default NULL,
`required_7616_02_mangos_command` bit(1) default NULL
`required_7622_03_mangos_creature_ai_texts` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
--
@@ -919,6 +919,105 @@ LOCK TABLES `disenchant_loot_template` WRITE;
/*!40000 ALTER TABLE `disenchant_loot_template` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `creature_ai_scripts`
--
DROP TABLE IF EXISTS `creature_ai_scripts`;
CREATE TABLE `creature_ai_scripts` (
`id` int(11) unsigned NOT NULL COMMENT 'Identifier' AUTO_INCREMENT,
`creature_id` int(11) unsigned NOT NULL default '0' COMMENT 'Creature Template Identifier',
`event_type` tinyint(5) unsigned NOT NULL default '0' COMMENT 'Event Type',
`event_inverse_phase_mask` int(11) signed NOT NULL default '0' COMMENT 'Mask which phases this event will not trigger in',
`event_chance` int(3) unsigned NOT NULL default '100',
`event_flags` int(3) unsigned NOT NULL default '0',
`event_param1` int(11) signed NOT NULL default '0',
`event_param2` int(11) signed NOT NULL default '0',
`event_param3` int(11) signed NOT NULL default '0',
`event_param4` int(11) signed NOT NULL default '0',
`action1_type` tinyint(5) unsigned NOT NULL default '0' COMMENT 'Action Type',
`action1_param1` int(11) signed NOT NULL default '0',
`action1_param2` int(11) signed NOT NULL default '0',
`action1_param3` int(11) signed NOT NULL default '0',
`action2_type` tinyint(5) unsigned NOT NULL default '0' COMMENT 'Action Type',
`action2_param1` int(11) signed NOT NULL default '0',
`action2_param2` int(11) signed NOT NULL default '0',
`action2_param3` int(11) signed NOT NULL default '0',
`action3_type` tinyint(5) unsigned NOT NULL default '0' COMMENT 'Action Type',
`action3_param1` int(11) signed NOT NULL default '0',
`action3_param2` int(11) signed NOT NULL default '0',
`action3_param3` int(11) signed NOT NULL default '0',
`comment` varchar(255) NOT NULL default '' COMMENT 'Event Comment',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='EventAI Scripts';
--
-- Dumping data for table `creature_ai_scripts`
--
LOCK TABLES `creature_ai_scripts` WRITE;
/*!40000 ALTER TABLE `creature_ai_scripts` DISABLE KEYS */;
/*!40000 ALTER TABLE `creature_ai_scripts` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `creature_ai_summons`
--
DROP TABLE IF EXISTS `creature_ai_summons`;
CREATE TABLE `creature_ai_summons` (
`id` int(11) unsigned NOT NULL COMMENT 'Location Identifier' AUTO_INCREMENT,
`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',
`spawntimesecs` int(11) unsigned NOT NULL default '120',
`comment` varchar(255) NOT NULL default '' COMMENT 'Summon Comment',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='EventAI Summoning Locations';
--
-- Dumping data for table `creature_ai_summons`
--
LOCK TABLES `creature_ai_summons` WRITE;
/*!40000 ALTER TABLE `creature_ai_summons` DISABLE KEYS */;
/*!40000 ALTER TABLE `creature_ai_summons` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `creature_ai_texts`
--
DROP TABLE IF EXISTS `creature_ai_texts`;
CREATE TABLE `creature_ai_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(3) unsigned NOT NULL DEFAULT '0',
`language` tinyint(3) unsigned NOT NULL DEFAULT '0',
`emote` tinyint(3) unsigned NOT NULL DEFAULT '0',
`comment` text,
PRIMARY KEY (`entry`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Script Texts';
--
-- Dumping data for table `creature_ai_texts`
--
LOCK TABLES `creature_ai_texts` WRITE;
/*!40000 ALTER TABLE `creature_ai_texts` DISABLE KEYS */;
/*!40000 ALTER TABLE `creature_ai_texts` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `event_scripts`
--

View File

@@ -0,0 +1,30 @@
ALTER TABLE db_version CHANGE COLUMN required_7616_02_mangos_command required_7622_01_mangos_creature_ai_scripts bit;
DROP TABLE IF EXISTS `creature_ai_scripts`;
CREATE TABLE `creature_ai_scripts` (
`id` int(11) unsigned NOT NULL COMMENT 'Identifier' AUTO_INCREMENT,
`creature_id` int(11) unsigned NOT NULL default '0' COMMENT 'Creature Template Identifier',
`event_type` tinyint(5) unsigned NOT NULL default '0' COMMENT 'Event Type',
`event_inverse_phase_mask` int(11) signed NOT NULL default '0' COMMENT 'Mask which phases this event will not trigger in',
`event_chance` int(3) unsigned NOT NULL default '100',
`event_flags` int(3) unsigned NOT NULL default '0',
`event_param1` int(11) signed NOT NULL default '0',
`event_param2` int(11) signed NOT NULL default '0',
`event_param3` int(11) signed NOT NULL default '0',
`event_param4` int(11) signed NOT NULL default '0',
`action1_type` tinyint(5) unsigned NOT NULL default '0' COMMENT 'Action Type',
`action1_param1` int(11) signed NOT NULL default '0',
`action1_param2` int(11) signed NOT NULL default '0',
`action1_param3` int(11) signed NOT NULL default '0',
`action2_type` tinyint(5) unsigned NOT NULL default '0' COMMENT 'Action Type',
`action2_param1` int(11) signed NOT NULL default '0',
`action2_param2` int(11) signed NOT NULL default '0',
`action2_param3` int(11) signed NOT NULL default '0',
`action3_type` tinyint(5) unsigned NOT NULL default '0' COMMENT 'Action Type',
`action3_param1` int(11) signed NOT NULL default '0',
`action3_param2` int(11) signed NOT NULL default '0',
`action3_param3` int(11) signed NOT NULL default '0',
`comment` varchar(255) NOT NULL default '' COMMENT 'Event Comment',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='EventAI Scripts';

View File

@@ -0,0 +1,14 @@
ALTER TABLE db_version CHANGE COLUMN required_7622_01_mangos_creature_ai_scripts required_7622_02_mangos_creature_ai_summons bit;
DROP TABLE IF EXISTS `creature_ai_summons`;
CREATE TABLE `creature_ai_summons` (
`id` int(11) unsigned NOT NULL COMMENT 'Location Identifier' AUTO_INCREMENT,
`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',
`spawntimesecs` int(11) unsigned NOT NULL default '120',
`comment` varchar(255) NOT NULL default '' COMMENT 'Summon Comment',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='EventAI Summoning Locations';

View File

@@ -0,0 +1,22 @@
ALTER TABLE db_version CHANGE COLUMN required_7622_02_mangos_creature_ai_summons required_7622_03_mangos_creature_ai_texts bit;
DROP TABLE IF EXISTS `creature_ai_texts`;
CREATE TABLE `creature_ai_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(3) unsigned NOT NULL DEFAULT '0',
`language` tinyint(3) unsigned NOT NULL DEFAULT '0',
`emote` tinyint(3) unsigned NOT NULL DEFAULT '0',
`comment` text,
PRIMARY KEY (`entry`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Script Texts';

View File

@@ -8,7 +8,6 @@
#include "DBCStores.h"
#include "ObjectMgr.h"
#include "ProgressBar.h"
#include "scripts/creature/mob_event_ai.h"
#define _FULLVERSION "TrinityScript"
@@ -31,18 +30,6 @@ struct StringTextData
uint32 Emote;
};
// 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,
CHAT_TYPE_ZONE_YELL = 6
};
#define TEXT_SOURCE_RANGE -1000000 //the amount of entries each text source has available
// Text Maps
@@ -51,14 +38,6 @@ UNORDERED_MAP<int32, StringTextData> TextMap;
// Waypoint lists
std::list<PointMovement> PointMovementList;
//Event AI structure. Used exclusivly by mob_event_ai.cpp (60 bytes each)
UNORDERED_MAP<uint32, std::vector<EventAI_Event> > EventAI_Event_Map;
//Event AI summon structure. Used exclusivly by mob_event_ai.cpp.
UNORDERED_MAP<uint32, EventAI_Summon> EventAI_Summon_Map;
uint32 EAI_ErrorLevel;
void FillSpellSummary();
void LoadOverridenSQLData();
void LoadOverridenDBCData();
@@ -74,7 +53,6 @@ extern void AddSC_boss_taerar();
extern void AddSC_boss_ysondre();
// -- Creature --
extern void AddSC_mob_event();
extern void AddSC_generic_creature();
// -- Custom --
@@ -916,613 +894,6 @@ void LoadDatabase()
outstring_log(">> Loaded 0 Script Waypoints. DB table `script_waypoint` is empty.");
}
//Gather additional data for EventAI
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.");
}
//Drop Existing EventAI List
EventAI_Event_Map.clear();
uint64 uiEAICreatureCount = 0;
result = TScriptDB.PQuery("SELECT COUNT(creature_id) FROM eventai_scripts GROUP BY creature_id");
if (result)
{
uiEAICreatureCount = result->GetRowCount();
delete result;
}
outstring_log("SD2: Loading EventAI scripts for %u creature(s)...", uiEAICreatureCount);
//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");
outstring_log("SD2: Loading EventAI scripts for %u creature(s)...", uiEAICreatureCount);
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();
uint32 creature_id = temp.creature_id;
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();
//Creature does not exist in database
if (!GetCreatureTemplateStore(temp.creature_id))
{
error_db_log("TSCR: Event %u has script for non-existing creature.", i);
continue;
}
//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);
continue;
}
//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_OOC_LOS:
{
if (temp.event_param2 > VISIBLE_RANGE || temp.event_param2 <= 0)
{
error_db_log("SD2: Creature %u are using event(%u), but param2 (MaxAllowedRange=%u) are not within allowed range.", temp.creature_id, i, temp.event_param2);
temp.event_param2 = VISIBLE_RANGE;
}
if (temp.event_param3 == 0 && temp.event_param4 == 0 && temp.event_flags & EFLAG_REPEATABLE)
{
error_db_log("SD2: Creature %u are using event(%u) with EFLAG_REPEATABLE, but param3(RepeatMin) and param4(RepeatMax) are 0. Repeatable disabled.", temp.creature_id, i);
temp.event_flags &= ~EFLAG_REPEATABLE;
}
if (temp.event_param4 < temp.event_param3)
error_db_log("SD2: 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_FRIENDLY_HP:
case EVENT_T_FRIENDLY_IS_CC:
{
if (temp.event_param4 < temp.event_param3)
error_db_log("SD2: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i);
}
break;
case EVENT_T_FRIENDLY_MISSING_BUFF:
{
if (!GetSpellStore()->LookupEntry(temp.event_param1))
{
error_db_log("SD2: Creature %u has non-existant SpellID(%u) defined in event %u.", temp.creature_id, temp.event_param1, i);
continue;
}
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_SUMMONED_UNIT:
{
if (!GetCreatureTemplateStore(temp.event_param1))
{
error_db_log("SD2: Creature %u has non-existant creature entry (%u) defined in event %u.", temp.creature_id, temp.event_param1, i);
continue;
}
}
break;
case EVENT_T_AGGRO:
case EVENT_T_DEATH:
case EVENT_T_EVADE:
case EVENT_T_SPAWNED:
case EVENT_T_REACHED_HOME:
{
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;
case EVENT_T_RECEIVE_EMOTE:
{
//no good way to check for valid textEmote (enum TextEmotes)
switch(temp.event_param2)
{
case CONDITION_AURA:
if (!GetSpellStore()->LookupEntry(temp.event_param3))
{
error_db_log("SD2: Creature %u using event %u: param3 (CondValue1: %u) are not valid.",temp.creature_id, i, temp.event_param3);
continue;
}
break;
case CONDITION_TEAM:
if (temp.event_param3 != HORDE || temp.event_param3 != ALLIANCE)
{
error_db_log("SD2: Creature %u using event %u: param3 (CondValue1: %u) are not valid.",temp.creature_id, i, temp.event_param3);
continue;
}
break;
case CONDITION_QUESTREWARDED:
case CONDITION_QUESTTAKEN:
if (!GetQuestTemplateStore(temp.event_param3))
{
error_db_log("SD2: Creature %u using event %u: param3 (CondValue1: %u) are not valid.",temp.creature_id, i, temp.event_param3);
continue;
}
break;
case CONDITION_ACTIVE_EVENT:
if (temp.event_param3 !=
(HOLIDAY_FIREWORKS_SPECTACULAR | HOLIDAY_FEAST_OF_WINTER_VEIL | HOLIDAY_NOBLEGARDEN |
HOLIDAY_CHILDRENS_WEEK | HOLIDAY_CALL_TO_ARMS_AV | HOLIDAY_CALL_TO_ARMS_WG |
HOLIDAY_CALL_TO_ARMS_AB | HOLIDAY_FISHING_EXTRAVAGANZA | HOLIDAY_HARVEST_FESTIVAL |
HOLIDAY_HALLOWS_END | HOLIDAY_LUNAR_FESTIVAL | HOLIDAY_LOVE_IS_IN_THE_AIR |
HOLIDAY_FIRE_FESTIVAL | HOLIDAY_CALL_TO_ARMS_ES | HOLIDAY_BREWFEST |
HOLIDAY_DARKMOON_FAIRE_ELWYNN | HOLIDAY_DARKMOON_FAIRE_THUNDER | HOLIDAY_DARKMOON_FAIRE_SHATTRATH |
HOLIDAY_CALL_TO_ARMS_SA | HOLIDAY_WOTLK_LAUNCH))
{
error_db_log("SD2: Creature %u using event %u: param3 (CondValue1: %u) are not valid.",temp.creature_id, i, temp.event_param3);
continue;
}
break;
case CONDITION_REPUTATION_RANK:
if (!temp.event_param3)
{
error_db_log("SD2: Creature %u using event %u: param3 (CondValue1: %u) are missing.",temp.creature_id, i, temp.event_param3);
continue;
}
if (temp.event_param4 > REP_EXALTED)
{
error_db_log("SD2: Creature %u using event %u: param4 (CondValue2: %u) are not valid.",temp.creature_id, i, temp.event_param4);
continue;
}
break;
case CONDITION_ITEM:
case CONDITION_ITEM_EQUIPPED:
case CONDITION_SKILL:
if (!temp.event_param3)
{
error_db_log("SD2: Creature %u using event %u: param3 (CondValue1: %u) are missing.",temp.creature_id, i, temp.event_param3);
continue;
}
if (!temp.event_param4)
{
error_db_log("SD2: Creature %u using event %u: param4 (CondValue2: %u) are missing.",temp.creature_id, i, temp.event_param4);
continue;
}
break;
case CONDITION_ZONEID:
if (!temp.event_param3)
{
error_db_log("SD2: Creature %u using event %u: param3 (CondValue1: %u) are missing.",temp.creature_id, i, temp.event_param3);
continue;
}
break;
case CONDITION_NONE:
break;
default:
{
error_db_log("SD2: Creature %u using event %u: param2 (Condition: %u) are not valid/not implemented for script.",temp.creature_id, i, temp.event_param3);
continue;
}
}
if (!(temp.event_flags & EFLAG_REPEATABLE))
{
error_db_log("SD2: Creature %u using event %u: EFLAG_REPEATABLE not set. Event must always be repeatable. Flag applied.", temp.creature_id, i);
temp.event_flags |= EFLAG_REPEATABLE;
}
}
break;
case EVENT_T_QUEST_ACCEPT:
case EVENT_T_QUEST_COMPLETE:
{
error_db_log("SD2: Creature %u using not implemented event (%u) in event %u.", temp.creature_id, temp.event_id, i);
continue;
}
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_TEXT:
{
if (temp.action[j].param1_s < 0)
{
if (TextMap.find(temp.action[j].param1_s) == TextMap.end())
error_db_log("TSCR: Event %u Action %u param1 refrences non-existing entry in texts table.", i, j+1);
}
if (temp.action[j].param2_s < 0)
{
if (TextMap.find(temp.action[j].param2_s) == TextMap.end())
error_db_log("TSCR: Event %u Action %u param2 refrences non-existing entry in texts table.", i, j+1);
if (!temp.action[j].param1_s)
error_db_log("TSCR: Event %u Action %u has param2, but param1 is not set. Required for randomized text.", i, j+1);
}
if (temp.action[j].param3_s < 0)
{
if (TextMap.find(temp.action[j].param3_s) == TextMap.end())
error_db_log("TSCR: Event %u Action %u param3 refrences non-existing entry in texts table.", i, j+1);
if (!temp.action[j].param1_s || !temp.action[j].param2_s)
error_db_log("TSCR: Event %u Action %u has param3, but param1 and/or param2 is not set. Required for randomized text.", i, j+1);
}
}
break;
case ACTION_T_SET_FACTION:
if (temp.action[j].param1 !=0 && !GetFactionStore()->LookupEntry(temp.action[j].param1))
{
error_db_log("TSCR: Event %u Action %u uses non-existant FactionId %u.", i, j+1, temp.action[j].param1);
temp.action[j].param1 = 0;
}
break;
case ACTION_T_MORPH_TO_ENTRY_OR_MODEL:
if (temp.action[j].param1 !=0 || temp.action[j].param2 !=0)
{
if (temp.action[j].param1 && !GetCreatureTemplateStore(temp.action[j].param1))
{
error_db_log("TSCR: Event %u Action %u uses non-existant Creature entry %u.", i, j+1, temp.action[j].param1);
temp.action[j].param1 = 0;
}
if (temp.action[j].param2 && !GetCreatureDisplayStore()->LookupEntry(temp.action[j].param2))
{
error_db_log("TSCR: Event %u Action %u uses non-existant ModelId %u.", i, j+1, temp.action[j].param2);
temp.action[j].param2 = 0;
}
}
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_SOUND:
{
if(!GetSoundEntriesStore()->LookupEntry(temp.action[j].param1))
error_db_log("TSCR: Event %u Action %u param1 uses non-existant SoundID %u.", i, j+1, temp.action[j].param1);
if(!GetSoundEntriesStore()->LookupEntry(temp.action[j].param2))
error_db_log("TSCR: Event %u Action %u param2 uses non-existant SoundID %u.", i, j+1, temp.action[j].param2);
if(!GetSoundEntriesStore()->LookupEntry(temp.action[j].param3))
error_db_log("TSCR: Event %u Action %u param3 uses non-existant SoundID %u.", i, j+1, temp.action[j].param3);
}
break;*/
case ACTION_T_CAST:
{
const SpellEntry *spell = GetSpellStore()->LookupEntry(temp.action[j].param1);
if (!spell)
error_db_log("SD2: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param1);
else
{
if (spell->RecoveryTime > 0 && temp.event_flags & EFLAG_REPEATABLE)
{
//output as debug for now, also because there's no general rule all spells have RecoveryTime
if (temp.event_param3 < spell->RecoveryTime)
debug_log("TSCR: Event %u Action %u uses SpellID %u but cooldown is longer(%u) than minumum defined in event param3(%u).", i, j+1,temp.action[j].param1, spell->RecoveryTime, temp.event_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_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_QUEST_EVENT:
{
if (Quest const* qid = GetQuestTemplateStore(temp.action[j].param1))
{
if (!qid->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
error_db_log("TSCR: Event %u Action %u. SpecialFlags for quest entry %u does not include |2, Action will not have any effect.", i, j+1, temp.action[j].param1);
}
else
error_db_log("TSCR: Event %u Action %u uses non-existant Quest entry %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_QUEST_EVENT_ALL:
{
if (Quest const* qid = GetQuestTemplateStore(temp.action[j].param1))
{
if (!qid->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
error_db_log("TSCR: Event %u Action %u. SpecialFlags for quest entry %u does not include |2, Action will not have any effect.", i, j+1, temp.action[j].param1);
}
else
error_db_log("TSCR: Event %u Action %u uses non-existant Quest entry %u.", i, j+1, temp.action[j].param1);
}
break;
case ACTION_T_CASTCREATUREGO:
{
if (!GetCreatureTemplateStore(temp.action[j].param1))
error_db_log("TSCR: Event %u Action %u uses non-existant creature entry %u.", i, j+1, temp.action[j].param1);
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("SD2: Event %u Action %u uses incorrect Target type", i, j+1);
}
break;
case ACTION_T_CASTCREATUREGO_ALL:
{
if (!GetQuestTemplateStore(temp.action[j].param1))
error_db_log("TSCR: Event %u Action %u uses non-existant Quest entry %u.", i, j+1, temp.action[j].param1);
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);
}
break;
//2nd param target
case ACTION_T_SUMMON_ID:
{
if (!GetCreatureTemplateStore(temp.action[j].param1))
error_db_log("TSCR: Event %u Action %u uses non-existant creature entry %u.", i, j+1, temp.action[j].param1);
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_KILLED_MONSTER:
{
if (!GetCreatureTemplateStore(temp.action[j].param1))
error_db_log("TSCR: Event %u Action %u uses non-existant creature entry %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_SUMMON:
{
if (!GetCreatureTemplateStore(temp.action[j].param1))
error_db_log("TSCR: Event %u Action %u uses non-existant creature entry %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_THREAT_SINGLE_PCT:
case ACTION_T_SET_UNIT_FLAG:
case ACTION_T_REMOVE_UNIT_FLAG:
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].param1 < OBJECT_END || temp.action[j].param1 >= UNIT_END)
error_db_log("TSCR: Event %u Action %u param1 (UNIT_FIELD*). Index out of range for intended use.", i, j+1);
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("SD2: Event %u Action %u is incrementing phase by 0. Was this intended?", i, j+1);
break;
case ACTION_T_SET_INST_DATA:
{
if (!(temp.event_flags & EFLAG_NORMAL) && !(temp.event_flags & EFLAG_HEROIC))
error_db_log("TSCR: Event %u Action %u. Cannot set instance data without event flags (normal/heroic).", i, j+1);
if (temp.action[j].param2 > SPECIAL)
error_db_log("TSCR: Event %u Action %u attempts to set instance data above encounter state 4. Custom case?", i, j+1);
}
break;
case ACTION_T_SET_INST_DATA64:
{
if (!(temp.event_flags & EFLAG_NORMAL) && !(temp.event_flags & EFLAG_HEROIC))
error_db_log("TSCR: Event %u Action %u. Cannot set instance data without event flags (normal/heroic).", i, j+1);
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_UPDATE_TEMPLATE:
{
if (!GetCreatureTemplateStore(temp.action[j].param1))
error_db_log("TSCR: Event %u Action %u uses non-existant creature entry %u.", i, j+1, temp.action[j].param1);
}
break;
case ACTION_T_RANDOM_SAY:
case ACTION_T_RANDOM_YELL:
case ACTION_T_RANDOM_TEXTEMOTE:
error_db_log("TSCR: Event %u Action %u currently unused ACTION type. Did you forget to update database?", 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_Map[creature_id].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();
@@ -1569,25 +940,6 @@ void ScriptsInit()
}
else outstring_log("TSCR: Using configuration file %s",_TRINITY_SCRIPT_CONFIG);
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.
@@ -1615,7 +967,6 @@ void ScriptsInit()
AddSC_boss_ysondre();
// -- Creature --
AddSC_mob_event();
AddSC_generic_creature();
// -- Custom --

View File

@@ -519,11 +519,11 @@ bool ScriptedAI::CanCast(Unit* Target, SpellEntry const *Spell, bool Triggered)
return false;
//Silenced so we can't cast
if (!Triggered && m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
if (!Triggered && me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
return false;
//Check for power
if (!Triggered && m_creature->GetPower((Powers)Spell->powerType) < Spell->manaCost)
if (!Triggered && me->GetPower((Powers)Spell->powerType) < Spell->manaCost)
return false;
SpellRangeEntry const *TempRange = NULL;
@@ -535,7 +535,8 @@ bool ScriptedAI::CanCast(Unit* Target, SpellEntry const *Spell, bool Triggered)
return false;
//Unit is out of range of this spell
if (m_creature->GetDistance(Target) > m_creature->GetSpellMaxRangeForTarget(Target, TempRange) || m_creature->GetDistance(Target) < m_creature->GetSpellMinRangeForTarget(Target, TempRange))
if (me->GetDistance(Target) > me->GetSpellMaxRangeForTarget(Target, TempRange)
|| me->GetDistance(Target) < me->GetSpellMinRangeForTarget(Target, TempRange))
return false;
return true;
@@ -636,39 +637,6 @@ void FillSpellSummary()
}
}
void ScriptedAI::DoZoneInCombat(Unit* pUnit)
{
if (!pUnit)
pUnit = m_creature;
Map *map = pUnit->GetMap();
if (!map->IsDungeon()) //use IsDungeon instead of Instanceable, in case battlegrounds will be instantiated
{
error_log("SD2: DoZoneInCombat call for map that isn't an instance (pUnit entry = %d)", pUnit->GetTypeId() == TYPEID_UNIT ? ((Creature*)pUnit)->GetEntry() : 0);
return;
}
if (!pUnit->CanHaveThreatList() || pUnit->getThreatManager().isThreatListEmpty())
{
error_log("SD2: DoZoneInCombat called for creature that either cannot have threat list or has empty threat list (pUnit entry = %d)", pUnit->GetTypeId() == TYPEID_UNIT ? ((Creature*)pUnit)->GetEntry() : 0);
return;
}
Map::PlayerList const &PlayerList = map->GetPlayers();
for(Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
{
if (Player* i_pl = i->getSource())
if (i_pl->isAlive())
{
pUnit->SetInCombatWith(i_pl);
i_pl->SetInCombatWith(pUnit);
pUnit->AddThreat(i_pl, 0.0f);
}
}
}
void ScriptedAI::DoResetThreat()
{
if (!m_creature->CanHaveThreatList() || m_creature->getThreatManager().isThreatListEmpty())

View File

@@ -148,9 +148,6 @@ struct TRINITY_DLL_DECL ScriptedAI : public CreatureAI
//Plays a sound to all nearby players
void DoPlaySoundToSet(Unit* unit, uint32 sound);
//Places the entire map into combat with creature
void DoZoneInCombat(Unit* pUnit = 0);
//Drops all threat to 0%. Does not remove players from the threat list
void DoResetThreat();

File diff suppressed because it is too large Load Diff

View File

@@ -1,223 +1,4 @@
/* Copyright (C) 2006 - 2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
* This program is free software licensed under GPL version 2
* Please see the included DOCS/LICENSE.TXT for more information */
#ifndef SC_EVENTAI_H
#define SC_EVENTAI_H
#define MAX_ACTIONS 3
enum Event_Types
{
EVENT_T_TIMER = 0, //InitialMin, InitialMax, RepeatMin, RepeatMax
EVENT_T_TIMER_OOC = 1, //InitialMin, InitialMax, RepeatMin, RepeatMax
EVENT_T_HP = 2, //HPMax%, HPMin%, RepeatMin, RepeatMax
EVENT_T_MANA = 3, //ManaMax%,ManaMin% RepeatMin, RepeatMax
EVENT_T_AGGRO = 4, //NONE
EVENT_T_KILL = 5, //RepeatMin, RepeatMax
EVENT_T_DEATH = 6, //NONE
EVENT_T_EVADE = 7, //NONE
EVENT_T_SPELLHIT = 8, //SpellID, School, RepeatMin, RepeatMax
EVENT_T_RANGE = 9, //MinDist, MaxDist, RepeatMin, RepeatMax
EVENT_T_OOC_LOS = 10, //NoHostile, NoFriendly, RepeatMin, RepeatMax
EVENT_T_SPAWNED = 11, //NONE
EVENT_T_TARGET_HP = 12, //HPMax%, HPMin%, RepeatMin, RepeatMax
EVENT_T_TARGET_CASTING = 13, //RepeatMin, RepeatMax
EVENT_T_FRIENDLY_HP = 14, //HPDeficit, Radius, RepeatMin, RepeatMax
EVENT_T_FRIENDLY_IS_CC = 15, //DispelType, Radius, RepeatMin, RepeatMax
EVENT_T_FRIENDLY_MISSING_BUFF = 16, //SpellId, Radius, RepeatMin, RepeatMax
EVENT_T_SUMMONED_UNIT = 17, //CreatureId, RepeatMin, RepeatMax
EVENT_T_TARGET_MANA = 18, //ManaMax%, ManaMin%, RepeatMin, RepeatMax
EVENT_T_QUEST_ACCEPT = 19, //QuestID
EVENT_T_QUEST_COMPLETE = 20, //
EVENT_T_REACHED_HOME = 21, //NONE
EVENT_T_RECEIVE_EMOTE = 22, //EmoteId, Condition, CondValue1, CondValue2
EVENT_T_END,
};
enum Action_Types
{
ACTION_T_NONE = 0, //No action
ACTION_T_TEXT = 1, //-TextId1, optionally -TextId2, optionally -TextId3(if -TextId2 exist). If more than just -TextId1 is defined, randomize. Negative values.
ACTION_T_SET_FACTION = 2, //FactionId (or 0 for default)
ACTION_T_MORPH_TO_ENTRY_OR_MODEL = 3, //Creature_template entry(param1) OR ModelId (param2) (or 0 for both to demorph)
ACTION_T_SOUND = 4, //SoundId
ACTION_T_EMOTE = 5, //EmoteId
ACTION_T_RANDOM_SAY = 6, //UNUSED
ACTION_T_RANDOM_YELL = 7, //UNUSED
ACTION_T_RANDOM_TEXTEMOTE = 8, //UNUSED
ACTION_T_RANDOM_SOUND = 9, //SoundId1, SoundId2, SoundId3 (-1 in any field means no output if randomed that field)
ACTION_T_RANDOM_EMOTE = 10, //EmoteId1, EmoteId2, EmoteId3 (-1 in any field means no output if randomed that field)
ACTION_T_CAST = 11, //SpellId, Target, CastFlags
ACTION_T_SUMMON = 12, //CreatureID, Target, Duration in ms
ACTION_T_THREAT_SINGLE_PCT = 13, //Threat%, Target
ACTION_T_THREAT_ALL_PCT = 14, //Threat%
ACTION_T_QUEST_EVENT = 15, //QuestID, Target
ACTION_T_CASTCREATUREGO = 16, //QuestID, SpellId, Target
ACTION_T_SET_UNIT_FIELD = 17, //Field_Number, Value, Target
ACTION_T_SET_UNIT_FLAG = 18, //Flags (may be more than one field OR'd together), Target
ACTION_T_REMOVE_UNIT_FLAG = 19, //Flags (may be more than one field OR'd together), Target
ACTION_T_AUTO_ATTACK = 20, //AllowAttackState (0 = stop attack, anything else means continue attacking)
ACTION_T_COMBAT_MOVEMENT = 21, //AllowCombatMovement (0 = stop combat based movement, anything else continue attacking)
ACTION_T_SET_PHASE = 22, //Phase
ACTION_T_INC_PHASE = 23, //Value (may be negative to decrement phase, should not be 0)
ACTION_T_EVADE = 24, //No Params
ACTION_T_FLEE = 25, //No Params
ACTION_T_QUEST_EVENT_ALL = 26, //QuestID
ACTION_T_CASTCREATUREGO_ALL = 27, //QuestId, SpellId
ACTION_T_REMOVEAURASFROMSPELL = 28, //Target, Spellid
ACTION_T_RANGED_MOVEMENT = 29, //Distance, Angle
ACTION_T_RANDOM_PHASE = 30, //PhaseId1, PhaseId2, PhaseId3
ACTION_T_RANDOM_PHASE_RANGE = 31, //PhaseMin, PhaseMax
ACTION_T_SUMMON_ID = 32, //CreatureId, Target, SpawnId
ACTION_T_KILLED_MONSTER = 33, //CreatureId, Target
ACTION_T_SET_INST_DATA = 34, //Field, Data
ACTION_T_SET_INST_DATA64 = 35, //Field, Target
ACTION_T_UPDATE_TEMPLATE = 36, //Entry, Team
ACTION_T_DIE = 37, //No Params
ACTION_T_ZONE_COMBAT_PULSE = 38, //No Params
ACTION_T_SET_ACTIVE = 101, //Apply
ACTION_T_SET_AGGRESSIVE = 102, //Apply
ACTION_T_ATTACK_START_PULSE = 103, //Distance
ACTION_T_END,
};
enum Target
{
//Self (m_creature)
TARGET_T_SELF = 0, //Self cast
//Hostile targets (if pet then returns pet owner)
TARGET_T_HOSTILE, //Our current target (ie: highest aggro)
TARGET_T_HOSTILE_SECOND_AGGRO, //Second highest aggro (generaly used for cleaves and some special attacks)
TARGET_T_HOSTILE_LAST_AGGRO, //Dead last on aggro (no idea what this could be used for)
TARGET_T_HOSTILE_RANDOM, //Just any random target on our threat list
TARGET_T_HOSTILE_RANDOM_NOT_TOP, //Any random target except top threat
//Invoker targets (if pet then returns pet owner)
TARGET_T_ACTION_INVOKER, //Unit who caused this Event to occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF)
//Hostile targets (including pets)
TARGET_T_HOSTILE_WPET, //Current target (can be a pet)
TARGET_T_HOSTILE_WPET_SECOND_AGGRO, //Second highest aggro (generaly used for cleaves and some special attacks)
TARGET_T_HOSTILE_WPET_LAST_AGGRO, //Dead last on aggro (no idea what this could be used for)
TARGET_T_HOSTILE_WPET_RANDOM, //Just any random target on our threat list
TARGET_T_HOSTILE_WPET_RANDOM_NOT_TOP, //Any random target except top threat
TARGET_T_ACTION_INVOKER_WPET,
TARGET_T_END
};
enum CastFlags
{
CAST_INTURRUPT_PREVIOUS = 0x01, //Interrupt any spell casting
CAST_TRIGGERED = 0x02, //Triggered (this makes spell cost zero mana and have no cast time)
CAST_FORCE_CAST = 0x04, //Forces cast even if creature is out of mana or out of range
CAST_NO_MELEE_IF_OOM = 0x08, //Prevents creature from entering melee if out of mana or out of range
CAST_FORCE_TARGET_SELF = 0x10, //Forces the target to cast this spell on itself
CAST_AURA_NOT_PRESENT = 0x20, //Only casts the spell if the target does not have an aura from the spell
};
enum EventFlags
{
EFLAG_REPEATABLE = 0x01, //Event repeats
EFLAG_NORMAL = 0x02, //Event only occurs in Normal instance difficulty
EFLAG_HEROIC = 0x04, //Event only occurs in Heroic instance difficulty
EFLAG_RESERVED_3 = 0x08,
EFLAG_RESERVED_4 = 0x10,
EFLAG_RESERVED_5 = 0x20,
EFLAG_RESERVED_6 = 0x40,
EFLAG_DEBUG_ONLY = 0x80, //Event only occurs in debug build of SD2 only
};
struct EventAI_Event
{
uint32 event_id;
uint32 creature_id;
uint16 event_type;
uint32 event_inverse_phase_mask;
uint8 event_chance;
uint8 event_flags;
union
{
uint32 event_param1;
int32 event_param1_s;
};
union
{
uint32 event_param2;
int32 event_param2_s;
};
union
{
uint32 event_param3;
int32 event_param3_s;
};
union
{
uint32 event_param4;
int32 event_param4_s;
};
struct _action
{
uint16 type;
union
{
uint32 param1;
int32 param1_s;
};
union
{
uint32 param2;
int32 param2_s;
};
union
{
uint32 param3;
int32 param3_s;
};
}action[MAX_ACTIONS];
};
//Event_Map
extern UNORDERED_MAP<uint32, std::vector<EventAI_Event> > EventAI_Event_Map;
struct EventAI_Summon
{
uint32 id;
float position_x;
float position_y;
float position_z;
float orientation;
uint32 SpawnTimeSecs;
};
//EventSummon_Map
extern UNORDERED_MAP<uint32, EventAI_Summon> EventAI_Summon_Map;
//EventAI Error handling
extern uint32 EAI_ErrorLevel;
/*
struct EventAI_CreatureError
{
bool ListEmpty;
bool NoInstance;
};
//Error prevention list
extern UNORDERED_MAP<uint32, EventAI_CreatureError> EventAI_CreatureErrorPreventionList;
//Defines
#define EVENTAI_EMPTY_EVENTLIST "SD2: Eventlist for Creature %i is empty but creature is using Mob_EventAI. Preventing EventAI on this creature."
*/
#endif

View File

@@ -325,6 +325,29 @@ enum InhabitTypeValues
INHABIT_ANYWHERE = INHABIT_GROUND | INHABIT_WATER | INHABIT_AIR
};
// Enums used by StringTextData::Type (CreatureEventAI)
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,
CHAT_TYPE_ZONE_YELL = 6
};
//Selection method used by SelectTarget (CreatureEventAI)
enum AttackingTarget
{
ATTACKING_TARGET_RANDOM = 0, //Just selects a random target
ATTACKING_TARGET_TOPAGGRO, //Selects targes from top aggro to bottom
ATTACKING_TARGET_BOTTOMAGGRO, //Selects targets from bottom aggro to top
ATTACKING_TARGET_RANDOM_PLAYER, //Just selects a random target (player only)
ATTACKING_TARGET_TOPAGGRO_PLAYER, //Selects targes from top aggro to bottom (player only)
ATTACKING_TARGET_BOTTOMAGGRO_PLAYER, //Selects targets from bottom aggro to top (player only)
};
// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
#if defined( __GNUC__ )
#pragma pack()

View File

@@ -70,6 +70,38 @@ void CreatureAI::OnCharmed(bool apply)
me->IsAIEnabled = false;
}
void CreatureAI::DoZoneInCombat(Unit* pUnit)
{
if (!pUnit)
pUnit = me;
Map *map = pUnit->GetMap();
if (!map->IsDungeon()) //use IsDungeon instead of Instanceable, in case battlegrounds will be instantiated
{
sLog.outError("DoZoneInCombat call for map that isn't an instance (pUnit entry = %d)", pUnit->GetTypeId() == TYPEID_UNIT ? ((Creature*)pUnit)->GetEntry() : 0);
return;
}
if (!pUnit->CanHaveThreatList() || pUnit->getThreatManager().isThreatListEmpty())
{
sLog.outError("DoZoneInCombat called for creature that either cannot have threat list or has empty threat list (pUnit entry = %d)", pUnit->GetTypeId() == TYPEID_UNIT ? ((Creature*)pUnit)->GetEntry() : 0);
return;
}
Map::PlayerList const &PlayerList = map->GetPlayers();
for(Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
{
if (Player* i_pl = i->getSource())
if (i_pl->isAlive())
{
pUnit->SetInCombatWith(i_pl);
i_pl->SetInCombatWith(pUnit);
pUnit->AddThreat(i_pl, 0.0f);
}
}
}
void CreatureAI::MoveInLineOfSight(Unit *who)
{
if(!me->getVictim() && me->canStartAttack(who))

View File

@@ -158,6 +158,8 @@ class TRINITY_DLL_SPEC CreatureAI : public UnitAI
// Called at reaching home after evade
virtual void JustReachedHome() {}
void DoZoneInCombat(Unit* pUnit = NULL);
};
struct SelectableAI : public FactoryHolder<CreatureAI>, public Permissible<Creature>

View File

@@ -26,6 +26,7 @@
#include "PossessedAI.h"
#include "TotemAI.h"
#include "OutdoorPvPObjectiveAI.h"
#include "CreatureEventAI.h"
#include "RandomMovementGenerator.h"
#include "CreatureAIImpl.h"
#include "MovementGeneratorImpl.h"
@@ -46,6 +47,7 @@ namespace AIRegistry
(new CreatureAIFactory<TotemAI>("TotemAI"))->RegisterSelf();
(new CreatureAIFactory<OutdoorPvPObjectiveAI>("OutdoorPvPObjectiveAI"))->RegisterSelf();
(new CreatureAIFactory<PossessedAI>("PossessedAI"))->RegisterSelf();
(new CreatureAIFactory<CreatureEventAI>("EventAI"))->RegisterSelf();
(new MovementGeneratorFactory<RandomMovementGenerator<Creature> >(RANDOM_MOTION_TYPE))->RegisterSelf();
(new MovementGeneratorFactory<WaypointMovementGenerator<Creature> >(WAYPOINT_MOTION_TYPE))->RegisterSelf();

1661
src/game/CreatureEventAI.cpp Normal file

File diff suppressed because it is too large Load Diff

309
src/game/CreatureEventAI.h Normal file
View File

@@ -0,0 +1,309 @@
/*
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef MANGOS_CREATURE_EAI_H
#define MANGOS_CREATURE_EAI_H
#include "Common.h"
#include "Creature.h"
#include "CreatureAI.h"
#include "Unit.h"
class Player;
class WorldObject;
#define EVENT_UPDATE_TIME 500
#define SPELL_RUN_AWAY 8225
#define MAX_ACTIONS 3
#define TEXT_SOURCE_RANGE -1000000 //the amount of entries each text source has available
enum Event_Types
{
EVENT_T_TIMER = 0, //InitialMin, InitialMax, RepeatMin, RepeatMax
EVENT_T_TIMER_OOC = 1, //InitialMin, InitialMax, RepeatMin, RepeatMax
EVENT_T_HP = 2, //HPMax%, HPMin%, RepeatMin, RepeatMax
EVENT_T_MANA = 3, //ManaMax%,ManaMin% RepeatMin, RepeatMax
EVENT_T_AGGRO = 4, //NONE
EVENT_T_KILL = 5, //RepeatMin, RepeatMax
EVENT_T_DEATH = 6, //NONE
EVENT_T_EVADE = 7, //NONE
EVENT_T_SPELLHIT = 8, //SpellID, School, RepeatMin, RepeatMax
EVENT_T_RANGE = 9, //MinDist, MaxDist, RepeatMin, RepeatMax
EVENT_T_OOC_LOS = 10, //NoHostile, NoFriendly, RepeatMin, RepeatMax
EVENT_T_SPAWNED = 11, //NONE
EVENT_T_TARGET_HP = 12, //HPMax%, HPMin%, RepeatMin, RepeatMax
EVENT_T_TARGET_CASTING = 13, //RepeatMin, RepeatMax
EVENT_T_FRIENDLY_HP = 14, //HPDeficit, Radius, RepeatMin, RepeatMax
EVENT_T_FRIENDLY_IS_CC = 15, //DispelType, Radius, RepeatMin, RepeatMax
EVENT_T_FRIENDLY_MISSING_BUFF = 16, //SpellId, Radius, RepeatMin, RepeatMax
EVENT_T_SUMMONED_UNIT = 17, //CreatureId, RepeatMin, RepeatMax
EVENT_T_TARGET_MANA = 18, //ManaMax%, ManaMin%, RepeatMin, RepeatMax
EVENT_T_QUEST_ACCEPT = 19, //QuestID
EVENT_T_QUEST_COMPLETE = 20, //
EVENT_T_REACHED_HOME = 21, //NONE
EVENT_T_RECEIVE_EMOTE = 22, //EmoteId, Condition, CondValue1, CondValue2
EVENT_T_END,
};
enum Action_Types
{
ACTION_T_NONE = 0, //No action
ACTION_T_TEXT = 1, //-TextId1, optionally -TextId2, optionally -TextId3(if -TextId2 exist). If more than just -TextId1 is defined, randomize. Negative values.
ACTION_T_SET_FACTION = 2, //FactionId (or 0 for default)
ACTION_T_MORPH_TO_ENTRY_OR_MODEL = 3, //Creature_template entry(param1) OR ModelId (param2) (or 0 for both to demorph)
ACTION_T_SOUND = 4, //SoundId
ACTION_T_EMOTE = 5, //EmoteId
ACTION_T_RANDOM_SAY = 6, //UNUSED
ACTION_T_RANDOM_YELL = 7, //UNUSED
ACTION_T_RANDOM_TEXTEMOTE = 8, //UNUSED
ACTION_T_RANDOM_SOUND = 9, //SoundId1, SoundId2, SoundId3 (-1 in any field means no output if randomed that field)
ACTION_T_RANDOM_EMOTE = 10, //EmoteId1, EmoteId2, EmoteId3 (-1 in any field means no output if randomed that field)
ACTION_T_CAST = 11, //SpellId, Target, CastFlags
ACTION_T_SUMMON = 12, //CreatureID, Target, Duration in ms
ACTION_T_THREAT_SINGLE_PCT = 13, //Threat%, Target
ACTION_T_THREAT_ALL_PCT = 14, //Threat%
ACTION_T_QUEST_EVENT = 15, //QuestID, Target
ACTION_T_CASTCREATUREGO = 16, //QuestID, SpellId, Target
ACTION_T_SET_UNIT_FIELD = 17, //Field_Number, Value, Target
ACTION_T_SET_UNIT_FLAG = 18, //Flags (may be more than one field OR'd together), Target
ACTION_T_REMOVE_UNIT_FLAG = 19, //Flags (may be more than one field OR'd together), Target
ACTION_T_AUTO_ATTACK = 20, //AllowAttackState (0 = stop attack, anything else means continue attacking)
ACTION_T_COMBAT_MOVEMENT = 21, //AllowCombatMovement (0 = stop combat based movement, anything else continue attacking)
ACTION_T_SET_PHASE = 22, //Phase
ACTION_T_INC_PHASE = 23, //Value (may be negative to decrement phase, should not be 0)
ACTION_T_EVADE = 24, //No Params
ACTION_T_FLEE = 25, //No Params
ACTION_T_QUEST_EVENT_ALL = 26, //QuestID
ACTION_T_CASTCREATUREGO_ALL = 27, //QuestId, SpellId
ACTION_T_REMOVEAURASFROMSPELL = 28, //Target, Spellid
ACTION_T_RANGED_MOVEMENT = 29, //Distance, Angle
ACTION_T_RANDOM_PHASE = 30, //PhaseId1, PhaseId2, PhaseId3
ACTION_T_RANDOM_PHASE_RANGE = 31, //PhaseMin, PhaseMax
ACTION_T_SUMMON_ID = 32, //CreatureId, Target, SpawnId
ACTION_T_KILLED_MONSTER = 33, //CreatureId, Target
ACTION_T_SET_INST_DATA = 34, //Field, Data
ACTION_T_SET_INST_DATA64 = 35, //Field, Target
ACTION_T_UPDATE_TEMPLATE = 36, //Entry, Team
ACTION_T_DIE = 37, //No Params
ACTION_T_ZONE_COMBAT_PULSE = 38, //No Params
ACTION_T_SET_ACTIVE = 101, //Apply
ACTION_T_SET_AGGRESSIVE = 102, //Apply
ACTION_T_ATTACK_START_PULSE = 103, //Distance
ACTION_T_END,
};
enum Target
{
//Self (m_creature)
TARGET_T_SELF = 0, //Self cast
//Hostile targets (if pet then returns pet owner)
TARGET_T_HOSTILE, //Our current target (ie: highest aggro)
TARGET_T_HOSTILE_SECOND_AGGRO, //Second highest aggro (generaly used for cleaves and some special attacks)
TARGET_T_HOSTILE_LAST_AGGRO, //Dead last on aggro (no idea what this could be used for)
TARGET_T_HOSTILE_RANDOM, //Just any random target on our threat list
TARGET_T_HOSTILE_RANDOM_NOT_TOP, //Any random target except top threat
//Invoker targets (if pet then returns pet owner)
TARGET_T_ACTION_INVOKER, //Unit who caused this Event to occur (only works for EVENT_T_AGGRO, EVENT_T_KILL, EVENT_T_DEATH, EVENT_T_SPELLHIT, EVENT_T_OOC_LOS, EVENT_T_FRIENDLY_HP, EVENT_T_FRIENDLY_IS_CC, EVENT_T_FRIENDLY_MISSING_BUFF)
//Hostile targets (including pets)
TARGET_T_HOSTILE_WPET, //Current target (can be a pet)
TARGET_T_HOSTILE_WPET_SECOND_AGGRO, //Second highest aggro (generaly used for cleaves and some special attacks)
TARGET_T_HOSTILE_WPET_LAST_AGGRO, //Dead last on aggro (no idea what this could be used for)
TARGET_T_HOSTILE_WPET_RANDOM, //Just any random target on our threat list
TARGET_T_HOSTILE_WPET_RANDOM_NOT_TOP, //Any random target except top threat
TARGET_T_ACTION_INVOKER_WPET,
TARGET_T_END
};
enum CastFlags
{
CAST_INTURRUPT_PREVIOUS = 0x01, //Interrupt any spell casting
CAST_TRIGGERED = 0x02, //Triggered (this makes spell cost zero mana and have no cast time)
CAST_FORCE_CAST = 0x04, //Forces cast even if creature is out of mana or out of range
CAST_NO_MELEE_IF_OOM = 0x08, //Prevents creature from entering melee if out of mana or out of range
CAST_FORCE_TARGET_SELF = 0x10, //Forces the target to cast this spell on itself
CAST_AURA_NOT_PRESENT = 0x20, //Only casts the spell if the target does not have an aura from the spell
};
enum EventFlags
{
EFLAG_REPEATABLE = 0x01, //Event repeats
EFLAG_NORMAL = 0x02, //Event only occurs in Normal instance difficulty
EFLAG_HEROIC = 0x04, //Event only occurs in Heroic instance difficulty
EFLAG_RESERVED_3 = 0x08,
EFLAG_RESERVED_4 = 0x10,
EFLAG_RESERVED_5 = 0x20,
EFLAG_RESERVED_6 = 0x40,
EFLAG_DEBUG_ONLY = 0x80, //Event only occurs in debug build of SD2 only
};
// String text additional data, used in (CreatureEventAI)
struct StringTextData
{
uint32 SoundId;
uint8 Type;
uint32 Language;
uint32 Emote;
};
// Text Maps
typedef UNORDERED_MAP<int32, StringTextData> CreatureEventAI_TextMap;
struct CreatureEventAI_Event
{
uint32 event_id;
uint32 creature_id;
uint16 event_type;
uint32 event_inverse_phase_mask;
uint8 event_chance;
uint8 event_flags;
union
{
uint32 event_param1;
int32 event_param1_s;
};
union
{
uint32 event_param2;
int32 event_param2_s;
};
union
{
uint32 event_param3;
int32 event_param3_s;
};
union
{
uint32 event_param4;
int32 event_param4_s;
};
struct _action
{
uint16 type;
union
{
uint32 param1;
int32 param1_s;
};
union
{
uint32 param2;
int32 param2_s;
};
union
{
uint32 param3;
int32 param3_s;
};
}action[MAX_ACTIONS];
};
//Event_Map
typedef UNORDERED_MAP<uint32, std::vector<CreatureEventAI_Event> > CreatureEventAI_Event_Map;
struct CreatureEventAI_Summon
{
uint32 id;
float position_x;
float position_y;
float position_z;
float orientation;
uint32 SpawnTimeSecs;
};
//EventSummon_Map
typedef UNORDERED_MAP<uint32, CreatureEventAI_Summon> CreatureEventAI_Summon_Map;
struct CreatureEventAIHolder
{
CreatureEventAIHolder(CreatureEventAI_Event p) : Event(p), Time(0), Enabled(true){}
CreatureEventAI_Event Event;
uint32 Time;
bool Enabled;
};
class TRINITY_DLL_SPEC CreatureEventAI : public CreatureAI
{
public:
CreatureEventAI(Creature *c);
~CreatureEventAI()
{
CreatureEventAIList.clear();
}
void JustRespawned();
void Reset();
void JustReachedHome();
void EnterEvadeMode();
void JustDied(Unit* killer);
void KilledUnit(Unit* victim);
void JustSummoned(Creature* pUnit);
void Aggro(Unit *who);
void AttackStart(Unit *who);
void MoveInLineOfSight(Unit *who);
void SpellHit(Unit* pUnit, const SpellEntry* pSpell);
void UpdateAI(const uint32 diff);
static int Permissible(const Creature *);
bool ProcessEvent(CreatureEventAIHolder& pHolder, Unit* pActionInvoker = NULL);
void ProcessAction(uint16 type, uint32 param1, uint32 param2, uint32 param3, uint32 rnd, uint32 EventId, Unit* pActionInvoker);
inline uint32 GetRandActionParam(uint32 rnd, uint32 param1, uint32 param2, uint32 param3);
inline Unit* GetTargetByType(uint32 Target, Unit* pActionInvoker);
inline Unit* SelectUnit(AttackingTarget target, uint32 position);
void DoScriptText(int32 textEntry, WorldObject* pSource, Unit* target);
bool CanCast(Unit* Target, SpellEntry const *Spell, bool Triggered);
bool ReceiveEmote(Player* pPlayer, Creature* pCreature, uint32 uiEmote);
Unit* DoSelectLowestHpFriendly(float range, uint32 MinHPDiff);
void DoFindFriendlyMissingBuff(std::list<Creature*>& _list, float range, uint32 spellid);
void DoFindFriendlyCC(std::list<Creature*>& _list, float range);
//Pointer to creature we are manipulating
Creature& m_creature;
//Bool for if we are in combat or not
bool InCombat;
//Holder for events (stores enabled, time, and eventid)
std::list<CreatureEventAIHolder> CreatureEventAIList;
uint32 EventUpdateTime; //Time between event updates
uint32 EventDiff; //Time between the last event call
bool bEmptyList;
//Variables used by Events themselves
uint8 Phase; //Current phase, max 32 phases
bool CombatMovementEnabled; //If we allow targeted movment gen (movement twoards top threat)
bool MeleeEnabled; //If we allow melee auto attack
uint32 AttackDistance; //Distance to attack from
float AttackAngle; //Angle of attack
uint32 TimetoFleeLeft;
bool IsFleeing;
};
#endif

View File

@@ -0,0 +1,560 @@
/*
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "Common.h"
#include "Database/DatabaseEnv.h"
#include "Database/SQLStorage.h"
#include "CreatureEventAI.h"
#include "CreatureEventAIMgr.h"
#include "ObjectMgr.h"
#include "ProgressBar.h"
#include "Policies/SingletonImp.h"
#include "ObjectDefines.h"
INSTANTIATE_SINGLETON_1(CreatureEventAIMgr);
// -------------------
void CreatureEventAIMgr::LoadCreatureEventAI_Texts()
{
// Drop Existing Text Map, only done once and we are ready to add data from multiple sources.
m_CreatureEventAI_TextMap.clear();
// Load EventAI Text
LoadTrinityStrings(WorldDatabase,"creature_ai_texts",-1,1+(TEXT_SOURCE_RANGE));
// Gather Additional data from EventAI Texts
QueryResult *result = WorldDatabase.PQuery("SELECT entry, sound, type, language, emote FROM creature_ai_texts");
sLog.outString("Loading EventAI Texts additional data...");
if (result)
{
barGoLink bar(result->GetRowCount());
uint32 count = 0;
do
{
bar.step();
Field* fields = result->Fetch();
StringTextData temp;
int32 i = fields[0].GetInt32();
temp.SoundId = fields[1].GetInt32();
temp.Type = fields[2].GetInt32();
temp.Language = fields[3].GetInt32();
temp.Emote = fields[4].GetInt32();
if (i >= 0)
{
sLog.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` is not a negative value.",i);
continue;
}
if (i <= TEXT_SOURCE_RANGE)
{
sLog.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` is out of accepted entry range for table.",i);
continue;
}
if (temp.SoundId)
{
if (!GetSoundEntriesStore()->LookupEntry(temp.SoundId))
sLog.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` has soundId %u but sound does not exist.",i,temp.SoundId);
}
if (!GetLanguageDescByID(temp.Language))
sLog.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` using Language %u but Language does not exist.",i,temp.Language);
if (temp.Type > CHAT_TYPE_BOSS_WHISPER)
sLog.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` has Type %u but this Chat Type does not exist.",i,temp.Type);
m_CreatureEventAI_TextMap[i] = temp;
++count;
} while (result->NextRow());
delete result;
sLog.outString();
sLog.outString(">> Loaded %u additional CreatureEventAI Texts data.", count);
}else
{
barGoLink bar(1);
bar.step();
sLog.outString();
sLog.outString(">> Loaded 0 additional CreatureEventAI Texts data. DB table `creature_ai_texts` is empty.");
}
}
// -------------------
void CreatureEventAIMgr::LoadCreatureEventAI_Summons()
{
//Drop Existing EventSummon Map
m_CreatureEventAI_Summon_Map.clear();
//Gather additional data for EventAI
QueryResult *result = WorldDatabase.PQuery("SELECT id, position_x, position_y, position_z, orientation, spawntimesecs FROM creature_ai_summons");
if (result)
{
barGoLink bar(result->GetRowCount());
uint32 Count = 0;
do
{
bar.step();
Field *fields = result->Fetch();
CreatureEventAI_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
m_CreatureEventAI_Summon_Map[i] = temp;
++Count;
}while (result->NextRow());
delete result;
sLog.outString();
sLog.outString(">> Loaded %u CreatureEventAI summon definitions", Count);
}else
{
barGoLink bar(1);
bar.step();
sLog.outString();
sLog.outString(">> Loaded 0 CreatureEventAI Summon definitions. DB table `creature_ai_summons` is empty.");
}
}
// -------------------
void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
{
//Drop Existing EventAI List
m_CreatureEventAI_Event_Map.clear();
//Gather event data
QueryResult *result = WorldDatabase.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 creature_ai_scripts");
if (result)
{
barGoLink bar(result->GetRowCount());
uint32 Count = 0;
do
{
bar.step();
Field *fields = result->Fetch();
CreatureEventAI_Event temp;
temp.event_id = fields[0].GetUInt32();
uint32 i = temp.event_id;
temp.creature_id = fields[1].GetUInt32();
uint32 creature_id = temp.creature_id;
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();
CreatureInfo const* cInfo = sCreatureStorage.LookupEntry<CreatureInfo>(temp.creature_id);
//Creature does not exist in database
if (!cInfo)
{
sLog.outErrorDb("CreatureEventAI: Event %u has script for non-existing creature.", i);
continue;
}
//Report any errors in event
if (temp.event_type >= EVENT_T_END)
sLog.outErrorDb("CreatureEventAI: 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)
sLog.outErrorDb("CreatureEventAI: Event %u has 0 percent chance. Event will never trigger!", i);
//Chance above 100, force it to be 100
if (temp.event_chance > 100)
{
sLog.outErrorDb("CreatureEventAI: 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)
sLog.outErrorDb("CreatureEventAI: 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)
sLog.outErrorDb("CreatureEventAI: 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)
{
sLog.outErrorDb("CreatureEventAI: 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)
{
sLog.outErrorDb("CreatureEventAI: 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)
sLog.outErrorDb("CreatureEventAI: 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)
sLog.outErrorDb("CreatureEventAI: 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)
sLog.outErrorDb("CreatureEventAI: 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)
sLog.outErrorDb("CreatureEventAI: 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)
sLog.outErrorDb("CreatureEventAI: 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)
sLog.outErrorDb("CreatureEventAI: 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)
sLog.outErrorDb("CreatureEventAI: 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:
case EVENT_T_REACHED_HOME:
{
if (temp.event_flags & EFLAG_REPEATABLE)
{
sLog.outErrorDb("CreatureEventAI: 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_TEXT:
{
if (temp.action[j].param1_s < 0)
{
if (m_CreatureEventAI_TextMap.find(temp.action[j].param1_s) == m_CreatureEventAI_TextMap.end())
sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 refrences non-existing entry in texts table.", i, j+1);
}
if (temp.action[j].param2_s < 0)
{
if (m_CreatureEventAI_TextMap.find(temp.action[j].param2_s) == m_CreatureEventAI_TextMap.end())
sLog.outErrorDb("CreatureEventAI: Event %u Action %u param2 refrences non-existing entry in texts table.", i, j+1);
if (!temp.action[j].param1_s)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u has param2, but param1 is not set. Required for randomized text.", i, j+1);
}
if (temp.action[j].param3_s < 0)
{
if (m_CreatureEventAI_TextMap.find(temp.action[j].param3_s) == m_CreatureEventAI_TextMap.end())
sLog.outErrorDb("CreatureEventAI: Event %u Action %u param3 refrences non-existing entry in texts table.", i, j+1);
if (!temp.action[j].param1_s || !temp.action[j].param2_s)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u has param3, but param1 and/or param2 is not set. Required for randomized text.", i, j+1);
}
}
break;
case ACTION_T_SET_FACTION:
if (temp.action[j].param1 !=0 && !GetFactionStore()->LookupEntry(temp.action[j].param1))
{
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant FactionId %u.", i, j+1, temp.action[j].param1);
temp.action[j].param1 = 0;
}
break;
case ACTION_T_MORPH_TO_ENTRY_OR_MODEL:
if (temp.action[j].param1 !=0 || temp.action[j].param2 !=0)
{
if (temp.action[j].param1 && !GetCreatureTemplateStore(temp.action[j].param1))
{
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant Creature entry %u.", i, j+1, temp.action[j].param1);
temp.action[j].param1 = 0;
}
if (temp.action[j].param2 && !GetCreatureDisplayStore()->LookupEntry(temp.action[j].param2))
{
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant ModelId %u.", i, j+1, temp.action[j].param2);
temp.action[j].param2 = 0;
}
}
break;
case ACTION_T_SOUND:
if (!GetSoundEntriesStore()->LookupEntry(temp.action[j].param1))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SoundID %u.", i, j+1, temp.action[j].param1);
break;
/*
case ACTION_T_RANDOM_SOUND:
{
if(!GetSoundEntriesStore()->LookupEntry(temp.action[j].param1))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 uses non-existant SoundID %u.", i, j+1, temp.action[j].param1);
if(!GetSoundEntriesStore()->LookupEntry(temp.action[j].param2))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u param2 uses non-existant SoundID %u.", i, j+1, temp.action[j].param2);
if(!GetSoundEntriesStore()->LookupEntry(temp.action[j].param3))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u param3 uses non-existant SoundID %u.", i, j+1, temp.action[j].param3);
}
break;
*/
case ACTION_T_CAST:
{
const SpellEntry *spell = GetSpellStore()->LookupEntry(temp.action[j].param1);
if (!spell)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param1);
else
{
if (spell->RecoveryTime > 0 && temp.event_flags & EFLAG_REPEATABLE)
{
//output as debug for now, also because there's no general rule all spells have RecoveryTime
if (temp.event_param3 < spell->RecoveryTime)
debug_log("CreatureEventAI: Event %u Action %u uses SpellID %u but cooldown is longer(%u) than minumum defined in event param3(%u).", i, j+1,temp.action[j].param1, spell->RecoveryTime, temp.event_param3);
}
}
if (temp.action[j].param2 >= TARGET_T_END)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
}
break;
case ACTION_T_REMOVEAURASFROMSPELL:
{
if (!GetSpellStore()->LookupEntry(temp.action[j].param2))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param2);
if (temp.action[j].param1 >= TARGET_T_END)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
}
break;
case ACTION_T_QUEST_EVENT:
{
if (Quest const* qid = GetQuestTemplateStore(temp.action[j].param1))
{
if (!qid->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u. SpecialFlags for quest entry %u does not include |2, Action will not have any effect.", i, j+1, temp.action[j].param1);
}
else
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant Quest entry %u.", i, j+1, temp.action[j].param1);
if (temp.action[j].param2 >= TARGET_T_END)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
}
break;
case ACTION_T_QUEST_EVENT_ALL:
{
if (Quest const* qid = GetQuestTemplateStore(temp.action[j].param1))
{
if (!qid->HasFlag(QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u. SpecialFlags for quest entry %u does not include |2, Action will not have any effect.", i, j+1, temp.action[j].param1);
}
else
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant Quest entry %u.", i, j+1, temp.action[j].param1);
}
break;
case ACTION_T_CASTCREATUREGO:
{
if (!GetCreatureTemplateStore(temp.action[j].param1))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, temp.action[j].param1);
if (!GetSpellStore()->LookupEntry(temp.action[j].param2))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param2);
if (temp.action[j].param3 >= TARGET_T_END)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
}
break;
case ACTION_T_CASTCREATUREGO_ALL:
{
if (!GetQuestTemplateStore(temp.action[j].param1))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant Quest entry %u.", i, j+1, temp.action[j].param1);
if (!GetSpellStore()->LookupEntry(temp.action[j].param2))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param2);
}
break;
//2nd param target
case ACTION_T_SUMMON_ID:
{
if (!GetCreatureTemplateStore(temp.action[j].param1))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, temp.action[j].param1);
if (m_CreatureEventAI_Summon_Map.find(temp.action[j].param3) == m_CreatureEventAI_Summon_Map.end())
sLog.outErrorDb("CreatureEventAI: Event %u Action %u summons missing CreatureEventAI_Summon %u", i, j+1, temp.action[j].param3);
if (temp.action[j].param2 >= TARGET_T_END)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
}
break;
case ACTION_T_KILLED_MONSTER:
{
if (!GetCreatureTemplateStore(temp.action[j].param1))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, temp.action[j].param1);
if (temp.action[j].param2 >= TARGET_T_END)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
}
break;
case ACTION_T_SUMMON:
{
if (!GetCreatureTemplateStore(temp.action[j].param1))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, temp.action[j].param1);
if (temp.action[j].param2 >= TARGET_T_END)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
}
break;
case ACTION_T_THREAT_SINGLE_PCT:
case ACTION_T_SET_UNIT_FLAG:
case ACTION_T_REMOVE_UNIT_FLAG:
if (temp.action[j].param2 >= TARGET_T_END)
sLog.outErrorDb("CreatureEventAI: 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].param1 < OBJECT_END || temp.action[j].param1 >= UNIT_END)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u param1 (UNIT_FIELD*). Index out of range for intended use.", i, j+1);
if (temp.action[j].param3 >= TARGET_T_END)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
break;
case ACTION_T_SET_PHASE:
if (temp.action[j].param1 > 31)
sLog.outErrorDb("CreatureEventAI: 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)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u is incrementing phase by 0. Was this intended?", i, j+1);
break;
case ACTION_T_SET_INST_DATA:
{
if (!(temp.event_flags & EFLAG_NORMAL) && !(temp.event_flags & EFLAG_HEROIC))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u. Cannot set instance data without event flags (normal/heroic).", i, j+1);
if (temp.action[j].param2 > 4/*SPECIAL*/)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set instance data above encounter state 4. Custom case?", i, j+1);
}
break;
case ACTION_T_SET_INST_DATA64:
{
if (!(temp.event_flags & EFLAG_NORMAL) && !(temp.event_flags & EFLAG_HEROIC))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u. Cannot set instance data without event flags (normal/heroic).", i, j+1);
if (temp.action[j].param2 >= TARGET_T_END)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i, j+1);
}
break;
case ACTION_T_UPDATE_TEMPLATE:
{
if (!GetCreatureTemplateStore(temp.action[j].param1))
sLog.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i, j+1, temp.action[j].param1);
}
break;
case ACTION_T_RANDOM_SAY:
case ACTION_T_RANDOM_YELL:
case ACTION_T_RANDOM_TEXTEMOTE:
sLog.outErrorDb("CreatureEventAI: Event %u Action %u currently unused ACTION type. Did you forget to update database?", i, j+1);
break;
default:
if (temp.action[j].type >= ACTION_T_END)
sLog.outErrorDb("CreatureEventAI: Event %u Action %u has incorrect action type. Maybe DB requires updated version of SD2.", i, j+1);
break;
}
}
//Add to list
m_CreatureEventAI_Event_Map[creature_id].push_back(temp);
++Count;
} while (result->NextRow());
delete result;
sLog.outString();
sLog.outString(">> Loaded %u CreatureEventAI scripts", Count);
}else
{
barGoLink bar(1);
bar.step();
sLog.outString();
sLog.outString(">> Loaded 0 CreatureEventAI scripts. DB table `creature_ai_scripts` is empty.");
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef MANGOS_CREATURE_EAI_MGR_H
#define MANGOS_CREATURE_EAI_MGR_H
#include "Common.h"
#include "CreatureEventAI.h"
class CreatureEventAIMgr
{
public:
CreatureEventAIMgr(){};
~CreatureEventAIMgr(){};
void LoadCreatureEventAI_Texts();
void LoadCreatureEventAI_Summons();
void LoadCreatureEventAI_Scripts();
CreatureEventAI_Event_Map& GetCreatureEventAIMap() { return m_CreatureEventAI_Event_Map; }
CreatureEventAI_Summon_Map& GetCreatureEventAISummonMap() { return m_CreatureEventAI_Summon_Map; }
CreatureEventAI_TextMap& GetCreatureEventAITextMap() { return m_CreatureEventAI_TextMap; }
private:
CreatureEventAI_Event_Map m_CreatureEventAI_Event_Map;
CreatureEventAI_Summon_Map m_CreatureEventAI_Summon_Map;
CreatureEventAI_TextMap m_CreatureEventAI_TextMap;
};
#define CreatureEAI_Mgr MaNGOS::Singleton<CreatureEventAIMgr>::Instance()
#endif

View File

@@ -23,6 +23,7 @@
#include "ObjectMgr.h"
#include "ProgressBar.h"
#include "Policies/SingletonImp.h"
#include "CreatureAI.h"
#define MAX_DESYNC 5.0f

View File

@@ -628,6 +628,62 @@ namespace Trinity
// Unit checks
class MostHPMissingInRange
{
public:
MostHPMissingInRange(Unit const* obj, float range, uint32 hp) : i_obj(obj), i_range(range), i_hp(hp) {}
bool operator()(Unit* u)
{
if(u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && u->GetMaxHealth() - u->GetHealth() > i_hp)
{
i_hp = u->GetMaxHealth() - u->GetHealth();
return true;
}
return false;
}
private:
Unit const* i_obj;
float i_range;
uint32 i_hp;
};
class FriendlyCCedInRange
{
public:
FriendlyCCedInRange(Unit const* obj, float range) : i_obj(obj), i_range(range) {}
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_STUNNED) || u->hasUnitState(UNIT_STAT_CONFUSED)))
{
return true;
}
return false;
}
private:
Unit const* i_obj;
float i_range;
};
class FriendlyMissingBuffInRange
{
public:
FriendlyMissingBuffInRange(Unit const* obj, float range, uint32 spellid) : i_obj(obj), i_range(range), i_spell(spellid) {}
bool operator()(Unit* u)
{
if(u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) &&
!(u->HasAura(i_spell, 0) || u->HasAura(i_spell, 1) || u->HasAura(i_spell, 2)))
{
return true;
}
return false;
}
private:
Unit const* i_obj;
float i_range;
uint32 i_spell;
};
class AnyUnfriendlyUnitInObjectRangeCheck
{
public:
@@ -915,63 +971,6 @@ namespace Trinity
float i_range;
};
// Searchers used by ScriptedAI
class MostHPMissingInRange
{
public:
MostHPMissingInRange(Unit const* obj, float range, uint32 hp) : i_obj(obj), i_range(range), i_hp(hp) {}
bool operator()(Unit* u)
{
if(u->isAlive() && u->isInCombat() && !i_obj->IsHostileTo(u) && i_obj->IsWithinDistInMap(u, i_range) && u->GetMaxHealth() - u->GetHealth() > i_hp)
{
i_hp = u->GetMaxHealth() - u->GetHealth();
return true;
}
return false;
}
private:
Unit const* i_obj;
float i_range;
uint32 i_hp;
};
class FriendlyCCedInRange
{
public:
FriendlyCCedInRange(Unit const* obj, float range) : i_obj(obj), i_range(range) {}
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_STUNNED) || u->hasUnitState(UNIT_STAT_CONFUSED)))
{
return true;
}
return false;
}
private:
Unit const* i_obj;
float i_range;
};
class FriendlyMissingBuffInRange
{
public:
FriendlyMissingBuffInRange(Unit const* obj, float range, uint32 spellid) : i_obj(obj), i_range(range), i_spell(spellid) {}
bool operator()(Unit* u)
{
if(u->isAlive() && u->isInCombat() && /*!i_obj->IsHostileTo(u)*/ i_obj->IsFriendlyTo(u) && i_obj->IsWithinDistInMap(u, i_range) &&
!(u->HasAura(i_spell)))
{
return true;
}
return false;
}
private:
Unit const* i_obj;
float i_range;
uint32 i_spell;
};
class AllFriendlyCreaturesInGrid
{
public:

View File

@@ -67,6 +67,10 @@ class TRINITY_DLL_SPEC InstanceData
//called on creature creation
virtual void OnCreatureCreate(Creature * /*creature*/, uint32 /*creature_entry*/) {}
//All-purpose data storage 64 bit
virtual uint64 GetData64(uint32 /*Data*/) { return 0; }
virtual void SetData64(uint32 /*Data*/, uint64 /*Value*/) { }
//All-purpose data storage 32 bit
virtual uint32 GetData(uint32) { return 0; }
virtual void SetData(uint32, uint32 data) {}

View File

@@ -30,6 +30,7 @@ noinst_LIBRARIES = libmangosgame.a
# libmangossgame library will later be reused by ...
libmangosgame_a_SOURCES = \
<<<<<<< HEAD:src/game/Makefile.am
<<<<<<< HEAD:src/game/Makefile.am
AccountMgr.cpp \
AccountMgr.h \
@@ -572,6 +573,272 @@ libmangosgame_a_SOURCES = \
GroupReference.h \
GroupRefManager.h
>>>>>>> 2429aaf2276d689e101ed88285f18449dbe4280d:src/game/Makefile.am
=======
AccountMgr.cpp \
AccountMgr.h \
AchievementMgr.h \
AchievementMgr.cpp \
AggressorAI.cpp \
AggressorAI.h \
AnimalRandomMovementGenerator.h \
ArenaTeam.cpp \
ArenaTeam.h \
ArenaTeamHandler.cpp \
AuctionHouseHandler.cpp \
AuctionHouseMgr.cpp \
AuctionHouseMgr.h \
Bag.cpp \
Bag.h \
BattleGround.cpp \
BattleGroundAA.cpp \
BattleGroundAB.cpp \
BattleGroundAV.cpp \
BattleGroundBE.cpp \
BattleGroundDS.cpp \
BattleGroundEY.cpp \
BattleGroundNA.cpp \
BattleGroundRL.cpp \
BattleGroundRV.cpp \
BattleGroundSA.cpp \
BattleGroundWS.cpp \
BattleGround.h \
BattleGroundAA.h \
BattleGroundAB.h \
BattleGroundAV.h \
BattleGroundBE.h \
BattleGroundDS.h \
BattleGroundEY.h \
BattleGroundNA.h \
BattleGroundRL.h \
BattleGroundRV.h \
BattleGroundSA.h \
BattleGroundWS.h \
BattleGroundHandler.cpp \
BattleGroundMgr.cpp \
BattleGroundMgr.h \
Calendar.cpp \
Calendar.h \
CalendarHandler.cpp \
Cell.h \
CellImpl.h \
Channel.cpp \
Channel.h \
ChannelHandler.cpp \
ChannelMgr.h \
CharacterHandler.cpp \
Chat.cpp \
Chat.h \
ChatHandler.cpp \
CombatHandler.cpp \
ConfusedMovementGenerator.cpp \
ConfusedMovementGenerator.h \
Corpse.cpp \
Corpse.h \
CreatureAI.cpp \
CreatureAI.h \
CreatureAIImpl.h \
CreatureAIRegistry.cpp \
CreatureAIRegistry.h \
CreatureAISelector.cpp \
CreatureAISelector.h \
CreatureEventAI.cpp \
CreatureEventAI.h \
CreatureEventAIMgr.cpp \
CreatureEventAIMgr.h \
Creature.cpp \
Creature.h \
DBCEnums.h \
DBCfmt.h \
DBCStores.cpp \
DBCStores.h \
DBCStructure.h \
debugcmds.cpp \
DestinationHolder.cpp \
DestinationHolder.h \
DestinationHolderImp.h \
DuelHandler.cpp \
DynamicObject.cpp \
DynamicObject.h \
FleeingMovementGenerator.cpp \
FleeingMovementGenerator.h \
Formulas.h \
GameEventMgr.cpp \
GameEventMgr.h \
GameObject.cpp \
GameObject.h \
GlobalEvents.cpp \
GlobalEvents.h \
GMTicketHandler.cpp \
GMTicketMgr.cpp \
GMTicketMgr.h \
GossipDef.cpp \
GossipDef.h \
GridDefines.h \
GridNotifiers.cpp \
GridNotifiers.h \
GridNotifiersImpl.h \
GridStates.cpp \
GridStates.h \
Group.cpp \
Group.h \
GroupHandler.cpp \
GuardAI.cpp \
GuardAI.h \
Guild.cpp \
Guild.h \
GuildHandler.cpp \
HomeMovementGenerator.cpp \
HomeMovementGenerator.h \
HostilRefManager.cpp \
HostilRefManager.h \
IdleMovementGenerator.cpp \
IdleMovementGenerator.h \
InstanceData.cpp \
InstanceData.h \
InstanceSaveMgr.cpp \
InstanceSaveMgr.h \
Item.cpp \
Item.h \
ItemEnchantmentMgr.cpp \
ItemEnchantmentMgr.h \
ItemHandler.cpp \
ItemPrototype.h \
Language.h \
Level0.cpp \
Level1.cpp \
Level2.cpp \
Level3.cpp \
LFGHandler.cpp \
LootHandler.cpp \
LootMgr.cpp \
LootMgr.h \
Mail.cpp \
Mail.h \
Map.cpp \
Map.h \
MapInstanced.cpp \
MapInstanced.h \
MapManager.cpp \
MapManager.h \
MapReference.h \
MapRefManager.h \
MiscHandler.cpp \
MotionMaster.cpp \
MotionMaster.h \
MovementGenerator.cpp \
MovementGenerator.h \
MovementGeneratorImpl.h \
MovementHandler.cpp \
NPCHandler.cpp \
NPCHandler.h \
NullCreatureAI.cpp \
NullCreatureAI.h \
ObjectAccessor.cpp \
ObjectAccessor.h \
Object.cpp \
ObjectDefines.h \
ObjectGridLoader.cpp \
ObjectGridLoader.h \
Object.h \
ObjectMgr.cpp \
ObjectMgr.h \
ObjectPosSelector.cpp \
ObjectPosSelector.h \
Opcodes.cpp \
Opcodes.h \
Path.h \
PetAI.cpp \
PetAI.h \
Pet.cpp \
Pet.h \
PetHandler.cpp \
PetitionsHandler.cpp \
Player.cpp \
Player.h \
PlayerDump.cpp \
PlayerDump.h \
PointMovementGenerator.cpp \
PointMovementGenerator.h \
PoolHandler.cpp \
PoolHandler.h \
QueryHandler.cpp \
QuestDef.cpp \
QuestDef.h \
QuestHandler.cpp \
RandomMovementGenerator.cpp \
RandomMovementGenerator.h \
ReactorAI.cpp \
ReactorAI.h \
ReputationMgr.cpp \
ReputationMgr.h \
ScriptCalls.cpp \
ScriptCalls.h \
SharedDefines.h \
SkillHandler.cpp \
SpellAuraDefines.h \
SpellAuras.cpp \
SpellAuras.h \
Spell.cpp \
SpellEffects.cpp \
Spell.h \
SkillDiscovery.cpp \
SkillDiscovery.h \
SkillExtraItems.cpp \
SkillExtraItems.h \
SpellHandler.cpp \
SocialMgr.cpp \
SocialMgr.h \
SpellMgr.cpp \
SpellMgr.h \
StatSystem.cpp \
TargetedMovementGenerator.cpp \
TargetedMovementGenerator.h \
TaxiHandler.cpp \
TemporarySummon.cpp \
TemporarySummon.h \
TotemAI.cpp \
TotemAI.h \
Totem.cpp \
Totem.h \
TradeHandler.cpp \
Transports.cpp \
Transports.h \
ThreatManager.cpp \
ThreatManager.h \
Traveller.h \
Unit.cpp \
Unit.h \
UnitEvents.h \
UpdateData.cpp \
UpdateData.h \
UpdateFields.h \
UpdateMask.h \
Vehicle.cpp \
Vehicle.h \
VoiceChatHandler.cpp \
WaypointManager.cpp \
WaypointManager.h \
WaypointMovementGenerator.cpp \
WaypointMovementGenerator.h \
Weather.cpp \
Weather.h \
World.cpp \
World.h \
WorldLog.cpp \
WorldLog.h \
WorldSession.cpp \
WorldSession.h \
WorldSocket.cpp \
WorldSocket.h \
WorldSocketMgr.cpp \
WorldSocketMgr.h \
FollowerReference.cpp \
FollowerReference.h \
FollowerRefManager.h \
GroupReference.cpp \
GroupReference.h \
GroupRefManager.h
>>>>>>> 5a6594330caefc0dc00a5fe792dcb0e344b457cb:src/game/Makefile.am
## Link against shared library
libmangosgame_a_LIBADD = ../shared/libmangosshared.a ../shared/Auth/libmangosauth.a ../shared/Config/libmangosconfig.a ../shared/Database/libmangosdatabase.a ../shared/vmap/libmangosvmaps.a

View File

@@ -28,7 +28,6 @@
#include "GameSystem/GridReference.h"
#include "ObjectDefines.h"
#include "GridDefines.h"
#include "CreatureAI.h"
#include "Map.h"
#include <set>
@@ -106,6 +105,7 @@ class InstanceData;
class GameObject;
class TempSummon;
class Vehicle;
class CreatureAI;
typedef UNORDERED_MAP<Player*, UpdateData> UpdateDataMapType;

View File

@@ -28,6 +28,7 @@
#include "Corpse.h"
#include "World.h"
#include "CellImpl.h"
#include "CreatureAI.h"
class TRINITY_DLL_DECL ObjectGridRespawnMover
{

View File

@@ -295,6 +295,7 @@ class Pet;
class Path;
class PetAura;
class Guardian;
class UnitAI;
struct SpellImmune
{

View File

@@ -40,6 +40,7 @@
#include "AchievementMgr.h"
#include "AuctionHouseMgr.h"
#include "ObjectMgr.h"
#include "CreatureEventAIMgr.h"
#include "SpellMgr.h"
#include "Chat.h"
#include "DBCStores.h"
@@ -1447,6 +1448,15 @@ void World::SetInitialWorldSettings()
sLog.outString( "Loading Scripts text locales..." ); // must be after Load*Scripts calls
objmgr.LoadDbScriptStrings();
sLog.outString( "Loading CreatureEventAI Texts...");
CreatureEAI_Mgr.LoadCreatureEventAI_Texts();
sLog.outString( "Loading CreatureEventAI Summons...");
CreatureEAI_Mgr.LoadCreatureEventAI_Summons();
sLog.outString( "Loading CreatureEventAI Scripts...");
CreatureEAI_Mgr.LoadCreatureEventAI_Scripts();
sLog.outString( "Initializing Scripts..." );
if(!LoadScriptingModule())
exit(1);

View File

@@ -659,6 +659,18 @@
<File
RelativePath="..\..\src\game\DynamicObject.h">
</File>
<File
RelativePath="..\..\src\game\CreatureEventAI.cpp">
</File>
<File
RelativePath="..\..\src\game\CreatureEventAI.h">
</File>
<File
RelativePath="..\..\src\game\CreatureEventAIMgr.cpp">
</File>
<File
RelativePath="..\..\src\game\CreatureEventAIMgr.h">
</File>
<File
RelativePath="..\..\src\game\FleeingMovementGenerator.cpp">
</File>

View File

@@ -1023,6 +1023,22 @@
RelativePath="..\..\src\game\DynamicObject.h"
>
</File>
<File
RelativePath="..\..\src\game\CreatureEventAI.cpp"
>
</File>
<File
RelativePath="..\..\src\game\CreatureEventAI.h"
>
</File>
<File
RelativePath="..\..\src\game\CreatureEventAIMgr.cpp"
>
</File>
<File
RelativePath="..\..\src\game\CreatureEventAIMgr.h"
>
</File>
<File
RelativePath="..\..\src\game\FleeingMovementGenerator.cpp"
>

View File

@@ -1024,6 +1024,22 @@
RelativePath="..\..\src\game\DynamicObject.h"
>
</File>
<File
RelativePath="..\..\src\game\CreatureEventAI.cpp"
>
</File>
<File
RelativePath="..\..\src\game\CreatureEventAI.h"
>
</File>
<File
RelativePath="..\..\src\game\CreatureEventAIMgr.cpp"
>
</File>
<File
RelativePath="..\..\src\game\CreatureEventAIMgr.h"
>
</File>
<File
RelativePath="..\..\src\game\FleeingMovementGenerator.cpp"
>