diff --git a/libs/ACSVM/include/CAPI/Thread.cpp b/libs/ACSVM/include/CAPI/Thread.cpp index 53a742e7a..7047128ac 100644 --- a/libs/ACSVM/include/CAPI/Thread.cpp +++ b/libs/ACSVM/include/CAPI/Thread.cpp @@ -155,6 +155,14 @@ ACSVM_Thread *ACSVM_AllocThread(ACSVM_Environment *env, return new(std::nothrow) ACSVM_Thread(env, *funcs, data); } +// +// ACSVM_AllocThreadInfo +// +ACSVM_ThreadInfo *ACSVM_AllocThreadInfo(void *data) +{ + return new(std::nothrow) ACSVM_ThreadInfo(data); +} + // // ACSVM_ThreadFromVoid // diff --git a/libs/ACSVM/include/CAPI/Thread.h b/libs/ACSVM/include/CAPI/Thread.h index 066f0cf7f..192aacc80 100644 --- a/libs/ACSVM/include/CAPI/Thread.h +++ b/libs/ACSVM/include/CAPI/Thread.h @@ -133,6 +133,8 @@ public: ACSVM_Thread *ACSVM_AllocThread(ACSVM_Environment *env, ACSVM_ThreadFuncs const *funcs, void *data); +ACSVM_ThreadInfo *ACSVM_AllocThreadInfo(void *data); + ACSVM_Thread *ACSVM_ThreadFromVoid(void *thread); void ACSVM_Thread_Exec(ACSVM_Thread *thread); diff --git a/libs/ACSVM/lib/libacsvm-capi.dll.a b/libs/ACSVM/lib/libacsvm-capi.dll.a index 00609ebda..e76867d99 100644 Binary files a/libs/ACSVM/lib/libacsvm-capi.dll.a and b/libs/ACSVM/lib/libacsvm-capi.dll.a differ diff --git a/src/g_game.c b/src/g_game.c index c295e1e97..5058ccc3f 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -60,6 +60,7 @@ #include "k_boss.h" #include "k_bot.h" #include "doomstat.h" +#include "k_acs.h" #ifdef HAVE_DISCORDRPC #include "discord.h" @@ -2913,6 +2914,8 @@ void G_DoReborn(INT32 playernum) if (oldmo) G_ChangePlayerReferences(oldmo, players[playernum].mo); } + + ACS_RunPlayerEnterScript(player); } void G_AddPlayer(INT32 playernum) diff --git a/src/k_acs-func.c b/src/k_acs-func.c index 7bdfea482..0ae6aa320 100644 --- a/src/k_acs-func.c +++ b/src/k_acs-func.c @@ -30,6 +30,7 @@ #include "p_local.h" #include "deh_tables.h" #include "fastcmp.h" +#include "hu_stuff.h" /*-------------------------------------------------- static bool ACS_GetMobjTypeFromString(const char *word, mobjtype_t *type) @@ -115,6 +116,34 @@ static bool ACS_CountThing(mobj_t *mobj, mobjtype_t type) return false; } +/*-------------------------------------------------- + static bool ACS_ActivatorIsLocal(ACSVM_Thread *thread) + + Helper function for many print functions. + Returns whenever or not the activator of the + thread is a display player or not. + + Input Arguments:- + thread: The thread we're exeucting on. + + Return:- + true if it's for a display player, + otherwise false. +--------------------------------------------------*/ +static bool ACS_ActivatorIsLocal(ACSVM_Thread *thread) +{ + acs_threadinfo_t *info = (acs_threadinfo_t *)ACSVM_Thread_GetInfo(thread); + + if ((info != NULL) + && (info->mo != NULL && P_MobjWasRemoved(info->mo) == false) + && (info->mo->player != NULL)) + { + return P_IsDisplayPlayer(info->mo->player); + } + + return false; +} + /*-------------------------------------------------- bool ACS_CF_Random(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC) @@ -315,10 +344,29 @@ bool ACS_CF_ChangeCeiling(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Wo return false; } +/*-------------------------------------------------- + bool ACS_CF_LineSide(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC) + + Pushes which side of the linedef was + activated. +--------------------------------------------------*/ +bool ACS_CF_LineSide(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC) +{ + acs_threadinfo_t *info = (acs_threadinfo_t *)ACSVM_Thread_GetInfo(thread); + + (void)argV; + (void)argC; + + ACSVM_Thread_DataStk_Push(thread, info->side); + return false; +} + /*-------------------------------------------------- bool ACS_CF_EndPrint(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC) - ACS wrapper for CONS_Printf. + One of the ACS wrappers for CEcho. This + version only prints if the activator is a + display player. --------------------------------------------------*/ bool ACS_CF_EndPrint(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC) { @@ -328,7 +376,13 @@ bool ACS_CF_EndPrint(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word ar (void)argC; buf = ACSVM_Thread_GetPrintBuf(thread); - CONS_Printf("%s\n", ACSVM_PrintBuf_GetData(buf)); + + if (ACS_ActivatorIsLocal(thread) == true) + { + HU_SetCEchoDuration(5); + HU_DoCEcho(ACSVM_PrintBuf_GetData(buf)); + } + ACSVM_PrintBuf_Drop(buf); return false; @@ -411,3 +465,52 @@ bool ACS_CF_Timer(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC) ACSVM_Thread_DataStk_Push(thread, leveltime); return false; } + +/*-------------------------------------------------- + bool ACS_CF_EndPrintBold(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC) + + One of the ACS wrappers for CEcho. This + version prints for all players. +--------------------------------------------------*/ +bool ACS_CF_EndPrintBold(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC) +{ + ACSVM_PrintBuf *buf = NULL; + + (void)argV; + (void)argC; + + buf = ACSVM_Thread_GetPrintBuf(thread); + + HU_SetCEchoDuration(5); + HU_DoCEcho(ACSVM_PrintBuf_GetData(buf)); + + ACSVM_PrintBuf_Drop(buf); + + return false; +} + +/*-------------------------------------------------- + bool ACS_CF_EndLog(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC) + + One of the ACS wrappers for CONS_Printf. + This version only prints if the activator + is a display player. +--------------------------------------------------*/ +bool ACS_CF_EndLog(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC) +{ + ACSVM_PrintBuf *buf = NULL; + + (void)argV; + (void)argC; + + buf = ACSVM_Thread_GetPrintBuf(thread); + + if (ACS_ActivatorIsLocal(thread) == true) + { + CONS_Printf("%s\n", ACSVM_PrintBuf_GetData(buf)); + } + + ACSVM_PrintBuf_Drop(buf); + + return false; +} diff --git a/src/k_acs.c b/src/k_acs.c index e06ddf824..656d70cbd 100644 --- a/src/k_acs.c +++ b/src/k_acs.c @@ -23,6 +23,10 @@ #include "r_state.h" #include "p_polyobj.h" #include "taglist.h" +#include "d_player.h" +#include "g_game.h" +#include "p_tick.h" +#include "p_local.h" #include "CAPI/BinaryIO.h" #include "CAPI/Environment.h" @@ -227,7 +231,7 @@ static void ACS_EnvConstruct(ACSVM_Environment *env) ACS_AddCodeDataCallFunc(env, 67, "", 2, ACS_CF_ChangeCeiling); ACS_AddCodeDataCallFunc(env, 68, "WWS", 0, ACS_CF_ChangeCeiling); // 69 to 79: Implemented by ACSVM - + ACS_AddCodeDataCallFunc(env, 80, "", 0, ACS_CF_LineSide); // 81 to 82: Implemented by ACSVM // 84 to 85: Implemented by ACSVM @@ -237,6 +241,8 @@ static void ACS_EnvConstruct(ACSVM_Environment *env) ACS_AddCodeDataCallFunc(env, 91, "", 0, ACS_CF_GameType); ACS_AddCodeDataCallFunc(env, 92, "", 0, ACS_CF_GameSpeed); ACS_AddCodeDataCallFunc(env, 93, "", 0, ACS_CF_Timer); + + ACS_AddCodeDataCallFunc(env, 101, "", 0, ACS_CF_EndPrintBold); // 136 to 137: Implemented by ACSVM // 157: Implemented by ACSVM @@ -256,7 +262,7 @@ static void ACS_EnvConstruct(ACSVM_Environment *env) // 256 to 257: Implemented by ACSVM // 263: Implemented by ACSVM - ACS_AddCodeDataCallFunc(env, 270, "", 0, ACS_CF_EndPrint); + ACS_AddCodeDataCallFunc(env, 270, "", 0, ACS_CF_EndLog); // 273 to 275: Implemented by ACSVM // 291 to 325: Implemented by ACSVM @@ -404,6 +410,85 @@ static bool ACS_EnvCheckTag(ACSVM_Environment const *env, ACSVM_Word type, ACSVM return true; } +/*-------------------------------------------------- + static void ACS_ThrDestruct(ACSVM_Thread *thread) + + ACSVM Thread hook. Runs as the thread + is in the process of being destroyed. + + Input Arguments:- + thread - The ACS thread data to destroy. + + Return:- + N/A +--------------------------------------------------*/ +static void ACS_ThrDestruct(ACSVM_Thread *thread) +{ + acs_threadinfo_t *info = ACSVM_Thread_GetInfo(thread); + + if (info != NULL) + { + Z_Free(info); + } +} + +/*-------------------------------------------------- + static void ACS_ThrStart(ACSVM_Thread *thread, void *data) + + ACSVM Thread hook. Runs immediately after + an ACS thread has been started. + + Input Arguments:- + thread - The ACS thread data. + data - ACS thread info, as a raw pointer. + + Return:- + The newly created ACS thread. +--------------------------------------------------*/ +static void ACS_ThrStart(ACSVM_Thread *thread, void *data) +{ + acs_threadinfo_t *activator = NULL; + + ACSVM_Thread_SetResult(thread, 1); + + if (data == NULL) + { + // Create an empty one, to reduce NULL checks. + // Might not be necessary. + activator = Z_Calloc(sizeof(acs_threadinfo_t), PU_STATIC, NULL); + } + else + { + activator = (acs_threadinfo_t *)data; + } + + ACSVM_Thread_SetInfo(thread, activator); +} + +/*-------------------------------------------------- + static ACSVM_Thread *ACS_EnvAllocThread(ACSVM_Environment *env) + + ACSVM Environment hook. Runs when an ACS + thread is being created. This is where + our own thread hooks are supposed to + be loaded. + + Input Arguments:- + env - The ACS environment data. + + Return:- + The newly created ACS thread. +--------------------------------------------------*/ +static ACSVM_Thread *ACS_EnvAllocThread(ACSVM_Environment *env) +{ + ACSVM_ThreadFuncs funcs = {0}; + + funcs.dtor = ACS_ThrDestruct; + funcs.start = ACS_ThrStart; + + return ACSVM_AllocThread(env, &funcs, NULL); +} + /*-------------------------------------------------- void ACS_Init(void) @@ -421,6 +506,7 @@ void ACS_Init(void) funcs.ctor = ACS_EnvConstruct; funcs.loadModule = ACS_EnvLoadModule; funcs.checkTag = ACS_EnvCheckTag; + funcs.allocThread = ACS_EnvAllocThread; ACSenv = ACSVM_AllocEnvironment(&funcs, NULL); @@ -520,7 +606,7 @@ void ACS_LoadLevelScripts(size_t mapID) // Start up new map scope. ACS_ResetMap(hub); - map = ACSVM_HubScope_GetMapScope(hub, 0); + map = ACSVM_HubScope_GetMapScope(hub, 0); // This is where you'd put in mapID if you add hub support. ACSVM_MapScope_SetActive(map, true); // Allocate module list. @@ -552,9 +638,70 @@ void ACS_LoadLevelScripts(size_t mapID) // Register the modules with map scope. ACSVM_MapScope_AddModules(map, modules, modules_len); } +} + +/*-------------------------------------------------- + void ACS_RunPlayerEnterScript(player_t *player) + + See header file for description. +--------------------------------------------------*/ +void ACS_RunPlayerEnterScript(player_t *player) +{ + ACSVM_GlobalScope *global = NULL; + ACSVM_HubScope *hub = NULL; + ACSVM_MapScope *map = NULL; + + acs_threadinfo_t *activator = NULL; + + global = ACSVM_Environment_GetGlobalScope(ACSenv, 0); + hub = ACSVM_GlobalScope_GetHubScope(global, 0); + map = ACSVM_HubScope_GetMapScope(hub, 0); + + activator = Z_Calloc(sizeof(acs_threadinfo_t), PU_STATIC, NULL); + + P_SetTarget(&activator->mo, player->mo); + + ACSVM_MapScope_ScriptStartTypeForced(map, ACS_ST_ENTER, NULL, 0, ACSVM_AllocThreadInfo(activator), NULL); +} + +/*-------------------------------------------------- + void ACS_RunLevelStartScripts(void) + + See header file for description. +--------------------------------------------------*/ +void ACS_RunLevelStartScripts(void) +{ + ACSVM_GlobalScope *global = NULL; + ACSVM_HubScope *hub = NULL; + ACSVM_MapScope *map = NULL; + + UINT8 i; + + global = ACSVM_Environment_GetGlobalScope(ACSenv, 0); + hub = ACSVM_GlobalScope_GetHubScope(global, 0); + map = ACSVM_HubScope_GetMapScope(hub, 0); // Start OPEN scripts. - ACSVM_MapScope_ScriptStartType(map, 1, NULL, 0, NULL, NULL); + ACSVM_MapScope_ScriptStartType(map, ACS_ST_OPEN, NULL, 0, NULL, NULL); + + // Start ENTER scripts. + for (i = 0; i < MAXPLAYERS; i++) + { + player_t *player = NULL; + + if (playeringame[i] == false) + { + continue; + } + + player = &players[i]; + if (player->spectator == true) + { + continue; + } + + ACS_RunPlayerEnterScript(player); + } } /*-------------------------------------------------- diff --git a/src/k_acs.h b/src/k_acs.h index 1e88d9fb1..3cd187028 100644 --- a/src/k_acs.h +++ b/src/k_acs.h @@ -16,6 +16,10 @@ #include "doomtype.h" #include "doomdef.h" +#include "p_mobj.h" +#include "r_defs.h" +#include "p_polyobj.h" +#include "d_player.h" #include "CAPI/BinaryIO.h" #include "CAPI/Environment.h" @@ -25,6 +29,9 @@ #include "CAPI/String.h" #include "CAPI/Thread.h" +// +// Special global script types. +// typedef enum { ACS_ST_OPEN = 1, // OPEN: Runs once when the level starts. @@ -33,12 +40,27 @@ typedef enum ACS_ST_ENTER = 4, // ENTER: Runs when a player enters the game; both on start of the level, and when un-spectating. } acs_scriptType_e; +// +// Script "waiting on tag" types. +// typedef enum { ACS_TAGTYPE_POLYOBJ, ACS_TAGTYPE_SECTOR, } acs_tagType_e; +// +// Thread activator info +// +typedef struct +{ + mobj_t *mo; // Object that activated this thread. + line_t *line; // Linedef that activated this thread. + UINT8 side; // Front / back side of said linedef. + sector_t *sector; // Sector that activated this thread. + polyobj_t *po; // Polyobject that activated this thread. +} acs_threadinfo_t; + /*-------------------------------------------------- ACSVM_Environment *ACS_GetEnvironment(void); @@ -96,6 +118,33 @@ void ACS_Shutdown(void); void ACS_LoadLevelScripts(size_t mapID); +/*-------------------------------------------------- + void ACS_RunPlayerEnterScript(player_t *player); + + Runs the map's special script for a player + entering the game. + + Input Arguments:- + player: The player to run the script for. + + Return:- + None +--------------------------------------------------*/ + +void ACS_RunPlayerEnterScript(player_t *player); + + +/*-------------------------------------------------- + void ACS_RunLevelStartScripts(void); + + Runs the map's special scripts for opening + the level, and for all players to enter + the game. +--------------------------------------------------*/ + +void ACS_RunLevelStartScripts(void); + + /*-------------------------------------------------- void ACS_Tick(void); @@ -105,6 +154,7 @@ void ACS_LoadLevelScripts(size_t mapID); void ACS_Tick(void); + /*-------------------------------------------------- bool ACS_CF_???(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC); @@ -132,11 +182,14 @@ bool ACS_CF_TagWait(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word arg bool ACS_CF_PolyWait(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC); bool ACS_CF_ChangeFloor(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC); bool ACS_CF_ChangeCeiling(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC); +bool ACS_CF_LineSide(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC); bool ACS_CF_EndPrint(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC); bool ACS_CF_PlayerCount(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC); bool ACS_CF_GameType(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC); bool ACS_CF_GameSpeed(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC); bool ACS_CF_Timer(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC); +bool ACS_CF_EndPrintBold(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC); +bool ACS_CF_EndLog(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC); #endif // __K_ACS__ diff --git a/src/p_setup.c b/src/p_setup.c index e0548c4c1..5999854a1 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8222,11 +8222,15 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) if (!fromnetsave) // uglier hack { INT32 buf = gametic % BACKUPTICS; + for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i]) G_CopyTiccmd(&players[i].cmd, &netcmds[buf][i], 1); } + + ACS_RunLevelStartScripts(); + P_MapStart(); // just in case MapLoad modifies tmthing LUA_HookInt(gamemap, HOOK(MapLoad)); P_MapEnd(); // just in case MapLoad modifies tm.thing