Scene system
Scene scripts
Scene scripts are a way to provide a means of implementing more complicated behavior, which couldn't be placed in db.
Generic structure
// headers (self-explaining)
#include "ScriptMgr.h"
#include "Player.h"
// enums to prevent magic numbers
enum EnumName
{
GIVE_ME_A_NAME = 123456,
};
// naming scheme: scene_[spellname/description], for example scene_demon_hunter_start, scene_enter_the_illidari_ashtongue
class scene_your_name_here : public SceneScript
{
public:
// should be the same as class name - name in "" is the one used by db in scene_template table
scene_your_name_here () : SceneScript("scene_your_name_here ") { }
// hook section starts here (see below for description)
void OnSceneStart(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/) override
{
}
void OnSceneTriggerEvent(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/, std::string const& triggerName) override
{
}
void OnSceneCancel(Player* player, uint32 sceneInstanceID, SceneTemplate const* sceneTemplate) override
{
}
void OnSceneComplete(Player* player, uint32 sceneInstanceID, SceneTemplate const* sceneTemplate) override
{
}
};
// this function call creates script loader object for us - seek that function at the end of the script file you're adding to
// if there's no such function see http://collab.kpsn.org/display/tc/How-to_CustomScript
void AddSC_scene_scripts()
{
// an entry for our script loader, there may be other entries aswell
/* ... */
new scene_your_name_here ();
}
SceneScript hooks
There are total 4 hooks you can use.
// As the name says code inside brackets is executed when scene starts, e.g. by spell or by "player->GetSceneMgr().PlayScene(SceneId);"
void OnSceneStart(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/) override
{
}
// Code inside brackets is executed when CMSG_SCENE_TRIGGER_EVENT with similar sceneInstanceID as scene is sent
void OnSceneTriggerEvent(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/, std::string const& triggerName) override
{
// IMPORTANT: you need to select correct triggerName otherwise your code is executed all the time if some triggerName is sent by client
// triggerName is sent by CMSG_SCENE_TRIGGER_EVENT (check PacketStruct), you can find it also in parsed sniff or inside SceneScript.db2 (lua)
if (triggerName == "IKILLEDIT")
player->KilledMonsterCredit(KILLED_MOB);
if (triggerName == "UPDATEPHASE")
player->UpdateAreaAndZonePhase();
}
// As the name says code inside brackets is executed when scene is canceled, e.g. player presses ESC and confirms
void OnSceneCancel(Player* player, uint32 sceneInstanceID, SceneTemplate const* sceneTemplate) override
{
}
// As the name says code inside brackets is executed when scene is properly completed
void OnSceneComplete(Player* player, uint32 sceneInstanceID, SceneTemplate const* sceneTemplate) override
{
}
Note: triggerNames are fixed names by Blizzard.
Example Script
Core part:
enum SceneCreatures
{
SEE_FELSABER_QUEST_KILL_CREDIT = 101534,
SEVIS_BRIGHTFLAME_ASHTONGUE = 99916
};
class scene_enter_the_illidari_ashtongue : public SceneScript
{
public:
scene_enter_the_illidari_ashtongue() : SceneScript("scene_enter_the_illidari_ashtongue") { }
void OnSceneStart(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/) override
{
//This must be Personal Spawn (NYI)
Creature* sevis = GetClosestCreatureWithEntry(player, SEVIS_BRIGHTFLAME_ASHTONGUE, 5);
if (sevis == nullptr)
return;
player->SummonCreature(SEVIS_BRIGHTFLAME_ASHTONGUE, sevis->GetPosition(), TEMPSUMMON_TIMED_DESPAWN, 18000);
player->UpdateAreaAndZonePhase();
}
void OnSceneTriggerEvent(Player* player, uint32 /*sceneInstanceID*/, SceneTemplate const* /*sceneTemplate*/, std::string const& triggerName) override
{
if (triggerName == "SEEFELSABERCREDIT")
player->KilledMonsterCredit(SEE_FELSABER_QUEST_KILL_CREDIT);
if (triggerName == "UPDATEPHASE")
player->UpdateAreaAndZonePhase();
}
};
void AddSC_scene_scripts()
{
new scene_enter_the_illidari_ashtongue();
}
DB part:
-- If scene_template entry exists UPDATE `scene_template` SET `ScriptName` = 'scene_enter_the_illidari_ashtongue' WHERE `SceneId` = 1053; -- If scene_template entry is missing DELETE FROM `scene_template` WHERE `SceneId` = 1053; INSERT INTO `scene_template` (`SceneId`, `Flags`, `ScriptPackageID`, `ScriptName`) VALUES (1053, 20, 1451, 'scene_enter_the_illidari_ashtongue');
, multiple selections available,