# Conflicts:
#	src/r_main.cpp
#	src/r_things.cpp
This commit is contained in:
nashmuhandes 2017-02-15 09:43:06 +08:00
commit 43550742d5
64 changed files with 2349 additions and 107 deletions

View file

@ -1033,6 +1033,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

@ -626,6 +626,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.
@ -1228,6 +1231,7 @@ public:
bool InStateSequence(FState * newstate, FState * basestate);
int GetTics(FState * newstate);
bool SetState (FState *newstate, bool nofunction=false);
virtual void SplashCheck();
virtual bool UpdateWaterLevel (bool splash=true);
bool isFast();
bool isSlow();

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

@ -111,6 +111,7 @@
#include "autosegs.h"
#include "fragglescript/t_fs.h"
#include "g_levellocals.h"
#include "events.h"
EXTERN_CVAR(Bool, hud_althud)
void DrawHUD();
@ -287,6 +288,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);
}
}
@ -307,8 +311,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)
{
@ -776,6 +779,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)))
@ -894,6 +900,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 ();
@ -2831,10 +2839,10 @@ void FStartupScreen::NetMessage(char const *,...) {}
void FStartupScreen::NetDone(void) {}
bool FStartupScreen::NetLoop(bool (*)(void *),void *) { return false; }
DEFINE_FIELD_X(InputEvent, event_t, type)
DEFINE_FIELD_X(InputEvent, event_t, subtype)
DEFINE_FIELD_X(InputEvent, event_t, data1)
DEFINE_FIELD_X(InputEvent, event_t, data2)
DEFINE_FIELD_X(InputEvent, event_t, data3)
DEFINE_FIELD_X(InputEvent, event_t, x)
DEFINE_FIELD_X(InputEvent, event_t, y)
DEFINE_FIELD_X(InputEventData, event_t, type)
DEFINE_FIELD_X(InputEventData, event_t, subtype)
DEFINE_FIELD_X(InputEventData, event_t, data1)
DEFINE_FIELD_X(InputEventData, event_t, data2)
DEFINE_FIELD_X(InputEventData, event_t, data3)
DEFINE_FIELD_X(InputEventData, event_t, x)
DEFINE_FIELD_X(InputEventData, event_t, y)

View file

@ -65,6 +65,7 @@
#include "a_keys.h"
#include "intermission/intermission.h"
#include "g_levellocals.h"
#include "events.h"
EXTERN_CVAR (Int, disableautosave)
EXTERN_CVAR (Int, autosavecount)
@ -2679,6 +2680,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

@ -92,6 +92,7 @@
#include "g_hub.h"
#include "g_levellocals.h"
#include "events.h"
static FRandom pr_dmspawn ("DMSpawn");
@ -1792,6 +1793,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

@ -1442,7 +1442,7 @@ class CommandDrawNumber : public CommandDrawString
int retv;
VMReturn ret(&retv);
GlobalVMStack.Call(func, params, 2, &ret, 1);
num = retv / TICRATE + 1;
num = retv < 0? 0 : retv / TICRATE + 1;
break;
}
case INVENTORY:

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

@ -97,6 +97,28 @@ void gl_CreateSections();
void AdjustSpriteOffsets()
{
int lump, lastlump = 0;
int sprid;
TMap<int, bool> donotprocess;
int numtex = Wads.GetNumLumps();
for (int i = 0; i < numtex; i++)
{
if (Wads.GetLumpFile(i) > 1) break; // we are past the IWAD
if (Wads.GetLumpNamespace(i) == ns_sprites && Wads.GetLumpFile(i) == FWadCollection::IWAD_FILENUM)
{
char str[9];
Wads.GetLumpName(str, i);
FTextureID texid = TexMan.CheckForTexture(str, FTexture::TEX_Sprite, 0);
if (texid.isValid() && Wads.GetLumpFile(TexMan[texid]->SourceLump) > FWadCollection::IWAD_FILENUM)
{
// This texture has been replaced by some PWAD.
memcpy(&sprid, str, 4);
donotprocess[sprid] = true;
}
}
}
while ((lump = Wads.FindLump("SPROFS", &lastlump, false)) != -1)
{
FScanner sc;
@ -108,6 +130,7 @@ void AdjustSpriteOffsets()
{
int x,y;
bool iwadonly = false;
bool forced = false;
FTextureID texno = TexMan.CheckForTexture(sc.String, FTexture::TEX_Sprite);
sc.MustGetStringName(",");
sc.MustGetNumber();
@ -119,6 +142,7 @@ void AdjustSpriteOffsets()
{
sc.MustGetString();
if (sc.Compare("iwad")) iwadonly = true;
if (sc.Compare("iwadforced")) forced = iwadonly = true;
}
if (texno.isValid())
{
@ -131,6 +155,11 @@ void AdjustSpriteOffsets()
int wadno = Wads.GetLumpFile(lumpnum);
if ((iwadonly && wadno==FWadCollection::IWAD_FILENUM) || (!iwadonly && wadno == ofslumpno))
{
if (wadno == FWadCollection::IWAD_FILENUM && !forced && iwadonly)
{
memcpy(&sprid, &tex->Name[0], 4);
if (donotprocess.CheckKey(sprid)) continue; // do not alter sprites that only get partially replaced.
}
tex->LeftOffset=x;
tex->TopOffset=y;
tex->KillNative();

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

@ -192,7 +192,7 @@ private:
bool PutWallCompat(int passflag);
void PutWall(bool translucent);
void PutPortal(int ptype);
void CheckTexturePosition();
void CheckTexturePosition(FTexCoordInfo *tci);
void RenderFogBoundaryCompat();
void RenderLightsCompat(int pass);

View file

@ -626,7 +626,7 @@ bool GLWall::SetWallCoordinates(seg_t * seg, FTexCoordInfo *tci, float textureto
//
//==========================================================================
void GLWall::CheckTexturePosition()
void GLWall::CheckTexturePosition(FTexCoordInfo *tci)
{
float sub;
@ -634,23 +634,47 @@ void GLWall::CheckTexturePosition()
// clamp texture coordinates to a reasonable range.
// Extremely large values can cause visual problems
if (tcs[UPLFT].v < tcs[UPRGT].v)
if (tci->mScale.Y > 0)
{
sub = float(xs_FloorToInt(tcs[UPLFT].v));
if (tcs[UPLFT].v < tcs[UPRGT].v)
{
sub = float(xs_FloorToInt(tcs[UPLFT].v));
}
else
{
sub = float(xs_FloorToInt(tcs[UPRGT].v));
}
tcs[UPLFT].v -= sub;
tcs[UPRGT].v -= sub;
tcs[LOLFT].v -= sub;
tcs[LORGT].v -= sub;
if ((tcs[UPLFT].v == 0.f && tcs[UPRGT].v == 0.f && tcs[LOLFT].v <= 1.f && tcs[LORGT].v <= 1.f) ||
(tcs[UPLFT].v >= 0.f && tcs[UPRGT].v >= 0.f && tcs[LOLFT].v == 1.f && tcs[LORGT].v == 1.f))
{
flags |= GLT_CLAMPY;
}
}
else
{
sub = float(xs_FloorToInt(tcs[UPRGT].v));
}
tcs[UPLFT].v -= sub;
tcs[UPRGT].v -= sub;
tcs[LOLFT].v -= sub;
tcs[LORGT].v -= sub;
if (tcs[LOLFT].v < tcs[LORGT].v)
{
sub = float(xs_FloorToInt(tcs[LOLFT].v));
}
else
{
sub = float(xs_FloorToInt(tcs[LORGT].v));
}
tcs[UPLFT].v -= sub;
tcs[UPRGT].v -= sub;
tcs[LOLFT].v -= sub;
tcs[LORGT].v -= sub;
if ((tcs[UPLFT].v == 0.f && tcs[UPRGT].v == 0.f && tcs[LOLFT].v <= 1.f && tcs[LORGT].v <= 1.f) ||
(tcs[UPLFT].v >= 0.f && tcs[UPRGT].v >= 0.f && tcs[LOLFT].v == 1.f && tcs[LORGT].v == 1.f))
{
flags |= GLT_CLAMPY;
if ((tcs[LOLFT].v == 0.f && tcs[LORGT].v == 0.f && tcs[UPLFT].v <= 1.f && tcs[UPRGT].v <= 1.f) ||
(tcs[LOLFT].v >= 0.f && tcs[LORGT].v >= 0.f && tcs[UPLFT].v == 1.f && tcs[UPRGT].v == 1.f))
{
flags |= GLT_CLAMPY;
}
}
// Check if this is marked as a skybox and if so, do the same for x.
@ -721,7 +745,7 @@ void GLWall::DoTexture(int _type,seg_t * seg, int peg,
else
{
CheckTexturePosition();
CheckTexturePosition(&tci);
// Add this wall to the render list
sector_t * sec = sub ? sub->sector : seg->frontsector;
@ -1139,7 +1163,7 @@ void GLWall::BuildFFBlock(seg_t * seg, F3DFloor * rover,
tcs[LOLFT].v = tci.FloatToTexV(to - ff_bottomleft);
tcs[LORGT].v = tci.FloatToTexV(to - ff_bottomright);
type = RENDERWALL_FFBLOCK;
CheckTexturePosition();
CheckTexturePosition(&tci);
}
ztop[0] = ff_topleft;

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

@ -50,6 +50,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
@ -348,6 +349,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

@ -381,7 +381,7 @@ void DMenu::Ticker ()
DEFINE_ACTION_FUNCTION(DMenu, Ticker)
{
PARAM_SELF_PROLOGUE(DMenu);
self->Drawer();
self->Ticker();
return 0;
}
@ -392,7 +392,7 @@ void DMenu::CallTicker()
VMValue params[] = { (DObject*)this };
GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr);
}
else Drawer();
else Ticker();
}
@ -448,6 +448,12 @@ DEFINE_ACTION_FUNCTION(DMenu, GetItem)
ACTION_RETURN_OBJECT(self->GetItem(name));
}
DEFINE_ACTION_FUNCTION(DOptionMenuDescriptor, GetItem)
{
PARAM_SELF_PROLOGUE(DOptionMenuDescriptor);
PARAM_NAME(name);
ACTION_RETURN_OBJECT(self->GetItem(name));
}
bool DMenu::DimAllowed()

View file

@ -1021,7 +1021,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_PlaySound)
if (!looping)
{
S_PlaySound(self, channel, soundid, (float)volume, (float)attenuation, local);
if (!(channel & CHAN_NOSTOP) || !S_IsActorPlayingSomething(self, channel & 7, soundid))
{
S_PlaySound(self, channel, soundid, (float)volume, (float)attenuation, local);
}
}
else
{

View file

@ -61,6 +61,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");
@ -385,6 +386,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))
{
@ -607,6 +611,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);
@ -1594,7 +1601,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)
@ -1608,7 +1620,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

@ -5288,6 +5288,14 @@ bool P_UseTraverse(AActor *usething, const DVector2 &start, const DVector2 &end,
if (P_ActivateThingSpecial(in->d.thing, usething))
return true;
}
IFVIRTUALPTR(usething, AActor, Used)
{
VMValue params[] = { usething, in->d.thing };
int ret;
VMReturn vret(&ret);
GlobalVMStack.Call(func, params, 2, &vret, 1);
if (ret) return true;
}
continue;
}

View file

@ -72,6 +72,7 @@
#include "virtual.h"
#include "g_levellocals.h"
#include "a_morph.h"
#include "events.h"
// MACROS ------------------------------------------------------------------
@ -4540,23 +4541,22 @@ void AActor::CheckSectorTransition(sector_t *oldsec)
//==========================================================================
//
// AActor::UpdateWaterLevel
// AActor::SplashCheck
//
// Returns true if actor should splash
//
//==========================================================================
bool AActor::UpdateWaterLevel (bool dosplash)
void AActor::SplashCheck()
{
BYTE lastwaterlevel = waterlevel;
double fh = -FLT_MAX;
bool reset=false;
bool reset = false;
waterlevel = 0;
if (Sector == NULL)
{
return false;
return;
}
if (Sector->MoreFlags & SECF_UNDERWATER) // intentionally not SECF_UNDERWATERMASK
@ -4568,7 +4568,7 @@ bool AActor::UpdateWaterLevel (bool dosplash)
const sector_t *hsec = Sector->GetHeightSec();
if (hsec != NULL)
{
fh = hsec->floorplane.ZatPoint (this);
fh = hsec->floorplane.ZatPoint(this);
//if (hsec->MoreFlags & SECF_UNDERWATERMASK) // also check Boom-style non-swimmable sectors
{
if (Z() < fh)
@ -4584,7 +4584,7 @@ bool AActor::UpdateWaterLevel (bool dosplash)
}
}
}
else if (!(hsec->MoreFlags & SECF_FAKEFLOORONLY) && (Top() > hsec->ceilingplane.ZatPoint (this)))
else if (!(hsec->MoreFlags & SECF_FAKEFLOORONLY) && (Top() > hsec->ceilingplane.ZatPoint(this)))
{
waterlevel = 3;
}
@ -4593,29 +4593,23 @@ bool AActor::UpdateWaterLevel (bool dosplash)
waterlevel = 0;
}
}
// even non-swimmable deep water must be checked here to do the splashes correctly
// But the water level must be reset when this function returns
if (!(hsec->MoreFlags&SECF_UNDERWATERMASK))
{
reset = true;
}
}
else
{
// Check 3D floors as well!
for(auto rover : Sector->e->XFloor.ffloors)
for (auto rover : Sector->e->XFloor.ffloors)
{
if (!(rover->flags & FF_EXISTS)) continue;
if (rover->flags & FF_SOLID) continue;
reset = !(rover->flags & FF_SWIMMABLE);
bool reset = !(rover->flags & FF_SWIMMABLE);
if (reset && rover->alpha == 0) continue;
double ff_bottom=rover->bottom.plane->ZatPoint(this);
double ff_top=rover->top.plane->ZatPoint(this);
double ff_bottom = rover->bottom.plane->ZatPoint(this);
double ff_top = rover->top.plane->ZatPoint(this);
if(ff_top <= Z() || ff_bottom > (Center())) continue;
fh=ff_top;
if (ff_top <= Z() || ff_bottom > (Center())) continue;
fh = ff_top;
if (Z() < fh)
{
waterlevel = 1;
@ -4634,17 +4628,106 @@ bool AActor::UpdateWaterLevel (bool dosplash)
}
}
}
// some additional checks to make deep sectors like Boom's splash without setting
// the water flags.
if (boomwaterlevel == 0 && waterlevel != 0 && dosplash)
if (boomwaterlevel == 0 && waterlevel != 0)
{
P_HitWater(this, Sector, PosAtZ(fh), true);
}
boomwaterlevel = waterlevel;
if (reset)
return;
}
//==========================================================================
//
// AActor::UpdateWaterLevel
//
// Returns true if actor should splash
//
//==========================================================================
bool AActor::UpdateWaterLevel(bool dosplash)
{
if (dosplash) SplashCheck();
double fh = -FLT_MAX;
bool reset = false;
waterlevel = 0;
if (Sector == NULL)
{
waterlevel = lastwaterlevel;
return false;
}
if (Sector->MoreFlags & SECF_UNDERWATER) // intentionally not SECF_UNDERWATERMASK
{
waterlevel = 3;
}
else
{
const sector_t *hsec = Sector->GetHeightSec();
if (hsec != NULL)
{
fh = hsec->floorplane.ZatPoint(this);
if (hsec->MoreFlags & SECF_UNDERWATERMASK) // also check Boom-style non-swimmable sectors
{
if (Z() < fh)
{
waterlevel = 1;
if (Center() < fh)
{
waterlevel = 2;
if ((player && Z() + player->viewheight <= fh) ||
(Top() <= fh))
{
waterlevel = 3;
}
}
}
else if (!(hsec->MoreFlags & SECF_FAKEFLOORONLY) && (Top() > hsec->ceilingplane.ZatPoint(this)))
{
waterlevel = 3;
}
else
{
waterlevel = 0;
}
}
}
else
{
// Check 3D floors as well!
for (auto rover : Sector->e->XFloor.ffloors)
{
if (!(rover->flags & FF_EXISTS)) continue;
if (rover->flags & FF_SOLID) continue;
if (!(rover->flags & FF_SWIMMABLE)) continue;
double ff_bottom = rover->bottom.plane->ZatPoint(this);
double ff_top = rover->top.plane->ZatPoint(this);
if (ff_top <= Z() || ff_bottom > (Center())) continue;
fh = ff_top;
if (Z() < fh)
{
waterlevel = 1;
if (Center() < fh)
{
waterlevel = 2;
if ((player && Z() + player->viewheight <= fh) ||
(Top() <= fh))
{
waterlevel = 3;
}
}
}
break;
}
}
}
return false; // we did the splash ourselves
}
@ -4974,6 +5057,12 @@ void AActor::PostBeginPlay ()
flags7 |= MF7_HANDLENODELAY;
}
void AActor::CallPostBeginPlay()
{
Super::CallPostBeginPlay();
E_WorldThingSpawned(this);
}
void AActor::MarkPrecacheSounds() const
{
SeeSound.MarkUsed();
@ -5105,6 +5194,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();
@ -5417,6 +5512,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)
@ -7463,6 +7561,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

@ -79,6 +79,7 @@
#ifndef NO_EDATA
#include "edata.h"
#endif
#include "events.h"
#include "fragglescript/t_fs.h"
@ -3433,6 +3434,8 @@ extern polyblock_t **PolyBlockMap;
void P_FreeLevelData ()
{
// [ZZ] delete per-map event handlers
E_Shutdown(true);
MapThingsConverted.Clear();
MapThingsUserDataIndex.Clear();
MapThingsUserData.Clear();
@ -3638,6 +3641,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
@ -4195,6 +4202,8 @@ void P_Init ()
static void P_Shutdown ()
{
// [ZZ] delete global event handlers
E_Shutdown(false);
R_DeinitSpriteData ();
P_DeinitKeyMessages ();
P_FreeLevelData ();

View file

@ -119,8 +119,8 @@ void P_LoadTranslator(const char *lumpname);
void P_TranslateLineDef (line_t *ld, maplinedef_t *mld, int lineindexforid = -1);
int P_TranslateSectorSpecial (int);
int GetUDMFInt(int type, int index, const char *key);
double GetUDMFFloat(int type, int index, const char *key);
int GetUDMFInt(int type, int index, FName key);
double GetUDMFFloat(int type, int index, FName key);
bool P_LoadGLNodes(MapData * map);
bool P_CheckNodes(MapData * map, bool rebuilt, int buildtime);

View file

@ -40,6 +40,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

@ -37,6 +37,7 @@
#include "r_utility.h"
#include "p_spec.h"
#include "g_levellocals.h"
#include "events.h"
extern gamestate_t wipegamestate;
@ -126,6 +127,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

@ -342,7 +342,7 @@ FUDMFKey *FUDMFKeys::Find(FName key)
//
//===========================================================================
int GetUDMFInt(int type, int index, const char *key)
int GetUDMFInt(int type, int index, FName key)
{
assert(type >=0 && type <=3);
@ -359,7 +359,16 @@ int GetUDMFInt(int type, int index, const char *key)
return 0;
}
double GetUDMFFloat(int type, int index, const char *key)
DEFINE_ACTION_FUNCTION(FLevelLocals, GetUDMFInt)
{
PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals);
PARAM_INT(type);
PARAM_INT(index);
PARAM_NAME(key);
ACTION_RETURN_INT(GetUDMFInt(type, index, key));
}
double GetUDMFFloat(int type, int index, FName key)
{
assert(type >=0 && type <=3);
@ -376,6 +385,41 @@ double GetUDMFFloat(int type, int index, const char *key)
return 0;
}
DEFINE_ACTION_FUNCTION(FLevelLocals, GetUDMFFloat)
{
PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals);
PARAM_INT(type);
PARAM_INT(index);
PARAM_NAME(key);
ACTION_RETURN_FLOAT(GetUDMFFloat(type, index, key));
}
FString GetUDMFString(int type, int index, FName key)
{
assert(type >= 0 && type <= 3);
FUDMFKeys *pKeys = UDMFKeys[type].CheckKey(index);
if (pKeys != NULL)
{
FUDMFKey *pKey = pKeys->Find(key);
if (pKey != NULL)
{
return pKey->StringVal;
}
}
return "";
}
DEFINE_ACTION_FUNCTION(FLevelLocals, GetUDMFString)
{
PARAM_SELF_STRUCT_PROLOGUE(FLevelLocals);
PARAM_INT(type);
PARAM_INT(index);
PARAM_NAME(key);
ACTION_RETURN_STRING(GetUDMFString(type, index, key));
}
//===========================================================================
//

View file

@ -225,7 +225,7 @@ static line_t *FindDestination(line_t *src, int tag)
}
}
}
return NULL;
return nullptr;
}
@ -275,7 +275,7 @@ static void SetRotation(FLinePortal *port)
void P_SpawnLinePortal(line_t* line)
{
// portal destination is special argument #0
line_t* dst = NULL;
line_t* dst = nullptr;
if (line->args[2] >= PORTT_VISUAL && line->args[2] <= PORTT_LINKED)
{
@ -304,7 +304,7 @@ void P_SpawnLinePortal(line_t* line)
port->mType = PORTT_TELEPORT;
}
}
if (port->mDestination != NULL)
if (port->mDestination != nullptr)
{
port->mDefFlags = port->mType == PORTT_VISUAL ? PORTF_VISIBLE : port->mType == PORTT_TELEPORT ? PORTF_TYPETELEPORT : PORTF_TYPEINTERACTIVE;
}
@ -357,7 +357,7 @@ void P_SpawnLinePortal(line_t* line)
void P_UpdatePortal(FLinePortal *port)
{
if (port->mDestination == NULL)
if (port->mDestination == nullptr)
{
// Portal has no destination: switch it off
port->mFlags = 0;
@ -442,16 +442,16 @@ static bool ChangePortalLine(line_t *line, int destid)
if (line->portalindex >= linePortals.Size()) return false;
FLinePortal *port = &linePortals[line->portalindex];
if (port->mType == PORTT_LINKED) return false; // linked portals cannot be changed.
if (destid == 0) port->mDestination = NULL;
if (destid == 0) port->mDestination = nullptr;
port->mDestination = FindDestination(line, destid);
if (port->mDestination == NULL)
if (port->mDestination == nullptr)
{
port->mFlags = 0;
}
else if (port->mType == PORTT_INTERACTIVE)
{
FLinePortal *portd = &linePortals[port->mDestination->portalindex];
if (portd != NULL && portd->mType == PORTT_INTERACTIVE && portd->mDestination == line)
FLinePortal *portd = port->mDestination->portalindex < linePortals.Size()? &linePortals[port->mDestination->portalindex] : nullptr;
if (portd != nullptr && portd->mType == PORTT_INTERACTIVE && portd->mDestination == line)
{
// this is a 2-way interactive portal
port->mFlags = port->mDefFlags | PORTF_INTERACTIVE;
@ -662,7 +662,7 @@ void P_TranslatePortalZ(line_t* src, double& z)
unsigned P_GetSkyboxPortal(AActor *actor)
{
if (actor == NULL) return 1; // this means a regular sky.
if (actor == nullptr) return 1; // this means a regular sky.
for (unsigned i = 0;i<level.sectorPortals.Size();i++)
{
if (level.sectorPortals[i].mSkybox == actor) return i;
@ -820,7 +820,7 @@ static bool CollectSectors(int groupid, sector_t *origin)
for (auto line : sec->Lines)
{
sector_t *other = line->frontsector == sec ? line->backsector : line->frontsector;
if (other != NULL && other != sec && other->PortalGroup != groupid)
if (other != nullptr && other != sec && other->PortalGroup != groupid)
{
other->PortalGroup = groupid;
list.Push(other);
@ -1098,10 +1098,10 @@ void P_CreateLinkedPortals()
}
// reject would just get in the way when checking sight through portals.
if (Displacements.size > 1 && rejectmatrix != NULL)
if (Displacements.size > 1 && rejectmatrix != nullptr)
{
delete[] rejectmatrix;
rejectmatrix = NULL;
rejectmatrix = nullptr;
}
// finally we must flag all planes which are obstructed by the sector's own ceiling or floor.
for (auto &sec : level.sectors)

View file

@ -47,6 +47,7 @@
#include "doomdef.h"
#include "doomstat.h"
#include "v_video.h"
#include "events.h"
#undef Class
@ -90,10 +91,16 @@ size_t s_skipMouseMoves;
void CheckGUICapture()
{
const bool wantCapture = (MENU_Off == menuactive)
bool wantCapture = (MENU_Off == menuactive)
? (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 +188,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 "v_palette.h"
#include "r_data/colormaps.h"
#include "g_levellocals.h"
#include "events.h"
#ifdef _MSC_VER
#pragma warning(disable:4244)

View file

@ -2046,11 +2046,11 @@ void PrepWall(float *vstep, fixed_t *upos, double walxrepeat, int x1, int x2)
float invZ = WallT.InvZorg + WallT.InvZstep * (float)(x1 + 0.5 - CenterX);
float uGradient = WallT.UoverZstep;
float zGradient = WallT.InvZstep;
float xrepeat = (float)walxrepeat;
float xrepeat = (float)fabs(walxrepeat);
float depthScale = (float)(WallT.InvZstep * WallTMapScale2);
float depthOrg = (float)(-WallT.UoverZstep * WallTMapScale2);
if (xrepeat < 0.0f)
if (walxrepeat < 0.0)
{
for (int x = x1; x < x2; x++)
{
@ -2084,9 +2084,9 @@ void PrepLWall(fixed_t *upos, double walxrepeat, int x1, int x2)
float invZ = WallT.InvZorg + WallT.InvZstep * (float)(x1 + 0.5 - CenterX);
float uGradient = WallT.UoverZstep;
float zGradient = WallT.InvZstep;
float xrepeat = (float)walxrepeat;
float xrepeat = (float)fabs(walxrepeat);
if (xrepeat < 0.0f)
if (walxrepeat < 0.0f)
{
for (int x = x1; x < x2; x++)
{

View file

@ -1261,6 +1261,7 @@ DEFINE_ACTION_FUNCTION(DObject, S_Sound)
PARAM_INT(channel);
PARAM_FLOAT_DEF(volume);
PARAM_FLOAT_DEF(attn);
S_Sound(channel, id, volume, attn);
return 0;
}

View file

@ -285,6 +285,7 @@ void S_PlaySound(AActor *a, int chan, FSoundID sid, float vol, float atten, bool
#define CHAN_JUSTSTARTED 512 // internal: Sound has not been updated yet.
#define CHAN_ABSTIME 1024// internal: Start time is absolute and does not depend on current time.
#define CHAN_VIRTUAL 2048// internal: Channel is currently virtual
#define CHAN_NOSTOP 4096// only for A_PlaySound. Does not start if channel is playing something.
// sound attenuation values
#define ATTN_NONE 0.f // full volume the entire level

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

@ -840,6 +840,21 @@ static void DispatchScriptProperty(FScanner &sc, PProperty *prop, AActor *defaul
bool val = sc.CheckNumber() ? !!sc.Number : true;
static_cast<PBool*>(f->Type)->SetValue(addr, !!val);
}
else if (f->Type == TypeName)
{
sc.MustGetString();
*(FName*)addr = sc.String;
}
else if (f->Type == TypeSound)
{
sc.MustGetString();
*(FSoundID*)addr = sc.String;
}
else if (f->Type == TypeColor)
{
if (sc.CheckNumber()) *(int*)addr = sc.Number;
else *(PalEntry*)addr = V_GetColor(nullptr, sc);
}
else if (f->Type->IsKindOf(RUNTIME_CLASS(PInt)))
{
sc.MustGetNumber();

View file

@ -1720,7 +1720,19 @@ void ZCCCompiler::DispatchScriptProperty(PProperty *prop, ZCC_PropertyStmt *prop
{
static_cast<PBool*>(f->Type)->SetValue(addr, !!GetIntConst(ex, ctx));
}
if (f->Type->IsKindOf(RUNTIME_CLASS(PInt)))
else if (f->Type == TypeName)
{
*(FName*)addr = GetStringConst(ex, ctx);
}
else if (f->Type == TypeSound)
{
*(FSoundID*)addr = GetStringConst(ex, ctx);
}
else if (f->Type == TypeColor && ex->ValueType == TypeString) // colors can also be specified as ints.
{
*(PalEntry*)addr = V_GetColor(nullptr, GetStringConst(ex, ctx).GetChars(), &ex->ScriptPosition);
}
else if (f->Type->IsKindOf(RUNTIME_CLASS(PInt)))
{
static_cast<PInt*>(f->Type)->SetValue(addr, GetIntConst(ex, 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"

View file

@ -329,7 +329,12 @@ class Actor : Thinker native
{
return -1;
}
// Called when the player presses 'use' and an actor is found
virtual bool Used(Actor user)
{
return false;
}
native static class<Actor> GetReplacement(class<Actor> cls);
native static class<Actor> GetReplacee(class<Actor> cls);

View file

@ -1,4 +1,4 @@
struct InputEvent native
struct InputEventData native
{
native uint8 type;
native uint8 subtype;
@ -418,6 +418,14 @@ class SpotState : Object native
struct LevelLocals native
{
enum EUDMF
{
UDMF_Line,
UDMF_Side,
UDMF_Sector,
//UDMF_Thing // not implemented
};
native readonly int time;
native readonly int maptime;
native readonly int totaltime;
@ -457,6 +465,11 @@ struct LevelLocals native
native bool frozen;
native bool infinite_flight;
// level_info_t *info cannot be done yet.
native String GetUDMFString(int type, int index, Name key);
native int GetUDMFInt(int type, int index, Name key);
native double GetUDMFFloat(int type, int index, Name key);
}
struct StringTable native

View file

@ -413,7 +413,8 @@ enum ESoundFlags
CHAN_MAYBE_LOCAL = 16,
CHAN_UI = 32,
CHAN_NOPAUSE = 64,
CHAN_PICKUP = (CHAN_ITEM|CHAN_MAYBE_LOCAL)
CHAN_PICKUP = (CHAN_ITEM|CHAN_MAYBE_LOCAL),
CHAN_NOSTOP = 4096
};

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);
}

View file

@ -124,7 +124,7 @@ class Lightning : Actor
if ((!thing.player && !thing.bBoss) || !(level.time&1))
{
thing.DamageMobj(self, target, 3, 'Electric');
A_PlaySound(AttackSound, CHAN_WEAPON, 1, true);
A_PlaySound(AttackSound, CHAN_WEAPON|CHAN_NOSTOP, 1, false);
if (thing.bIsMonster && random[LightningHit]() < 64)
{
thing.Howl ();

View file

@ -84,6 +84,20 @@ struct Side native
native Vertex V2();
native int Index();
int GetUDMFInt(Name nm)
{
return Level.GetUDMFInt(LevelLocals.UDMF_Side, Index(), nm);
}
double GetUDMFFloat(Name nm)
{
return Level.GetUDMFFloat(LevelLocals.UDMF_Side, Index(), nm);
}
String GetUDMFString(Name nm)
{
return Level.GetUDMFString(LevelLocals.UDMF_Side, Index(), nm);
}
};
struct Line native
@ -142,6 +156,19 @@ struct Line native
native Line getPortalDestination();
native int getPortalAlignment();
native int Index();
int GetUDMFInt(Name nm)
{
return Level.GetUDMFInt(LevelLocals.UDMF_Line, Index(), nm);
}
double GetUDMFFloat(Name nm)
{
return Level.GetUDMFFloat(LevelLocals.UDMF_Line, Index(), nm);
}
String GetUDMFString(Name nm)
{
return Level.GetUDMFString(LevelLocals.UDMF_Line, Index(), nm);
}
}
struct SecPlane native
@ -398,4 +425,18 @@ struct Sector native
{
Flags &= ~SECF_SECRET;
}
int GetUDMFInt(Name nm)
{
return Level.GetUDMFInt(LevelLocals.UDMF_Sector, Index(), nm);
}
double GetUDMFFloat(Name nm)
{
return Level.GetUDMFFloat(LevelLocals.UDMF_Sector, Index(), nm);
}
String GetUDMFString(Name nm)
{
return Level.GetUDMFString(LevelLocals.UDMF_Sector, Index(), nm);
}
}

View file

@ -86,7 +86,7 @@ class ListMenu : Menu native
return NULL;
}
//bool Responder (InputEvent ev);
//bool Responder (InputEventData ev);
//bool MenuEvent (int mkey, bool fromcontroller);
//bool MouseEvent(int type, int x, int y);
//void Ticker ();

View file

@ -105,7 +105,7 @@ class Menu : Object native
virtual void ReleaseFocus() {}
virtual void ResetColor() {}
native virtual bool Responder(InputEvent ev);
native virtual bool Responder(InputEventData ev);
native virtual bool MenuEvent (int mkey, bool fromcontroller);
native virtual bool MouseEvent(int type, int mx, int my);
native virtual void Ticker();

View file

@ -57,7 +57,7 @@ class OptionMenuDescriptor : MenuDescriptor native
native bool mDontDim;
native void CalcIndent();
//native OptionMenuItem GetItem(Name iname);
native OptionMenuItem GetItem(Name iname);
void Reset()
{
// Reset the default settings (ignore all other values in the struct)
@ -120,17 +120,17 @@ class OptionMenu : Menu
//
//=============================================================================
override bool Responder (InputEvent ev)
override bool Responder (InputEventData ev)
{
if (ev.type == InputEvent.GUI_Event)
if (ev.type == InputEventData.GUI_Event)
{
if (ev.subtype == InputEvent.GUI_WheelUp)
if (ev.subtype == InputEventData.GUI_WheelUp)
{
int scrollamt = MIN(2, mDesc.mScrollPos);
mDesc.mScrollPos -= scrollamt;
return true;
}
else if (ev.subtype == InputEvent.GUI_WheelDown)
else if (ev.subtype == InputEventData.GUI_WheelDown)
{
if (CanScrollDown)
{

View file

@ -132,11 +132,11 @@ class OptionMenuItemCommand : OptionMenuItemSubmenu
override bool Activate()
{
// This needs to perform a few checks to prevent abuse by malicious modders.
let m = Menu.GetCurrentMenu();
let m = OptionMenu(Menu.GetCurrentMenu());
// don't execute if no menu is active
if (m == null) return false;
// don't execute if this item cannot be found in the current menu.
if (m.GetItem(mAction) != self) return false;
if (m.mDesc.GetItem(mAction) != self) return false;
Menu.MenuSound("menu/choose");
DoCommand(mAction);
return true;
@ -396,16 +396,16 @@ class EnterKey : Menu
}
}
override bool Responder(InputEvent ev)
override bool Responder(InputEventData ev)
{
// This checks raw keys, not GUI keys.
if (ev.type == InputEvent.KeyDown)
if (ev.type == InputEventData.KeyDown)
{
mOwner.SendKey(ev.data1);
menuactive = Menu.On;
SetMenuMessage(0);
Close();
mParentMenu.MenuEvent((ev.data1 == InputEvent.KEY_ESCAPE)? Menu.MKEY_Abort : Menu.MKEY_Input, 0);
mParentMenu.MenuEvent((ev.data1 == InputEventData.KEY_ESCAPE)? Menu.MKEY_Abort : Menu.MKEY_Input, 0);
return true;
}
return false;
@ -1197,6 +1197,7 @@ class OptionMenuItemNumberField : OptionMenuFieldBase
mCVar.SetFloat(value);
Menu.MenuSound("menu/change");
}
else return Super.MenuEvent(mkey, fromcontroller);
return true;
}

View file

@ -57,9 +57,9 @@ class VideoModeMenu : OptionMenu
return Super.MenuEvent(mkey, fromcontroller);
}
override bool Responder(InputEvent ev)
override bool Responder(InputEventData ev)
{
if (ev.type == InputEvent.GUI_Event && ev.subtype == InputEvent.GUI_KeyDown && (ev.data1 == 0x54 || ev.data1 == 0x74))
if (ev.type == InputEventData.GUI_Event && ev.subtype == InputEventData.GUI_KeyDown && (ev.data1 == 0x54 || ev.data1 == 0x74))
{
if (SetSelectedSize())
{

View file

@ -130,7 +130,7 @@ class PlayerPawn : Actor native
return powerup.EffectTics, maxtics;
}
}
return 0, 0;
return -1, -1;
}
native int GetMaxHealth();