/* * This file is part of the TrinityCore 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 General Public License as published by the * Free Software Foundation; either version 2 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 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 . */ #include "SceneMgr.h" #include "Chat.h" #include "DB2Stores.h" #include "Language.h" #include "ObjectMgr.h" #include "Player.h" #include "ScenePackets.h" #include "ScriptMgr.h" #include "SpellAuraEffects.h" SceneMgr::SceneMgr(Player* player) : _player(player) { _standaloneSceneInstanceID = 0; _isDebuggingScenes = false; } SceneMgr::~SceneMgr() = default; uint32 SceneMgr::PlayScene(uint32 sceneId, Position const* position /*= nullptr*/) { SceneTemplate const* sceneTemplate = sObjectMgr->GetSceneTemplate(sceneId); return PlaySceneByTemplate(sceneTemplate, position); } uint32 SceneMgr::PlaySceneByTemplate(SceneTemplate const* sceneTemplate, Position const* position /*= nullptr*/) { if (!sceneTemplate) return 0; SceneScriptPackageEntry const* entry = sSceneScriptPackageStore.LookupEntry(sceneTemplate->ScenePackageId); if (!entry) return 0; // By default, take player position if (!position) position = GetPlayer(); uint32 sceneInstanceID = GetNewStandaloneSceneInstanceID(); if (_isDebuggingScenes) ChatHandler(GetPlayer()->GetSession()).PSendSysMessage(LANG_COMMAND_SCENE_DEBUG_PLAY, sceneInstanceID, sceneTemplate->ScenePackageId, sceneTemplate->PlaybackFlags.AsUnderlyingType()); WorldPackets::Scenes::PlayScene playScene; playScene.SceneID = sceneTemplate->SceneId; playScene.PlaybackFlags = sceneTemplate->PlaybackFlags.AsUnderlyingType(); playScene.SceneInstanceID = sceneInstanceID; playScene.SceneScriptPackageID = sceneTemplate->ScenePackageId; playScene.Location = *position; if (!GetPlayer()->GetVehicle()) // skip vehicles passed as transport here until further research playScene.TransportGUID = GetPlayer()->GetTransGUID(); playScene.Encrypted = sceneTemplate->Encrypted; playScene.Write(); if (GetPlayer()->IsInWorld()) GetPlayer()->SendDirectMessage(playScene.GetRawPacket()); else _delayedScenes.push_back(playScene.Move()); AddInstanceIdToSceneMap(sceneInstanceID, sceneTemplate); sScriptMgr->OnSceneStart(GetPlayer(), sceneInstanceID, sceneTemplate); return sceneInstanceID; } uint32 SceneMgr::PlaySceneByPackageId(uint32 sceneScriptPackageId, EnumFlag playbackflags /*= SCENEFLAG_UNK16*/, Position const* position /*= nullptr*/) { SceneTemplate sceneTemplate; sceneTemplate.SceneId = 0; sceneTemplate.ScenePackageId = sceneScriptPackageId; sceneTemplate.PlaybackFlags = playbackflags; sceneTemplate.Encrypted = false; sceneTemplate.ScriptId = 0; return PlaySceneByTemplate(&sceneTemplate, position); } void SceneMgr::CancelScene(uint32 sceneInstanceID, bool removeFromMap /*= true*/) { if (removeFromMap) RemoveSceneInstanceId(sceneInstanceID); WorldPackets::Scenes::CancelScene cancelScene; cancelScene.SceneInstanceID = sceneInstanceID; GetPlayer()->SendDirectMessage(cancelScene.Write()); } void SceneMgr::OnSceneTrigger(uint32 sceneInstanceID, std::string const& triggerName) { if (!HasScene(sceneInstanceID)) return; if (_isDebuggingScenes) ChatHandler(GetPlayer()->GetSession()).PSendSysMessage(LANG_COMMAND_SCENE_DEBUG_TRIGGER, sceneInstanceID, triggerName.c_str()); SceneTemplate const* sceneTemplate = GetSceneTemplateFromInstanceId(sceneInstanceID); sScriptMgr->OnSceneTrigger(GetPlayer(), sceneInstanceID, sceneTemplate, triggerName); } void SceneMgr::OnSceneCancel(uint32 sceneInstanceID) { if (!HasScene(sceneInstanceID)) return; if (_isDebuggingScenes) ChatHandler(GetPlayer()->GetSession()).PSendSysMessage(LANG_COMMAND_SCENE_DEBUG_CANCEL, sceneInstanceID); SceneTemplate sceneTemplate = *GetSceneTemplateFromInstanceId(sceneInstanceID); if (sceneTemplate.PlaybackFlags.HasFlag(SceneFlag::NotCancelable)) return; // Must be done before removing aura RemoveSceneInstanceId(sceneInstanceID); if (sceneTemplate.SceneId != 0) RemoveAurasDueToSceneId(sceneTemplate.SceneId); sScriptMgr->OnSceneCancel(GetPlayer(), sceneInstanceID, &sceneTemplate); if (sceneTemplate.PlaybackFlags.HasFlag(SceneFlag::FadeToBlackscreenOnCancel)) CancelScene(sceneInstanceID, false); } void SceneMgr::OnSceneComplete(uint32 sceneInstanceID) { if (!HasScene(sceneInstanceID)) return; if (_isDebuggingScenes) ChatHandler(GetPlayer()->GetSession()).PSendSysMessage(LANG_COMMAND_SCENE_DEBUG_COMPLETE, sceneInstanceID); SceneTemplate sceneTemplate = *GetSceneTemplateFromInstanceId(sceneInstanceID); // Must be done before removing aura RemoveSceneInstanceId(sceneInstanceID); if (sceneTemplate.SceneId != 0) RemoveAurasDueToSceneId(sceneTemplate.SceneId); sScriptMgr->OnSceneComplete(GetPlayer(), sceneInstanceID, &sceneTemplate); if (sceneTemplate.PlaybackFlags.HasFlag(SceneFlag::FadeToBlackscreenOnComplete)) CancelScene(sceneInstanceID, false); } bool SceneMgr::HasScene(uint32 sceneInstanceID, uint32 sceneScriptPackageId /*= 0*/) const { auto itr = _scenesByInstance.find(sceneInstanceID); if (itr != _scenesByInstance.end()) return !sceneScriptPackageId || sceneScriptPackageId == itr->second->ScenePackageId; return false; } void SceneMgr::AddInstanceIdToSceneMap(uint32 sceneInstanceID, SceneTemplate const* sceneTemplate) { _scenesByInstance[sceneInstanceID] = std::make_unique(*sceneTemplate); } void SceneMgr::CancelSceneBySceneId(uint32 sceneId) { std::vector instancesIds; for (auto const& itr : _scenesByInstance) if (itr.second->SceneId == sceneId) instancesIds.push_back(itr.first); for (uint32 sceneInstanceID : instancesIds) CancelScene(sceneInstanceID); } void SceneMgr::CancelSceneByPackageId(uint32 sceneScriptPackageId) { std::vector instancesIds; for (auto const& itr : _scenesByInstance) if (itr.second->ScenePackageId == sceneScriptPackageId) instancesIds.push_back(itr.first); for (uint32 sceneInstanceID : instancesIds) CancelScene(sceneInstanceID); } void SceneMgr::RemoveSceneInstanceId(uint32 sceneInstanceID) { _scenesByInstance.erase(sceneInstanceID); } void SceneMgr::RemoveAurasDueToSceneId(uint32 sceneId) { Player::AuraEffectList const& scenePlayAuras = GetPlayer()->GetAuraEffectsByType(SPELL_AURA_PLAY_SCENE); for (AuraEffect* scenePlayAura : scenePlayAuras) { if (uint32(scenePlayAura->GetMiscValue()) == sceneId) { GetPlayer()->RemoveAura(scenePlayAura->GetBase()); break; } } } SceneTemplate const* SceneMgr::GetSceneTemplateFromInstanceId(uint32 sceneInstanceID) const { auto itr = _scenesByInstance.find(sceneInstanceID); if (itr != _scenesByInstance.end()) return itr->second.get(); return nullptr; } uint32 SceneMgr::GetActiveSceneCount(uint32 sceneScriptPackageId /*= 0*/) const { uint32 activeSceneCount = 0; for (auto const& itr : _scenesByInstance) if (!sceneScriptPackageId || itr.second->ScenePackageId == sceneScriptPackageId) ++activeSceneCount; return activeSceneCount; } Optional SceneMgr::GetInstanceIdBySceneId(uint32 sceneId) const { for (auto const& itr : _scenesByInstance) { if (itr.second->SceneId == sceneId) return itr.first; } return std::nullopt; } void SceneMgr::TriggerDelayedScenes() { for (WorldPacket& playScene : _delayedScenes) GetPlayer()->SendDirectMessage(&playScene); _delayedScenes.clear(); }