/* 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 ScriptDev2DB; Config SD2Config; 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 (!SD2Config.GetString("ScriptDev2DatabaseInfo", &dbstring)) error_log("SD2: Missing ScriptDev2 Database Info from configuration file"); //Initilize connection to DB if (!dbstring || !ScriptDev2DB.Initialize(dbstring)) error_db_log("SD2: Unable to connect to Database"); else { //***Preform all DB queries here*** QueryResult *result; //Get Version information result = ScriptDev2DB.PQuery("SELECT `version`" "FROM `sd2_db_version`"); if (result) { Field *fields = result->Fetch(); outstring_log(" "); outstring_log("SD2: Database version is: %s", fields[0].GetString()); outstring_log(" "); delete result; }else error_db_log("SD2: Missing sd2_db_version information."); // Drop existing Event AI Localized Text hash map EventAI_LocalizedTextMap.clear(); // Gather EventAI Localized Texts result = ScriptDev2DB.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("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("SD2: Loaded %u EventAI Localized Texts", count); }else outstring_log("SD2: 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 = ScriptDev2DB.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("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("SD2: Loaded %u Script Localized Texts", count); }else outstring_log("SD2: 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 = ScriptDev2DB.PQuery("SELECT `id`,`text` FROM `eventai_texts`"); if (result) { outstring_log( "SD2: 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("SD2: EventAI text %u is empty", i); EventAI_Text_Map[i] = text; ++Count; }while (result->NextRow()); delete result; outstring_log(""); outstring_log("SD2: >> Loaded %u EventAI_Texts", Count); }else outstring_log("SD2: WARNING >> Loaded 0 EventAI_Texts. DB table `EventAI_Texts` is empty."); //Gather event data result = ScriptDev2DB.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( "SD2: 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("SD2: >> Loaded %u EventAI_Summons", Count); }else outstring_log("SD2: WARNING >> Loaded 0 EventAI_Summons. DB table `EventAI_Summons` is empty."); //Gather event data result = ScriptDev2DB.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( "SD2: 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("SD2: 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("SD2: 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("SD2: 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("SD2: 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("SD2: 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("SD2: 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("SD2: 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("SD2: 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("SD2: 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("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_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("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_TIMER: case EVENT_T_TIMER_OOC: { if (temp.event_param2 < temp.event_param1) error_db_log("SD2: 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("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_KILL: case EVENT_T_TARGET_CASTING: { if (temp.event_param2 < temp.event_param1) error_db_log("SD2: 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("SD2: 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("SD2: 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("SD2: 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("SD2: 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("SD2: 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("SD2: 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("SD2: 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("SD2: 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("SD2: 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; //2nd param target case ACTION_T_SUMMON_ID: { if (EventAI_Summon_Map.find(temp.action[j].param3) == EventAI_Summon_Map.end()) error_db_log("SD2: 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("SD2: 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("SD2: 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("SD2: 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("SD2: 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_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("SD2: 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("SD2: 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("SD2: >> Loaded %u EventAI_Events", Count); }else outstring_log("SD2: WARNING >> Loaded 0 EventAI_Scripts. DB table `EventAI_Scripts` is empty."); // Gather Script Text result = ScriptDev2DB.PQuery("SELECT `id`, `sound`, `type`, `language`, `text`" "FROM `script_texts`;"); // Drop Existing Script Text Map Script_TextMap.clear(); if(result) { outstring_log("SD2: 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("SD2: 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("SD2: Id %u in table script_texts has no text.", i); Script_TextMap[i] = temp; ++count; }while(result->NextRow()); delete result; outstring_log(""); outstring_log("SD2: Loaded %u Script Texts", count); }else outstring_log("SD2 WARNING >> Loaded 0 Script Texts. Database table `script_texts` is empty."); //Free database thread and resources ScriptDev2DB.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("SD2: Locale set to invalid language id. Defaulting to 0."); } outstring_log("SD2: Using locale %u", Locale); outstring_log(""); EAI_ErrorLevel = SD2Config.GetIntDefault("EAIErrorLevel", 1); switch (EAI_ErrorLevel) { case 0: outstring_log("SD2: EventAI Error Reporting level set to 0 (Startup Errors only)"); break; case 1: outstring_log("SD2: EventAI Error Reporting level set to 1 (Startup errors and Runtime event errors)"); break; case 2: outstring_log("SD2: EventAI Error Reporting level set to 2 (Startup errors, Runtime event errors, and Creation errors)"); break; default: outstring_log("SD2: 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 SD2Config.SetSource) LoadDatabase(); nrscripts = 0; for(int i=0;i::iterator i = EventAI_LocalizedTextMap.find(entry); if (i == EventAI_LocalizedTextMap.end()) { error_log("SD2: 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("SD2: 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("SD2: 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("SD2 ERROR: 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("SD2: ProcessScriptText invalid Source pointer."); return; } HM_NAMESPACE::hash_map::iterator i = Script_TextMap.find(id); if (i == Script_TextMap.end()) { error_log("SD2: ProcessScriptText could not find id %u.",id); return; } if((*i).second.SoundId) { if(GetSoundEntriesStore()->LookupEntry((*i).second.SoundId)) { WorldPacket data(4); data.SetOpcode(SMSG_PLAY_SOUND); data << uint32((*i).second.SoundId); pSource->SendMessageToSet(&data,false); } else error_log("SD2: 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("SD2: 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("SD2: 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("SD2: 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("SD2: 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); }