2019-02-02 15:43:11 +00:00
# pragma once
2017-01-22 00:33:53 +00:00
# include "dobject.h"
2017-01-23 21:05:51 +00:00
# include "serializer.h"
2017-02-03 10:28:40 +00:00
# include "d_event.h"
2017-03-29 21:51:53 +00:00
# include "sbar.h"
2020-09-30 01:56:36 +00:00
# include "info.h"
2017-01-22 00:33:53 +00:00
2017-01-22 06:56:57 +00:00
class DStaticEventHandler ;
2019-02-02 15:43:11 +00:00
struct EventManager ;
2020-04-29 15:51:04 +00:00
struct line_t ;
struct sector_t ;
struct FLevelLocals ;
2017-01-22 05:04:35 +00:00
2018-10-31 14:52:39 +00:00
enum class EventHandlerType
{
Global ,
PerMap
} ;
2017-01-30 06:47:15 +00:00
// ==============================================
//
// EventHandler - base class
//
// ==============================================
2017-01-22 06:56:57 +00:00
class DStaticEventHandler : public DObject // make it a part of normal GC process
2017-01-22 00:33:53 +00:00
{
2017-02-26 09:58:22 +00:00
DECLARE_CLASS ( DStaticEventHandler , DObject ) ;
2017-02-09 13:35:45 +00:00
HAS_OBJECT_POINTERS
2017-01-22 00:33:53 +00:00
public :
2017-01-30 05:50:09 +00:00
DStaticEventHandler ( )
{
prev = 0 ;
next = 0 ;
2017-02-03 10:28:40 +00:00
Order = 0 ;
IsUiProcessor = false ;
2017-01-30 05:50:09 +00:00
}
2019-02-02 15:43:11 +00:00
EventManager * owner ;
2017-01-22 06:56:57 +00:00
DStaticEventHandler * prev ;
DStaticEventHandler * next ;
virtual bool IsStatic ( ) { return true ; }
2017-01-22 00:33:53 +00:00
2017-02-03 10:28:40 +00:00
//
int Order ;
bool IsUiProcessor ;
2017-02-03 18:34:34 +00:00
bool RequireMouse ;
2017-02-02 17:57:00 +00:00
2017-01-23 22:17:12 +00:00
// serialization handler. let's keep it here so that I don't get lost in serialized/not serialized fields
void Serialize ( FSerializer & arc ) override
{
Super : : Serialize ( arc ) ;
2017-02-09 13:35:45 +00:00
/*
2017-01-23 22:17:12 +00:00
if ( arc . isReading ( ) )
{
Printf ( " DStaticEventHandler::Serialize: reading object %s \n " , GetClass ( ) - > TypeName . GetChars ( ) ) ;
}
else
{
Printf ( " DStaticEventHandler::Serialize: store object %s \n " , GetClass ( ) - > TypeName . GetChars ( ) ) ;
}
2017-02-09 13:35:45 +00:00
*/
2017-02-03 10:28:40 +00:00
2019-02-02 15:43:11 +00:00
arc ( " next " , next ) ;
arc ( " prev " , prev ) ;
2017-02-03 10:28:40 +00:00
arc ( " Order " , Order ) ;
arc ( " IsUiProcessor " , IsUiProcessor ) ;
2017-02-03 18:34:34 +00:00
arc ( " RequireMouse " , RequireMouse ) ;
2017-01-23 22:17:12 +00:00
}
2017-01-22 00:33:53 +00:00
// destroy handler. this unlinks EventHandler from the list automatically.
void OnDestroy ( ) override ;
2017-02-02 18:26:56 +00:00
//
2017-02-03 10:28:40 +00:00
void OnRegister ( ) ; // you can set order and IsUi here.
void OnUnregister ( ) ;
//
void WorldLoaded ( ) ;
void WorldUnloaded ( ) ;
2018-04-14 08:27:48 +00:00
void WorldThingSpawned ( AActor * actor ) ;
void WorldThingDied ( AActor * actor , AActor * inflictor ) ;
2020-09-30 01:56:36 +00:00
void WorldThingGround ( AActor * actor , FState * st ) ;
2018-04-14 08:27:48 +00:00
void WorldThingRevived ( AActor * actor ) ;
void WorldThingDamaged ( AActor * actor , AActor * inflictor , AActor * source , int damage , FName mod , int flags , DAngle angle ) ;
void WorldThingDestroyed ( AActor * actor ) ;
2018-04-14 08:33:17 +00:00
void WorldLinePreActivated ( line_t * line , AActor * actor , int activationType , bool * shouldactivate ) ;
void WorldLineActivated ( line_t * line , AActor * actor , int activationType ) ;
2018-11-06 02:59:17 +00:00
int WorldSectorDamaged ( sector_t * sector , AActor * source , int damage , FName damagetype , int part , DVector3 position , bool isradius ) ;
int WorldLineDamaged ( line_t * line , AActor * source , int damage , FName damagetype , int side , DVector3 position , bool isradius ) ;
2017-02-03 10:28:40 +00:00
void WorldLightning ( ) ;
void WorldTick ( ) ;
2017-02-02 18:26:56 +00:00
//
2017-02-03 10:28:40 +00:00
void RenderFrame ( ) ;
2017-03-29 21:51:53 +00:00
void RenderOverlay ( EHudState state ) ;
2019-06-23 01:02:35 +00:00
void RenderUnderlay ( EHudState state ) ;
2017-02-02 17:57:00 +00:00
2017-02-02 18:26:56 +00:00
//
2017-02-03 10:28:40 +00:00
void PlayerEntered ( int num , bool fromhub ) ;
2020-08-25 15:54:20 +00:00
void PlayerSpawned ( int num ) ;
2017-02-03 10:28:40 +00:00
void PlayerRespawned ( int num ) ;
void PlayerDied ( int num ) ;
void PlayerDisconnected ( int num ) ;
2017-02-02 18:26:56 +00:00
2017-02-03 10:28:40 +00:00
// return true if handled.
2017-03-07 09:43:14 +00:00
bool InputProcess ( const event_t * ev ) ;
bool UiProcess ( const event_t * ev ) ;
2017-03-09 12:49:18 +00:00
void UiTick ( ) ;
2018-03-09 01:06:41 +00:00
void PostUiTick ( ) ;
2017-02-06 13:52:20 +00:00
//
2017-03-06 09:25:30 +00:00
void ConsoleProcess ( int player , FString name , int arg1 , int arg2 , int arg3 , bool manual ) ;
2018-08-15 15:46:03 +00:00
//
2018-08-16 18:46:40 +00:00
void CheckReplacement ( PClassActor * replacee , PClassActor * * replacement , bool * final ) ;
2019-01-28 00:03:04 +00:00
void CheckReplacee ( PClassActor * * replacee , PClassActor * replacement , bool * final ) ;
2018-09-15 02:57:07 +00:00
//
void NewGame ( ) ;
2017-01-22 00:33:53 +00:00
} ;
2017-01-22 06:56:57 +00:00
class DEventHandler : public DStaticEventHandler
{
DECLARE_CLASS ( DEventHandler , DStaticEventHandler ) // TODO: make sure this does not horribly break anything
public :
bool IsStatic ( ) override { return false ; }
} ;
2017-01-22 00:33:53 +00:00
2017-03-06 21:27:51 +00:00
struct FRenderEvent
2017-01-30 23:28:47 +00:00
{
2017-01-22 05:04:35 +00:00
// these are for all render events
2017-01-22 00:33:53 +00:00
DVector3 ViewPos ;
DAngle ViewAngle ;
DAngle ViewPitch ;
DAngle ViewRoll ;
2017-03-06 21:27:51 +00:00
double FracTic = 0 ; // 0..1 value that describes where we are inside the current gametic, render-wise.
AActor * Camera = nullptr ;
2017-03-29 21:51:53 +00:00
int HudState ;
2017-01-22 06:56:57 +00:00
} ;
2017-01-22 00:33:53 +00:00
2017-03-06 21:27:51 +00:00
struct FWorldEvent
2017-01-30 06:47:15 +00:00
{
2017-01-30 23:28:47 +00:00
// for loaded/unloaded
2017-03-06 21:27:51 +00:00
bool IsSaveGame = false ;
bool IsReopen = false ;
2017-01-30 23:28:47 +00:00
// for thingspawned, thingdied, thingdestroyed
2017-03-06 21:27:51 +00:00
AActor * Thing = nullptr ; // for thingdied
AActor * Inflictor = nullptr ; // can be null - for damagemobj
AActor * DamageSource = nullptr ; // can be null
2018-11-06 02:59:17 +00:00
int Damage = 0 ; // thingdamaged, sector/line damaged
FName DamageType = NAME_None ; // thingdamaged, sector/line damaged
int DamageFlags = 0 ; // thingdamaged
DAngle DamageAngle ; // thingdamaged
2018-03-24 14:59:20 +00:00
// for line(pre)activated
2018-03-17 15:01:47 +00:00
line_t * ActivatedLine = nullptr ;
2018-04-14 08:33:17 +00:00
int ActivationType = 0 ;
2018-03-24 14:59:20 +00:00
bool ShouldActivate = true ;
2018-11-06 02:59:17 +00:00
// for line/sector damaged
int DamageSectorPart = 0 ;
line_t * DamageLine = nullptr ;
sector_t * DamageSector = nullptr ;
int DamageLineSide = - 1 ;
DVector3 DamagePosition ;
bool DamageIsRadius ; // radius damage yes/no
int NewDamage = 0 ; // sector/line damaged. allows modifying damage
2020-09-30 01:56:36 +00:00
FState * CrushedState = nullptr ; // custom crush state set in thingground
2017-01-30 06:47:15 +00:00
} ;
2017-03-06 21:27:51 +00:00
struct FPlayerEvent
2017-02-02 18:26:56 +00:00
{
// 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 ;
} ;
2017-02-03 10:28:40 +00:00
2017-03-06 21:27:51 +00:00
struct FConsoleEvent
2017-02-06 13:52:20 +00:00
{
// player that activated this event. note that it's always -1 for non-playsim events (i.e. these not called with netevent)
int Player ;
//
FString Name ;
int Args [ 3 ] ;
2017-03-06 09:25:30 +00:00
//
bool IsManual ;
2017-02-06 13:52:20 +00:00
} ;
2018-08-15 15:46:03 +00:00
struct FReplaceEvent
{
PClassActor * Replacee ;
PClassActor * Replacement ;
2018-08-16 18:46:40 +00:00
bool IsFinal ;
2018-08-15 15:46:03 +00:00
} ;
2019-01-28 00:03:04 +00:00
struct FReplacedEvent
{
PClassActor * Replacee ;
PClassActor * Replacement ;
bool IsFinal ;
} ;
2019-02-02 09:46:34 +00:00
struct EventManager
{
2019-02-02 15:43:11 +00:00
FLevelLocals * Level = nullptr ;
2019-02-02 09:46:34 +00:00
DStaticEventHandler * FirstEventHandler = nullptr ;
DStaticEventHandler * LastEventHandler = nullptr ;
2019-02-02 15:43:11 +00:00
EventManager ( ) = default ;
EventManager ( FLevelLocals * l ) { Level = l ; }
~ EventManager ( ) { Shutdown ( ) ; }
bool ShouldCallStatic ( bool forplay ) ;
2019-03-26 16:02:40 +00:00
// for use after loading a savegame. The old handler explicitly reinstalled all handlers instead of doing a list deserialization which resulted in OnRegister being called even when a save was loaded.
void CallOnRegister ( ) ;
2019-02-02 09:46:34 +00:00
// register
bool RegisterHandler ( DStaticEventHandler * handler ) ;
// unregister
bool UnregisterHandler ( DStaticEventHandler * handler ) ;
// find
bool CheckHandler ( DStaticEventHandler * handler ) ;
// check type
bool IsStaticType ( PClass * type ) ;
// init static handlers
2019-02-06 14:33:19 +00:00
void InitStaticHandlers ( FLevelLocals * l , bool map ) ;
2019-02-02 09:46:34 +00:00
// shutdown handlers
2019-02-02 15:43:11 +00:00
void Shutdown ( ) ;
2019-02-02 09:46:34 +00:00
// called right after the map has loaded (approximately same time as OPEN ACS scripts)
void WorldLoaded ( ) ;
// called when the map is about to unload (approximately same time as UNLOADING ACS scripts)
void WorldUnloaded ( ) ;
// called around PostBeginPlay of each actor.
void WorldThingSpawned ( AActor * actor ) ;
// called after AActor::Die of each actor.
void WorldThingDied ( AActor * actor , AActor * inflictor ) ;
2020-09-06 12:34:40 +00:00
// called inside AActor::Grind just before the corpse is destroyed
2020-09-30 01:56:36 +00:00
void WorldThingGround ( AActor * actor , FState * st ) ;
2019-02-02 09:46:34 +00:00
// called after AActor::Revive.
void WorldThingRevived ( AActor * actor ) ;
// called before P_DamageMobj and before AActor::DamageMobj virtuals.
void WorldThingDamaged ( AActor * actor , AActor * inflictor , AActor * source , int damage , FName mod , int flags , DAngle angle ) ;
// called before AActor::Destroy of each actor.
void WorldThingDestroyed ( AActor * actor ) ;
// called in P_ActivateLine before executing special, set shouldactivate to false to prevent activation.
void WorldLinePreActivated ( line_t * line , AActor * actor , int activationType , bool * shouldactivate ) ;
// called in P_ActivateLine after successful special execution.
void WorldLineActivated ( line_t * line , AActor * actor , int activationType ) ;
// called in P_DamageSector and P_DamageLinedef before receiving damage to the sector. returns actual damage
int WorldSectorDamaged ( sector_t * sector , AActor * source , int damage , FName damagetype , int part , DVector3 position , bool isradius ) ;
// called in P_DamageLinedef before receiving damage to the linedef. returns actual damage
int WorldLineDamaged ( line_t * line , AActor * source , int damage , FName damagetype , int side , DVector3 position , bool isradius ) ;
// same as ACS SCRIPT_Lightning
void WorldLightning ( ) ;
// this executes on every tick, before everything, only when in valid level and not paused
void WorldTick ( ) ;
// this executes on every tick on UI side, always
void UiTick ( ) ;
// this executes on every tick on UI side, always AND immediately after everything else
void PostUiTick ( ) ;
// called on each render frame once.
void RenderFrame ( ) ;
// called after everything's been rendered, but before console/menus
void RenderOverlay ( EHudState state ) ;
2019-06-23 01:02:35 +00:00
// called after everything's been rendered, but before console/menus/huds
void RenderUnderlay ( EHudState state ) ;
2019-02-02 09:46:34 +00:00
// this executes when a player enters the level (once). PlayerEnter+inhub = RETURN
void PlayerEntered ( int num , bool fromhub ) ;
2020-08-25 15:54:20 +00:00
// this executes at the same time as ENTER scripts
void PlayerSpawned ( int num ) ;
2019-02-02 09:46:34 +00:00
// this executes when a player respawns. includes resurrect cheat.
void PlayerRespawned ( int num ) ;
// this executes when a player dies (partially duplicating worldthingdied, but whatever)
void PlayerDied ( int num ) ;
// this executes when a player leaves the game
void PlayerDisconnected ( int num ) ;
// this executes on events.
bool Responder ( const event_t * ev ) ; // splits events into InputProcess and UiProcess
// this executes on console/net events.
void Console ( int player , FString name , int arg1 , int arg2 , int arg3 , bool manual ) ;
// called when looking up the replacement for an actor class
bool CheckReplacement ( PClassActor * replacee , PClassActor * * replacement ) ;
// called when looking up the replaced for an actor class
bool CheckReplacee ( PClassActor * * replacee , PClassActor * replacement ) ;
// called on new game
2019-02-02 15:43:11 +00:00
void NewGame ( ) ;
2019-02-02 09:46:34 +00:00
// send networked event. unified function.
bool SendNetworkEvent ( FString name , int arg1 , int arg2 , int arg3 , bool manual ) ;
// check if there is anything that should receive GUI events
bool CheckUiProcessors ( ) ;
// check if we need native mouse due to UiProcessors
bool CheckRequireMouse ( ) ;
void InitHandler ( PClass * type ) ;
FWorldEvent SetupWorldEvent ( ) ;
FRenderEvent SetupRenderEvent ( ) ;
2019-02-02 15:43:11 +00:00
void SetOwnerForHandlers ( )
{
for ( DStaticEventHandler * existinghandler = FirstEventHandler ; existinghandler ; existinghandler = existinghandler - > next )
{
existinghandler - > owner = this ;
}
}
2019-02-02 09:46:34 +00:00
} ;
2019-04-06 07:06:41 +00:00
extern EventManager staticEventManager ;