[c12559] DBScripts - Add Map/Zone wide sound support to COMMAND_PLAY_SOUND

This commit is contained in:
Xfurry 2013-05-31 09:19:13 +01:00 committed by Antz
parent d275d04145
commit 7fec4dacae
4 changed files with 346 additions and 219 deletions

View file

@ -206,7 +206,8 @@ Where "A -> B" means that the command is executed from A with B as target.
16 SCRIPT_COMMAND_PLAY_SOUND source = any object, target=any/player
* datalong = sound_id
* datalong2 (bitmask: 0/1=anyone/target, 0/2=with distance dependent, so 1|2 = 3 is target with distance dependent)
* datalong2 (bitmask: 0/1=target-player, 0/2=with distance dependent, 0/4=map wide, 0/8=zone wide;
so 1|2 = 3 is target with distance dependent)
17 SCRIPT_COMMAND_CREATE_ITEM source or target must be player
* datalong = item entry

View file

@ -17,7 +17,7 @@
*/
#include "ScriptMgr.h"
#include "Policies/SingletonImp.h"
#include "Policies/Singleton.h"
#include "Log.h"
#include "ProgressBar.h"
#include "ObjectMgr.h"
@ -28,6 +28,9 @@
#include "Cell.h"
#include "CellImpl.h"
#include "SQLStorages.h"
#include "BattleGround/BattleGround.h"
#include "OutdoorPvP/OutdoorPvP.h"
#include "WaypointMovementGenerator.h"
#include "revision_nr.h"
@ -38,6 +41,7 @@ ScriptMapMapName sGameObjectScripts;
ScriptMapMapName sGameObjectTemplateScripts;
ScriptMapMapName sEventScripts;
ScriptMapMapName sGossipScripts;
ScriptMapMapName sCreatureDeathScripts;
ScriptMapMapName sCreatureMovementScripts;
INSTANTIATE_SINGLETON_1(ScriptMgr);
@ -368,7 +372,7 @@ void ScriptMgr::LoadScripts(ScriptMapMapName& scripts, const char* tablename)
info->type == GAMEOBJECT_TYPE_BUTTON ||
info->type == GAMEOBJECT_TYPE_TRAP)
{
sLog.outErrorDb("Table `%s` have gameobject type (%u) unsupported by command SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u", tablename, info->id, tmp.id);
sLog.outErrorDb("Table `%s` have gameobject type (%u) unsupported by command SCRIPT_COMMAND_RESPAWN_GAMEOBJECT for script id %u", tablename, info->type, tmp.id);
continue;
}
break;
@ -458,6 +462,11 @@ void ScriptMgr::LoadScripts(ScriptMapMapName& scripts, const char* tablename)
tablename, tmp.playSound.soundId, tmp.id);
continue;
}
// bitmask: 0/1=target-player, 0/2=with distance dependent, 0/4=map wide, 0/8=zone wide
if (tmp.playSound.flags & ~(1 | 2 | 4 | 8))
sLog.outErrorDb("Table `%s` using unsupported sound flags (datalong2: %u) in SCRIPT_COMMAND_PLAY_SOUND for script id %u, unsupported flags will be ignored", tablename, tmp.playSound.flags, tmp.id);
if ((tmp.playSound.flags & (1 | 2)) > 0 && (tmp.playSound.flags & (4 | 8)) > 0)
sLog.outErrorDb("Table `%s` uses sound flags (datalong2: %u) in SCRIPT_COMMAND_PLAY_SOUND for script id %u, combining (1|2) with (4|8) makes no sense", tablename, tmp.playSound.flags, tmp.id);
break;
}
case SCRIPT_COMMAND_CREATE_ITEM: // 17
@ -622,6 +631,17 @@ void ScriptMgr::LoadScripts(ScriptMapMapName& scripts, const char* tablename)
}
break;
}
case SCRIPT_COMMAND_TERMINATE_SCRIPT: // 31
{
if (tmp.terminateScript.npcEntry && !ObjectMgr::GetCreatureTemplate(tmp.terminateScript.npcEntry))
{
sLog.outErrorDb("Table `%s` has datalong = %u in SCRIPT_COMMAND_TERMINATE_SCRIPT for script id %u, but this npc entry does not exist.", tablename, tmp.sendTaxiPath.taxiPathId, tmp.id);
continue;
}
break;
}
case SCRIPT_COMMAND_PAUSE_WAYPOINTS: // 32
break;
default:
{
sLog.outErrorDb("Table `%s` unknown command %u, skipping.", tablename, tmp.command);
@ -648,55 +668,55 @@ void ScriptMgr::LoadScripts(ScriptMapMapName& scripts, const char* tablename)
void ScriptMgr::LoadGameObjectScripts()
{
LoadScripts(sGameObjectScripts, "gameobject_scripts");
LoadScripts(sGameObjectScripts, "dbscripts_on_go_use");
// check ids
for (ScriptMapMap::const_iterator itr = sGameObjectScripts.second.begin(); itr != sGameObjectScripts.second.end(); ++itr)
{
if (!sObjectMgr.GetGOData(itr->first))
sLog.outErrorDb("Table `gameobject_scripts` has not existing gameobject (GUID: %u) as script id", itr->first);
sLog.outErrorDb("Table `dbscripts_on_go_use` has not existing gameobject (GUID: %u) as script id", itr->first);
}
}
void ScriptMgr::LoadGameObjectTemplateScripts()
{
LoadScripts(sGameObjectTemplateScripts, "gameobject_template_scripts");
LoadScripts(sGameObjectTemplateScripts, "dbscripts_on_go_template_use");
// check ids
for (ScriptMapMap::const_iterator itr = sGameObjectTemplateScripts.second.begin(); itr != sGameObjectTemplateScripts.second.end(); ++itr)
{
if (!sObjectMgr.GetGameObjectInfo(itr->first))
sLog.outErrorDb("Table `gameobject_template_scripts` has not existing gameobject (Entry: %u) as script id", itr->first);
sLog.outErrorDb("Table `dbscripts_on_go_template_use` has not existing gameobject (Entry: %u) as script id", itr->first);
}
}
void ScriptMgr::LoadQuestEndScripts()
{
LoadScripts(sQuestEndScripts, "quest_end_scripts");
LoadScripts(sQuestEndScripts, "dbscripts_on_quest_end");
// check ids
for (ScriptMapMap::const_iterator itr = sQuestEndScripts.second.begin(); itr != sQuestEndScripts.second.end(); ++itr)
{
if (!sObjectMgr.GetQuestTemplate(itr->first))
sLog.outErrorDb("Table `quest_end_scripts` has not existing quest (Id: %u) as script id", itr->first);
sLog.outErrorDb("Table `dbscripts_on_quest_end` has not existing quest (Id: %u) as script id", itr->first);
}
}
void ScriptMgr::LoadQuestStartScripts()
{
LoadScripts(sQuestStartScripts, "quest_start_scripts");
LoadScripts(sQuestStartScripts, "dbscripts_on_quest_start");
// check ids
for (ScriptMapMap::const_iterator itr = sQuestStartScripts.second.begin(); itr != sQuestStartScripts.second.end(); ++itr)
{
if (!sObjectMgr.GetQuestTemplate(itr->first))
sLog.outErrorDb("Table `quest_start_scripts` has not existing quest (Id: %u) as script id", itr->first);
sLog.outErrorDb("Table `dbscripts_on_quest_start` has not existing quest (Id: %u) as script id", itr->first);
}
}
void ScriptMgr::LoadSpellScripts()
{
LoadScripts(sSpellScripts, "spell_scripts");
LoadScripts(sSpellScripts, "dbscripts_on_spell");
// check ids
for (ScriptMapMap::const_iterator itr = sSpellScripts.second.begin(); itr != sSpellScripts.second.end(); ++itr)
@ -704,7 +724,7 @@ void ScriptMgr::LoadSpellScripts()
SpellEntry const* spellInfo = sSpellStore.LookupEntry(itr->first);
if (!spellInfo)
{
sLog.outErrorDb("Table `spell_scripts` has not existing spell (Id: %u) as script id", itr->first);
sLog.outErrorDb("Table `dbscripts_on_spell` has not existing spell (Id: %u) as script id", itr->first);
continue;
}
@ -720,97 +740,53 @@ void ScriptMgr::LoadSpellScripts()
}
if (!found)
sLog.outErrorDb("Table `spell_scripts` has unsupported spell (Id: %u)", itr->first);
sLog.outErrorDb("Table `dbscripts_on_spell` has unsupported spell (Id: %u)", itr->first);
}
}
void ScriptMgr::LoadEventScripts()
{
LoadScripts(sEventScripts, "event_scripts");
LoadScripts(sEventScripts, "dbscripts_on_event");
std::set<uint32> evt_scripts;
// Load all possible script entries from gameobjects
for (uint32 i = 1; i < sGOStorage.MaxEntry; ++i)
{
if (GameObjectInfo const* goInfo = sGOStorage.LookupEntry<GameObjectInfo>(i))
{
if (uint32 eventId = goInfo->GetEventScriptId())
evt_scripts.insert(eventId);
if (goInfo->type == GAMEOBJECT_TYPE_CAPTURE_POINT)
{
evt_scripts.insert(goInfo->capturePoint.neutralEventID1);
evt_scripts.insert(goInfo->capturePoint.neutralEventID2);
evt_scripts.insert(goInfo->capturePoint.contestedEventID1);
evt_scripts.insert(goInfo->capturePoint.contestedEventID2);
evt_scripts.insert(goInfo->capturePoint.progressEventID1);
evt_scripts.insert(goInfo->capturePoint.progressEventID2);
evt_scripts.insert(goInfo->capturePoint.winEventID1);
evt_scripts.insert(goInfo->capturePoint.winEventID2);
}
}
}
// Load all possible script entries from spells
for (uint32 i = 1; i < sSpellStore.GetNumRows(); ++i)
{
SpellEntry const* spell = sSpellStore.LookupEntry(i);
if (spell)
{
for (int j = 0; j < MAX_EFFECT_INDEX; ++j)
{
SpellEffectEntry const* spellEffect = spell->GetSpellEffect(SpellEffectIndex(j));
if (!spellEffect)
continue;
if (spellEffect->Effect == SPELL_EFFECT_SEND_EVENT)
{
if (spellEffect->EffectMiscValue)
evt_scripts.insert(spellEffect->EffectMiscValue);
}
}
}
}
for (size_t path_idx = 0; path_idx < sTaxiPathNodesByPath.size(); ++path_idx)
{
for (size_t node_idx = 0; node_idx < sTaxiPathNodesByPath[path_idx].size(); ++node_idx)
{
TaxiPathNodeEntry const& node = sTaxiPathNodesByPath[path_idx][node_idx];
if (node.arrivalEventID)
evt_scripts.insert(node.arrivalEventID);
if (node.departureEventID)
evt_scripts.insert(node.departureEventID);
}
}
std::set<uint32> eventIds; // Store possible event ids
CollectPossibleEventIds(eventIds);
// Then check if all scripts are in above list of possible script entries
for (ScriptMapMap::const_iterator itr = sEventScripts.second.begin(); itr != sEventScripts.second.end(); ++itr)
{
std::set<uint32>::const_iterator itr2 = evt_scripts.find(itr->first);
if (itr2 == evt_scripts.end())
sLog.outErrorDb("Table `event_scripts` has script (Id: %u) not referring to any gameobject_template type 10 data2 field, type 3 data6 field, type 13 data 2 field, type 29 or any spell effect %u or path taxi node data",
std::set<uint32>::const_iterator itr2 = eventIds.find(itr->first);
if (itr2 == eventIds.end())
sLog.outErrorDb("Table `dbscripts_on_event` has script (Id: %u) not referring to any fitting gameobject_template or any spell effect %u or path taxi node data",
itr->first, SPELL_EFFECT_SEND_EVENT);
}
}
void ScriptMgr::LoadGossipScripts()
{
LoadScripts(sGossipScripts, "gossip_scripts");
LoadScripts(sGossipScripts, "dbscripts_on_gossip");
// checks are done in LoadGossipMenuItems and LoadGossipMenu
}
void ScriptMgr::LoadCreatureMovementScripts()
{
LoadScripts(sCreatureMovementScripts, "creature_movement_scripts");
LoadScripts(sCreatureMovementScripts, "dbscripts_on_creature_movement");
// checks are done in WaypointManager::Load
}
void ScriptMgr::LoadCreatureDeathScripts()
{
LoadScripts(sCreatureDeathScripts, "dbscripts_on_creature_death");
// check ids
for(ScriptMapMap::const_iterator itr = sCreatureDeathScripts.second.begin(); itr != sCreatureDeathScripts.second.end(); ++itr)
{
if (!sObjectMgr.GetCreatureTemplate(itr->first))
sLog.outErrorDb("Table `dbscripts_on_creature_death` has not existing creature (Entry: %u) as script id", itr->first);
}
}
void ScriptMgr::LoadDbScriptStrings()
{
sObjectMgr.LoadMangosStrings(WorldDatabase, "db_script_string", MIN_DB_SCRIPT_STRING_ID, MAX_DB_SCRIPT_STRING_ID);
@ -828,6 +804,7 @@ void ScriptMgr::LoadDbScriptStrings()
CheckScriptTexts(sGameObjectTemplateScripts, ids);
CheckScriptTexts(sEventScripts, ids);
CheckScriptTexts(sGossipScripts, ids);
CheckScriptTexts(sCreatureDeathScripts, ids);
CheckScriptTexts(sCreatureMovementScripts, ids);
sWaypointMgr.CheckTextsExistance(ids);
@ -1019,23 +996,32 @@ Player* ScriptAction::GetPlayerTargetOrSourceAndLog(WorldObject* pSource, WorldO
}
/// Handle one Script Step
void ScriptAction::HandleScriptStep()
// Return true if and only if further parts of this script shall be skipped
bool ScriptAction::HandleScriptStep()
{
Object* source = NULL;
Object* target = NULL;
if (!GetScriptCommandObject(m_sourceGuid, true, source))
return;
if (!GetScriptCommandObject(m_targetGuid, false, target))
return;
WorldObject* pSource;
WorldObject* pTarget;
Object* pSourceOrItem; // Stores a provided pSource (if exists as WorldObject) or source-item
// Give some debug log output for easier use
DEBUG_LOG("DB-SCRIPTS: Process table `%s` id %u, command %u for source %s (%sin world), target %s (%sin world)", m_table, m_script->id, m_script->command, m_sourceGuid.GetString().c_str(), source ? "" : "not ", m_targetGuid.GetString().c_str(), target ? "" : "not ");
{ // Add scope for source & target variables so that they are not used below
Object* source = NULL;
Object* target = NULL;
if (!GetScriptCommandObject(m_sourceGuid, true, source))
return false;
if (!GetScriptCommandObject(m_targetGuid, false, target))
return false;
// Get expected source and target (if defined with buddy)
WorldObject* pSource = source && source->isType(TYPEMASK_WORLDOBJECT) ? (WorldObject*)source : NULL;
WorldObject* pTarget = target && target->isType(TYPEMASK_WORLDOBJECT) ? (WorldObject*)target : NULL;
if (!GetScriptProcessTargets(pSource, pTarget, pSource, pTarget))
return;
// Give some debug log output for easier use
DEBUG_LOG("DB-SCRIPTS: Process table `%s` id %u, command %u for source %s (%sin world), target %s (%sin world)", m_table, m_script->id, m_script->command, m_sourceGuid.GetString().c_str(), source ? "" : "not ", m_targetGuid.GetString().c_str(), target ? "" : "not ");
// Get expected source and target (if defined with buddy)
pSource = source && source->isType(TYPEMASK_WORLDOBJECT) ? (WorldObject*)source : NULL;
pTarget = target && target->isType(TYPEMASK_WORLDOBJECT) ? (WorldObject*)target : NULL;
if (!GetScriptProcessTargets(pSource, pTarget, pSource, pTarget))
return false;
pSourceOrItem = pSource ? pSource : (source && source->isType(TYPEMASK_ITEM) ? source : NULL);
}
switch (m_script->command)
{
@ -1111,20 +1097,18 @@ void ScriptAction::HandleScriptStep()
break;
}
case SCRIPT_COMMAND_FIELD_SET: // 2
// TODO
if (!source)
if (!pSourceOrItem)
{
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u call for NULL object.", m_table, m_script->id, m_script->command);
break;
}
if (m_script->setField.fieldId <= OBJECT_FIELD_ENTRY || m_script->setField.fieldId >= source->GetValuesCount())
if (m_script->setField.fieldId <= OBJECT_FIELD_ENTRY || m_script->setField.fieldId >= pSourceOrItem->GetValuesCount())
{
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u call for wrong field %u (max count: %u) in object (TypeId: %u).", m_table, m_script->id, m_script->command, m_script->setField.fieldId, source->GetValuesCount(), source->GetTypeId());
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u call for wrong field %u (max count: %u) in %s.",
m_table, m_script->id, m_script->command, m_script->setField.fieldId, pSourceOrItem->GetValuesCount(), pSourceOrItem->GetGuidStr().c_str());
break;
}
source->SetUInt32Value(m_script->setField.fieldId, m_script->setField.fieldValue);
pSourceOrItem->SetUInt32Value(m_script->setField.fieldId, m_script->setField.fieldValue);
break;
case SCRIPT_COMMAND_MOVE_TO: // 3
{
@ -1158,36 +1142,32 @@ void ScriptAction::HandleScriptStep()
break;
}
case SCRIPT_COMMAND_FLAG_SET: // 4
// TODO
if (!source)
if (!pSourceOrItem)
{
sLog.outError("SCRIPT_COMMAND_FLAG_SET (script id %u) call for NULL object.", m_script->id);
break;
}
if (m_script->setFlag.fieldId <= OBJECT_FIELD_ENTRY || m_script->setFlag.fieldId >= source->GetValuesCount())
if (m_script->setFlag.fieldId <= OBJECT_FIELD_ENTRY || m_script->setFlag.fieldId >= pSourceOrItem->GetValuesCount())
{
sLog.outError("SCRIPT_COMMAND_FLAG_SET (script id %u) call for wrong field %u (max count: %u) in object (TypeId: %u).",
m_script->id, m_script->setFlag.fieldId, source->GetValuesCount(), source->GetTypeId());
sLog.outError("SCRIPT_COMMAND_FLAG_SET (script id %u) call for wrong field %u (max count: %u) in %s.",
m_script->id, m_script->setFlag.fieldId, pSourceOrItem->GetValuesCount(), pSourceOrItem->GetGuidStr().c_str());
break;
}
source->SetFlag(m_script->setFlag.fieldId, m_script->setFlag.fieldValue);
pSourceOrItem->SetFlag(m_script->setFlag.fieldId, m_script->setFlag.fieldValue);
break;
case SCRIPT_COMMAND_FLAG_REMOVE: // 5
// TODO
if (!source)
if (!pSourceOrItem)
{
sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE (script id %u) call for NULL object.", m_script->id);
break;
}
if (m_script->removeFlag.fieldId <= OBJECT_FIELD_ENTRY || m_script->removeFlag.fieldId >= source->GetValuesCount())
if (m_script->removeFlag.fieldId <= OBJECT_FIELD_ENTRY || m_script->removeFlag.fieldId >= pSourceOrItem->GetValuesCount())
{
sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE (script id %u) call for wrong field %u (max count: %u) in object (TypeId: %u).",
m_script->id, m_script->removeFlag.fieldId, source->GetValuesCount(), source->GetTypeId());
sLog.outError("SCRIPT_COMMAND_FLAG_REMOVE (script id %u) call for wrong field %u (max count: %u) in %s.",
m_script->id, m_script->removeFlag.fieldId, pSourceOrItem->GetValuesCount(), pSourceOrItem->GetGuidStr().c_str());
break;
}
source->RemoveFlag(m_script->removeFlag.fieldId, m_script->removeFlag.fieldValue);
pSourceOrItem->RemoveFlag(m_script->removeFlag.fieldId, m_script->removeFlag.fieldValue);
break;
case SCRIPT_COMMAND_TELEPORT_TO: // 6
{
@ -1323,7 +1303,7 @@ void ScriptAction::HandleScriptStep()
float z = m_script->z;
float o = m_script->o;
Creature* pCreature = pSource->SummonCreature(m_script->summonCreature.creatureEntry, x, y, z, o, m_script->summonCreature.despawnDelay ? TEMPSUMMON_TIMED_OR_DEAD_DESPAWN : TEMPSUMMON_DEAD_DESPAWN, m_script->summonCreature.despawnDelay, (m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL) ? true : false);
Creature* pCreature = pSource->SummonCreature(m_script->summonCreature.creatureEntry, x, y, z, o, m_script->summonCreature.despawnDelay ? TEMPSUMMON_TIMED_OOC_OR_DEAD_DESPAWN : TEMPSUMMON_DEAD_DESPAWN, m_script->summonCreature.despawnDelay, (m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL) ? true : false);
if (!pCreature)
{
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u failed for creature (entry: %u).", m_table, m_script->id, m_script->command, m_script->summonCreature.creatureEntry);
@ -1374,7 +1354,7 @@ void ScriptAction::HandleScriptStep()
pDoor->UseDoorOrButton(time_to_reset);
if (pTarget && pTarget->isType(TYPEMASK_GAMEOBJECT) && ((GameObject*)pTarget)->GetGoType() == GAMEOBJECT_TYPE_BUTTON)
((GameObject*)target)->UseDoorOrButton(time_to_reset);
((GameObject*)pTarget)->UseDoorOrButton(time_to_reset);
break;
}
@ -1408,7 +1388,7 @@ void ScriptAction::HandleScriptStep()
break;
}
case SCRIPT_COMMAND_PLAY_SOUND: // 16 // TODO
case SCRIPT_COMMAND_PLAY_SOUND: // 16
{
if (!pSource)
{
@ -1416,31 +1396,21 @@ void ScriptAction::HandleScriptStep()
break;
}
// bitmask: 0/1=anyone/target, 0/2=with distance dependent
Player* pTarget = NULL;
// bitmask: 0/1=target-player, 0/2=with distance dependent, 0/4=map wide, 0/8=zone wide
Player* pSoundTarget = NULL;
if (m_script->playSound.flags & 1)
{
if (!target)
{
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u in targeted mode call for NULL target.", m_table, m_script->id, m_script->command);
pSoundTarget = GetPlayerTargetOrSourceAndLog(pSource, pTarget);
if (!pSoundTarget)
break;
}
if (target->GetTypeId() != TYPEID_PLAYER)
{
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u in targeted mode call for non-player (TypeId: %u), skipping.", m_table, m_script->id, m_script->command, target->GetTypeId());
break;
}
pTarget = (Player*)target;
}
// bitmask: 0/1=anyone/target, 0/2=with distance dependent
if (m_script->playSound.flags & 2)
pSource->PlayDistanceSound(m_script->playSound.soundId, pTarget);
pSource->PlayDistanceSound(m_script->playSound.soundId, pSoundTarget);
else if (m_script->playSound.flags & (4 | 8))
m_map->PlayDirectSoundToMap(m_script->playSound.soundId, m_script->playSound.flags & 8 ? pSource->GetZoneId() : 0);
else
pSource->PlayDirectSound(m_script->playSound.soundId, pTarget);
pSource->PlayDirectSound(m_script->playSound.soundId, pSoundTarget);
break;
}
@ -1575,7 +1545,7 @@ void ScriptAction::HandleScriptStep()
if (LogIfNotCreature(pSource))
break;
((Creature*)pSource)->SetWalk(!m_script->run.run);
((Creature*)pSource)->SetWalk(!m_script->run.run, true);
break;
}
@ -1587,7 +1557,7 @@ void ScriptAction::HandleScriptStep()
break;
Creature* pAttacker = static_cast<Creature*>(pSource);
Unit* unitTarget = static_cast<Unit*>(target);
Unit* unitTarget = static_cast<Unit*>(pTarget);
if (pAttacker->IsFriendlyTo(unitTarget))
{
@ -1667,10 +1637,64 @@ void ScriptAction::HandleScriptStep()
pPlayer->ActivateTaxiPathTo(m_script->sendTaxiPath.taxiPathId);
break;
}
case SCRIPT_COMMAND_TERMINATE_SCRIPT: // 31
{
bool result = false;
if (m_script->terminateScript.npcEntry)
{
WorldObject* pSearcher = pSource ? pSource : pTarget;
if (pSearcher->GetTypeId() == TYPEID_PLAYER && pTarget && pTarget->GetTypeId() != TYPEID_PLAYER)
pSearcher = pTarget;
Creature* pCreatureBuddy = NULL;
MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck u_check(*pSearcher, m_script->terminateScript.npcEntry, true, false, m_script->terminateScript.searchDist);
MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(pCreatureBuddy, u_check);
Cell::VisitGridObjects(pSearcher, searcher, m_script->terminateScript.searchDist);
if (!(m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL) && !pCreatureBuddy)
{
DEBUG_LOG("DB-SCRIPTS: Process table `%s` id %u, terminate further steps of this script! (as searched npc %u was not found alive)", m_table, m_script->id, m_script->terminateScript.npcEntry);
result = true;
}
else if (m_script->data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL && pCreatureBuddy)
{
DEBUG_LOG("DB-SCRIPTS: Process table `%s` id %u, terminate further steps of this script! (as searched npc %u was found alive)", m_table, m_script->id, m_script->terminateScript.npcEntry);
result = true;
}
}
else
result = true;
if (result) // Terminate further steps of this script
{
if (m_script->textId[0] && !LogIfNotCreature(pSource))
{
Creature* cSource = static_cast<Creature*>(pSource);
if (cSource->GetMotionMaster()->GetCurrentMovementGeneratorType() == WAYPOINT_MOTION_TYPE)
(static_cast<WaypointMovementGenerator<Creature>* >(cSource->GetMotionMaster()->top()))->AddToWaypointPauseTime(m_script->textId[0]);
}
return true;
}
break;
}
case SCRIPT_COMMAND_PAUSE_WAYPOINTS: // 32
{
if (LogIfNotCreature(pSource))
return false;
if (m_script->pauseWaypoint.doPause)
((Creature*)pSource)->addUnitState(UNIT_STAT_WAYPOINT_PAUSED);
else
((Creature*)pSource)->clearUnitState(UNIT_STAT_WAYPOINT_PAUSED);
break;
}
default:
sLog.outError(" DB-SCRIPTS: Process table `%s` id %u, command %u unknown command used.", m_table, m_script->id, m_script->command);
break;
}
return false;
}
// /////////////////////////////////////////////////////////
@ -1741,66 +1765,8 @@ void ScriptMgr::LoadEventIdScripts()
BarGoLink bar(result->GetRowCount());
// TODO: remove duplicate code below, same way to collect event id's used in LoadEventScripts()
std::set<uint32> evt_scripts;
// Load all possible event entries from gameobjects
for (uint32 i = 1; i < sGOStorage.MaxEntry; ++i)
{
if (GameObjectInfo const* goInfo = sGOStorage.LookupEntry<GameObjectInfo>(i))
{
if (uint32 eventId = goInfo->GetEventScriptId())
evt_scripts.insert(eventId);
if (goInfo->type == GAMEOBJECT_TYPE_CAPTURE_POINT)
{
evt_scripts.insert(goInfo->capturePoint.neutralEventID1);
evt_scripts.insert(goInfo->capturePoint.neutralEventID2);
evt_scripts.insert(goInfo->capturePoint.contestedEventID1);
evt_scripts.insert(goInfo->capturePoint.contestedEventID2);
evt_scripts.insert(goInfo->capturePoint.progressEventID1);
evt_scripts.insert(goInfo->capturePoint.progressEventID2);
evt_scripts.insert(goInfo->capturePoint.winEventID1);
evt_scripts.insert(goInfo->capturePoint.winEventID2);
}
}
}
// Load all possible event entries from spells
for (uint32 i = 1; i < sSpellStore.GetNumRows(); ++i)
{
SpellEntry const* spell = sSpellStore.LookupEntry(i);
if (spell)
{
for (int j = 0; j < MAX_EFFECT_INDEX; ++j)
{
SpellEffectEntry const* spellEffect = spell->GetSpellEffect(SpellEffectIndex(j));
if (!spellEffect)
continue;
if (spellEffect->Effect == SPELL_EFFECT_SEND_EVENT)
{
if (spellEffect->EffectMiscValue)
evt_scripts.insert(spellEffect->EffectMiscValue);
}
}
}
}
// Load all possible event entries from taxi path nodes
for (size_t path_idx = 0; path_idx < sTaxiPathNodesByPath.size(); ++path_idx)
{
for (size_t node_idx = 0; node_idx < sTaxiPathNodesByPath[path_idx].size(); ++node_idx)
{
TaxiPathNodeEntry const& node = sTaxiPathNodesByPath[path_idx][node_idx];
if (node.arrivalEventID)
evt_scripts.insert(node.arrivalEventID);
if (node.departureEventID)
evt_scripts.insert(node.departureEventID);
}
}
std::set<uint32> eventIds; // Store possible event ids
CollectPossibleEventIds(eventIds);
do
{
@ -1812,8 +1778,8 @@ void ScriptMgr::LoadEventIdScripts()
uint32 eventId = fields[0].GetUInt32();
const char* scriptName = fields[1].GetString();
std::set<uint32>::const_iterator itr = evt_scripts.find(eventId);
if (itr == evt_scripts.end())
std::set<uint32>::const_iterator itr = eventIds.find(eventId);
if (itr == eventIds.end())
sLog.outErrorDb("Table `scripted_event_id` has id %u not referring to any gameobject_template type 10 data2 field, type 3 data6 field, type 13 data 2 field, type 29 or any spell effect %u or path taxi node data",
eventId, SPELL_EFFECT_SEND_EVENT);
@ -2146,6 +2112,125 @@ void ScriptMgr::UnloadScriptLibrary()
m_pOnAuraDummy = NULL;
}
void ScriptMgr::CollectPossibleEventIds(std::set<uint32>& eventIds)
{
// Load all possible script entries from gameobjects
for (SQLStorageBase::SQLSIterator<GameObjectInfo> itr = sGOStorage.getDataBegin<GameObjectInfo>(); itr < sGOStorage.getDataEnd<GameObjectInfo>(); ++itr)
{
switch (itr->type)
{
case GAMEOBJECT_TYPE_GOOBER:
eventIds.insert(itr->goober.eventId);
break;
case GAMEOBJECT_TYPE_CHEST:
eventIds.insert(itr->chest.eventId);
break;
case GAMEOBJECT_TYPE_CAMERA:
eventIds.insert(itr->camera.eventID);
break;
case GAMEOBJECT_TYPE_CAPTURE_POINT:
eventIds.insert(itr->capturePoint.neutralEventID1);
eventIds.insert(itr->capturePoint.neutralEventID2);
eventIds.insert(itr->capturePoint.contestedEventID1);
eventIds.insert(itr->capturePoint.contestedEventID2);
eventIds.insert(itr->capturePoint.progressEventID1);
eventIds.insert(itr->capturePoint.progressEventID2);
eventIds.insert(itr->capturePoint.winEventID1);
eventIds.insert(itr->capturePoint.winEventID2);
break;
case GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING:
eventIds.insert(itr->destructibleBuilding.damagedEvent);
eventIds.insert(itr->destructibleBuilding.destroyedEvent);
eventIds.insert(itr->destructibleBuilding.intactEvent);
eventIds.insert(itr->destructibleBuilding.rebuildingEvent);
break;
default:
break;
}
}
// Load all possible script entries from spells
for (uint32 i = 1; i < sSpellStore.GetNumRows(); ++i)
{
SpellEntry const* spell = sSpellStore.LookupEntry(i);
if (spell)
{
for (int j = 0; j < MAX_EFFECT_INDEX; ++j)
{
SpellEffectEntry const* spellEffect = spell->GetSpellEffect(SpellEffectIndex(j));
if (!spellEffect)
continue;
if (spellEffect->Effect == SPELL_EFFECT_SEND_EVENT)
{
if (spellEffect->EffectMiscValue)
eventIds.insert(spellEffect->EffectMiscValue);
}
}
}
}
// Load all possible event entries from taxi path nodes
for (size_t path_idx = 0; path_idx < sTaxiPathNodesByPath.size(); ++path_idx)
{
for (size_t node_idx = 0; node_idx < sTaxiPathNodesByPath[path_idx].size(); ++node_idx)
{
TaxiPathNodeEntry const& node = sTaxiPathNodesByPath[path_idx][node_idx];
if (node.arrivalEventID)
eventIds.insert(node.arrivalEventID);
if (node.departureEventID)
eventIds.insert(node.departureEventID);
}
}
}
// Starters for events
bool StartEvents_Event(Map* map, uint32 id, Object* source, Object* target, bool isStart/*=true*/, Unit* forwardToPvp/*=NULL*/)
{
MANGOS_ASSERT(source);
// Handle SD2 script
if (sScriptMgr.OnProcessEvent(id, source, target, isStart))
return true;
// Handle PvP Calls
if (forwardToPvp && source->GetTypeId() == TYPEID_GAMEOBJECT)
{
BattleGround* bg = NULL;
OutdoorPvP* opvp = NULL;
if (forwardToPvp->GetTypeId() == TYPEID_PLAYER)
{
bg = ((Player*)forwardToPvp)->GetBattleGround();
if (!bg)
opvp = sOutdoorPvPMgr.GetScript(((Player*)forwardToPvp)->GetCachedZoneId());
}
else
{
if (map->IsBattleGroundOrArena())
bg = ((BattleGroundMap*)map)->GetBG();
else // Use the go, because GOs don't move
opvp = sOutdoorPvPMgr.GetScript(((GameObject*)source)->GetZoneId());
}
if (bg && bg->HandleEvent(id, static_cast<GameObject*>(source)))
return true;
if (opvp && opvp->HandleEvent(id, static_cast<GameObject*>(source)))
return true;
}
Map::ScriptExecutionParam execParam = Map::SCRIPT_EXEC_PARAM_UNIQUE_BY_SOURCE_TARGET;
if (source->isType(TYPEMASK_CREATURE_OR_GAMEOBJECT))
execParam = Map::SCRIPT_EXEC_PARAM_UNIQUE_BY_SOURCE;
else if (target && target->isType(TYPEMASK_CREATURE_OR_GAMEOBJECT))
execParam = Map::SCRIPT_EXEC_PARAM_UNIQUE_BY_TARGET;
return map->ScriptsStart(sEventScripts, id, source, target, execParam);
}
// Wrappers
uint32 GetAreaTriggerScriptId(uint32 triggerId)
{
return sScriptMgr.GetAreaTriggerScriptId(triggerId);

View file

@ -44,13 +44,13 @@ class WorldObject;
enum ScriptCommand // resSource, resTarget are the resulting Source/ Target after buddy search is done
{
SCRIPT_COMMAND_TALK = 0, // resSource = WorldObject, resTarget = Unit/none
// datalong1 (see enum ChatType for supported CHAT_TYPE_'s), datalong2 = language
// dataint = text entry from db_script_string -table. dataint2-4 optional for random selected texts.
// datalong1 (see enum ChatType for supported CHAT_TYPE_'s), datalong2 = language
// dataint = text entry from db_script_string -table. dataint2-4 optional for random selected texts.
SCRIPT_COMMAND_EMOTE = 1, // resSource = Unit, resTarget = Unit/none
// datalong1 = emote_id
// datalong1 = emote_id
SCRIPT_COMMAND_FIELD_SET = 2, // source = any, datalong = field_id, datalong2 = value
SCRIPT_COMMAND_MOVE_TO = 3, // resSource = Creature, datalong2 = travel_speed*100, x/y/z
// data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL: teleport unit to position
// data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL: teleport unit to position
SCRIPT_COMMAND_FLAG_SET = 4, // source = any, datalong = field_id, datalong2 = bitmask
SCRIPT_COMMAND_FLAG_REMOVE = 5, // source = any, datalong = field_id, datalong2 = bitmask
SCRIPT_COMMAND_TELEPORT_TO = 6, // source or target with Player, datalong2 = map_id, x/y/z
@ -58,39 +58,46 @@ enum ScriptCommand // resSource, resTar
SCRIPT_COMMAND_KILL_CREDIT = 8, // source or target with Player, datalong = creature entry (or 0 for target-entry), datalong2 = bool (0=personal credit, 1=group credit)
SCRIPT_COMMAND_RESPAWN_GAMEOBJECT = 9, // source = any, datalong=db_guid, datalong2=despawn_delay
SCRIPT_COMMAND_TEMP_SUMMON_CREATURE = 10, // source = any, datalong=creature entry, datalong2=despawn_delay
// data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL = summon active
// data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL = summon active
SCRIPT_COMMAND_OPEN_DOOR = 11, // datalong=db_guid (or not provided), datalong2=reset_delay
SCRIPT_COMMAND_CLOSE_DOOR = 12, // datalong=db_guid (or not provided), datalong2=reset_delay
SCRIPT_COMMAND_ACTIVATE_OBJECT = 13, // source = unit, target=GO
SCRIPT_COMMAND_REMOVE_AURA = 14, // resSource = Unit, datalong = spell_id
SCRIPT_COMMAND_CAST_SPELL = 15, // resSource = Unit, cast spell at resTarget = Unit
// datalong=spellid
// data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL = cast triggered
SCRIPT_COMMAND_PLAY_SOUND = 16, // resSource = WorldObject, target=any/player, datalong (sound_id), datalong2 (bitmask: 0/1=anyone/target, 0/2=with distance dependent, so 1|2 = 3 is target with distance dependent)
// datalong=spellid
// data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL = cast triggered
SCRIPT_COMMAND_PLAY_SOUND = 16, // resSource = WorldObject, target=any/player, datalong (sound_id), datalong2 (bitmask: 0/1=target-player, 0/2=with distance dependent, 0/4=map wide, 0/8=zone wide; so 1|2 = 3 is target with distance dependent)
SCRIPT_COMMAND_CREATE_ITEM = 17, // source or target must be player, datalong = item entry, datalong2 = amount
SCRIPT_COMMAND_DESPAWN_SELF = 18, // resSource = Creature, datalong = despawn delay
SCRIPT_COMMAND_PLAY_MOVIE = 19, // target can only be a player, datalog = movie id
SCRIPT_COMMAND_MOVEMENT = 20, // resSource = Creature. datalong = MovementType (0:idle, 1:random or 2:waypoint), datalong2 = wander-distance
// data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL = Random-movement around current position
// data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL = Random-movement around current position
SCRIPT_COMMAND_SET_ACTIVEOBJECT = 21, // resSource = Creature
// datalong=bool 0=off, 1=on
// datalong=bool 0=off, 1=on
SCRIPT_COMMAND_SET_FACTION = 22, // resSource = Creature
// datalong=factionId, datalong2=faction_flags
// datalong=factionId, datalong2=faction_flags
SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL = 23, // resSource = Creature, datalong=creature entry/modelid
// data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL = use datalong value as modelid explicit
// data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL = use datalong value as modelid explicit
SCRIPT_COMMAND_MOUNT_TO_ENTRY_OR_MODEL = 24, // resSource = Creature, datalong=creature entry/modelid
// data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL = use datalong value as modelid explicit
// data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL = use datalong value as modelid explicit
SCRIPT_COMMAND_SET_RUN = 25, // resSource = Creature
// datalong= bool 0=off, 1=on
// datalong= bool 0=off, 1=on
SCRIPT_COMMAND_ATTACK_START = 26, // resSource = Creature, resTarget = Unit
SCRIPT_COMMAND_GO_LOCK_STATE = 27, // resSource = GameObject
// datalong= 1=lock, 2=unlock, 4=set not-interactable, 8=set interactable
// datalong= 1=lock, 2=unlock, 4=set not-interactable, 8=set interactable
SCRIPT_COMMAND_STAND_STATE = 28, // resSource = Creature
// datalong = stand state (enum UnitStandStateType)
// datalong = stand state (enum UnitStandStateType)
SCRIPT_COMMAND_MODIFY_NPC_FLAGS = 29, // resSource = Creature
// datalong=NPCFlags
// datalong2:0x00=toggle, 0x01=add, 0x02=remove
// datalong=NPCFlags
// datalong2:0x00=toggle, 0x01=add, 0x02=remove
SCRIPT_COMMAND_SEND_TAXI_PATH = 30, // datalong = taxi path id (source or target must be player)
SCRIPT_COMMAND_TERMINATE_SCRIPT = 31, // datalong = search for npc entry if provided
// datalong2= search distance
// data_flags & SCRIPT_FLAG_COMMAND_ADDITIONAL: terminate steps of this script if npc found
// ELSE: terminate steps of this script if npc not found
// dataint=diff to change a waittime of current Waypoint Movement
SCRIPT_COMMAND_PAUSE_WAYPOINTS = 32, // resSource = Creature
// datalong = 0: unpause waypoint 1: pause waypoint
};
#define MAX_TEXT_ID 4 // used for SCRIPT_COMMAND_TALK
@ -287,12 +294,25 @@ struct ScriptInfo
uint32 change_flag; // datalong2
} npcFlag;
struct
struct // SCRIPT_COMMAND_SEND_TAXI_PATH (30)
{
uint32 taxiPathId; // datalong
uint32 empty;
} sendTaxiPath;
struct // SCRIPT_COMMAND_TERMINATE_SCRIPT (31)
{
uint32 npcEntry; // datalong
uint32 searchDist; // datalong2
// changeWaypointWaitTime // dataint
} terminateScript;
struct // SCRIPT_COMMAND_PAUSE_WAYPOINTS (32)
{
uint32 doPause; // datalong
uint32 empty;
} pauseWaypoint;
struct
{
uint32 data[2];
@ -351,6 +371,7 @@ struct ScriptInfo
case SCRIPT_COMMAND_MOVEMENT:
case SCRIPT_COMMAND_MORPH_TO_ENTRY_OR_MODEL:
case SCRIPT_COMMAND_MOUNT_TO_ENTRY_OR_MODEL:
case SCRIPT_COMMAND_TERMINATE_SCRIPT:
return true;
default:
return false;
@ -365,7 +386,21 @@ class ScriptAction
m_table(_table), m_map(_map), m_sourceGuid(_sourceGuid), m_targetGuid(_targetGuid), m_ownerGuid(_ownerGuid), m_script(_script)
{}
void HandleScriptStep();
bool HandleScriptStep(); // return true IF AND ONLY IF the script should be terminated
const char* GetTableName() const { return m_table; }
uint32 GetId() const { return m_script->id; }
ObjectGuid GetSourceGuid() const { return m_sourceGuid; }
ObjectGuid GetTargetGuid() const { return m_targetGuid; }
ObjectGuid GetOwnerGuid() const { return m_ownerGuid; }
bool IsSameScript(const char* table, uint32 id, ObjectGuid sourceGuid, ObjectGuid targetGuid, ObjectGuid ownerGuid) const
{
return table == m_table && id == GetId() &&
(sourceGuid == m_sourceGuid || !sourceGuid) &&
(targetGuid == m_targetGuid || !targetGuid) &&
(ownerGuid == m_ownerGuid || !ownerGuid);
}
private:
const char* m_table; // of which table the script was started
@ -395,6 +430,7 @@ extern ScriptMapMapName sGameObjectScripts;
extern ScriptMapMapName sGameObjectTemplateScripts;
extern ScriptMapMapName sEventScripts;
extern ScriptMapMapName sGossipScripts;
extern ScriptMapMapName sCreatureDeathScripts;
extern ScriptMapMapName sCreatureMovementScripts;
enum ScriptLoadResult
@ -418,6 +454,7 @@ class ScriptMgr
void LoadEventScripts();
void LoadSpellScripts();
void LoadGossipScripts();
void LoadCreatureDeathScripts();
void LoadCreatureMovementScripts();
void LoadDbScriptStrings();
@ -468,6 +505,7 @@ class ScriptMgr
bool OnAuraDummy(Aura const* pAura, bool apply);
private:
void CollectPossibleEventIds(std::set<uint32>& eventIds);
void LoadScripts(ScriptMapMapName& scripts, const char* tablename);
void CheckScriptTexts(ScriptMapMapName const& scripts, std::set<int32>& ids);
@ -520,6 +558,9 @@ class ScriptMgr
bool (MANGOS_IMPORT* m_pOnAuraDummy)(Aura const*, bool);
};
// Starters for events
bool StartEvents_Event(Map* map, uint32 id, Object* source, Object* target, bool isStart = true, Unit* forwardToPvp = NULL);
#define sScriptMgr MaNGOS::Singleton<ScriptMgr>::Instance()
MANGOS_DLL_SPEC uint32 GetAreaTriggerScriptId(uint32 triggerId);

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "12558"
#define REVISION_NR "12559"
#endif // __REVISION_NR_H__