feat(Core/WorldState): improved WorldState scripting (#20141)
* implement world state script based on https://github.com/cmangos/mangos-wotlk/commit/0b87ca9d9edf2d4752a3c0f8e9cf85c6689ca861 Co-authored-by: killerwife <killerwife@gmail.com> * refactor to use onleave and onenter instead of spell_area allows players to right click remove adal's buff * add MapMgr.h * refactor: use condition enum instead of uint32, prefix WORLD_STATE where needed * remove lock from WorldState::Update sWorldState->Update() is only called from World::Update * remove unsafe SmartAI action of setWorldState --------- Co-authored-by: killerwife <killerwife@gmail.com>
This commit is contained in:
@@ -35,6 +35,7 @@
|
||||
#include "SmartAI.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "Vehicle.h"
|
||||
#include "WorldState.h"
|
||||
|
||||
/// @todo: this import is not necessary for compilation and marked as unused by the IDE
|
||||
// however, for some reasons removing it would cause a damn linking issue
|
||||
@@ -3269,6 +3270,11 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
|
||||
|
||||
break;
|
||||
}
|
||||
case SMART_ACTION_WORLD_SCRIPT:
|
||||
{
|
||||
sWorldState->HandleExternalEvent(static_cast<WorldStateEvent>(e.action.worldStateScript.eventId), e.action.worldStateScript.param);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Unhandled Action type {}", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
break;
|
||||
|
||||
@@ -777,6 +777,7 @@ bool SmartAIMgr::CheckUnusedActionParams(SmartScriptHolder const& e)
|
||||
case SMART_ACTION_MOVEMENT_STOP: return NO_PARAMS;
|
||||
case SMART_ACTION_MOVEMENT_PAUSE: return sizeof(SmartAction::move);
|
||||
case SMART_ACTION_MOVEMENT_RESUME: return sizeof(SmartAction::move);
|
||||
case SMART_ACTION_WORLD_SCRIPT: return sizeof(SmartAction::worldStateScript);
|
||||
default:
|
||||
LOG_WARN("sql.sql", "SmartAIMgr: entryorguid {} source_type {} id {} action_type {} is using an action with no unused params specified in SmartAIMgr::CheckUnusedActionParams(), please report this.",
|
||||
e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
|
||||
@@ -1960,6 +1961,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
|
||||
case SMART_ACTION_MOVEMENT_STOP:
|
||||
case SMART_ACTION_MOVEMENT_PAUSE:
|
||||
case SMART_ACTION_MOVEMENT_RESUME:
|
||||
case SMART_ACTION_WORLD_SCRIPT:
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR("sql.sql", "SmartAIMgr: Not handled action_type({}), event_type({}), Entry {} SourceType {} Event {}, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
|
||||
|
||||
@@ -727,8 +727,9 @@ enum SMART_ACTION
|
||||
SMART_ACTION_MOVEMENT_STOP = 234, //
|
||||
SMART_ACTION_MOVEMENT_PAUSE = 235, // timer
|
||||
SMART_ACTION_MOVEMENT_RESUME = 236, // timerOverride
|
||||
SMART_ACTION_WORLD_SCRIPT = 237, // eventId, param
|
||||
|
||||
SMART_ACTION_AC_END = 237, // placeholder
|
||||
SMART_ACTION_AC_END = 238, // placeholder
|
||||
};
|
||||
|
||||
enum class SmartActionSummonCreatureFlags
|
||||
@@ -1472,6 +1473,12 @@ struct SmartAction
|
||||
{
|
||||
uint32 timer;
|
||||
} move;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 eventId;
|
||||
uint32 param;
|
||||
} worldStateScript;
|
||||
//! Note for any new future actions
|
||||
//! All parameters must have type uint32
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "Spell.h"
|
||||
#include "SpellAuras.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "WorldState.h"
|
||||
|
||||
// Checks if object meets the condition
|
||||
// Can have CONDITION_SOURCE_TYPE_NONE && !mReferenceId if called from a special event (ie: eventAI)
|
||||
@@ -570,6 +571,11 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo)
|
||||
condMeets = unit->IsCharmed();
|
||||
break;
|
||||
}
|
||||
case CONDITION_WORLD_SCRIPT:
|
||||
{
|
||||
condMeets = sWorldState->IsConditionFulfilled(static_cast<WorldStateCondition>(ConditionValue1), static_cast<WorldStateConditionState>(ConditionValue2));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
condMeets = false;
|
||||
break;
|
||||
@@ -770,6 +776,9 @@ uint32 Condition::GetSearcherTypeMaskForCondition()
|
||||
case CONDITION_CHARMED:
|
||||
mask |= GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER;
|
||||
break;
|
||||
case CONDITION_WORLD_SCRIPT:
|
||||
mask |= GRID_MAP_TYPE_MASK_ALL;
|
||||
break;
|
||||
default:
|
||||
ASSERT(false && "Condition::GetSearcherTypeMaskForCondition - missing condition handling!");
|
||||
break;
|
||||
|
||||
@@ -86,7 +86,9 @@ enum ConditionTypes
|
||||
CONDITION_AC_START = 100,
|
||||
CONDITION_QUEST_SATISFY_EXCLUSIVE = 101, // quest_id 0 0 true if satisfied exclusive group
|
||||
CONDITION_HAS_AURA_TYPE = 102, // aura_type 0 0 true if has aura type
|
||||
CONDITION_AC_END = 103 // placeholder
|
||||
CONDITION_WORLD_SCRIPT = 103, // conditionId state 0 true if WorldState::IsConditionFulfilled returns true
|
||||
|
||||
CONDITION_AC_END = 104 // placeholder
|
||||
};
|
||||
|
||||
/*! Documentation on implementing a new ConditionSourceType:
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "WorldState.h"
|
||||
#include <cmath>
|
||||
|
||||
/// @todo: this import is not necessary for compilation and marked as unused by the IDE
|
||||
@@ -1722,6 +1723,7 @@ void Player::RemoveFromWorld()
|
||||
m_session->DoLootRelease(lguid);
|
||||
sOutdoorPvPMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
|
||||
sBattlefieldMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
|
||||
sWorldState->HandlePlayerLeaveZone(this, static_cast<WorldStateZoneId>(m_zoneUpdateId));
|
||||
}
|
||||
|
||||
// Remove items from world before self - player must be found in Item::RemoveFromObjectUpdate
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "Vehicle.h"
|
||||
#include "Weather.h"
|
||||
#include "WeatherMgr.h"
|
||||
#include "WorldState.h"
|
||||
#include "WorldStatePackets.h"
|
||||
|
||||
/// @todo: this import is not necessary for compilation and marked as unused by the IDE
|
||||
@@ -1215,6 +1216,8 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)
|
||||
{
|
||||
sOutdoorPvPMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
|
||||
sOutdoorPvPMgr->HandlePlayerEnterZone(this, newZone);
|
||||
sWorldState->HandlePlayerLeaveZone(this, static_cast<WorldStateZoneId>(m_zoneUpdateId));
|
||||
sWorldState->HandlePlayerEnterZone(this, static_cast<WorldStateZoneId>(newZone));
|
||||
sBattlefieldMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
|
||||
sBattlefieldMgr->HandlePlayerEnterZone(this, newZone);
|
||||
SendInitWorldStates(newZone,
|
||||
|
||||
@@ -180,6 +180,7 @@ enum eScriptFlags
|
||||
// Playsound flags
|
||||
SF_PLAYSOUND_TARGET_PLAYER = 0x1,
|
||||
SF_PLAYSOUND_DISTANCE_SOUND = 0x2,
|
||||
SF_PLAYSOUND_DISTANCE_RADIUS = 0x4,
|
||||
|
||||
// Orientation flags
|
||||
SF_ORIENTATION_FACE_TARGET = 0x1,
|
||||
@@ -307,6 +308,7 @@ struct ScriptInfo
|
||||
{
|
||||
uint32 SoundID; // datalong
|
||||
uint32 Flags; // datalong2
|
||||
int32 Radius; // dataint
|
||||
} Playsound;
|
||||
|
||||
struct // SCRIPT_COMMAND_CREATE_ITEM (17)
|
||||
|
||||
@@ -730,8 +730,10 @@ void Map::ScriptsProcess()
|
||||
break;
|
||||
}
|
||||
|
||||
// Playsound.Flags bitmask: 0/2=without/with distance dependent
|
||||
if (step.script->Playsound.Flags & SF_PLAYSOUND_DISTANCE_SOUND)
|
||||
// Playsound.Flags bitmask: 0/2/4=without/with distance dependent/radius
|
||||
if (step.script->Playsound.Flags & SF_PLAYSOUND_DISTANCE_RADIUS)
|
||||
object->PlayRadiusSound(step.script->Playsound.SoundID, step.script->Playsound.Radius);
|
||||
else if (step.script->Playsound.Flags & SF_PLAYSOUND_DISTANCE_SOUND)
|
||||
object->PlayDistanceSound(step.script->Playsound.SoundID, player);
|
||||
else
|
||||
object->PlayDirectSound(step.script->Playsound.SoundID, player);
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSocket.h"
|
||||
#include "WorldState.h"
|
||||
#include <zlib.h>
|
||||
|
||||
#include "BanMgr.h"
|
||||
@@ -617,6 +618,7 @@ void WorldSession::LogoutPlayer(bool save)
|
||||
_player->RepopAtGraveyard();
|
||||
|
||||
sOutdoorPvPMgr->HandlePlayerLeaveZone(_player, _player->GetZoneId());
|
||||
sWorldState->HandlePlayerLeaveZone(_player, static_cast<WorldStateZoneId>(_player->GetZoneId()));
|
||||
|
||||
// pussywizard: remove from battleground queues on logout
|
||||
for (int i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
|
||||
|
||||
@@ -1389,18 +1389,6 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13); // 50000yd
|
||||
});
|
||||
|
||||
// A'dal's Song of Battle
|
||||
ApplySpellFix({ 39953 }, [](SpellInfo* spellInfo)
|
||||
{
|
||||
spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_SRC_CASTER);
|
||||
spellInfo->Effects[EFFECT_1].TargetA = SpellImplicitTargetInfo(TARGET_SRC_CASTER);
|
||||
spellInfo->Effects[EFFECT_2].TargetA = SpellImplicitTargetInfo(TARGET_SRC_CASTER);
|
||||
spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ALLY);
|
||||
spellInfo->Effects[EFFECT_1].TargetB = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ALLY);
|
||||
spellInfo->Effects[EFFECT_2].TargetB = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ALLY);
|
||||
spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(367); // 2 Hours
|
||||
});
|
||||
|
||||
ApplySpellFix({
|
||||
57607, // WintergraspCatapult - Spell Plague Barrel - EffectRadiusIndex
|
||||
57619, // WintergraspDemolisher - Spell Hourl Boulder - EffectRadiusIndex
|
||||
|
||||
@@ -92,6 +92,7 @@
|
||||
#include "WhoListCacheMgr.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "WorldState.h"
|
||||
#include <boost/asio/ip/address.hpp>
|
||||
#include <cmath>
|
||||
|
||||
@@ -2411,6 +2412,11 @@ void World::Update(uint32 diff)
|
||||
sOutdoorPvPMgr->Update(diff);
|
||||
}
|
||||
|
||||
{
|
||||
METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update worldstate"));
|
||||
sWorldState->Update(diff);
|
||||
}
|
||||
|
||||
{
|
||||
METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update battlefields"));
|
||||
sBattlefieldMgr->Update(diff);
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "MapMgr.h"
|
||||
#include "Player.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "WorldState.h"
|
||||
|
||||
WorldState* WorldState::instance()
|
||||
{
|
||||
static WorldState instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
WorldState::WorldState() : _isMagtheridonHeadSpawnedHorde(false), _isMagtheridonHeadSpawnedAlliance(false)
|
||||
{
|
||||
_transportStates[WORLD_STATE_CONDITION_THE_IRON_EAGLE] = WORLD_STATE_CONDITION_STATE_NONE;
|
||||
_transportStates[WORLD_STATE_CONDITION_THE_PURPLE_PRINCESS] = WORLD_STATE_CONDITION_STATE_NONE;
|
||||
_transportStates[WORLD_STATE_CONDITION_THE_THUNDERCALLER] = WORLD_STATE_CONDITION_STATE_NONE;
|
||||
}
|
||||
|
||||
WorldState::~WorldState()
|
||||
{
|
||||
}
|
||||
|
||||
bool WorldState::IsConditionFulfilled(WorldStateCondition conditionId, WorldStateConditionState state) const
|
||||
{
|
||||
switch (conditionId)
|
||||
{
|
||||
case WORLD_STATE_CONDITION_TROLLBANES_COMMAND:
|
||||
return _isMagtheridonHeadSpawnedAlliance;
|
||||
case WORLD_STATE_CONDITION_NAZGRELS_FAVOR:
|
||||
return _isMagtheridonHeadSpawnedHorde;
|
||||
case WORLD_STATE_CONDITION_THE_IRON_EAGLE:
|
||||
case WORLD_STATE_CONDITION_THE_PURPLE_PRINCESS:
|
||||
case WORLD_STATE_CONDITION_THE_THUNDERCALLER:
|
||||
return _transportStates.at(conditionId) == state;
|
||||
default:
|
||||
LOG_ERROR("scripts", "WorldState::IsConditionFulfilled: Unhandled WorldStateCondition {}", conditionId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void WorldState::HandleConditionStateChange(WorldStateCondition conditionId, WorldStateConditionState state)
|
||||
{
|
||||
_transportStates[conditionId] = state;
|
||||
}
|
||||
|
||||
void WorldState::HandleExternalEvent(WorldStateEvent eventId, uint32 param)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
switch (eventId)
|
||||
{
|
||||
case WORLD_STATE_CUSTOM_EVENT_ON_ADALS_SONG_OF_BATTLE:
|
||||
if (!_adalSongOfBattleTimer)
|
||||
{
|
||||
_adalSongOfBattleTimer = 120 * MINUTE * IN_MILLISECONDS;
|
||||
BuffAdalsSongOfBattle();
|
||||
}
|
||||
break;
|
||||
case WORLD_STATE_CUSTOM_EVENT_ON_MAGTHERIDON_HEAD_SPAWN:
|
||||
if (param == TEAM_ALLIANCE)
|
||||
{
|
||||
_isMagtheridonHeadSpawnedAlliance = true;
|
||||
BuffMagtheridonTeam(TEAM_ALLIANCE);
|
||||
}
|
||||
else
|
||||
{
|
||||
_isMagtheridonHeadSpawnedHorde = true;
|
||||
BuffMagtheridonTeam(TEAM_HORDE);
|
||||
}
|
||||
break;
|
||||
case WORLD_STATE_CUSTOM_EVENT_ON_MAGTHERIDON_HEAD_DESPAWN:
|
||||
if (param == TEAM_ALLIANCE)
|
||||
{
|
||||
_isMagtheridonHeadSpawnedAlliance = false;
|
||||
DispelMagtheridonTeam(TEAM_ALLIANCE);
|
||||
}
|
||||
else
|
||||
{
|
||||
_isMagtheridonHeadSpawnedHorde = false;
|
||||
DispelMagtheridonTeam(TEAM_HORDE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WorldState::Update(uint32 diff)
|
||||
{
|
||||
if (_adalSongOfBattleTimer)
|
||||
{
|
||||
if (_adalSongOfBattleTimer <= diff)
|
||||
{
|
||||
_adalSongOfBattleTimer = 0;
|
||||
DispelAdalsSongOfBattle();
|
||||
}
|
||||
else
|
||||
{
|
||||
_adalSongOfBattleTimer -= diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WorldState::HandlePlayerEnterZone(Player* player, WorldStateZoneId zoneId)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
switch (zoneId)
|
||||
{
|
||||
case ZONEID_SHATTRATH:
|
||||
case ZONEID_BOTANICA:
|
||||
case ZONEID_MECHANAR:
|
||||
case ZONEID_ARCATRAZ:
|
||||
if (_adalSongOfBattleTimer)
|
||||
player->CastSpell(player, SPELL_ADAL_SONG_OF_BATTLE, true);
|
||||
break;
|
||||
case ZONEID_HELLFIRE_PENINSULA:
|
||||
case ZONEID_HELLFIRE_RAMPARTS:
|
||||
case ZONEID_HELLFIRE_CITADEL:
|
||||
case ZONEID_BLOOD_FURNACE:
|
||||
case ZONEID_SHATTERED_HALLS:
|
||||
case ZONEID_MAGTHERIDON_LAIR:
|
||||
if (_isMagtheridonHeadSpawnedAlliance && player->GetTeamId() == TEAM_ALLIANCE)
|
||||
player->CastSpell(player, SPELL_TROLLBANES_COMMAND, true);
|
||||
else if (_isMagtheridonHeadSpawnedHorde && player->GetTeamId() == TEAM_HORDE)
|
||||
player->CastSpell(player, SPELL_NAZGRELS_FAVOR, true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
void WorldState::HandlePlayerLeaveZone(Player* player, WorldStateZoneId zoneId)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(_mutex);
|
||||
switch (zoneId)
|
||||
{
|
||||
case ZONEID_SHATTRATH:
|
||||
case ZONEID_BOTANICA:
|
||||
case ZONEID_MECHANAR:
|
||||
case ZONEID_ARCATRAZ:
|
||||
if (!_adalSongOfBattleTimer)
|
||||
player->RemoveAurasDueToSpell(SPELL_ADAL_SONG_OF_BATTLE);
|
||||
break;
|
||||
case ZONEID_HELLFIRE_PENINSULA:
|
||||
case ZONEID_HELLFIRE_RAMPARTS:
|
||||
case ZONEID_HELLFIRE_CITADEL:
|
||||
case ZONEID_BLOOD_FURNACE:
|
||||
case ZONEID_SHATTERED_HALLS:
|
||||
case ZONEID_MAGTHERIDON_LAIR:
|
||||
if (player->GetTeamId() == TEAM_ALLIANCE)
|
||||
player->RemoveAurasDueToSpell(SPELL_TROLLBANES_COMMAND);
|
||||
else if (player->GetTeamId() == TEAM_HORDE)
|
||||
player->RemoveAurasDueToSpell(SPELL_NAZGRELS_FAVOR);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
void WorldState::BuffMagtheridonTeam(TeamId team)
|
||||
{
|
||||
sMapMgr->DoForAllMaps([&](Map* map) -> void
|
||||
{
|
||||
switch (map->GetId())
|
||||
{
|
||||
case 530: // Outland
|
||||
map->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
if (player->GetZoneId() == ZONEID_HELLFIRE_PENINSULA && player->GetTeamId() == TEAM_ALLIANCE && team == TEAM_ALLIANCE)
|
||||
player->CastSpell(player, SPELL_TROLLBANES_COMMAND, true);
|
||||
else if (player->GetZoneId() == ZONEID_HELLFIRE_PENINSULA && player->GetTeamId() == TEAM_HORDE && team == TEAM_HORDE)
|
||||
player->CastSpell(player, SPELL_NAZGRELS_FAVOR, true);
|
||||
});
|
||||
break;
|
||||
case 540: // The Shattered Halls
|
||||
case 542: // The Blood Furnace
|
||||
case 543: // Ramparts
|
||||
case 544: // Magtheridon's Lair
|
||||
map->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
if (player->GetTeamId() == TEAM_ALLIANCE && team == TEAM_ALLIANCE)
|
||||
player->CastSpell(player, SPELL_TROLLBANES_COMMAND, true);
|
||||
else if (player->GetTeamId() == TEAM_HORDE && team == TEAM_HORDE)
|
||||
player->CastSpell(player, SPELL_NAZGRELS_FAVOR, true);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void WorldState::DispelMagtheridonTeam(TeamId team)
|
||||
{
|
||||
sMapMgr->DoForAllMaps([&](Map* map) -> void
|
||||
{
|
||||
switch (map->GetId())
|
||||
{
|
||||
case 530: // Outland
|
||||
map->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
if (player->GetZoneId() == ZONEID_HELLFIRE_PENINSULA && player->GetTeamId() == TEAM_ALLIANCE && team == TEAM_ALLIANCE)
|
||||
player->RemoveAurasDueToSpell(SPELL_TROLLBANES_COMMAND);
|
||||
else if (player->GetZoneId() == ZONEID_HELLFIRE_PENINSULA && player->GetTeamId() == TEAM_HORDE && team == TEAM_HORDE)
|
||||
player->RemoveAurasDueToSpell(SPELL_NAZGRELS_FAVOR);
|
||||
});
|
||||
break;
|
||||
case 540: // The Shattered Halls
|
||||
case 542: // The Blood Furnace
|
||||
case 543: // Ramparts
|
||||
case 544: // Magtheridon's Lair
|
||||
map->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
if (player->GetTeamId() == TEAM_ALLIANCE && team == TEAM_ALLIANCE)
|
||||
player->RemoveAurasDueToSpell(SPELL_TROLLBANES_COMMAND);
|
||||
else if (player->GetTeamId() == TEAM_HORDE && team == TEAM_HORDE)
|
||||
player->RemoveAurasDueToSpell(SPELL_NAZGRELS_FAVOR);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void WorldState::BuffAdalsSongOfBattle()
|
||||
{
|
||||
sMapMgr->DoForAllMaps([&](Map* map) -> void
|
||||
{
|
||||
switch (map->GetId())
|
||||
{
|
||||
case 530: // Outland
|
||||
map->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
if (player->GetZoneId() == ZONEID_SHATTRATH)
|
||||
player->CastSpell(player, SPELL_ADAL_SONG_OF_BATTLE, true);
|
||||
});
|
||||
break;
|
||||
case 552: // Arcatraz
|
||||
case 553: // Botanica
|
||||
case 554: // Mechanar
|
||||
map->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
player->CastSpell(player, SPELL_ADAL_SONG_OF_BATTLE, true);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void WorldState::DispelAdalsSongOfBattle()
|
||||
{
|
||||
sMapMgr->DoForAllMaps([&](Map* map) -> void
|
||||
{
|
||||
switch (map->GetId())
|
||||
{
|
||||
case 530: // Outland
|
||||
map->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
if (player->GetZoneId() == ZONEID_SHATTRATH)
|
||||
player->RemoveAurasDueToSpell(SPELL_ADAL_SONG_OF_BATTLE);
|
||||
});
|
||||
break;
|
||||
case 552: // Arcatraz
|
||||
case 553: // Botanica
|
||||
case 554: // Mechanar
|
||||
map->DoForAllPlayers([&](Player* player)
|
||||
{
|
||||
player->RemoveAurasDueToSpell(SPELL_ADAL_SONG_OF_BATTLE);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Affero General Public License as published by the
|
||||
* Free Software Foundation; either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef WORLD_STATE_H
|
||||
#define WORLD_STATE_H
|
||||
|
||||
#include "Player.h"
|
||||
#include <atomic>
|
||||
|
||||
enum WorldStateCondition
|
||||
{
|
||||
WORLD_STATE_CONDITION_TROLLBANES_COMMAND = 39911,
|
||||
WORLD_STATE_CONDITION_NAZGRELS_FAVOR = 39913,
|
||||
// Zeppelins
|
||||
WORLD_STATE_CONDITION_THE_THUNDERCALLER = 164871,
|
||||
WORLD_STATE_CONDITION_THE_IRON_EAGLE = 175080,
|
||||
WORLD_STATE_CONDITION_THE_PURPLE_PRINCESS = 176495,
|
||||
};
|
||||
|
||||
enum WorldStateConditionState
|
||||
{
|
||||
WORLD_STATE_CONDITION_STATE_NONE = 0,
|
||||
};
|
||||
|
||||
enum WorldStateEvent
|
||||
{
|
||||
WORLD_STATE_CUSTOM_EVENT_ON_ADALS_SONG_OF_BATTLE = 39953,
|
||||
WORLD_STATE_CUSTOM_EVENT_ON_MAGTHERIDON_HEAD_SPAWN = 184640,
|
||||
WORLD_STATE_CUSTOM_EVENT_ON_MAGTHERIDON_HEAD_DESPAWN = 184641,
|
||||
};
|
||||
|
||||
enum WorldStateZoneId
|
||||
{
|
||||
ZONEID_SHATTRATH = 3703,
|
||||
ZONEID_BOTANICA = 3847,
|
||||
ZONEID_ARCATRAZ = 3848,
|
||||
ZONEID_MECHANAR = 3849,
|
||||
|
||||
ZONEID_HELLFIRE_PENINSULA = 3483,
|
||||
ZONEID_HELLFIRE_RAMPARTS = 3562,
|
||||
ZONEID_HELLFIRE_CITADEL = 3563,
|
||||
ZONEID_BLOOD_FURNACE = 3713,
|
||||
ZONEID_SHATTERED_HALLS = 3714,
|
||||
ZONEID_MAGTHERIDON_LAIR = 3836,
|
||||
};
|
||||
|
||||
enum WorldStateSpells
|
||||
{
|
||||
SPELL_ADAL_SONG_OF_BATTLE = 39953,
|
||||
|
||||
SPELL_TROLLBANES_COMMAND = 39911,
|
||||
SPELL_NAZGRELS_FAVOR = 39913,
|
||||
};
|
||||
|
||||
// Intended for implementing server wide scripts, note: all behaviour must be safeguarded towards multithreading
|
||||
class WorldState
|
||||
{
|
||||
public:
|
||||
WorldState();
|
||||
virtual ~WorldState();
|
||||
static WorldState* instance();
|
||||
void HandlePlayerEnterZone(Player* player, WorldStateZoneId zoneId);
|
||||
void HandlePlayerLeaveZone(Player* player, WorldStateZoneId zoneId);
|
||||
bool IsConditionFulfilled(WorldStateCondition conditionId, WorldStateConditionState state = WORLD_STATE_CONDITION_STATE_NONE) const;
|
||||
void HandleConditionStateChange(WorldStateCondition conditionId, WorldStateConditionState state);
|
||||
void HandleExternalEvent(WorldStateEvent eventId, uint32 param);
|
||||
void Update(uint32 diff);
|
||||
private:
|
||||
void BuffAdalsSongOfBattle();
|
||||
void DispelAdalsSongOfBattle();
|
||||
uint32 _adalSongOfBattleTimer;
|
||||
void BuffMagtheridonTeam(TeamId team);
|
||||
void DispelMagtheridonTeam(TeamId team);
|
||||
bool _isMagtheridonHeadSpawnedHorde;
|
||||
bool _isMagtheridonHeadSpawnedAlliance;
|
||||
std::map<WorldStateCondition, std::atomic<WorldStateConditionState>> _transportStates; // atomic to avoid having to lock
|
||||
std::mutex _mutex; // all World State operations are threat unsafe
|
||||
};
|
||||
|
||||
#define sWorldState WorldState::instance()
|
||||
#endif
|
||||
Reference in New Issue
Block a user