/* Copyright (C) 2006 - 2008 TrinityScript * This program is free software licensed under GPL version 2 * Please see the included DOCS/LICENSE.TXT for more information */ #include "precompiled.h" #include "Config/Config.h" #include "Database/DatabaseEnv.h" #include "Database/DBCStores.h" #include "ObjectMgr.h" #include "ProgressBar.h" #include "scripts/creature/mob_event_ai.h" #define _FULLVERSION "TrinityScript" #ifndef _TRINITY_SCRIPT_CONFIG # define _TRINITY_SCRIPT_CONFIG "trinitycore.conf" #endif _TRINITY_SCRIPT_CONFIG //*** Global data *** int num_db_scripts; int num_sc_scripts; Script *m_scripts[MAX_SCRIPTS]; DatabaseType TScriptDB; Config TScriptConfig; // String text additional data, used in TextMap struct StringTextData { uint32 SoundId; uint8 Type; uint32 Language; }; // Enums used by StringTextData::Type enum ChatType { CHAT_TYPE_SAY = 0, CHAT_TYPE_YELL = 1, CHAT_TYPE_TEXT_EMOTE = 2, CHAT_TYPE_BOSS_EMOTE = 3, CHAT_TYPE_WHISPER = 4, CHAT_TYPE_BOSS_WHISPER = 5, }; #define TEXT_SOURCE_RANGE -1000000 //the amount of entries each text source has available // Text Maps UNORDERED_MAP TextMap; //*** 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. UNORDERED_MAP EventAI_Summon_Map; //Event AI error prevention structure. Used at runtime to prevent error log spam of same creature id. //UNORDERED_MAP EventAI_CreatureErrorPreventionList; uint32 EAI_ErrorLevel; //*** End EventAI data *** void FillSpellSummary(); // -- Scripts to be added -- // -- Areatrigger -- extern void AddSC_areatrigger_scripts(); // -- Boss -- extern void AddSC_boss_emeriss(); extern void AddSC_boss_taerar(); extern void AddSC_boss_ysondre(); // -- Creature -- extern void AddSC_mob_event(); extern void AddSC_generic_creature(); // -- Custom -- extern void AddSC_custom_example(); extern void AddSC_custom_gossip_codebox(); extern void AddSC_test(); // -- GO -- extern void AddSC_go_scripts(); // -- Guard -- extern void AddSC_guards(); // -- Honor -- // -- Item -- extern void AddSC_item_scripts(); extern void AddSC_item_test(); // -- NPC -- extern void AddSC_npc_professions(); extern void AddSC_npcs_special(); // -- Servers -- //-------------------- //------ ZONE -------- //Alterac Mountains extern void AddSC_alterac_mountains(); //Arathi Highlands //Ashenvale Forest //Aunchindoun //--Auchenai Crypts extern void AddSC_boss_exarch_maladaar(); //--Mana Tombs extern void AddSC_boss_nexusprince_shaffar(); extern void AddSC_boss_pandemonius(); //--Sekketh Halls extern void AddSC_boss_darkweaver_syth(); extern void AddSC_boss_talon_king_ikiss(); extern void AddSC_instance_sethekk_halls(); //--Shadow Labyrinth extern void AddSC_boss_ambassador_hellmaw(); extern void AddSC_boss_blackheart_the_inciter(); extern void AddSC_boss_grandmaster_vorpil(); extern void AddSC_boss_murmur(); extern void AddSC_instance_shadow_labyrinth(); //Azshara extern void AddSC_boss_azuregos(); extern void AddSC_azshara(); //Azuremyst Isle extern void AddSC_azuremyst_isle(); //Badlands //Barrens extern void AddSC_the_barrens(); //Black Temple extern void AddSC_black_temple(); extern void AddSC_boss_illidan(); extern void AddSC_boss_shade_of_akama(); extern void AddSC_boss_supremus(); extern void AddSC_boss_gurtogg_bloodboil(); extern void AddSC_boss_mother_shahraz(); extern void AddSC_boss_reliquary_of_souls(); extern void AddSC_boss_teron_gorefiend(); extern void AddSC_boss_najentus(); extern void AddSC_boss_illidari_council(); extern void AddSC_instance_black_temple(); //Blackfathom Depths //Blackrock Depths extern void AddSC_blackrock_depths(); extern void AddSC_boss_ambassador_flamelash(); extern void AddSC_boss_angerrel(); extern void AddSC_boss_anubshiah(); extern void AddSC_boss_doomrel(); extern void AddSC_boss_doperel(); extern void AddSC_boss_draganthaurissan(); extern void AddSC_boss_general_angerforge(); extern void AddSC_boss_gloomrel(); extern void AddSC_boss_gorosh_the_dervish(); extern void AddSC_boss_grizzle(); extern void AddSC_boss_haterel(); extern void AddSC_boss_high_interrogator_gerstahn(); extern void AddSC_boss_magmus(); extern void AddSC_boss_moira_bronzebeard(); extern void AddSC_boss_seethrel(); extern void AddSC_boss_vilerel(); //Blackrock Spire extern void AddSC_boss_drakkisath(); extern void AddSC_boss_halycon(); extern void AddSC_boss_highlordomokk(); extern void AddSC_boss_mothersmolderweb(); extern void AddSC_boss_overlordwyrmthalak(); extern void AddSC_boss_shadowvosh(); extern void AddSC_boss_thebeast(); extern void AddSC_boss_warmastervoone(); extern void AddSC_boss_quatermasterzigris(); extern void AddSC_boss_pyroguard_emberseer(); extern void AddSC_boss_gyth(); extern void AddSC_boss_rend_blackhand(); //Blackwing lair extern void AddSC_boss_razorgore(); extern void AddSC_boss_vael(); extern void AddSC_boss_broodlord(); extern void AddSC_boss_firemaw(); extern void AddSC_boss_ebonroc(); extern void AddSC_boss_flamegor(); extern void AddSC_boss_chromaggus(); extern void AddSC_boss_nefarian(); extern void AddSC_boss_victor_nefarius(); //Blade's Edge Mountains extern void AddSC_blades_edge_mountains(); //Blasted lands extern void AddSC_boss_kruul(); extern void AddSC_blasted_lands(); //Bloodmyst Isle extern void AddSC_bloodmyst_isle(); //Burning steppes extern void AddSC_burning_steppes(); //Caverns of Time //--Battle for Mt. Hyjal extern void AddSC_hyjal(); extern void AddSC_boss_archimonde(); extern void AddSC_instance_mount_hyjal(); //--Old Hillsbrad extern void AddSC_boss_captain_skarloc(); extern void AddSC_boss_epoch_hunter(); extern void AddSC_boss_lieutenant_drake(); extern void AddSC_instance_old_hillsbrad(); extern void AddSC_old_hillsbrad(); //--The Dark Portal extern void AddSC_boss_aeonus(); extern void AddSC_boss_chrono_lord_deja(); extern void AddSC_boss_temporus(); //Coilfang Resevoir //--Serpent Shrine Cavern extern void AddSC_boss_fathomlord_karathress(); extern void AddSC_boss_hydross_the_unstable(); extern void AddSC_boss_lady_vashj(); extern void AddSC_boss_leotheras_the_blind(); extern void AddSC_boss_morogrim_tidewalker(); extern void AddSC_instance_serpentshrine_cavern(); extern void AddSC_boss_the_lurker_below(); //--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_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 //Sunwell Plateau extern void AddSC_instance_sunwell_plateau(); extern void AddSC_boss_kalecgos(); extern void AddSC_boss_brutallus(); extern void AddSC_boss_felmyst(); extern void AddSC_boss_eredar_twins(); //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_alar(); 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(); extern void AddSC_boss_pathaleon_the_calculator(); extern void AddSC_instance_mechanar(); //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 extern void AddSC_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_akilzon(); extern void AddSC_boss_halazzi(); extern void AddSC_boss_hex_lord_malacrass(); extern void AddSC_boss_janalai(); extern void AddSC_boss_nalorakk(); extern void AddSC_boss_zuljin(); extern void AddSC_instance_zulaman(); extern void AddSC_zulaman(); // ------------------- void LoadDatabase() { //Get db string from file char const* dbstring = NULL; if (!TScriptConfig.GetString("WorldDatabaseInfo", &dbstring) ) { error_log("TSCR: Missing world database info from configuration file. Load database aborted."); return; } //Initialize connection to DB if (dbstring && TScriptDB.Initialize(dbstring) ) outstring_log("TSCR: TrinityScript database: %s",dbstring); else { error_log("TSCR: Unable to connect to Database. Load database aborted."); return; } //***Preform all DB queries here*** QueryResult *result; //Get Version information result = TScriptDB.PQuery("SELECT version FROM script_db_version"); if (result) { Field *fields = result->Fetch(); outstring_log("TSCR: Database version is: %s", fields[0].GetString()); outstring_log(""); delete result; }else { error_log("TSCR: Missing `script_db_version` information."); outstring_log(""); } // Drop Existing Text Map, only done once and we are ready to add data from multiple sources. TextMap.clear(); // Load EventAI Text outstring_log("TSCR: Loading EventAI Texts..."); LoadTrinityStrings(TScriptDB,"eventai_texts",-1,1+(TEXT_SOURCE_RANGE)); // Gather Additional data from EventAI Texts result = TScriptDB.PQuery("SELECT entry, sound, type, language FROM eventai_texts"); outstring_log("TSCR: 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(); if (i >= 0) { error_db_log("TSCR: Entry %i in table `eventai_texts` is not a negative value.",i); continue; } if (i <= TEXT_SOURCE_RANGE) { error_db_log("TSCR: Entry %i in table `eventai_texts` is out of accepted entry range for table.",i); continue; } if (temp.SoundId) { if (!GetSoundEntriesStore()->LookupEntry(temp.SoundId)) error_db_log("TSCR: Entry %i in table `eventai_texts` has soundId %u but sound does not exist.",i,temp.SoundId); } if (!GetLanguageDescByID(temp.Language)) error_db_log("TSCR: Entry %i in table `eventai_texts` using Language %u but Language does not exist.",i,temp.Language); if (temp.Type > CHAT_TYPE_BOSS_WHISPER) error_db_log("TSCR: Entry %i in table `eventai_texts` has Type %u but this Chat Type does not exist.",i,temp.Type); TextMap[i] = temp; ++count; } while (result->NextRow()); delete result; outstring_log(""); outstring_log(">> TSCR: Loaded %u additional EventAI Texts data.", count); }else { barGoLink bar(1); bar.step(); outstring_log(""); outstring_log(">> Loaded 0 additional EventAI Texts data. DB table `eventai_texts` is empty."); } // Load Script Text outstring_log("TSCR: Loading Script Texts..."); LoadTrinityStrings(TScriptDB,"script_texts",TEXT_SOURCE_RANGE,1+(TEXT_SOURCE_RANGE*2)); // Gather Additional data from Script Texts result = TScriptDB.PQuery("SELECT entry, sound, type, language FROM script_texts"); outstring_log("TSCR: Loading Script Texts additional data..."); if (result) { barGoLink bar(result->GetRowCount()); uint32 count = 0; do { bar.step(); Field* fields = result->Fetch(); StringTextData temp; int32 i = fields[0].GetInt32(); temp.SoundId = fields[1].GetInt32(); temp.Type = fields[2].GetInt32(); temp.Language = fields[3].GetInt32(); if (i >= 0) { error_db_log("TSCR: Entry %i in table `script_texts` is not a negative value.",i); continue; } if (i > TEXT_SOURCE_RANGE || i <= TEXT_SOURCE_RANGE*2) { error_db_log("TSCR: Entry %i in table `script_texts` is out of accepted entry range for table.",i); continue; } if (temp.SoundId) { if (!GetSoundEntriesStore()->LookupEntry(temp.SoundId)) error_db_log("TSCR: Entry %i in table `script_texts` has soundId %u but sound does not exist.",i,temp.SoundId); } if (!GetLanguageDescByID(temp.Language)) error_db_log("TSCR: Entry %i in table `script_texts` using Language %u but Language does not exist.",i,temp.Language); if (temp.Type > CHAT_TYPE_BOSS_WHISPER) error_db_log("TSCR: Entry %i in table `script_texts` has Type %u but this Chat Type does not exist.",i,temp.Type); TextMap[i] = temp; ++count; } while (result->NextRow()); delete result; outstring_log(""); outstring_log(">> TSCR: Loaded %u additional Script Texts data.", count); }else { barGoLink bar(1); bar.step(); outstring_log(""); outstring_log(">> Loaded 0 additional Script Texts data. DB table `script_texts` is empty."); } // Load Custom Text outstring_log("TSCR: Loading Custom Texts..."); LoadTrinityStrings(TScriptDB,"custom_texts",TEXT_SOURCE_RANGE*2,1+(TEXT_SOURCE_RANGE*3)); // Gather Additional data from Custom Texts result = TScriptDB.PQuery("SELECT entry, sound, type, language FROM custom_texts"); outstring_log("TSCR: Loading Custom Texts additional data..."); if (result) { barGoLink bar(result->GetRowCount()); uint32 count = 0; do { bar.step(); Field* fields = result->Fetch(); StringTextData temp; int32 i = fields[0].GetInt32(); temp.SoundId = fields[1].GetInt32(); temp.Type = fields[2].GetInt32(); temp.Language = fields[3].GetInt32(); if (i >= 0) { error_db_log("TSCR: Entry %i in table `custom_texts` is not a negative value.",i); continue; } if (i > TEXT_SOURCE_RANGE*2 || i <= TEXT_SOURCE_RANGE*3) { error_db_log("TSCR: Entry %i in table `custom_texts` is out of accepted entry range for table.",i); continue; } if (temp.SoundId) { if (!GetSoundEntriesStore()->LookupEntry(temp.SoundId)) error_db_log("TSCR: Entry %i in table `custom_texts` has soundId %u but sound does not exist.",i,temp.SoundId); } if (!GetLanguageDescByID(temp.Language)) error_db_log("TSCR: Entry %i in table `custom_texts` using Language %u but Language does not exist.",i,temp.Language); if (temp.Type > CHAT_TYPE_BOSS_WHISPER) error_db_log("TSCR: Entry %i in table `custom_texts` has Type %u but this Chat Type does not exist.",i,temp.Type); TextMap[i] = temp; ++count; } while (result->NextRow()); delete result; outstring_log(""); outstring_log(">> Loaded %u additional Custom Texts data.", count); }else { barGoLink bar(1); bar.step(); outstring_log(""); outstring_log(">> Loaded 0 additional Custom Texts data. DB table `custom_texts` is empty."); } //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."); } //Gather event data result = TScriptDB.PQuery("SELECT id, creature_id, event_type, event_inverse_phase_mask, event_chance, event_flags, " "event_param1, event_param2, event_param3, event_param4, " "action1_type, action1_param1, action1_param2, action1_param3, " "action2_type, action2_param1, action2_param2, action2_param3, " "action3_type, action3_param1, action3_param2, action3_param3 " "FROM eventai_scripts"); //Drop Existing EventAI List EventAI_Event_List.clear(); outstring_log("TSCR: Loading EventAI scripts..."); if (result) { barGoLink bar(result->GetRowCount()); uint32 Count = 0; do { bar.step(); Field *fields = result->Fetch(); EventAI_Event temp; temp.event_id = fields[0].GetUInt32(); uint32 i = temp.event_id; temp.creature_id = fields[1].GetUInt32(); temp.event_type = fields[2].GetUInt16(); temp.event_inverse_phase_mask = fields[3].GetUInt32(); temp.event_chance = fields[4].GetUInt8(); temp.event_flags = fields[5].GetUInt8(); temp.event_param1 = fields[6].GetUInt32(); temp.event_param2 = fields[7].GetUInt32(); temp.event_param3 = fields[8].GetUInt32(); temp.event_param4 = fields[9].GetUInt32(); //Report any errors in event if (temp.event_type >= EVENT_T_END) error_db_log("TSCR: Event %u has incorrect event type. Maybe DB requires updated version of SD2.", i); //No chance of this event occuring if (temp.event_chance == 0) error_db_log("TSCR: Event %u has 0 percent chance. Event will never trigger!", i); //Chance above 100, force it to be 100 if (temp.event_chance > 100) { error_db_log("TSCR: Creature %u are using event %u with more than 100 percent chance. Adjusting to 100 percent.", temp.creature_id, i); temp.event_chance = 100; } //Individual event checks switch (temp.event_type) { case EVENT_T_HP: case EVENT_T_MANA: case EVENT_T_TARGET_HP: { if (temp.event_param2 > 100) error_db_log("TSCR: Creature %u are using percentage event(%u) with param2 (MinPercent) > 100. Event will never trigger! ", temp.creature_id, i); if (temp.event_param1 <= temp.event_param2) error_db_log("TSCR: Creature %u are using percentage event(%u) with param1 <= param2 (MaxPercent <= MinPercent). Event will never trigger! ", temp.creature_id, i); if (temp.event_flags & EFLAG_REPEATABLE && !temp.event_param3 && !temp.event_param4) { error_db_log("TSCR: Creature %u has param3 and param4=0 (RepeatMin/RepeatMax) but cannot be repeatable without timers. Removing EFLAG_REPEATABLE for event %u.", temp.creature_id, i); temp.event_flags &= ~EFLAG_REPEATABLE; } } break; case EVENT_T_SPELLHIT: { if (temp.event_param1) { SpellEntry const* pSpell = GetSpellStore()->LookupEntry(temp.event_param1); if (!pSpell) { error_db_log("TSCR: Creature %u has non-existant SpellID(%u) defined in event %u.", temp.creature_id, temp.event_param1, i); continue; } if (temp.event_param2_s != -1 && temp.event_param2 != pSpell->SchoolMask) error_db_log("TSCR: Creature %u has param1(spellId %u) but param2 is not -1 and not equal to spell's school mask. Event %u can never trigger.", temp.creature_id, temp.event_param1, i); } //TODO: fix this system with SPELL_SCHOOL_MASK. Current complicate things, using int32(-1) instead of just 0 //SPELL_SCHOOL_MASK_NONE = 0 and does not exist, thus it can not ever trigger or be used in SpellHit() if (temp.event_param2_s != -1 && temp.event_param2_s > SPELL_SCHOOL_MASK_ALL) error_db_log("TSCR: Creature %u is using invalid SpellSchoolMask(%u) defined in event %u.", temp.creature_id, temp.event_param2, i); if (temp.event_param4 < temp.event_param3) error_db_log("TSCR: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); } break; case EVENT_T_RANGE: case EVENT_T_OOC_LOS: case EVENT_T_FRIENDLY_HP: case EVENT_T_FRIENDLY_IS_CC: case EVENT_T_FRIENDLY_MISSING_BUFF: { if (temp.event_param4 < temp.event_param3) error_db_log("TSCR: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); } break; case EVENT_T_TIMER: case EVENT_T_TIMER_OOC: { if (temp.event_param2 < temp.event_param1) error_db_log("TSCR: Creature %u are using timed event(%u) with param2 < param1 (InitialMax < InitialMin). Event will never repeat.", temp.creature_id, i); if (temp.event_param4 < temp.event_param3) error_db_log("TSCR: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); } break; case EVENT_T_KILL: case EVENT_T_TARGET_CASTING: { if (temp.event_param2 < temp.event_param1) error_db_log("TSCR: Creature %u are using event(%u) with param2 < param1 (RepeatMax < RepeatMin). Event will never repeat.", temp.creature_id, i); } break; case EVENT_T_AGGRO: case EVENT_T_DEATH: case EVENT_T_EVADE: case EVENT_T_SPAWNED: { if (temp.event_flags & EFLAG_REPEATABLE) { error_db_log("TSCR: Creature %u has EFLAG_REPEATABLE set. Event can never be repeatable. Removing flag for event %u.", temp.creature_id, i); temp.event_flags &= ~EFLAG_REPEATABLE; } } break; } for (uint32 j = 0; j < MAX_ACTIONS; j++) { temp.action[j].type = fields[10+(j*4)].GetUInt16(); temp.action[j].param1 = fields[11+(j*4)].GetUInt32(); temp.action[j].param2 = fields[12+(j*4)].GetUInt32(); temp.action[j].param3 = fields[13+(j*4)].GetUInt32(); //Report any errors in actions switch (temp.action[j].type) { case ACTION_T_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_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: { if (!GetSpellStore()->LookupEntry(temp.action[j].param1)) error_db_log("TSCR: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param1); if (temp.action[j].param2 >= TARGET_T_END) error_db_log("TSCR: Event %u Action %u uses incorrect Target type", i, j+1); } break; case ACTION_T_REMOVEAURASFROMSPELL: { if (!GetSpellStore()->LookupEntry(temp.action[j].param2)) error_db_log("TSCR: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param2); if (temp.action[j].param1 >= TARGET_T_END) error_db_log("TSCR: Event %u Action %u uses incorrect Target type", i, j+1); } break; case ACTION_T_CASTCREATUREGO: { if (!GetSpellStore()->LookupEntry(temp.action[j].param2)) error_db_log("TSCR: Event %u Action %u uses non-existant SpellID %u.", i, j+1, temp.action[j].param2); if (temp.action[j].param3 >= TARGET_T_END) error_db_log("TSCR: Event %u Action %u uses incorrect Target type", i, j+1); } break; //2nd param target case ACTION_T_SUMMON_ID: { if (EventAI_Summon_Map.find(temp.action[j].param3) == EventAI_Summon_Map.end()) error_db_log("TSCR: Event %u Action %u summons missing EventAI_Summon %u", i, j+1, temp.action[j].param3); if (temp.action[j].param2 >= TARGET_T_END) error_db_log("TSCR: Event %u Action %u uses incorrect Target type", i, j+1); } break; case ACTION_T_SUMMON: case ACTION_T_THREAT_SINGLE_PCT: case ACTION_T_QUEST_EVENT: case ACTION_T_SET_UNIT_FLAG: case ACTION_T_REMOVE_UNIT_FLAG: case ACTION_T_SET_INST_DATA64: if (temp.action[j].param2 >= TARGET_T_END) error_db_log("TSCR: Event %u Action %u uses incorrect Target type", i, j+1); break; //3rd param target case ACTION_T_SET_UNIT_FIELD: if (temp.action[j].param3 >= TARGET_T_END) error_db_log("TSCR: Event %u Action %u uses incorrect Target type", i, j+1); break; case ACTION_T_SET_PHASE: if (temp.action[j].param1 > 31) error_db_log("TSCR: Event %u Action %u attempts to set phase > 31. Phase mask cannot be used past phase 31.", i, j+1); break; case ACTION_T_INC_PHASE: if (!temp.action[j].param1) error_db_log("TSCR: Event %u Action %u is incrementing phase by 0. Was this intended?", i, j+1); break; case ACTION_T_KILLED_MONSTER: if (temp.event_type != EVENT_T_DEATH) outstring_log("SD2 WARNING: Event %u Action %u calling ACTION_T_KILLED_MONSTER outside of EVENT_T_DEATH", i, j+1); break; case ACTION_T_SET_INST_DATA: if (temp.action[j].param2 > 3) error_db_log("TSCR: Event %u Action %u attempts to set instance data above encounter state 3. Custom case?", i, j+1); break; case ACTION_T_YELL: case ACTION_T_TEXTEMOTE: 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_List.push_back(temp); ++Count; } while (result->NextRow()); delete result; outstring_log(""); outstring_log(">> Loaded %u EventAI scripts", Count); }else { barGoLink bar(1); bar.step(); outstring_log(""); outstring_log(">> Loaded 0 EventAI scripts. DB table `eventai_scripts` is empty."); } //Free database thread and resources TScriptDB.HaltDelayThread(); } struct TSpellSummary { uint8 Targets; // set of enum SelectTarget uint8 Effects; // set of enum SelectEffect }extern *SpellSummary; TRINITY_DLL_EXPORT void ScriptsFree() { // Free Spell Summary delete []SpellSummary; // Free resources before library unload for(int i=0;i> Loaded %i C++ Scripts (of %i ScriptNames defined in Mangos database)", num_sc_scripts, num_db_scripts); } //********************************* //*** Functions used globally *** void DoScriptText(int32 textEntry, WorldObject* pSource, Unit* target) { if (!pSource) { error_log("TSCR: DoScriptText entry %i, invalid Source pointer.",textEntry); return; } if (textEntry >= 0) { error_log("TSCR: DoScriptText with source entry %u (TypeId=%u, guid=%u) attempts to process text entry %i, but text entry must be negative.",pSource->GetEntry(),pSource->GetTypeId(),pSource->GetGUIDLow(),textEntry); return; } UNORDERED_MAP::iterator i = TextMap.find(textEntry); if (i == TextMap.end()) { error_log("TSCR: DoScriptText with source entry %u (TypeId=%u, guid=%u) could not find text entry %i.",pSource->GetEntry(),pSource->GetTypeId(),pSource->GetGUIDLow(),textEntry); return; } debug_log("TSCR: DoScriptText: text entry=%i, Sound=%u, Type=%u, Language=%u",textEntry,(*i).second.SoundId,(*i).second.Type,(*i).second.Language); if((*i).second.SoundId) { if( GetSoundEntriesStore()->LookupEntry((*i).second.SoundId) ) { pSource->SendPlaySound((*i).second.SoundId, false); } else error_log("TSCR: DoScriptText entry %i tried to process invalid sound id %u.",textEntry,(*i).second.SoundId); } switch((*i).second.Type) { case CHAT_TYPE_SAY: pSource->MonsterSay(textEntry, (*i).second.Language, target ? target->GetGUID() : 0); break; case CHAT_TYPE_YELL: pSource->MonsterYell(textEntry, (*i).second.Language, target ? target->GetGUID() : 0); break; case CHAT_TYPE_TEXT_EMOTE: pSource->MonsterTextEmote(textEntry, target ? target->GetGUID() : 0); break; case CHAT_TYPE_BOSS_EMOTE: pSource->MonsterTextEmote(textEntry, target ? target->GetGUID() : 0, true); break; case CHAT_TYPE_WHISPER: { if (target && target->GetTypeId() == TYPEID_PLAYER) pSource->MonsterWhisper(textEntry, target->GetGUID()); else error_log("TSCR: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", textEntry); }break; case CHAT_TYPE_BOSS_WHISPER: { if (target && target->GetTypeId() == TYPEID_PLAYER) pSource->MonsterWhisper(textEntry, target->GetGUID(), true); else error_log("TSCR: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", textEntry); }break; } } //********************************* //*** Functions used internally *** void Script::RegisterSelf() { int id = GetScriptId(Name.c_str()); if (id != 0) { m_scripts[id] = this; ++num_sc_scripts; } else debug_log("SD2: RegisterSelf, but script named %s does not have ScriptName assigned in database.",(this)->Name.c_str()); } //******************************** //*** Functions to be Exported *** TRINITY_DLL_EXPORT char const* ScriptsVersion() { return "Default Trinity scripting library"; } TRINITY_DLL_EXPORT bool GossipHello ( Player * player, Creature *_Creature ) { Script *tmpscript = m_scripts[_Creature->GetScriptId()]; if (!tmpscript || !tmpscript->pGossipHello) return false; player->PlayerTalkClass->ClearMenus(); return tmpscript->pGossipHello(player,_Creature); } TRINITY_DLL_EXPORT bool GossipSelect( Player *player, Creature *_Creature, uint32 sender, uint32 action ) { debug_log("TSCR: Gossip selection, sender: %d, action: %d",sender, action); Script *tmpscript = m_scripts[_Creature->GetScriptId()]; if (!tmpscript || !tmpscript->pGossipSelect) return false; player->PlayerTalkClass->ClearMenus(); return tmpscript->pGossipSelect(player,_Creature,sender,action); } TRINITY_DLL_EXPORT bool GossipSelectWithCode( Player *player, Creature *_Creature, uint32 sender, uint32 action, const char* sCode ) { debug_log("TSCR: Gossip selection with code, sender: %d, action: %d",sender, action); Script *tmpscript = m_scripts[_Creature->GetScriptId()]; if (!tmpscript || !tmpscript->pGossipSelectWithCode) return false; player->PlayerTalkClass->ClearMenus(); return tmpscript->pGossipSelectWithCode(player,_Creature,sender,action,sCode); } TRINITY_DLL_EXPORT bool QuestAccept( Player *player, Creature *_Creature, Quest const *_Quest ) { Script *tmpscript = m_scripts[_Creature->GetScriptId()]; if (!tmpscript || !tmpscript->pQuestAccept) return false; player->PlayerTalkClass->ClearMenus(); return tmpscript->pQuestAccept(player,_Creature,_Quest); } TRINITY_DLL_EXPORT bool QuestSelect( Player *player, Creature *_Creature, Quest const *_Quest ) { Script *tmpscript = m_scripts[_Creature->GetScriptId()]; if (!tmpscript || !tmpscript->pQuestSelect) return false; player->PlayerTalkClass->ClearMenus(); return tmpscript->pQuestSelect(player,_Creature,_Quest); } TRINITY_DLL_EXPORT bool QuestComplete( Player *player, Creature *_Creature, Quest const *_Quest ) { Script *tmpscript = m_scripts[_Creature->GetScriptId()]; if (!tmpscript || !tmpscript->pQuestComplete) return false; player->PlayerTalkClass->ClearMenus(); return tmpscript->pQuestComplete(player,_Creature,_Quest); } TRINITY_DLL_EXPORT bool ChooseReward( Player *player, Creature *_Creature, Quest const *_Quest, uint32 opt ) { Script *tmpscript = m_scripts[_Creature->GetScriptId()]; if (!tmpscript || !tmpscript->pChooseReward) return false; player->PlayerTalkClass->ClearMenus(); return tmpscript->pChooseReward(player,_Creature,_Quest,opt); } TRINITY_DLL_EXPORT uint32 NPCDialogStatus( Player *player, Creature *_Creature ) { Script *tmpscript = m_scripts[_Creature->GetScriptId()]; if (!tmpscript || !tmpscript->pNPCDialogStatus) return 100; player->PlayerTalkClass->ClearMenus(); return tmpscript->pNPCDialogStatus(player,_Creature); } TRINITY_DLL_EXPORT uint32 GODialogStatus( Player *player, GameObject *_GO ) { Script *tmpscript = m_scripts[_GO->GetGOInfo()->ScriptId]; if (!tmpscript || !tmpscript->pGODialogStatus) return 100; player->PlayerTalkClass->ClearMenus(); return tmpscript->pGODialogStatus(player,_GO); } TRINITY_DLL_EXPORT bool ItemHello( Player *player, Item *_Item, Quest const *_Quest ) { Script *tmpscript = m_scripts[_Item->GetProto()->ScriptId]; if (!tmpscript || !tmpscript->pItemHello) return false; player->PlayerTalkClass->ClearMenus(); return tmpscript->pItemHello(player,_Item,_Quest); } TRINITY_DLL_EXPORT bool ItemQuestAccept( Player *player, Item *_Item, Quest const *_Quest ) { Script *tmpscript = m_scripts[_Item->GetProto()->ScriptId]; if (!tmpscript || !tmpscript->pItemQuestAccept) return false; player->PlayerTalkClass->ClearMenus(); return tmpscript->pItemQuestAccept(player,_Item,_Quest); } TRINITY_DLL_EXPORT bool GOHello( Player *player, GameObject *_GO ) { Script *tmpscript = m_scripts[_GO->GetGOInfo()->ScriptId]; if (!tmpscript || !tmpscript->pGOHello) return false; player->PlayerTalkClass->ClearMenus(); return tmpscript->pGOHello(player,_GO); } TRINITY_DLL_EXPORT bool GOQuestAccept( Player *player, GameObject *_GO, Quest const *_Quest ) { Script *tmpscript = m_scripts[_GO->GetGOInfo()->ScriptId]; if (!tmpscript || !tmpscript->pGOQuestAccept) return false; player->PlayerTalkClass->ClearMenus(); return tmpscript->pGOQuestAccept(player,_GO,_Quest); } TRINITY_DLL_EXPORT bool GOChooseReward( Player *player, GameObject *_GO, Quest const *_Quest, uint32 opt ) { Script *tmpscript = m_scripts[_GO->GetGOInfo()->ScriptId]; if (!tmpscript || !tmpscript->pGOChooseReward) return false; player->PlayerTalkClass->ClearMenus(); return tmpscript->pGOChooseReward(player,_GO,_Quest,opt); } TRINITY_DLL_EXPORT bool AreaTrigger( Player *player, AreaTriggerEntry * atEntry) { Script *tmpscript = m_scripts[GetAreaTriggerScriptId(atEntry->id)]; if (!tmpscript || !tmpscript->pAreaTrigger) return false; return tmpscript->pAreaTrigger(player, atEntry); } TRINITY_DLL_EXPORT CreatureAI* GetAI(Creature *_Creature) { Script *tmpscript = m_scripts[_Creature->GetScriptId()]; if (!tmpscript || !tmpscript->GetAI) return NULL; return tmpscript->GetAI(_Creature); } TRINITY_DLL_EXPORT bool ItemUse( Player *player, Item* _Item, SpellCastTargets const& targets) { Script *tmpscript = m_scripts[_Item->GetProto()->ScriptId]; if (!tmpscript || !tmpscript->pItemUse) return false; return tmpscript->pItemUse(player,_Item,targets); } TRINITY_DLL_EXPORT bool ReceiveEmote( Player *player, Creature *_Creature, uint32 emote ) { Script *tmpscript = m_scripts[_Creature->GetScriptId()]; if (!tmpscript || !tmpscript->pReceiveEmote) return false; return tmpscript->pReceiveEmote(player, _Creature, emote); } TRINITY_DLL_EXPORT InstanceData* CreateInstanceData(Map *map) { if (!map->IsDungeon()) return NULL; Script *tmpscript = m_scripts[((InstanceMap*)map)->GetScriptId()]; if (!tmpscript || !tmpscript->GetInstanceData) return NULL; return tmpscript->GetInstanceData(map); }