From 7fa50c22e576b38cdc6d5f515dffe66e954c7ad2 Mon Sep 17 00:00:00 2001 From: ZZYZX Date: Thu, 2 Feb 2017 20:26:56 +0200 Subject: [PATCH] Added player events --- src/events.cpp | 101 +++++++++++++++++++++++++++++++ src/events.h | 38 ++++++++++++ wadsrc/static/zscript/events.txt | 18 ++++++ 3 files changed, 157 insertions(+) diff --git a/src/events.cpp b/src/events.cpp index 23a8a8800..bd78ad128 100755 --- a/src/events.cpp +++ b/src/events.cpp @@ -337,6 +337,30 @@ void E_WorldThingDestroyed(AActor* actor) handler->WorldThingDestroyed(actor); } +void E_PlayerEntered(int num) +{ + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + handler->PlayerEntered(num); +} + +void E_PlayerRespawned(int num) +{ + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + handler->PlayerRespawned(num); +} + +void E_PlayerDied(int num) +{ + for (DStaticEventHandler* handler = E_FirstEventHandler; handler; handler = handler->next) + handler->PlayerDied(num); +} + +void E_PlayerDisconnected(int num) +{ + for (DStaticEventHandler* handler = E_LastEventHandler; handler; handler = handler->prev) + handler->PlayerDisconnected(num); +} + // normal event loopers (non-special, argument-less) DEFINE_EVENT_LOOPER(RenderFrame) DEFINE_EVENT_LOOPER(WorldLightning) @@ -348,6 +372,7 @@ IMPLEMENT_CLASS(DEventHandler, false, false); IMPLEMENT_CLASS(DBaseEvent, false, false) IMPLEMENT_CLASS(DRenderEvent, false, false) IMPLEMENT_CLASS(DWorldEvent, false, false) +IMPLEMENT_CLASS(DPlayerEvent, false, false) DEFINE_FIELD_X(RenderEvent, DRenderEvent, ViewPos); DEFINE_FIELD_X(RenderEvent, DRenderEvent, ViewAngle); @@ -357,6 +382,7 @@ DEFINE_FIELD_X(RenderEvent, DRenderEvent, FracTic); DEFINE_FIELD_X(RenderEvent, DRenderEvent, Camera); DEFINE_FIELD_X(WorldEvent, DWorldEvent, IsSaveGame); +DEFINE_FIELD_X(WorldEvent, DWorldEvent, IsReopen); DEFINE_FIELD_X(WorldEvent, DWorldEvent, Thing); DEFINE_FIELD_X(WorldEvent, DWorldEvent, Inflictor); DEFINE_FIELD_X(WorldEvent, DWorldEvent, Damage); @@ -365,6 +391,9 @@ DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageType); DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageFlags); DEFINE_FIELD_X(WorldEvent, DWorldEvent, DamageAngle); +DEFINE_FIELD_X(PlayerEvent, DPlayerEvent, PlayerNumber); +DEFINE_FIELD_X(PlayerEvent, DPlayerEvent, IsReturn); + DEFINE_ACTION_FUNCTION(DEventHandler, Create) { PARAM_PROLOGUE; @@ -486,8 +515,14 @@ DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingDamaged) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldThingDestroyed) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldLightning) DEFINE_EMPTY_HANDLER(DStaticEventHandler, WorldTick) + DEFINE_EMPTY_HANDLER(DStaticEventHandler, RenderFrame) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, PlayerEntered) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, PlayerRespawned) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, PlayerDied) +DEFINE_EMPTY_HANDLER(DStaticEventHandler, PlayerDisconnected) + DEFINE_ACTION_FUNCTION(DStaticEventHandler, GetOrder) { PARAM_SELF_PROLOGUE(DStaticEventHandler); @@ -505,6 +540,7 @@ static DWorldEvent* E_SetupWorldEvent() static DWorldEvent* e = nullptr; if (!e) e = (DWorldEvent*)RUNTIME_CLASS(DWorldEvent)->CreateNew(); e->IsSaveGame = savegamerestore; + e->IsReopen = level.FromSnapshot; e->Thing = nullptr; e->Inflictor = nullptr; e->Damage = 0; @@ -669,6 +705,71 @@ void DStaticEventHandler::RenderFrame() } } +static DPlayerEvent* E_SetupPlayerEvent() +{ + static DPlayerEvent* e = nullptr; + if (!e) e = (DPlayerEvent*)RUNTIME_CLASS(DPlayerEvent)->CreateNew(); + e->PlayerNumber = -1; + e->IsReturn = level.FromSnapshot; + return e; +} + +void DStaticEventHandler::PlayerEntered(int num) +{ + IFVIRTUAL(DStaticEventHandler, PlayerEntered) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_PlayerEntered_VMPtr) + return; + DPlayerEvent* e = E_SetupPlayerEvent(); + e->PlayerNumber = num; + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + +void DStaticEventHandler::PlayerRespawned(int num) +{ + IFVIRTUAL(DStaticEventHandler, PlayerRespawned) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_PlayerRespawned_VMPtr) + return; + DPlayerEvent* e = E_SetupPlayerEvent(); + e->PlayerNumber = num; + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + +void DStaticEventHandler::PlayerDied(int num) +{ + IFVIRTUAL(DStaticEventHandler, PlayerDied) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_PlayerDied_VMPtr) + return; + DPlayerEvent* e = E_SetupPlayerEvent(); + e->PlayerNumber = num; + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + +void DStaticEventHandler::PlayerDisconnected(int num) +{ + IFVIRTUAL(DStaticEventHandler, PlayerDisconnected) + { + // don't create excessive DObjects if not going to be processed anyway + if (func == DStaticEventHandler_PlayerDisconnected_VMPtr) + return; + DPlayerEvent* e = E_SetupPlayerEvent(); + e->PlayerNumber = num; + VMValue params[2] = { (DStaticEventHandler*)this, e }; + GlobalVMStack.Call(func, params, 2, nullptr, 0, nullptr); + } +} + // void DStaticEventHandler::OnDestroy() { diff --git a/src/events.h b/src/events.h index 50a227c77..130f2eb17 100755 --- a/src/events.h +++ b/src/events.h @@ -41,6 +41,14 @@ void E_WorldLightning(); void E_WorldTick(); // called on each render frame once. void E_RenderFrame(); +// this executes when a player enters the level (once). PlayerEnter+inhub = RETURN +void E_PlayerEntered(int num); +// this executes when a player respawns. includes resurrect cheat. +void E_PlayerRespawned(int num); +// this executes when a player dies (partially duplicating worldthingdied, but whatever) +void E_PlayerDied(int num); +// this executes when a player leaves the game +void E_PlayerDisconnected(int num); // serialization stuff void E_SerializeEvents(FSerializer& arc); @@ -89,6 +97,7 @@ public: // destroy handler. this unlinks EventHandler from the list automatically. void OnDestroy() override; + // virtual void WorldLoaded(); virtual void WorldUnloaded(); virtual void WorldThingSpawned(AActor*); @@ -98,8 +107,16 @@ public: virtual void WorldThingDestroyed(AActor*); virtual void WorldLightning(); virtual void WorldTick(); + + // virtual void RenderFrame(); + // + virtual void PlayerEntered(int num); + virtual void PlayerRespawned(int num); + virtual void PlayerDied(int num); + virtual void PlayerDisconnected(int num); + // gets the order of this item. int GetOrder(); }; @@ -153,6 +170,7 @@ class DWorldEvent : public DBaseEvent public: // for loaded/unloaded bool IsSaveGame; + bool IsReopen; // for thingspawned, thingdied, thingdestroyed AActor* Thing; // for thingdied @@ -167,6 +185,7 @@ public: DWorldEvent() { IsSaveGame = false; + IsReopen = false; Thing = nullptr; Inflictor = nullptr; Damage = 0; @@ -175,4 +194,23 @@ public: } }; +class DPlayerEvent : public DBaseEvent +{ + DECLARE_CLASS(DPlayerEvent, DBaseEvent) +public: + // we currently have only one member: player index + // in ZScript, we have global players[] array from which we can + // get both the player itself and player's body, + // so no need to pass it here. + int PlayerNumber; + // we set this to true if level was reopened (RETURN scripts) + bool IsReturn; + + DPlayerEvent() + { + PlayerNumber = -1; + IsReturn = false; + } +}; + #endif \ No newline at end of file diff --git a/wadsrc/static/zscript/events.txt b/wadsrc/static/zscript/events.txt index 3f155c145..e6b826554 100755 --- a/wadsrc/static/zscript/events.txt +++ b/wadsrc/static/zscript/events.txt @@ -14,6 +14,8 @@ class WorldEvent : BaseEvent native { // for loaded/unloaded native readonly bool IsSaveGame; + // this will be true if we are re-entering the hub level. + native readonly bool IsReopen; // for thingspawned/thingdied/thingdestroyed native readonly Actor Thing; // for thingdied. can be null @@ -26,6 +28,15 @@ class WorldEvent : BaseEvent native native readonly double DamageAngle; } +class PlayerEvent : BaseEvent native +{ + // this is the player number that caused the event. + // note: you can get player struct from this by using players[e.PlayerNumber] + native readonly int PlayerNumber; + // this will be true if we are re-entering the hub level. + native readonly bool IsReturn; +} + class StaticEventHandler : Object native { // static event handlers CAN register other static event handlers. @@ -48,8 +59,15 @@ class StaticEventHandler : Object native virtual native void WorldLightning(WorldEvent e); // for the sake of completeness. virtual native void WorldTick(WorldEvent e); + // virtual native void RenderFrame(RenderEvent e); + // + virtual native void PlayerEntered(PlayerEvent e); + virtual native void PlayerRespawned(PlayerEvent e); + virtual native void PlayerDied(PlayerEvent e); + virtual native void PlayerDisconnected(PlayerEvent e); + // this function should return a value that will be queried on Register() to decide the relative order of this handler to every other. // this is most useful in UI systems. // default is 0.