Merge branch 'thereisnospoon' of https://github.com/jewalky/gzdoom

# Conflicts:
#	src/dobject.h
This commit is contained in:
Christoph Oelckers 2017-02-14 19:10:02 +01:00
commit 2234d36c7a
40 changed files with 1970 additions and 15 deletions

View file

@ -1211,6 +1211,7 @@ set (PCH_SOURCES
scripting/zscript/zcc_compile.cpp
scripting/zscript/zcc_parser.cpp
sfmt/SFMT.cpp
events.cpp
)
enable_precompiled_headers( g_pch.h PCH_SOURCES )

View file

@ -625,6 +625,9 @@ public:
virtual void BeginPlay(); // Called immediately after the actor is created
void CallBeginPlay();
// [ZZ] custom postbeginplay (calls E_WorldThingSpawned)
void CallPostBeginPlay() override;
void LevelSpawned(); // Called after BeginPlay if this actor was spawned by the world
void HandleSpawnFlags(); // Translates SpawnFlags into in-game flags.

View file

@ -61,6 +61,7 @@ Everything that is changed is marked (maybe commented) with "Added by MC"
#include "d_netinf.h"
#include "d_player.h"
#include "doomerrors.h"
#include "events.h"
static FRandom pr_botspawn ("BotSpawn");
@ -418,6 +419,9 @@ void FCajunMaster::RemoveAllBots (bool fromlist)
}
}
}
// [ZZ] run event hook
E_PlayerDisconnected(i);
//
FBehavior::StaticStartTypedScripts (SCRIPT_Disconnect, players[i].mo, true, i, true);
ClearPlayer (i, !fromlist);
}

View file

@ -69,6 +69,8 @@
#include "c_consolebuffer.h"
#include "g_levellocals.h"
FString FStringFormat(VM_ARGS); // extern from thingdef_data.cpp
#include "gi.h"
#define LEFTMARGIN 8

View file

@ -110,6 +110,7 @@
#include "autosegs.h"
#include "fragglescript/t_fs.h"
#include "g_levellocals.h"
#include "events.h"
EXTERN_CVAR(Bool, hud_althud)
void DrawHUD();
@ -286,6 +287,9 @@ void D_ProcessEvents (void)
continue; // console ate the event
if (M_Responder (ev))
continue; // menu ate the event
// check events
if (E_Responder(ev)) // [ZZ] ZScript ate the event
continue;
G_Responder (ev);
}
}
@ -306,8 +310,7 @@ void D_PostEvent (const event_t *ev)
return;
}
events[eventhead] = *ev;
if (ev->type == EV_Mouse && !paused && menuactive == MENU_Off && ConsoleState != c_down && ConsoleState != c_falling
)
if (ev->type == EV_Mouse && !paused && menuactive == MENU_Off && ConsoleState != c_down && ConsoleState != c_falling && !E_CheckUiProcessors())
{
if (Button_Mlook.bDown || freelook)
{
@ -775,6 +778,9 @@ void D_Display ()
screen->SetBlendingRect(viewwindowx, viewwindowy,
viewwindowx + viewwidth, viewwindowy + viewheight);
// [ZZ] execute event hook that we just started the frame
E_RenderFrame();
//
Renderer->RenderView(&players[consoleplayer]);
if ((hw2d = screen->Begin2D(viewactive)))
@ -893,6 +899,8 @@ void D_Display ()
{
NetUpdate (); // send out any new accumulation
// normal update
// draw ZScript UI stuff
E_RenderOverlay();
C_DrawConsole (hw2d); // draw console
M_Drawer (); // menu is drawn even on top of everything
FStat::PrintStat ();

View file

@ -64,6 +64,7 @@
#include "a_keys.h"
#include "intermission/intermission.h"
#include "g_levellocals.h"
#include "events.h"
EXTERN_CVAR (Int, disableautosave)
EXTERN_CVAR (Int, autosavecount)
@ -2678,6 +2679,17 @@ void Net_DoCommand (int type, BYTE **stream, int player)
G_ChangeLevel(NULL, 0, 0);
break;
case DEM_NETEVENT:
{
FString ename = ReadString(stream);
int argn = ReadByte(stream);
int arg[3] = { 0, 0, 0 };
for (int i = 0; i < argn; i++)
arg[i] = ReadLong(stream);
E_Console(player, ename, arg[0], arg[1], arg[2]);
}
break;
default:
I_Error ("Unknown net command: %d", type);
break;

View file

@ -159,6 +159,7 @@ enum EDemoCommand
DEM_SETSLOTPNUM, // 67 Byte: player number, the rest is the same as DEM_SETSLOT
DEM_REMOVE, // 68
DEM_FINISHGAME, // 69
DEM_NETEVENT // 70 String: Event name, Byte: Arg count; each arg is a 4-byte int
};
// The following are implemented by cht_DoCheat in m_cheat.cpp

View file

@ -203,8 +203,9 @@ enum EObjectFlags
OF_SerialSuccess = 1 << 9, // For debugging Serialize() calls
OF_Sentinel = 1 << 10, // Object is serving as the sentinel in a ring list
OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk)
OF_Released = 1 << 12, // Object was released from the GC system and should not be processed by GC function
OF_Abstract = 1 << 13, // Marks a class that cannot be created with CreateNew
OF_Spawned = 1 << 12, // Thinker was spawned at all (some thinkers get deleted before spawning)
OF_Released = 1 << 13, // Object was released from the GC system and should not be processed by GC function
OF_Abstract = 1 << 14, // Marks a class that cannot be created with CreateNew
};
template<class T> class TObjPtr;

View file

@ -309,6 +309,7 @@ DEFINE_ACTION_FUNCTION(DThinker, PostBeginPlay)
void DThinker::CallPostBeginPlay()
{
ObjectFlags |= OF_Spawned;
IFVIRTUAL(DThinker, PostBeginPlay)
{
// Without the type cast this picks the 'void *' assignment...

View file

@ -71,7 +71,7 @@ public:
virtual void Tick ();
void CallTick();
virtual void PostBeginPlay (); // Called just before the first tick
void CallPostBeginPlay();
virtual void CallPostBeginPlay(); // different in actor.
virtual void PostSerialize();
size_t PropagateMark();

1117
src/events.cpp Executable file

File diff suppressed because it is too large Load diff

303
src/events.h Executable file
View file

@ -0,0 +1,303 @@
#ifndef EVENTS_H
#define EVENTS_H
#include "dobject.h"
#include "serializer.h"
#include "d_event.h"
#include "d_gui.h"
class DStaticEventHandler;
// register
bool E_RegisterHandler(DStaticEventHandler* handler);
// unregister
bool E_UnregisterHandler(DStaticEventHandler* handler);
// find
bool E_CheckHandler(DStaticEventHandler* handler);
// check type
bool E_IsStaticType(PClass* type);
// init static handlers
void E_InitStaticHandlers(bool map);
// shutdown handlers
void E_Shutdown(bool map);
// called right after the map has loaded (approximately same time as OPEN ACS scripts)
void E_WorldLoaded();
// called when the map is about to unload (approximately same time as UNLOADING ACS scripts)
void E_WorldUnloaded();
// called right after the map has loaded (every time, UNSAFE VERSION)
void E_WorldLoadedUnsafe();
// called right before the map is unloaded (every time, UNSAFE VERSION)
void E_WorldUnloadedUnsafe();
// called around PostBeginPlay of each actor.
void E_WorldThingSpawned(AActor* actor);
// called after AActor::Die of each actor.
void E_WorldThingDied(AActor* actor, AActor* inflictor);
// called after AActor::Revive.
void E_WorldThingRevived(AActor* actor);
// called before P_DamageMobj and before AActor::DamageMobj virtuals.
void E_WorldThingDamaged(AActor* actor, AActor* inflictor, AActor* source, int damage, FName mod, int flags, DAngle angle);
// called before AActor::Destroy of each actor.
void E_WorldThingDestroyed(AActor* actor);
// same as ACS SCRIPT_Lightning
void E_WorldLightning();
// this executes on every tick, before everything
void E_WorldTick();
// called on each render frame once.
void E_RenderFrame();
// called after everything's been rendered, but before console/menus
void E_RenderOverlay();
// this executes when a player enters the level (once). PlayerEnter+inhub = RETURN
void E_PlayerEntered(int num, bool fromhub);
// 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);
// this executes on events.
bool E_Responder(event_t* ev); // splits events into InputProcess and UiProcess
// this executes on console/net events.
void E_Console(int player, FString name, int arg1, int arg2, int arg3);
// check if there is anything that should receive GUI events
bool E_CheckUiProcessors();
// check if we need native mouse due to UiProcessors
bool E_CheckRequireMouse();
// serialization stuff
void E_SerializeEvents(FSerializer& arc);
// ==============================================
//
// EventHandler - base class
//
// ==============================================
class DStaticEventHandler : public DObject // make it a part of normal GC process
{
DECLARE_CLASS(DStaticEventHandler, DObject)
public:
DStaticEventHandler()
{
prev = 0;
next = 0;
Order = 0;
IsUiProcessor = false;
}
DStaticEventHandler* prev;
DStaticEventHandler* next;
virtual bool IsStatic() { return true; }
//
int Order;
bool IsUiProcessor;
bool RequireMouse;
// 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);
if (arc.isReading())
{
Printf("DStaticEventHandler::Serialize: reading object %s\n", GetClass()->TypeName.GetChars());
}
else
{
Printf("DStaticEventHandler::Serialize: store object %s\n", GetClass()->TypeName.GetChars());
}
arc("Order", Order);
arc("IsUiProcessor", IsUiProcessor);
arc("RequireMouse", RequireMouse);
}
// destroy handler. this unlinks EventHandler from the list automatically.
void OnDestroy() override;
//
void OnRegister(); // you can set order and IsUi here.
void OnUnregister();
//
void WorldLoaded();
void WorldUnloaded();
void WorldThingSpawned(AActor*);
void WorldThingDied(AActor*, AActor*);
void WorldThingRevived(AActor*);
void WorldThingDamaged(AActor*, AActor*, AActor*, int, FName, int, DAngle);
void WorldThingDestroyed(AActor*);
void WorldLightning();
void WorldTick();
//
void RenderFrame();
void RenderOverlay();
//
void PlayerEntered(int num, bool fromhub);
void PlayerRespawned(int num);
void PlayerDied(int num);
void PlayerDisconnected(int num);
// return true if handled.
bool InputProcess(event_t* ev);
bool UiProcess(event_t* ev);
//
void ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3);
};
class DEventHandler : public DStaticEventHandler
{
DECLARE_CLASS(DEventHandler, DStaticEventHandler) // TODO: make sure this does not horribly break anything
public:
bool IsStatic() override { return false; }
};
extern DStaticEventHandler* E_FirstEventHandler;
// we cannot call this DEvent because in ZScript, 'event' is a keyword
class DBaseEvent : public DObject
{
DECLARE_CLASS(DBaseEvent, DObject)
public:
DBaseEvent()
{
// each type of event is created only once to avoid new/delete hell
// since from what I remember object creation and deletion results in a lot of GC processing
// (and we aren't supposed to pass event objects around anyway)
this->ObjectFlags |= OF_Fixed;
// we don't want to store events into the savegames because they are global.
this->ObjectFlags |= OF_Transient;
}
};
class DRenderEvent : public DBaseEvent
{
DECLARE_CLASS(DRenderEvent, DBaseEvent)
public:
// these are for all render events
DVector3 ViewPos;
DAngle ViewAngle;
DAngle ViewPitch;
DAngle ViewRoll;
double FracTic; // 0..1 value that describes where we are inside the current gametic, render-wise.
AActor* Camera;
DRenderEvent()
{
FracTic = 0;
Camera = nullptr;
}
};
class DWorldEvent : public DBaseEvent
{
DECLARE_CLASS(DWorldEvent, DBaseEvent)
public:
// for loaded/unloaded
bool IsSaveGame;
bool IsReopen;
// for thingspawned, thingdied, thingdestroyed
AActor* Thing;
// for thingdied
AActor* Inflictor; // can be null
// for damagemobj
int Damage;
AActor* DamageSource; // can be null
FName DamageType;
int DamageFlags;
DAngle DamageAngle;
DWorldEvent()
{
IsSaveGame = false;
IsReopen = false;
Thing = nullptr;
Inflictor = nullptr;
Damage = 0;
DamageSource = nullptr;
DamageFlags = 0;
}
};
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;
}
};
class DUiEvent : public DBaseEvent
{
DECLARE_CLASS(DUiEvent, DBaseEvent)
public:
// this essentially translates event_t UI events to ZScript.
EGUIEvent Type;
// for keys/chars/whatever
FString KeyString;
int KeyChar;
// for mouse
int MouseX;
int MouseY;
// global (?)
bool IsShift;
bool IsCtrl;
bool IsAlt;
DUiEvent()
{
Type = EV_GUI_None;
}
};
class DInputEvent : public DBaseEvent
{
DECLARE_CLASS(DInputEvent, DBaseEvent)
public:
// this translates regular event_t events to ZScript (not UI, UI events are sent via DUiEvent and only if requested!)
EGenericEvent Type;
// for keys
int KeyScan;
FString KeyString;
int KeyChar;
// for mouse
int MouseX;
int MouseY;
DInputEvent()
{
Type = EV_None;
}
};
class DConsoleEvent : public DBaseEvent
{
DECLARE_CLASS(DConsoleEvent, DBaseEvent)
public:
// 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];
DConsoleEvent()
{
Player = -1;
}
};
#endif

View file

@ -91,6 +91,7 @@
#include "g_hub.h"
#include "g_levellocals.h"
#include "events.h"
static FRandom pr_dmspawn ("DMSpawn");
@ -1791,6 +1792,8 @@ void G_DoPlayerPop(int playernum)
// [RH] Make the player disappear
FBehavior::StaticStopMyScripts(players[playernum].mo);
// [ZZ] fire player disconnect hook
E_PlayerDisconnected(playernum);
// [RH] Let the scripts know the player left
FBehavior::StaticStartTypedScripts(SCRIPT_Disconnect, players[playernum].mo, true, playernum, true);
if (players[playernum].mo != NULL)

View file

@ -85,6 +85,7 @@
#include "p_spec.h"
#include "serializer.h"
#include "virtual.h"
#include "events.h"
#include "gi.h"
@ -406,6 +407,10 @@ void G_InitNew (const char *mapname, bool bTitleLevel)
bool wantFast;
int i;
// did we have any level before?
if (level.info != nullptr)
E_WorldUnloadedUnsafe();
if (!savegamerestore)
{
G_ClearHubInfo();
@ -655,6 +660,10 @@ void G_ChangeLevel(const char *levelname, int position, int flags, int nextSkill
// [RH] Give scripts a chance to do something
unloading = true;
FBehavior::StaticStartTypedScripts (SCRIPT_Unloading, NULL, false, 0, true);
// [ZZ] safe world unload
E_WorldUnloaded();
// [ZZ] unsafe world unload (changemap != map)
E_WorldUnloadedUnsafe();
unloading = false;
STAT_ChangeLevel(nextlevel);
@ -1012,6 +1021,7 @@ void G_DoLoadLevel (int position, bool autosave)
}
level.maptime = 0;
P_SetupLevel (level.MapName, position);
AM_LevelInit();
@ -1053,6 +1063,7 @@ void G_DoLoadLevel (int position, bool autosave)
}
level.starttime = gametic;
G_UnSnapshotLevel (!savegamerestore); // [RH] Restore the state of the level.
G_FinishTravel ();
// For each player, if they are viewing through a player, make sure it is themselves.
@ -1064,6 +1075,10 @@ void G_DoLoadLevel (int position, bool autosave)
}
}
StatusBar->AttachToPlayer (&players[consoleplayer]);
// unsafe world load
E_WorldLoadedUnsafe();
// regular world load (savegames are handled internally)
E_WorldLoaded();
P_DoDeferedScripts (); // [RH] Do script actions that were triggered on another map.
if (demoplayback || oldgs == GS_STARTUP || oldgs == GS_TITLELEVEL)
@ -1241,6 +1256,10 @@ void G_FinishTravel ()
FPlayerStart *start;
int pnum;
//
APlayerPawn* pawns[MAXPLAYERS];
int pawnsnum = 0;
next = it.Next ();
while ( (pawn = next) != NULL)
{
@ -1332,12 +1351,23 @@ void G_FinishTravel ()
{
pawn->Speed = pawn->GetDefault()->Speed;
}
if (level.FromSnapshot)
{
FBehavior::StaticStartTypedScripts (SCRIPT_Return, pawn, true);
// [ZZ] we probably don't want to fire any scripts before all players are in, especially with runNow = true.
pawns[pawnsnum++] = pawn;
}
// [Nash] run REOPEN scripts upon map re-entry
FBehavior::StaticStartTypedScripts(SCRIPT_Reopen, NULL, false);
// [ZZ] fire the reopen hook.
// if level is loaded from snapshot, and we don't have savegamerestore, this means we returned from a hub.
if (level.FromSnapshot)
{
// [Nash] run REOPEN scripts upon map re-entry
FBehavior::StaticStartTypedScripts(SCRIPT_Reopen, NULL, false);
for (int i = 0; i < pawnsnum; i++)
{
// [ZZ] fire the enter hook.
E_PlayerEntered(pawns[i]->player - players, true);
//
FBehavior::StaticStartTypedScripts(SCRIPT_Return, pawns[i], true);
}
}

View file

@ -338,6 +338,8 @@ struct level_info_t
TArray<FSoundID> PrecacheSounds;
TArray<FString> PrecacheTextures;
TArray<FName> PrecacheClasses;
TArray<FString> EventHandlers;
level_info_t()
{

View file

@ -52,6 +52,7 @@
#include "version.h"
#include "v_text.h"
#include "g_levellocals.h"
#include "events.h"
TArray<cluster_info_t> wadclusterinfos;
TArray<level_info_t> wadlevelinfos;
@ -1046,6 +1047,17 @@ DEFINE_MAP_OPTION(PrecacheSounds, true)
} while (parse.sc.CheckString(","));
}
DEFINE_MAP_OPTION(EventHandlers, true)
{
parse.ParseAssign();
do
{
parse.sc.MustGetString();
info->EventHandlers.Push(parse.sc.String);
} while (parse.sc.CheckString(","));
}
DEFINE_MAP_OPTION(PrecacheTextures, true)
{
parse.ParseAssign();

View file

@ -11,6 +11,7 @@
#include "r_state.h"
#include "serializer.h"
#include "g_levellocals.h"
#include "events.h"
static FRandom pr_lightning ("Lightning");
@ -129,6 +130,9 @@ void DLightningThinker::LightningFlash ()
level.flags |= LEVEL_SWAPSKIES; // set alternate sky
S_Sound (CHAN_AUTO, "world/thunder", 1.0, ATTN_NONE);
// [ZZ] just in case
E_WorldLightning();
// start LIGHTNING scripts
FBehavior::StaticStartTypedScripts (SCRIPT_Lightning, NULL, false); // [RH] Run lightning scripts
// Calculate the next lighting flash

View file

@ -317,6 +317,8 @@ void FMapInfoParser::ParseGameInfo()
GAMEINFOKEY_STRINGARRAY(PrecachedClasses, "precacheclasses", 0, false)
GAMEINFOKEY_STRINGARRAY(PrecachedTextures, "precachetextures", 0, false)
GAMEINFOKEY_STRINGARRAY(PrecachedSounds, "precachesounds", 0, false)
GAMEINFOKEY_STRINGARRAY(EventHandlers, "addeventhandlers", 0, true)
GAMEINFOKEY_STRINGARRAY(EventHandlers, "eventhandlers", 0, false)
GAMEINFOKEY_STRING(PauseSign, "pausesign")
GAMEINFOKEY_STRING(quitSound, "quitSound")
GAMEINFOKEY_STRING(BorderFlat, "borderFlat")

View file

@ -124,6 +124,7 @@ struct gameinfo_t
TArray<FName> PrecachedClasses;
TArray<FString> PrecachedTextures;
TArray<FSoundID> PrecachedSounds;
TArray<FString> EventHandlers;
FString titleMusic;
int titleOrder;

View file

@ -44,6 +44,7 @@
#include "gl/gl_functions.h"
#include "serializer.h"
#include "g_levellocals.h"
#include "events.h"
#include "gl/dynlights/gl_lightbuffer.h"
#include "gl/system/gl_interface.h"

View file

@ -37,6 +37,7 @@
#include "a_pickups.h"
#include "d_player.h"
#include "g_levellocals.h"
#include "events.h"
#include "gl/system/gl_interface.h"
#include "gl/system/gl_framebuffer.h"

View file

@ -54,6 +54,7 @@
#include "thingdef.h"
#include "d_player.h"
#include "doomerrors.h"
#include "events.h"
extern void LoadActors ();
extern void InitBotStuff();
@ -210,6 +211,9 @@ void PClassActor::StaticInit()
ClearStrifeTypes();
LoadActors ();
InitBotStuff();
// reinit GLOBAL static stuff from gameinfo, once classes are loaded.
E_InitStaticHandlers(false);
}
//==========================================================================

View file

@ -49,6 +49,7 @@
#include "a_morph.h"
#include "g_levellocals.h"
#include "virtual.h"
#include "events.h"
// [RH] Actually handle the cheat. The cheat code in st_stuff.c now just
// writes some bytes to the network data stream, and the network code
@ -347,6 +348,12 @@ void cht_DoCheat (player_t *player, int cheat)
P_UndoPlayerMorph(player, player);
}
// player is now alive.
// fire E_PlayerRespawned and start the ACS SCRIPT_Respawn.
E_PlayerRespawned(player - players);
//
FBehavior::StaticStartTypedScripts(SCRIPT_Respawn, player->mo, true);
}
}
break;

View file

@ -60,6 +60,7 @@
#include "a_morph.h"
#include "virtual.h"
#include "g_levellocals.h"
#include "events.h"
static FRandom pr_obituary ("Obituary");
static FRandom pr_botrespawn ("BotRespawn");
@ -384,6 +385,9 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags)
target = source;
}
// [ZZ] Fire WorldThingDied script hook.
E_WorldThingDied(this, inflictor);
// [JM] Fire KILL type scripts for actor. Not needed for players, since they have the "DEATH" script type.
if (!player && !(flags7 & MF7_NOKILLSCRIPTS) && ((flags7 & MF7_USEKILLSCRIPTS) || gameinfo.forcekillscripts))
{
@ -606,6 +610,9 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags)
// [RH] Death messages
ClientObituary (this, inflictor, source, dmgflags);
// [ZZ] fire player death hook
E_PlayerDied(player - players);
// Death script execution, care of Skull Tag
FBehavior::StaticStartTypedScripts (SCRIPT_Death, this, true);
@ -1593,7 +1600,12 @@ DEFINE_ACTION_FUNCTION(AActor, DamageMobj)
PARAM_NAME(mod);
PARAM_INT_DEF(flags);
PARAM_FLOAT_DEF(angle);
ACTION_RETURN_INT(DamageMobj(self, inflictor, source, damage, mod, flags, angle));
// [ZZ] event handlers need the result.
int realdamage = DamageMobj(self, inflictor, source, damage, mod, flags, angle);
if (!realdamage) ACTION_RETURN_INT(0);
E_WorldThingDamaged(self, inflictor, source, realdamage, mod, flags, angle);
ACTION_RETURN_INT(realdamage);
}
int P_DamageMobj(AActor *target, AActor *inflictor, AActor *source, int damage, FName mod, int flags, DAngle angle)
@ -1607,7 +1619,14 @@ int P_DamageMobj(AActor *target, AActor *inflictor, AActor *source, int damage,
GlobalVMStack.Call(func, params, 7, &ret, 1, nullptr);
return retval;
}
else return DamageMobj(target, inflictor, source, damage, mod, flags, angle);
else
{
int realdamage = DamageMobj(target, inflictor, source, damage, mod, flags, angle);
if (!realdamage) return 0;
// [ZZ] event handlers only need the resultant damage (they can't do anything about it anyway)
E_WorldThingDamaged(target, inflictor, source, realdamage, mod, flags, angle);
return realdamage;
}
}

View file

@ -71,6 +71,7 @@
#include "virtual.h"
#include "g_levellocals.h"
#include "a_morph.h"
#include "events.h"
// MACROS ------------------------------------------------------------------
@ -4973,6 +4974,12 @@ void AActor::PostBeginPlay ()
flags7 |= MF7_HANDLENODELAY;
}
void AActor::CallPostBeginPlay()
{
Super::CallPostBeginPlay();
E_WorldThingSpawned(this);
}
void AActor::MarkPrecacheSounds() const
{
SeeSound.MarkUsed();
@ -5104,6 +5111,12 @@ void AActor::CallDeactivate(AActor *activator)
void AActor::OnDestroy ()
{
// [ZZ] call destroy event hook.
// note that this differs from ThingSpawned in that you can actually override OnDestroy to avoid calling the hook.
// but you can't really do that without utterly breaking the game, so it's ok.
// note: if OnDestroy is ever made optional, E_WorldThingDestroyed should still be called for ANY thing.
E_WorldThingDestroyed(this);
ClearRenderSectorList();
ClearRenderLineList();
@ -5416,6 +5429,9 @@ APlayerPawn *P_SpawnPlayer (FPlayerStart *mthing, int playernum, int flags)
{
if (state == PST_ENTER || (state == PST_LIVE && !savegamerestore))
{
// [ZZ] fire non-hub ENTER event
// level.time is a hack to make sure that we don't call it on dummy player initialization during hub return.
if (!level.time) E_PlayerEntered(p - players, false);
FBehavior::StaticStartTypedScripts (SCRIPT_Enter, p->mo, true);
}
else if (state == PST_REBORN)
@ -7462,6 +7478,9 @@ void AActor::Revive()
{
level.total_monsters++;
}
// [ZZ] resurrect hook
E_WorldThingRevived(this);
}
int AActor::GetGibHealth() const

View file

@ -63,6 +63,7 @@
#include "r_renderer.h"
#include "serializer.h"
#include "g_levellocals.h"
#include "events.h"
static TStaticArray<sector_t> loadsectors;
static TStaticArray<line_t> loadlines;
@ -968,6 +969,8 @@ void G_SerializeLevel(FSerializer &arc, bool hubload)
arc("sectorportals", level.sectorPortals);
if (arc.isReading()) P_CollectLinkedPortals();
// [ZZ] serialize events
E_SerializeEvents(arc);
DThinker::SerializeThinkers(arc, !hubload);
arc.Array("polyobjs", polyobjs, po_NumPolyobjs);
arc("subsectors", subsectors);

View file

@ -78,6 +78,7 @@
#ifndef NO_EDATA
#include "edata.h"
#endif
#include "events.h"
#include "fragglescript/t_fs.h"
@ -3432,6 +3433,8 @@ extern polyblock_t **PolyBlockMap;
void P_FreeLevelData ()
{
// [ZZ] delete per-map event handlers
E_Shutdown(true);
MapThingsConverted.Clear();
MapThingsUserDataIndex.Clear();
MapThingsUserData.Clear();
@ -3637,6 +3640,10 @@ void P_SetupLevel (const char *lumpname, int position)
I_Error("Unable to open map '%s'\n", lumpname);
}
// [ZZ] init per-map static handlers. we need to call this before everything is set up because otherwise scripts don't receive PlayerEntered event
// (which happens at god-knows-what stage in this function, but definitely not the last part, because otherwise it'd work to put E_InitStaticHandlers before the player spawning)
E_InitStaticHandlers(true);
// generate a checksum for the level, to be included and checked with savegames.
map->GetChecksum(level.md5);
// find map num
@ -4194,6 +4201,8 @@ void P_Init ()
static void P_Shutdown ()
{
// [ZZ] delete global event handlers
E_Shutdown(false);
R_DeinitSpriteData ();
P_DeinitKeyMessages ();
P_FreeLevelData ();

View file

@ -39,6 +39,7 @@
#include "d_event.h"
#include "g_level.h"
#include "gstrings.h"
#include "events.h"
#include "i_system.h"
#include "m_argv.h"

View file

@ -36,6 +36,7 @@
#include "r_utility.h"
#include "p_spec.h"
#include "g_levellocals.h"
#include "events.h"
extern gamestate_t wipegamestate;
@ -125,6 +126,8 @@ void P_Ticker (void)
/*Added by MC: Freeze mode.*/!(bglobal.freeze && players[i].Bot != NULL))
P_PlayerThink (&players[i]);
// [ZZ] call the WorldTick hook
E_WorldTick();
StatusBar->Tick (); // [RH] moved this here
level.Tick (); // [RH] let the level tick
DThinker::RunThinkers ();

View file

@ -47,6 +47,7 @@
#include "doomdef.h"
#include "doomstat.h"
#include "v_video.h"
#include "events.h"
#undef Class
@ -94,6 +95,10 @@ void CheckGUICapture()
? (c_down == ConsoleState || c_falling == ConsoleState || chatmodeon)
: (MENU_On == menuactive || MENU_OnNoPause == menuactive);
// [ZZ] check active event handlers that want the UI processing
if (!wantCapture && E_CheckUiProcessors())
wantCapture = true;
if (wantCapture != GUICapture)
{
GUICapture = wantCapture;
@ -181,6 +186,9 @@ void CheckNativeMouse()
&& (MENU_On == menuactive || MENU_OnNoPause == menuactive);
}
if (!wantNative && E_CheckRequireMouse())
wantNative = true;
I_SetNativeMouse(wantNative);
}

View file

@ -17,6 +17,7 @@
#include "dikeys.h"
#include "templates.h"
#include "s_sound.h"
#include "events.h"
static void I_CheckGUICapture ();
static void I_CheckNativeMouse ();
@ -154,6 +155,10 @@ static void I_CheckGUICapture ()
wantCapt = (menuactive == MENU_On || menuactive == MENU_OnNoPause);
}
// [ZZ] check active event handlers that want the UI processing
if (!wantCapt && E_CheckUiProcessors())
wantCapt = true;
if (wantCapt != GUICapture)
{
GUICapture = wantCapt;
@ -331,6 +336,12 @@ void MessagePump (const SDL_Event &sev)
event.subtype = sev.type == SDL_MOUSEBUTTONDOWN ? EV_GUI_LButtonDown : EV_GUI_LButtonUp;
event.subtype += (sev.button.button - 1) * 3;
}
SDL_Keymod kmod = SDL_GetModState();
event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) |
((kmod & KMOD_CTRL) ? GKM_CTRL : 0) |
((kmod & KMOD_ALT) ? GKM_ALT : 0);
D_PostEvent(&event);
}
break;
@ -340,6 +351,10 @@ void MessagePump (const SDL_Event &sev)
{
event.type = EV_GUI_Event;
event.subtype = sev.wheel.y > 0 ? EV_GUI_WheelUp : EV_GUI_WheelDown;
SDL_Keymod kmod = SDL_GetModState();
event.data3 = ((kmod & KMOD_SHIFT) ? GKM_SHIFT : 0) |
((kmod & KMOD_CTRL) ? GKM_CTRL : 0) |
((kmod & KMOD_ALT) ? GKM_ALT : 0);
D_PostEvent (&event);
}
else

View file

@ -59,6 +59,7 @@
#include "r_data/colormaps.h"
#include "p_maputl.h"
#include "r_thread.h"
#include "events.h"
CVAR (String, r_viewsize, "", CVAR_NOSET)
CVAR (Bool, r_shadercolormaps, true, CVAR_ARCHIVE)

View file

@ -59,6 +59,7 @@
#include "v_palette.h"
#include "r_data/colormaps.h"
#include "g_levellocals.h"
#include "events.h"
#ifdef _MSC_VER
#pragma warning(disable:4244)

View file

@ -66,6 +66,7 @@
#include "p_maputl.h"
#include "g_levellocals.h"
#include "r_thread.h"
#include "events.h"
EXTERN_CVAR(Bool, st_scale)
EXTERN_CVAR(Bool, r_shadercolormaps)

View file

@ -8368,9 +8368,9 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
if (x)
{
if (x->ValueType == TypeName ||
x->ValueType == TypeSound)
x->ValueType == TypeSound) // spriteID can be a string too.
{
x = new FxStringCast(ArgList[i]);
x = new FxStringCast(x);
x = x->Resolve(ctx);
}
}

View file

@ -61,7 +61,7 @@ const char *GetVersionString();
// Protocol version used in demos.
// Bump it if you change existing DEM_ commands or add new ones.
// Otherwise, it should be safe to leave it alone.
#define DEMOGAMEVERSION 0x21E
#define DEMOGAMEVERSION 0x21F
// Minimum demo version we can play.
// Bump it whenever you change or remove existing DEM_ commands.

View file

@ -101,6 +101,7 @@
#include "d_event.h"
#include "v_text.h"
#include "version.h"
#include "events.h"
// Prototypes and declarations.
#include "rawinput.h"
@ -187,6 +188,10 @@ static void I_CheckGUICapture ()
wantCapt = (menuactive == MENU_On || menuactive == MENU_OnNoPause);
}
// [ZZ] check active event handlers that want the UI processing
if (!wantCapt && E_CheckUiProcessors())
wantCapt = true;
if (wantCapt != GUICapture)
{
GUICapture = wantCapt;

View file

@ -18,6 +18,7 @@
#include "win32iface.h"
#include "rawinput.h"
#include "menu/menu.h"
#include "events.h"
// MACROS ------------------------------------------------------------------
@ -282,6 +283,9 @@ void I_CheckNativeMouse(bool preferNative)
}
}
if (!want_native && E_CheckRequireMouse())
want_native = true;
//Printf ("%d %d %d\n", wantNative, preferNative, NativeMouse);
if (want_native != NativeMouse)

View file

@ -5,6 +5,7 @@
#include "zscript/constants.txt"
#include "zscript/actor.txt"
#include "zscript/actor_checks.txt"
#include "zscript/events.txt"
#include "zscript/menu/menuitembase.txt"
#include "zscript/menu/menu.txt"

345
wadsrc/static/zscript/events.txt Executable file
View file

@ -0,0 +1,345 @@
class BaseEvent native { } // just a base class. it doesn't inherit from Object on the scripting side so you can't call Destroy() on it and break everything.
class RenderEvent : BaseEvent native
{
native readonly Vector3 ViewPos;
native readonly double ViewAngle;
native readonly double ViewPitch;
native readonly double ViewRoll;
native readonly double FracTic;
native readonly Actor Camera;
}
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
native readonly Actor Inflictor;
// for thingdamaged.
native readonly int Damage;
native readonly Actor DamageSource;
native readonly Name DamageType;
native readonly EDmgFlags DamageFlags;
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 UiEvent : BaseEvent native
{
// d_gui.h
enum EGUIEvent
{
Type_None,
Type_KeyDown,
Type_KeyRepeat,
Type_KeyUp,
Type_Char,
Type_FirstMouseEvent, // ?
Type_MouseMove,
Type_LButtonDown,
Type_LButtonUp,
Type_LButtonClick,
Type_MButtonDown,
Type_MButtonUp,
Type_MButtonClick,
Type_RButtonDown,
Type_RButtonUp,
Type_RButtonClick,
Type_WheelUp,
Type_WheelDown,
Type_WheelRight, // ???
Type_WheelLeft, // ???
Type_BackButtonDown, // ???
Type_BackButtonUp, // ???
Type_FwdButtonDown, // ???
Type_FwdButtonUp, // ???
Type_LastMouseEvent
}
// for KeyDown, KeyRepeat, KeyUp
enum ESpecialGUIKeys
{
Key_PgDn = 1,
Key_PgUp = 2,
Key_Home = 3,
Key_End = 4,
Key_Left = 5,
Key_Right = 6,
Key_Alert = 7, // ASCII bell
Key_Backspace = 8, // ASCII
Key_Tab = 9, // ASCII
Key_LineFeed = 10, // ASCII
Key_Down = 10,
Key_VTab = 11, // ASCII
Key_Up = 11,
Key_FormFeed = 12, // ASCII
Key_Return = 13, // ASCII
Key_F1 = 14,
Key_F2 = 15,
Key_F3 = 16,
Key_F4 = 17,
Key_F5 = 18,
Key_F6 = 19,
Key_F7 = 20,
Key_F8 = 21,
Key_F9 = 22,
Key_F10 = 23,
Key_F11 = 24,
Key_F12 = 25,
Key_Del = 26,
Key_Escape = 27, // ASCII
Key_Free1 = 28,
Key_Free2 = 29,
Key_Back = 30, // browser back key
Key_CEscape = 31 // color escape
}
//
native readonly EGUIEvent Type;
//
native readonly String KeyString;
native readonly int KeyChar;
//
native readonly int MouseX;
native readonly int MouseY;
//
native readonly bool IsShift;
native readonly bool IsCtrl;
native readonly bool IsAlt;
}
class InputEvent : BaseEvent native
{
enum EGenericEvent
{
Type_None,
Type_KeyDown,
Type_KeyUp,
Type_Mouse,
Type_GUI, // unused, kept for completeness
Type_DeviceChange
}
// ew.
enum EDoomInputKeys
{
Key_Pause = 0xc5, // DIK_PAUSE
Key_RightArrow = 0xcd, // DIK_RIGHT
Key_LeftArrow = 0xcb, // DIK_LEFT
Key_UpArrow = 0xc8, // DIK_UP
Key_DownArrow = 0xd0, // DIK_DOWN
Key_Escape = 0x01, // DIK_ESCAPE
Key_Enter = 0x1c, // DIK_RETURN
Key_Space = 0x39, // DIK_SPACE
Key_Tab = 0x0f, // DIK_TAB
Key_F1 = 0x3b, // DIK_F1
Key_F2 = 0x3c, // DIK_F2
Key_F3 = 0x3d, // DIK_F3
Key_F4 = 0x3e, // DIK_F4
Key_F5 = 0x3f, // DIK_F5
Key_F6 = 0x40, // DIK_F6
Key_F7 = 0x41, // DIK_F7
Key_F8 = 0x42, // DIK_F8
Key_F9 = 0x43, // DIK_F9
Key_F10 = 0x44, // DIK_F10
Key_F11 = 0x57, // DIK_F11
Key_F12 = 0x58, // DIK_F12
Key_Grave = 0x29, // DIK_GRAVE
Key_Backspace = 0x0e, // DIK_BACK
Key_Equals = 0x0d, // DIK_EQUALS
Key_Minus = 0x0c, // DIK_MINUS
Key_LShift = 0x2A, // DIK_LSHIFT
Key_LCtrl = 0x1d, // DIK_LCONTROL
Key_LAlt = 0x38, // DIK_LMENU
Key_RShift = Key_LSHIFT,
Key_RCtrl = Key_LCTRL,
Key_RAlt = Key_LALT,
Key_Ins = 0xd2, // DIK_INSERT
Key_Del = 0xd3, // DIK_DELETE
Key_End = 0xcf, // DIK_END
Key_Home = 0xc7, // DIK_HOME
Key_PgUp = 0xc9, // DIK_PRIOR
Key_PgDn = 0xd1, // DIK_NEXT
Key_Mouse1 = 0x100,
Key_Mouse2 = 0x101,
Key_Mouse3 = 0x102,
Key_Mouse4 = 0x103,
Key_Mouse5 = 0x104,
Key_Mouse6 = 0x105,
Key_Mouse7 = 0x106,
Key_Mouse8 = 0x107,
Key_FirstJoyButton = 0x108,
Key_Joy1 = (Key_FirstJoyButton+0),
Key_Joy2 = (Key_FirstJoyButton+1),
Key_Joy3 = (Key_FirstJoyButton+2),
Key_Joy4 = (Key_FirstJoyButton+3),
Key_Joy5 = (Key_FirstJoyButton+4),
Key_Joy6 = (Key_FirstJoyButton+5),
Key_Joy7 = (Key_FirstJoyButton+6),
Key_Joy8 = (Key_FirstJoyButton+7),
Key_LastJoyButton = 0x187,
Key_JoyPOV1_Up = 0x188,
Key_JoyPOV1_Right = 0x189,
Key_JoyPOV1_Down = 0x18a,
Key_JoyPOV1_Left = 0x18b,
Key_JoyPOV2_Up = 0x18c,
Key_JoyPOV3_Up = 0x190,
Key_JoyPOV4_Up = 0x194,
Key_MWheelUp = 0x198,
Key_MWheelDown = 0x199,
Key_MWheelRight = 0x19A,
Key_MWheelLeft = 0x19B,
Key_JoyAxis1Plus = 0x19C,
Key_JoyAxis1Minus = 0x19D,
Key_JoyAxis2Plus = 0x19E,
Key_JoyAxis2Minus = 0x19F,
Key_JoyAxis3Plus = 0x1A0,
Key_JoyAxis3Minus = 0x1A1,
Key_JoyAxis4Plus = 0x1A2,
Key_JoyAxis4Minus = 0x1A3,
Key_JoyAxis5Plus = 0x1A4,
Key_JoyAxis5Minus = 0x1A5,
Key_JoyAxis6Plus = 0x1A6,
Key_JoyAxis6Minus = 0x1A7,
Key_JoyAxis7Plus = 0x1A8,
Key_JoyAxis7Minus = 0x1A9,
Key_JoyAxis8Plus = 0x1AA,
Key_JoyAxis8Minus = 0x1AB,
Num_JoyAxisButtons = 8,
Key_Pad_LThumb_Right = 0x1AC,
Key_Pad_LThumb_Left = 0x1AD,
Key_Pad_LThumb_Down = 0x1AE,
Key_Pad_LThumb_Up = 0x1AF,
Key_Pad_RThumb_Right = 0x1B0,
Key_Pad_RThumb_Left = 0x1B1,
Key_Pad_RThumb_Down = 0x1B2,
Key_Pad_RThumb_Up = 0x1B3,
Key_Pad_DPad_Up = 0x1B4,
Key_Pad_DPad_Down = 0x1B5,
Key_Pad_DPad_Left = 0x1B6,
Key_Pad_DPad_Right = 0x1B7,
Key_Pad_Start = 0x1B8,
Key_Pad_Back = 0x1B9,
Key_Pad_LThumb = 0x1BA,
Key_Pad_RThumb = 0x1BB,
Key_Pad_LShoulder = 0x1BC,
Key_Pad_RShoulder = 0x1BD,
Key_Pad_LTrigger = 0x1BE,
Key_Pad_RTrigger = 0x1BF,
Key_Pad_A = 0x1C0,
Key_Pad_B = 0x1C1,
Key_Pad_X = 0x1C2,
Key_Pad_Y = 0x1C3,
Num_Keys = 0x1C4
}
//
native readonly EGenericEvent Type;
//
native readonly int KeyScan; // as in EDoomInputKeys enum
native readonly String KeyString;
native readonly int KeyChar; // ASCII char (if any)
//
native readonly int MouseX;
native readonly int MouseY;
}
class ConsoleEvent : BaseEvent native
{
// for net events, this will be the activator.
// for UI events, this is always -1, and you need to check if level is loaded and use players[consoleplayer].
native readonly int Player;
native readonly String Name;
native readonly int Args[3];
}
class StaticEventHandler : Object native
{
// static event handlers CAN register other static event handlers.
// unlike EventHandler.Create that will not create them.
protected static native StaticEventHandler Create(class<StaticEventHandler> type);
protected static native StaticEventHandler CreateOnce(class<StaticEventHandler> type);
protected static native StaticEventHandler Find(Class<StaticEventHandler> type); // just for convenience. who knows.
protected static native bool Register(StaticEventHandler handler);
protected static native bool Unregister(StaticEventHandler handler);
// these are called when the handler gets registered or unregistered
// you can set Order/IsUiProcessor here.
virtual native void OnRegister();
virtual native void OnUnregister();
// actual handlers are here
virtual native void WorldLoaded(WorldEvent e);
virtual native void WorldUnloaded(WorldEvent e);
virtual native void WorldThingSpawned(WorldEvent e);
virtual native void WorldThingDied(WorldEvent e);
virtual native void WorldThingRevived(WorldEvent e);
virtual native void WorldThingDamaged(WorldEvent e);
virtual native void WorldThingDestroyed(WorldEvent e);
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 RenderOverlay(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);
//
virtual native bool UiProcess(UiEvent e);
virtual native bool InputProcess(InputEvent e);
//
virtual native void ConsoleProcess(ConsoleEvent e);
// this value 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.
native readonly int Order;
native void SetOrder(int order);
// this value will be queried on user input to decide whether to send UiProcess to this handler.
native bool IsUiProcessor;
// this value determines whether mouse input is required.
native bool RequireMouse;
}
class EventHandler : StaticEventHandler native
{
static native StaticEventHandler Create(class<StaticEventHandler> type);
static native StaticEventHandler CreateOnce(class<StaticEventHandler> type);
static native StaticEventHandler Find(class<StaticEventHandler> type);
static native bool Register(StaticEventHandler handler);
static native bool Unregister(StaticEventHandler handler);
}