Skip to content

Commit 52913f5

Browse files
committed
Allow external handling of internal ACS functions from other ports
For ACS functions that should not be baked into the engine, allow hooking into them externally so that ZScript mods can still make use of them.
1 parent 52a5452 commit 52913f5

File tree

5 files changed

+194
-2
lines changed

5 files changed

+194
-2
lines changed

src/d_main.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ void I_ShutdownInput();
158158
void SetConsoleNotifyBuffer();
159159
void I_UpdateDiscordPresence(bool SendPresence, const char* curstatus, const char* appid, const char* steamappid);
160160
bool M_SetSpecialMenu(FName& menu, int param); // game specific checks
161+
void SetHandledACSFunctions();
161162

162163
const FIWADInfo *D_FindIWAD(TArray<FString> &wadfiles, const char *iwad, const char *basewad);
163164
void InitWidgetResources(const char* basewad);
@@ -3086,6 +3087,7 @@ static int FileSystemPrintf(FSMessageLevel level, const char* fmt, ...)
30863087
static int D_InitGame(const FIWADInfo* iwad_info, std::vector<std::string>& allwads, std::vector<std::string>& pwads)
30873088
{
30883089
NetworkEntityManager::InitializeNetworkEntities();
3090+
SetHandledACSFunctions();
30893091

30903092
if (!restart)
30913093
{

src/events.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -975,6 +975,18 @@ void EventManager::NetCommand(FNetworkCommand& cmd)
975975
handler->NetCommandProcess(cmd);
976976
}
977977

978+
int EventManager::ProcessACSFunction(int func, const TArray<int>* args)
979+
{
980+
int res = 0;
981+
if (ShouldCallStatic(false))
982+
res = staticEventManager.ProcessACSFunction(func, args);
983+
984+
for (DStaticEventHandler* handler = FirstEventHandler; handler; handler = handler->next)
985+
handler->ACSFunctionProcess(func, args, res);
986+
987+
return res;
988+
}
989+
978990
void EventManager::Console(int player, FString name, int arg1, int arg2, int arg3, bool manual, bool ui)
979991
{
980992
if (ShouldCallStatic(false)) staticEventManager.Console(player, name, arg1, arg2, arg3, manual, ui);
@@ -2274,6 +2286,23 @@ void DStaticEventHandler::NetCommandProcess(FNetworkCommand& cmd)
22742286
}
22752287
}
22762288

2289+
void DStaticEventHandler::ACSFunctionProcess(int code, const TArray<int>* args, int& res)
2290+
{
2291+
IFVIRTUAL(DStaticEventHandler, ACSFunctionProcess)
2292+
{
2293+
if (isEmpty(func))
2294+
return;
2295+
2296+
TArray<int> funcArgs = {};
2297+
if (args != nullptr)
2298+
funcArgs = *args;
2299+
2300+
VMValue params[] = { this, code, &funcArgs };
2301+
VMReturn returns[] = { &res };
2302+
VMCall(func, params, 3, returns, 1);
2303+
}
2304+
}
2305+
22772306
void DStaticEventHandler::ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3, bool manual, bool ui)
22782307
{
22792308
if (player < 0)

src/events.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ class DStaticEventHandler : public DObject // make it a part of normal GC proces
345345
//
346346
void ConsoleProcess(int player, FString name, int arg1, int arg2, int arg3, bool manual, bool ui);
347347
void NetCommandProcess(FNetworkCommand& cmd);
348+
void ACSFunctionProcess(int func, const TArray<int>* args, int& res);
348349

349350
//
350351
void CheckReplacement(PClassActor* replacee, PClassActor** replacement, bool* final);
@@ -539,6 +540,8 @@ struct EventManager
539540
void Console(int player, FString name, int arg1, int arg2, int arg3, bool manual, bool ui);
540541
// This reads from ZScript network commands.
541542
void NetCommand(FNetworkCommand& cmd);
543+
// Custom handling for known but unsupported ACS events.
544+
int ProcessACSFunction(int func, const TArray<int>* args);
542545

543546
// called when looking up the replacement for an actor class
544547
bool CheckReplacement(PClassActor* replacee, PClassActor** replacement);

src/playsim/p_acs.cpp

Lines changed: 94 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
#include "s_music.h"
7979
#include "v_video.h"
8080
#include "texturemanager.h"
81+
#include "events.h"
8182

8283
// P-codes for ACS scripts
8384
enum
@@ -4823,6 +4824,77 @@ enum EACSFunctions
48234824
ACSF_SetTeamScore, // (int team, int value
48244825
};
48254826

4827+
// Op code -> minimum arg count
4828+
static TMap<int, int> HandledACSFunctions = {};
4829+
4830+
void SetHandledACSFunctions()
4831+
{
4832+
// Zandronum
4833+
HandledACSFunctions[100] = 0; // ResetMap
4834+
HandledACSFunctions[101] = 1; // PlayerIsSpectator
4835+
// ConsolePlayerNumber will be intentionally left out until proper client-side
4836+
// ACS scripts are implemented. Right now it'd just leave the game prone to desyncs.
4837+
HandledACSFunctions[103] = 2; // GetTeamProperty
4838+
HandledACSFunctions[104] = 1; // GetPlayersLivesLeft
4839+
HandledACSFunctions[105] = 2; // SetPlayerLivesLeft
4840+
HandledACSFunctions[106] = 2; // KickFromGame
4841+
HandledACSFunctions[107] = 0; // GetGamemodeState
4842+
HandledACSFunctions[108] = 3; // SetDBEntry
4843+
HandledACSFunctions[109] = 2; // GetDBEntry
4844+
HandledACSFunctions[110] = 3; // SetDBEntryString
4845+
HandledACSFunctions[111] = 2; // GetDBEntryString
4846+
HandledACSFunctions[112] = 3; // IncrementDBEntry
4847+
HandledACSFunctions[113] = 1; // PlayerIsLoggedIn
4848+
HandledACSFunctions[114] = 1; // GetPlayerAccountName
4849+
HandledACSFunctions[115] = 4; // SortDBEntries
4850+
HandledACSFunctions[116] = 1; // CountDBResults
4851+
HandledACSFunctions[117] = 1; // FreeDBResults
4852+
HandledACSFunctions[118] = 2; // GetDBResultKeyString
4853+
HandledACSFunctions[119] = 2; // GetDBResultValueString
4854+
HandledACSFunctions[120] = 2; // GetDBResultValue
4855+
HandledACSFunctions[121] = 3; // GetDBEntryRank
4856+
HandledACSFunctions[122] = 4; // RequestScriptPuke
4857+
HandledACSFunctions[123] = 0; // BeginDBTransaction
4858+
HandledACSFunctions[124] = 0; // EndDBTransaction
4859+
HandledACSFunctions[125] = 1; // GetDBEntries
4860+
HandledACSFunctions[126] = 1; // NamedRequestScriptPuke
4861+
// System time functions are intentionally left out since they're prone to causing desyncs. Can be added
4862+
// in if client/server ever becomes a thing.
4863+
HandledACSFunctions[130] = 2; // SetDeadSpectator
4864+
HandledACSFunctions[131] = 1; // SetActivatorToPlayer
4865+
HandledACSFunctions[132] = 1; // SetCurrentGamemode
4866+
HandledACSFunctions[133] = 0; // GetCurrentGamemode
4867+
HandledACSFunctions[134] = 2; // SetGamemodeLimit
4868+
// Player class handling isn't implemented yet.
4869+
HandledACSFunctions[136] = 2; // SetPlayerChasecam
4870+
HandledACSFunctions[137] = 1; // GetPlayerChasecam
4871+
HandledACSFunctions[138] = 3; // SetPlayerScore
4872+
HandledACSFunctions[139] = 2; // GetPlayerScore
4873+
HandledACSFunctions[140] = 0; // InDemoMode
4874+
// Client-side scripts aren't implemented yet for ClientScript functions.
4875+
HandledACSFunctions[146] = 2; // SendNetworkString
4876+
HandledACSFunctions[147] = 2; // NamedSendNetworkString
4877+
HandledACSFunctions[148] = 2; // GetChatMessage
4878+
HandledACSFunctions[149] = 0; // GetMapRotationSize
4879+
HandledACSFunctions[150] = 2; // GetMapRotationInfo
4880+
HandledACSFunctions[151] = 0; // GetCurrentMapPosition
4881+
HandledACSFunctions[152] = 0; // GetEventResult
4882+
HandledACSFunctions[153] = 2; // GetActorSectorLocation
4883+
HandledACSFunctions[154] = 3; // ChangeTeamScore
4884+
HandledACSFunctions[155] = 2; // SetGameplaySettings
4885+
HandledACSFunctions[156] = 3; // SetCustomPlayerValue
4886+
HandledACSFunctions[157] = 2; // GetCustomPlayerValue
4887+
HandledACSFunctions[158] = 2; // ResetCustomDataToDefault
4888+
HandledACSFunctions[159] = 1; // LumpOpen
4889+
HandledACSFunctions[160] = 2; // LumpRead
4890+
HandledACSFunctions[161] = 2; // LumpReadString
4891+
HandledACSFunctions[166] = 2; // LumpGetInfo
4892+
HandledACSFunctions[167] = 1; // LumpClose
4893+
4894+
// Eternity
4895+
HandledACSFunctions[302] = 1; // SetAirFriction
4896+
}
4897+
48264898
int DLevelScript::SideFromID(int id, int side)
48274899
{
48284900
if (side != 0 && side != 1) return -1;
@@ -7249,8 +7321,28 @@ int DLevelScript::RunScript()
72497321
int argCount = NEXTBYTE;
72507322
int funcIndex = NEXTSHORT;
72517323

7252-
int retval, minCount = 0;
7253-
retval = CallFunction(argCount, funcIndex, &STACK(argCount), minCount);
7324+
int retval = 0, minCount = 0;
7325+
auto undefined = HandledACSFunctions.CheckKey(funcIndex);
7326+
if (undefined != nullptr)
7327+
{
7328+
if (argCount >= *undefined || (Level->i_compatflags2 & COMPATF2_NOACSARGCHECK))
7329+
{
7330+
TArray<int> args = {};
7331+
auto argStart = &STACK(argCount);
7332+
for (size_t p = 0u; p < argCount; ++p)
7333+
args.Push(argStart[p]);
7334+
7335+
retval = primaryLevel->localEventManager->ProcessACSFunction(funcIndex, &args);
7336+
}
7337+
else
7338+
{
7339+
minCount = *undefined;
7340+
}
7341+
}
7342+
else
7343+
{
7344+
retval = CallFunction(argCount, funcIndex, &STACK(argCount), minCount);
7345+
}
72547346
if (minCount != 0)
72557347
{
72567348
Printf("Called ACS function index %d with too few args: %d (need %d)\n", funcIndex, argCount, minCount);

wadsrc/static/zscript/events.zs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,71 @@ struct ReplacedEvent native version("3.7")
144144
native bool IsFinal;
145145
}
146146

147+
enum EACSFunction
148+
{
149+
ACSF_ResetMap = 100,
150+
ACSF_PlayerIsSpectator,
151+
152+
ACSF_GetTeamProperty = 103,
153+
ACSF_GetPlayerLivesLeft,
154+
ACSF_SetPlayerLivesLeft,
155+
ACSF_KickFromGame,
156+
ACSF_GetGamemodeState,
157+
ACSF_SetDBEntry,
158+
ACSF_GetDBEntry,
159+
ACSF_SetDBEntryString,
160+
ACSF_GetDBEntryString,
161+
ACSF_IncrementDBEntry,
162+
ACSF_PlayerIsLoggedIn,
163+
ACSF_GetPlayerAccountName,
164+
ACSF_SortDBEntries,
165+
ACSF_CountDBResults,
166+
ACSF_FreeDBResults,
167+
ACSF_GetDBResultKeyString,
168+
ACSF_GetDBResultValueString,
169+
ACSF_GetDBResultValue,
170+
ACSF_GetDBEntryRank,
171+
ACSF_RequestScriptPuke,
172+
ACSF_BeginDBTransaction,
173+
ACSF_EndDBTransaction,
174+
ACSF_GetDBEntries,
175+
ACSF_NamedRequestScriptPuke,
176+
177+
ACSF_SetDeadSpectator = 130,
178+
ACSF_SetActivatorToPlayer,
179+
ACSF_SetCurrentGamemode,
180+
ACSF_GetCurrentGamemode,
181+
ACSF_SetGamemodeLimit,
182+
183+
ACSF_SetPlayerChasecam = 136,
184+
ACSF_GetPlayerChasecam,
185+
ACSF_SetPlayerScore,
186+
ACSF_GetPlayerScore,
187+
ACSF_InDemoMode,
188+
189+
ACSF_SendNetworkString = 146,
190+
ACSF_NamedSendNetworkString,
191+
ACSF_GetChatMessage,
192+
ACSF_GetMapRotationSize,
193+
ACSF_GetMapRotationInfo,
194+
ACSF_GetCurrentMapPosition,
195+
ACSF_GetEventResult,
196+
ACSF_GetActorSectorLocation,
197+
ACSF_ChangeTeamScore,
198+
ACSF_SetGameplaySettings,
199+
ACSF_SetCustomPlayerValue,
200+
ACSF_GetCustomPlayerValue,
201+
ACSF_ResetCustomDataToDefault,
202+
ACSF_LumpOpen,
203+
ACSF_LumpRead,
204+
ACSF_LumpReadString,
205+
206+
ACSF_LumpGetInfo = 166,
207+
ACSF_LumpClose,
208+
209+
ACSF_SetAirFriction = 302,
210+
}
211+
147212
class StaticEventHandler : Object native play version("2.4")
148213
{
149214
// static event handlers CAN register other static event handlers.
@@ -200,6 +265,7 @@ class StaticEventHandler : Object native play version("2.4")
200265
virtual ui void InterfaceProcess(ConsoleEvent e) {}
201266
virtual void NetworkProcess(ConsoleEvent e) {}
202267
version("4.12") virtual void NetworkCommandProcess(NetworkCommand cmd) {}
268+
version("4.15") virtual int ACSFunctionProcess(EACSFunction func, Array<int> args) { return 0; }
203269

204270
//
205271
virtual void CheckReplacement(ReplaceEvent e) {}

0 commit comments

Comments
 (0)