void LoadDatabase() { std::string strSD2DBinfo = SD2Config.GetStringDefault("ScriptDev2DatabaseInfo", ""); if (strSD2DBinfo.empty()) { script_error_log("Missing Scriptdev2 database info from configuration file. Load database aborted."); return; } // Initialize connection to DB if (SD2Database.Initialize(strSD2DBinfo.c_str())) { outstring_log("SD2: ScriptDev2 database initialized."); outstring_log("\n"); pSystemMgr.LoadVersion(); pSystemMgr.LoadScriptTexts(); pSystemMgr.LoadScriptTextsCustom(); pSystemMgr.LoadScriptGossipTexts(); pSystemMgr.LoadScriptWaypoints(); } else { script_error_log("Unable to connect to Database. Load database aborted."); return; } SD2Database.HaltDelayThread(); }
void ReceiveAIEvent(AIEventType eventType, Creature* /*pSender*/, Unit* pInvoker, uint32 uiMiscValue) override { if (eventType == AI_EVENT_START_ESCORT && pInvoker->GetTypeId() == TYPEID_PLAYER) { m_creature->SetFactionTemporary(FACTION_ESCORT_N_NEUTRAL_ACTIVE, TEMPFACTION_RESTORE_RESPAWN); Start(false, (Player*)pInvoker, GetQuestTemplateStore(uiMiscValue)); // ToDo: add additional WP when DB will support it if (m_creature->GetPositionZ() < 310.0f) { SetEscortPaused(true); //SetCurrentWaypoint(WP_ID_SPAWN_1); //SetEscortPaused(false); script_error_log("NPC entry %u, location %f, %f, %f does not have waypoints implemented for current spawn location. Please contact customer support!", m_creature->GetEntry(), m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); } else if (m_creature->GetPositionZ() < 330.0f) { SetEscortPaused(true); //SetCurrentWaypoint(WP_ID_SPAWN_2); //SetEscortPaused(false); script_error_log("NPC entry %u, location %f, %f, %f does not have waypoints implemented for current spawn location. Please contact customer support!", m_creature->GetEntry(), m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); } // else just use standard WP // open cage if (GameObject* pCage = GetClosestGameObjectWithEntry(m_creature, GO_PRISONER_CAGE, 10.0f)) pCage->Use(m_creature); } }
MANGOS_DLL_EXPORT void InitScriptLibrary() { // ScriptDev2 startup outstring_log(""); outstring_log(" MMM MMM MM"); outstring_log("M MM M M M M"); outstring_log("MM M M M"); outstring_log(" MMM M M M"); outstring_log(" MM M M MMMM"); outstring_log("MM M M M "); outstring_log(" MMM MMM http://www.scriptdev2.com"); outstring_log(""); // Get configuration file bool configFailure = false; if (!SD2Config.SetSource(_MANGOSD_CONFIG)) configFailure = true; else outstring_log("SD2: Using configuration file %s", _MANGOSD_CONFIG); // Set SD2 Error Log File std::string sd2LogFile = SD2Config.GetStringDefault("SD2ErrorLogFile", "SD2Errors.log"); setScriptLibraryErrorFile(sd2LogFile.c_str(), "SD2"); if (configFailure) script_error_log("Unable to open configuration file. Database will be unaccessible. Configuration values will use default."); // Check config file version if (SD2Config.GetIntDefault("ConfVersion", 0) != _MANGOSDCONFVERSION) script_error_log("Configuration file version doesn't match expected version. Some config variables may be wrong or missing."); outstring_log(""); // Load database (must be called after SD2Config.SetSource). LoadDatabase(); outstring_log("SD2: Loading C++ scripts"); BarGoLink bar(1); bar.step(); outstring_log(""); // Resize script ids to needed ammount of assigned ScriptNames (from core) m_scripts.resize(GetScriptIdsCount(), NULL); FillSpellSummary(); AddScripts(); // Check existance scripts for all registered by core script names for (uint32 i = 1; i < GetScriptIdsCount(); ++i) { if (!m_scripts[i]) script_error_log("No script found for ScriptName '%s'.", GetScriptName(i)); } outstring_log(">> Loaded %i C++ Scripts.", num_sc_scripts); }
// TODO: get rid of this many variables passed in function. void npc_escortAI::Start(bool bRun, const Player* pPlayer, const Quest* pQuest, bool bInstantRespawn, bool bCanLoopPath) { if (m_creature->getVictim()) { script_error_log("EscortAI attempt to Start while in combat."); return; } if (HasEscortState(STATE_ESCORT_ESCORTING)) { script_error_log("EscortAI attempt to Start while already escorting."); return; } if (!WaypointList.empty()) WaypointList.clear(); FillPointMovementListForCreature(); if (WaypointList.empty()) { error_db_log("SD2: EscortAI Start with 0 waypoints (possible missing entry in script_waypoint)."); return; } // set variables m_bIsRunning = bRun; m_playerGuid = pPlayer ? pPlayer->GetObjectGuid() : ObjectGuid(); m_pQuestForEscort = pQuest; m_bCanInstantRespawn = bInstantRespawn; m_bCanReturnToStart = bCanLoopPath; if (m_bCanReturnToStart && m_bCanInstantRespawn) debug_log("SD2: EscortAI is set to return home after waypoint end and instant respawn at waypoint end. Creature will never despawn."); if (m_creature->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE) { m_creature->GetMotionMaster()->MovementExpired(); m_creature->GetMotionMaster()->MoveIdle(); debug_log("SD2: EscortAI start with WAYPOINT_MOTION_TYPE, changed to MoveIdle."); } // disable npcflags m_creature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); debug_log("SD2: EscortAI started with " SIZEFMTD " waypoints. Run = %d, PlayerGuid = %s", WaypointList.size(), m_bIsRunning, m_playerGuid.GetString().c_str()); CurrentWP = WaypointList.begin(); // Set initial speed m_creature->SetWalk(!m_bIsRunning); AddEscortState(STATE_ESCORT_ESCORTING); JustStartedEscort(); }
// Wrapper to get the event started void DoStartValentineEvent(ObjectGuid starterGuid) { if (!m_pInstance) return; m_EventStarterGuid = starterGuid; if (Creature* pHummel = m_pInstance->GetSingleCreatureFromStorage(NPC_HUMMEL)) { // I'm not sure if this unit flag should be used, but it's clear that the NPC shouldn't be attacked until the dialogue is finished pHummel->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); // WARNING: workaround -> faction should be set here - FIX THIS after the aura bug in core is fixed // pHummel->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_REACH_HOME | TEMPFACTION_RESTORE_RESPAWN); } StartNextDialogueText(QUEST_BEEN_SERVED); // Move Baxter to position if (Creature* pBaxter = m_pInstance->GetSingleCreatureFromStorage(NPC_BAXTER)) { pBaxter->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); // WARNING: workaround -> faction should be set here - FIX THIS after the aura bug in core is fixed // pBaxter->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_REACH_HOME | TEMPFACTION_RESTORE_RESPAWN); if (GameObject* pVials = m_pInstance->GetSingleGameObjectFromStorage(GO_APOTHECARE_VIALS)) { float fX, fY, fZ; pVials->GetContactPoint(pBaxter, fX, fY, fZ, CONTACT_DISTANCE); pBaxter->SetWalk(false); pBaxter->GetMotionMaster()->MovePoint(1, fX, fY, fZ); } else script_error_log("Gameobject %u couldn't be found or something really bad happened.", GO_APOTHECARE_VIALS); } // Move Frye to position if (Creature* pFrye = m_pInstance->GetSingleCreatureFromStorage(NPC_FRYE)) { pFrye->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); // WARNING: workaround -> faction should be set here - FIX THIS after the aura bug in core is fixed // pFrye->SetFactionTemporary(FACTION_HOSTILE, TEMPFACTION_RESTORE_REACH_HOME | TEMPFACTION_RESTORE_RESPAWN); if (GameObject* pChemistry = m_pInstance->GetSingleGameObjectFromStorage(GO_CHEMISTRY_SET)) { float fX, fY, fZ; pChemistry->GetContactPoint(pFrye, fX, fY, fZ, CONTACT_DISTANCE); pFrye->SetWalk(false); pFrye->GetMotionMaster()->MovePoint(1, fX, fY, fZ); } else script_error_log("Gameobject %u couldn't be found or something really bad happened.", GO_CHEMISTRY_SET); } }
/** * Function that either simulates or does script text for a map * * @param iTextEntry Entry of the text, stored in SD2-database, only type CHAT_TYPE_ZONE_YELL supported * @param uiCreatureEntry Id of the creature of whom saying will be simulated * @param pMap Given Map on which the map-wide text is displayed * @param pCreatureSource Can be NULL. If pointer to Creature is given, then the creature does the map-wide text * @param pTarget Can be NULL. Possible target for the text */ void DoOrSimulateScriptTextForMap(int32 iTextEntry, uint32 uiCreatureEntry, Map* pMap, Creature* pCreatureSource /*=NULL*/, Unit* pTarget /*=NULL*/) { if (!pMap) { script_error_log("DoOrSimulateScriptTextForMap entry %i, invalid Map pointer.", iTextEntry); return; } if (iTextEntry >= 0) { script_error_log("DoOrSimulateScriptTextForMap with source entry %u for map %u attempts to process text entry %i, but text entry must be negative.", uiCreatureEntry, pMap->GetId(), iTextEntry); return; } CreatureInfo const* pInfo = GetCreatureTemplateStore(uiCreatureEntry); if (!pInfo) { script_error_log("DoOrSimulateScriptTextForMap has invalid source entry %u for map %u.", uiCreatureEntry, pMap->GetId()); return; } MangosStringLocale const* pData = GetMangosStringData(iTextEntry); if (!pData) { script_error_log("DoOrSimulateScriptTextForMap with source entry %u for map %u could not find text entry %i.", uiCreatureEntry, pMap->GetId(), iTextEntry); return; } debug_log("SD2: DoOrSimulateScriptTextForMap: text entry=%i, Sound=%u, Type=%u, Language=%u, Emote=%u", iTextEntry, pData->SoundId, pData->Type, pData->LanguageId, pData->Emote); if (pData->Type != CHAT_TYPE_ZONE_YELL) { script_error_log("DoSimulateScriptTextForMap entry %i has not supported chat type %u.", iTextEntry, pData->Type); return; } if (pData->SoundId) { pMap->PlayDirectSoundToMap(pData->SoundId); } if (pCreatureSource) // If provided pointer for sayer, use direct version { pMap->MonsterYellToMap(pCreatureSource->GetObjectGuid(), iTextEntry, pData->LanguageId, pTarget); } else // Simulate yell { pMap->MonsterYellToMap(pInfo, iTextEntry, pData->LanguageId, pTarget); } }
void npc_escortAI::SetCurrentWaypoint(uint32 uiPointId) { if (!(HasEscortState(STATE_ESCORT_PAUSED))) // Only when paused { script_error_log("EscortAI for %s tried to set new waypoint %u, but not paused", m_creature->GetGuidStr().c_str(), uiPointId); return; } if (!m_creature->GetMotionMaster()->SetNextWaypoint(uiPointId)) { script_error_log("EscortAI for %s current waypoint tried to set to id %u, but doesn't exist in this path", m_creature->GetGuidStr().c_str(), uiPointId); return; } }
// TODO: get rid of this many variables passed in function. void npc_escortAI::Start(bool bRun, const Player* pPlayer, const Quest* pQuest, bool bInstantRespawn, bool bCanLoopPath) { if (m_creature->getVictim()) { script_error_log("EscortAI attempt to Start while in combat."); return; } if (HasEscortState(STATE_ESCORT_ESCORTING)) { script_error_log("EscortAI attempt to Start while already escorting."); return; } if (!pSystemMgr.GetPathInfo(m_creature->GetEntry(), 1)) { script_error_log("EscortAI attempt to start escorting for %s, but has no waypoints loaded", m_creature->GetGuidStr().c_str()); return; } // set variables m_bIsRunning = bRun; m_playerGuid = pPlayer ? pPlayer->GetObjectGuid() : ObjectGuid(); m_pQuestForEscort = pQuest; m_bCanInstantRespawn = bInstantRespawn; m_bCanReturnToStart = bCanLoopPath; if (m_bCanReturnToStart && m_bCanInstantRespawn) debug_log("SD2: EscortAI is set to return home after waypoint end and instant respawn at waypoint end. Creature will never despawn."); // disable npcflags m_creature->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE); AddEscortState(STATE_ESCORT_ESCORTING); // Set initial speed m_creature->SetWalk(!m_bIsRunning); m_creature->StopMoving(); // Start moving along the path with 2500ms delay m_creature->GetMotionMaster()->Clear(false, true); m_creature->GetMotionMaster()->MoveWaypoint(1, 3, 2500); JustStartedEscort(); }
void instance_sunwell_plateau::DoSortFlightTriggers() { if (m_lAllFlightTriggersList.empty()) { script_error_log("Instance Sunwell Plateau: ERROR Failed to load flight triggers for creature id %u.", NPC_FELMYST); return; } std::list<Creature*> lTriggers; // Valid pointers, only used locally for (GuidList::const_iterator itr = m_lAllFlightTriggersList.begin(); itr != m_lAllFlightTriggersList.end(); ++itr) { if (Creature* pTrigger = instance->GetCreature(*itr)) lTriggers.push_back(pTrigger); } if (lTriggers.empty()) return; // sort the flight triggers; first by position X, then group them by Y (left and right) lTriggers.sort(sortByPositionX); for (std::list<Creature*>::iterator itr = lTriggers.begin(); itr != lTriggers.end(); ++itr) { if ((*itr)->GetPositionY() < 600.0f) m_vRightFlightTriggersVect.push_back((*itr)->GetObjectGuid()); else m_vLeftFlightTriggersVect.push_back((*itr)->GetObjectGuid()); } }
bool ScriptedAI::EnterEvadeIfOutOfCombatArea(const uint32 diff) { if (m_uiEvadeCheckCooldown < diff) m_uiEvadeCheckCooldown = 2500; else { m_uiEvadeCheckCooldown -= diff; return false; } if (m_creature->IsInEvadeMode() || !m_creature->getVictim()) return false; float x = m_creature->GetPositionX(); float y = m_creature->GetPositionY(); float z = m_creature->GetPositionZ(); switch (m_creature->GetEntry()) { case NPC_BROODLORD: // broodlord (not move down stairs) if (z > 448.60f) return false; break; default: script_error_log("EnterEvadeIfOutOfCombatArea used for creature entry %u, but does not have any definition.", m_creature->GetEntry()); return false; } EnterEvadeMode(); return true; }
void instance_violet_hold::SetRandomBosses() { // Store bosses that are already done for (uint8 i = 0; i < MAX_MINIBOSSES; ++i) { if (m_auiEncounter[aBossInformation[i].uiType] == DONE) m_vRandomBosses.push_back(CreateBossSpawnByEntry(aBossInformation[i].uiEntry)); } if (m_vRandomBosses.size() < 2) // Get some new random bosses { std::random_shuffle(m_vRandomBossList.begin(), m_vRandomBossList.end()); // two required, in case the first is already pushed to m_vRandomBosses if (m_vRandomBossList.size() < 2) script_error_log("instance_violet_hold, Mini Bosses are not properly spawned"); else m_vRandomBossList.resize(2); // Fill up some random bosses for (std::vector<uint32>::const_iterator itr = m_vRandomBossList.begin(); itr != m_vRandomBossList.end(); ++itr) { if (m_vRandomBosses.empty() || m_vRandomBosses[0]->uiEntry != *itr) m_vRandomBosses.push_back(CreateBossSpawnByEntry(*itr)); } } for (uint8 i = 0; i < m_vRandomBosses.size(); ++i) debug_log("SD2: instance_violet_hold random boss %u is entry %u", i, m_vRandomBosses[i]->uiEntry); }
void SystemMgr::LoadVersion() { // Get Version information QueryResult* pResult = SD2Database.PQuery("SELECT version FROM sd2_db_version LIMIT 1"); if (pResult) { Field* pFields = pResult->Fetch(); strSD2Version = pFields[0].GetCppString(); delete pResult; } else script_error_log("Missing `sd2_db_version` information."); // Setup version info and display it if (strSD2Version.empty()) strSD2Version.append("ScriptDev2 "); strSD2Version.append(_FULLSD2VERSION); outstring_log("Loading %s", strSD2Version.c_str()); outstring_log(""); }
void instance_blackrock_spire::DoProcessEmberseerEvent() { if (GetData(TYPE_EMBERSEER) == DONE || GetData(TYPE_EMBERSEER) == IN_PROGRESS) return; if (m_lIncarceratorGUIDList.empty()) { script_error_log("Npc %u couldn't be found. Please check your DB content!", NPC_BLACKHAND_INCARCERATOR); return; } // start to grow if (Creature* pEmberseer = GetSingleCreatureFromStorage(NPC_PYROGUARD_EMBERSEER)) { // If already casting, return if (pEmberseer->HasAura(SPELL_EMBERSEER_GROWING)) return; DoScriptText(EMOTE_BEGIN, pEmberseer); pEmberseer->CastSpell(pEmberseer, SPELL_EMBERSEER_GROWING, true); } // remove the incarcerators flags and stop casting for (GuidList::const_iterator itr = m_lIncarceratorGUIDList.begin(); itr != m_lIncarceratorGUIDList.end(); ++itr) { if (Creature* pCreature = instance->GetCreature(*itr)) { if (pCreature->isAlive()) { pCreature->InterruptNonMeleeSpells(false); pCreature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PASSIVE); } } } }
// Can also be self invoked for random working void StartLumbering(Unit* pInvoker) { m_uiStopSleepingTimer = 0; if (GameObject* pLumber = GetClosestGameObjectWithEntry(m_creature, GO_LUMBERPILE, 15.0f)) { m_creature->RemoveAurasDueToSpell(SPELL_PEON_SLEEP); float fX, fY, fZ; m_creature->SetWalk(false); pLumber->GetContactPoint(m_creature, fX, fY, fZ, CONTACT_DISTANCE); if (pInvoker->GetTypeId() == TYPEID_PLAYER) { DoScriptText(SAY_PEON_AWAKE_1, m_creature); ((Player*)pInvoker)->KilledMonsterCredit(m_creature->GetEntry(), m_creature->GetObjectGuid()); m_creature->GetMotionMaster()->MovePoint(1, fX, fY, fZ); } else { m_creature->GetMotionMaster()->MovePoint(2, fX, fY, fZ); } } else { script_error_log("No GameObject of entry %u was found in range or something really bad happened.", GO_LUMBERPILE); } }
void npc_doctorAI::PatientSaved(Creature* /*soldier*/, Player* pPlayer, Location* pPoint) { if (pPlayer && m_playerGuid == pPlayer->GetObjectGuid()) { if (pPlayer->GetQuestStatus(QUEST_TRIAGE_A) == QUEST_STATUS_INCOMPLETE || pPlayer->GetQuestStatus(QUEST_TRIAGE_H) == QUEST_STATUS_INCOMPLETE) { ++m_uiPatientSavedCount; if (m_uiPatientSavedCount == 15) { for (GuidList::const_iterator itr = m_lPatientGuids.begin(); itr != m_lPatientGuids.end(); ++itr) { if (Creature* Patient = m_creature->GetMap()->GetCreature(*itr)) Patient->SetDeathState(JUST_DIED); } switch (m_creature->GetEntry()) { case DOCTOR_ALLIANCE: pPlayer->RewardPlayerAndGroupAtEventExplored(QUEST_TRIAGE_A, m_creature); break; case DOCTOR_HORDE: pPlayer->RewardPlayerAndGroupAtEventExplored(QUEST_TRIAGE_H, m_creature); break; default: script_error_log("Invalid entry for Triage doctor. Please check your database"); return; } Reset(); return; } m_vPatientSummonCoordinates.push_back(pPoint); } } }
void InitSentinelsNear(Unit* pTarget) { if (!m_lAssistList.empty()) { for (GuidList::const_iterator itr = m_lAssistList.begin(); itr != m_lAssistList.end(); ++itr) { if (*itr == m_creature->GetObjectGuid()) continue; if (Creature* pBuddy = m_creature->GetMap()->GetCreature(*itr)) { if (pBuddy->isAlive()) pBuddy->AI()->AttackStart(pTarget); } } return; } std::list<Creature*> lAssistList; GetCreatureListWithEntryInGrid(lAssistList, m_creature, m_creature->GetEntry(), 80.0f); for (std::list<Creature*>::iterator iter = lAssistList.begin(); iter != lAssistList.end(); ++iter) { m_lAssistList.push_back((*iter)->GetObjectGuid()); if ((*iter)->GetObjectGuid() == m_creature->GetObjectGuid()) continue; (*iter)->AI()->AttackStart(pTarget); } if (m_lAssistList.size() != MAX_BUDDY) script_error_log("npc_anubisath_sentinel for %s found too few/too many buddies, expected %u.", m_creature->GetGuidStr().c_str(), MAX_BUDDY); }
bool GOUse_go_ethereum_prison(Player* pPlayer, GameObject* pGo) { uint8 uiRandom = urand(0, countof(uiNpcPrisonEntry) - 1); if (Creature* pCreature = pPlayer->SummonCreature(uiNpcPrisonEntry[uiRandom], pGo->GetPositionX(), pGo->GetPositionY(), pGo->GetPositionZ(), pGo->GetAngle(pPlayer), TEMPSUMMON_TIMED_OOC_DESPAWN, 30000)) { if (!pCreature->IsHostileTo(pPlayer)) { uint32 uiSpell = 0; if (FactionTemplateEntry const* pFaction = pCreature->getFactionTemplateEntry()) { switch (pFaction->faction) { case FACTION_LC: uiSpell = SPELL_REP_LC; break; case FACTION_SHAT: uiSpell = SPELL_REP_SHAT; break; case FACTION_CE: uiSpell = SPELL_REP_CE; break; case FACTION_CON: uiSpell = SPELL_REP_CON; break; case FACTION_KT: uiSpell = SPELL_REP_KT; break; case FACTION_SPOR: uiSpell = SPELL_REP_SPOR; break; } if (uiSpell) pCreature->CastSpell(pPlayer, uiSpell, TRIGGERED_NONE); else script_error_log("go_ethereum_prison summoned creature (entry %u) but faction (%u) are not expected by script.", pCreature->GetEntry(), pCreature->getFaction()); } } } return false; }
bool ScriptedAI::EnterEvadeIfOutOfCombatArea(const uint32 uiDiff) { if (m_uiEvadeCheckCooldown < uiDiff) m_uiEvadeCheckCooldown = 2500; else { m_uiEvadeCheckCooldown -= uiDiff; return false; } if (m_creature->IsInEvadeMode() || !m_creature->getVictim()) return false; float fX = m_creature->GetPositionX(); float fY = m_creature->GetPositionY(); float fZ = m_creature->GetPositionZ(); switch (m_creature->GetEntry()) { case NPC_BROODLORD: // broodlord (not move down stairs) if (fZ > 448.60f) return false; break; case NPC_VOID_REAVER: // void reaver (calculate from center of room) if (m_creature->GetDistance2d(432.59f, 371.93f) < 105.0f) return false; break; case NPC_JAN_ALAI: // jan'alai (calculate by Z) if (fZ > 12.0f) return false; break; case NPC_SARTHARION: // sartharion (calculate box) if (fX > 3203.97f && fX < 3289.40f && fY < 576.70f && fY > 484.68f) return false; break; case NPC_TALON_KING_IKISS: { float fX, fY, fZ; m_creature->GetRespawnCoord(fX, fY, fZ); if (m_creature->GetDistance2d(fX, fY) < 70.0f) return false; break; } case NPC_KARGATH_BLADEFIST: if (fX < 255.0f && fX > 205.0f) return false; break; case NPC_ANUBARAK: if (fY < 281.0f && fY > 228.0f) return false; break; default: script_error_log("EnterEvadeIfOutOfCombatArea used for creature entry %u, but does not have any definition.", m_creature->GetEntry()); return false; } EnterEvadeMode(); return true; }
// Right is right side from gothik (eastern) bool instance_naxxramas::IsInRightSideGothArea(Unit* pUnit) { if (GameObject* pCombatGate = GetSingleGameObjectFromStorage(GO_MILI_GOTH_COMBAT_GATE)) return (pCombatGate->GetPositionY() >= pUnit->GetPositionY()); script_error_log("left/right side check, Gothik combat area failed."); return true; }
npc_khadgars_servantAI(Creature* pCreature) : npc_escortAI(pCreature) { if (pCreature->GetOwner() && pCreature->GetOwner()->GetTypeId() == TYPEID_PLAYER) { Start(false, (Player*)pCreature->GetOwner()); } else { script_error_log("npc_khadgars_servant can not obtain owner or owner is not a player."); } Reset(); }
void npc_escortAI::MovementInform(uint32 uiMoveType, uint32 uiPointId) { if (uiMoveType != POINT_MOTION_TYPE || !HasEscortState(STATE_ESCORT_ESCORTING)) { return; } // Combat start position reached, continue waypoint movement if (uiPointId == POINT_LAST_POINT) { debug_log("SD2: EscortAI has returned to original position before combat"); m_creature->SetWalk(!m_bIsRunning); RemoveEscortState(STATE_ESCORT_RETURNING); } else if (uiPointId == POINT_HOME) { debug_log("SD2: EscortAI has returned to original home location and will continue from beginning of waypoint list."); CurrentWP = WaypointList.begin(); m_uiWPWaitTimer = 0; } else { // Make sure that we are still on the right waypoint if (CurrentWP->uiId != uiPointId) { script_error_log("EscortAI for Npc %u reached waypoint out of order %u, expected %u.", m_creature->GetEntry(), uiPointId, CurrentWP->uiId); return; } debug_log("SD2: EscortAI waypoint %u reached.", CurrentWP->uiId); // In case we were moving while in combat, we should evade back to this position m_creature->SetCombatStartPosition(m_creature->GetPositionX(), m_creature->GetPositionY(), m_creature->GetPositionZ()); // Call WP function WaypointReached(CurrentWP->uiId); m_uiWPWaitTimer = CurrentWP->uiWaitTime; ++CurrentWP; } if (!m_uiWPWaitTimer) { // Continue WP Movement if Can if (HasEscortState(STATE_ESCORT_ESCORTING) && !HasEscortState(STATE_ESCORT_PAUSED | STATE_ESCORT_RETURNING) && !m_creature->getVictim()) { MoveToNextWaypoint(); } else { m_uiWPWaitTimer = 1; } } }
npc_ancestral_wolfAI(Creature* pCreature) : npc_escortAI(pCreature) { if (pCreature->GetOwner() && pCreature->GetOwner()->GetTypeId() == TYPEID_PLAYER) Start(false, (Player*)pCreature->GetOwner()); else script_error_log("npc_ancestral_wolf can not obtain owner or owner is not a player."); Reset(); }
/** * Function that does script text * * @param iTextEntry Entry of the text, stored in SD2-database * @param pSource Source of the text * @param pTarget Can be NULL (depending on CHAT_TYPE of iTextEntry). Possible target for the text */ void DoScriptText(int32 iTextEntry, WorldObject* pSource, Unit* pTarget) { if (!pSource) { script_error_log("DoScriptText entry %i, invalid Source pointer.", iTextEntry); return; } if (iTextEntry >= 0) { script_error_log("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(), iTextEntry); return; } DoDisplayText(pSource, iTextEntry, pTarget); // TODO - maybe add some call-stack like error output if above function returns false }
void JustDied(Unit* pKiller) override { // Allow the body to begin the transition if (m_pInstance) { if (Creature* pCthun = m_pInstance->GetSingleCreatureFromStorage(NPC_CTHUN)) pCthun->AI()->AttackStart(pKiller); else script_error_log("C'thun could not be found. Please check your database!"); } }
void UpdateAI(const uint32 uiDiff) override { if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if (m_uiCheckBuddyTimer) { if (m_uiCheckBuddyTimer <= uiDiff) { Creature* pBuddy = m_creature->GetMap()->GetCreature(m_buddyGuid); if (!pBuddy) { script_error_log("npc_storm_tempered_keeper for %s couldn't find its buddy.", m_creature->GetGuidStr().c_str()); m_uiCheckBuddyTimer = 0; return; } // check if buddy is withind distance or alive if (!pBuddy->IsWithinDistInMap(m_creature, MAX_KEEPER_DISTANCE)) { if (DoCastSpellIfCan(m_creature, SPELL_SEPARATION_ANXIETY) == CAST_OK) m_uiCheckBuddyTimer = 5000; } else if (!pBuddy->isAlive()) { if (DoCastSpellIfCan(m_creature, SPELL_VENGEFUL_SURGE) == CAST_OK) m_uiCheckBuddyTimer = 0; } else m_uiCheckBuddyTimer = 1000; } else m_uiCheckBuddyTimer -= uiDiff; // spawn a sphere only if the buddy is stil alive if (m_uiSphereTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_SUMMON_CHARGED_SPHERE) == CAST_OK) m_uiSphereTimer = urand(20000, 35000); } else m_uiSphereTimer -= uiDiff; } if (m_uiLightningTimer < uiDiff) { if (DoCastSpellIfCan(m_creature, SPELL_FORKED_LIGHTNING) == CAST_OK) m_uiLightningTimer = urand(10000, 15000); } else m_uiLightningTimer -= uiDiff; DoMeleeAttackIfReady(); }
/// Returns a pointer to a loaded GameObject that was stored in m_goEntryGuidStore. Can return nullptr GameObject* ScriptedInstance::GetSingleGameObjectFromStorage(uint32 entry) { EntryGuidMap::iterator find = m_goEntryGuidStore.find(entry); if (find != m_goEntryGuidStore.end()) return instance->GetGameObject(find->second); // Output log, possible reason is not added GO to map, or not yet loaded; script_error_log("Script requested gameobject with entry %u, but no gameobject of this entry was created yet, or it was not stored by script for map %u.", entry, instance->GetId()); return nullptr; }
void LoadDatabase() { std::string strSD2DBinfo = SD2Config.GetStringDefault("WorldDatabaseInfo", ""); if (strSD2DBinfo.empty()) { script_error_log("Missing Scriptdev2 database info from configuration file. Load database aborted."); return; } // Initialize connection to DB if (SD2Database.Initialize(strSD2DBinfo.c_str())) { outstring_log("SD2: ScriptDev2 database initialized."); outstring_log(""); // Extract DB-Name std::string::size_type n = strSD2DBinfo.rfind(';'); std::string dbname; if (n != std::string::npos && n + 1 != std::string::npos) dbname = strSD2DBinfo.substr(n + 1); else dbname = "SD2_Database"; dbname.append(".script_waypoint"); SetExternalWaypointTable(dbname.c_str()); // Load content // pSystemMgr.LoadVersion(); // currently we are not checking for version; function to be completely removed in the future pSystemMgr.LoadScriptTexts(); pSystemMgr.LoadScriptTextsCustom(); pSystemMgr.LoadScriptGossipTexts(); pSystemMgr.LoadScriptWaypoints(); } else { script_error_log("Unable to connect to Database. Load database aborted."); return; } SD2Database.HaltDelayThread(); }
void instance_ruins_of_ahnqiraj::DoSendNextArmyWave() { // The next army wave is sent into battle after 2 min or after the previous wave is finished if (GetData(TYPE_RAJAXX) != IN_PROGRESS) return; // The last wave is General Rajaxx itself if (m_uiCurrentArmyWave == MAX_ARMY_WAVES) { if (Creature* pRajaxx = GetSingleCreatureFromStorage(NPC_RAJAXX)) { DoScriptText(SAY_INTRO, pRajaxx); pRajaxx->SetInCombatWithZone(); } } else { // Increase the wave id if some are already dead while (m_sArmyWavesGuids[m_uiCurrentArmyWave].empty() && m_uiCurrentArmyWave < MAX_ARMY_WAVES) ++m_uiCurrentArmyWave; if (m_uiCurrentArmyWave == MAX_ARMY_WAVES) { script_error_log("Instance Ruins of Ahn'Qiraj: ERROR Something unexpected happened. Please report to SD2 team."); return; } float fX, fY, fZ; for (auto itr : m_sArmyWavesGuids[m_uiCurrentArmyWave]) { if (Creature* pTemp = instance->GetCreature(itr)) { if (!pTemp->isAlive()) continue; pTemp->SetWalk(false); pTemp->GetRandomPoint(aAndorovMoveLocs[4].m_fX, aAndorovMoveLocs[4].m_fY, aAndorovMoveLocs[4].m_fZ, 10.0f, fX, fY, fZ); pTemp->GetMotionMaster()->MovePoint(0, fX, fY, fZ); } } // Yell on each wave (except the first 2) if (aArmySortingParameters[m_uiCurrentArmyWave].m_uiYellEntry) { if (Creature* pRajaxx = GetSingleCreatureFromStorage(NPC_RAJAXX)) DoScriptText(aArmySortingParameters[m_uiCurrentArmyWave].m_uiYellEntry, pRajaxx); } } // on wowwiki it states that there were 3 min between the waves, but this was reduced in later patches m_uiArmyDelayTimer = 2 * MINUTE * IN_MILLISECONDS; ++m_uiCurrentArmyWave; }
/// Returns a pointer to a loaded Creature that was stored in m_goEntryGuidStore. Can return nullptr Creature* ScriptedInstance::GetSingleCreatureFromStorage(uint32 entry, bool skipDebugLog /*=false*/) { EntryGuidMap::iterator find = m_npcEntryGuidStore.find(entry); if (find != m_npcEntryGuidStore.end()) return instance->GetCreature(find->second); // Output log, possible reason is not added GO to map, or not yet loaded; if (!skipDebugLog) script_error_log("Script requested creature with entry %u, but no npc of this entry was created yet, or it was not stored by script for map %u.", entry, instance->GetId()); return nullptr; }
void ScriptedAI::DoTeleportPlayer(Unit* pUnit, float fX, float fY, float fZ, float fO) { if (!pUnit) return; if (pUnit->GetTypeId() != TYPEID_PLAYER) { script_error_log("%s tried to teleport non-player (%s) to x: %f y:%f z: %f o: %f. Aborted.", m_creature->GetGuidStr().c_str(), pUnit->GetGuidStr().c_str(), fX, fY, fZ, fO); return; } ((Player*)pUnit)->TeleportTo(pUnit->GetMapId(), fX, fY, fZ, fO, TELE_TO_NOT_LEAVE_COMBAT); }