From adb3eb74630c38dad80e819e18a87ba91800ea48 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 7 Oct 2023 14:36:20 -0700 Subject: [PATCH] ACS_Execute, ACS_ExecuteAlways: handle map stringargs --- src/acs/interface.cpp | 85 ++++++++++++++++++++++++++++++++++++------- src/acs/interface.h | 14 ++++--- src/p_spec.c | 20 +--------- 3 files changed, 82 insertions(+), 37 deletions(-) diff --git a/src/acs/interface.cpp b/src/acs/interface.cpp index 4c14a8e2e..8b56b6ebe 100644 --- a/src/acs/interface.cpp +++ b/src/acs/interface.cpp @@ -11,11 +11,14 @@ /// \file interface.cpp /// \brief Action Code Script: Interface for the rest of SRB2's game logic +#include #include #include #include #include +#include + #include "acsvm.hpp" #include "interface.h" @@ -347,31 +350,63 @@ void ACS_Tick(void) } /*-------------------------------------------------- - boolean ACS_Execute(const char *name, const INT32 *args, size_t numArgs, activator_t *activator) + static std::vector ACS_MixArgs(tcb::span args, tcb::span stringArgs) - See header file for description. + Convert strings to ACS arguments and position them + correctly among integer arguments. + + Input Arguments:- + args: Integer arguments. + stringArgs: C string arguments. + + Return:- + Final argument vector. --------------------------------------------------*/ -boolean ACS_Execute(const char *name, const INT32 *args, size_t numArgs, activator_t *activator) +static std::vector ACS_MixArgs(tcb::span args, tcb::span stringArgs) { - Environment *env = &ACSEnv; + std::vector argV; + size_t first = std::min(args.size(), stringArgs.size()); - ACSVM::GlobalScope *const global = env->getGlobalScope(0); - ACSVM::HubScope *const hub = global->getHubScope(0); - ACSVM::MapScope *const map = hub->getMapScope(0); - ACSVM::ScopeID scope{global->id, hub->id, map->id}; + auto new_string = [env = &ACSEnv](const char* str) -> ACSVM::Word { return ~env->getString(str, strlen(str))->idx; }; - ThreadInfo info{activator}; + for (size_t i = 0; i < first; ++i) + { + // args[i] must be 0. + // + // If ACS_Execute is called from ACS, stringargs[i] + // will always be set, because there is no + // differentiation between integers and strings on + // arguments passed to a function. In this case, + // string arguments already exist in the ACS string + // table beforehand (and set in args[i]), so no + // conversion is required here. + // + // If ACS_Execute is called from a map line special, + // args[i] may be left unset (0), while stringArgs[i] + // is set. In this case, conversion to ACS string + // table is necessary. + argV.push_back(!args[i] && stringArgs[i] ? new_string(stringArgs[i]) : args[i]); + } - ACSVM::String *script = env->getString(name, strlen(name)); - return map->scriptStart(script, scope, {reinterpret_cast(args), numArgs, &info}); + for (size_t i = first; i < args.size(); ++i) + { + argV.push_back(args[i]); + } + + for (size_t i = first; i < stringArgs.size(); ++i) + { + argV.push_back(new_string(stringArgs[i] ? stringArgs[i] : "")); + } + + return argV; } /*-------------------------------------------------- - boolean ACS_ExecuteAlways(const char *name, const INT32 *args, size_t numArgs, activator_t *activator) + boolean ACS_Execute(const char *name, const INT32 *args, size_t numArgs, const char *const *stringArgs, size_t numStringArgs, activator_t *activator) See header file for description. --------------------------------------------------*/ -boolean ACS_ExecuteAlways(const char *name, const INT32 *args, size_t numArgs, activator_t *activator) +boolean ACS_Execute(const char *name, const INT32 *args, size_t numArgs, const char *const *stringArgs, size_t numStringArgs, activator_t *activator) { Environment *env = &ACSEnv; @@ -383,7 +418,29 @@ boolean ACS_ExecuteAlways(const char *name, const INT32 *args, size_t numArgs, a ThreadInfo info{activator}; ACSVM::String *script = env->getString(name, strlen(name)); - return map->scriptStartForced(script, scope, {reinterpret_cast(args), numArgs, &info}); + std::vector argV = ACS_MixArgs(tcb::span {args, numArgs}, tcb::span {stringArgs, numStringArgs}); + return map->scriptStart(script, scope, {argV.data(), argV.size(), &info}); +} + +/*-------------------------------------------------- + boolean ACS_ExecuteAlways(const char *name, const INT32 *args, size_t numArgs, const char *const *stringArgs, size_t numStringArgs, activator_t *activator) + + See header file for description. +--------------------------------------------------*/ +boolean ACS_ExecuteAlways(const char *name, const INT32 *args, size_t numArgs, const char *const *stringArgs, size_t numStringArgs, activator_t *activator) +{ + Environment *env = &ACSEnv; + + ACSVM::GlobalScope *const global = env->getGlobalScope(0); + ACSVM::HubScope *const hub = global->getHubScope(0); + ACSVM::MapScope *const map = hub->getMapScope(0); + ACSVM::ScopeID scope{global->id, hub->id, map->id}; + + ThreadInfo info{activator}; + + ACSVM::String *script = env->getString(name, strlen(name)); + std::vector argV = ACS_MixArgs(tcb::span {args, numArgs}, tcb::span {stringArgs, numStringArgs}); + return map->scriptStartForced(script, scope, {argV.data(), argV.size(), &info}); } /*-------------------------------------------------- diff --git a/src/acs/interface.h b/src/acs/interface.h index 5e9c9ba9f..32ba78b90 100644 --- a/src/acs/interface.h +++ b/src/acs/interface.h @@ -201,7 +201,7 @@ void ACS_Tick(void); /*-------------------------------------------------- - boolean ACS_Execute(const char *name, const INT32 *args, size_t numArgs, activator_t *activator); + boolean ACS_Execute(const INT32 *args, size_t numArgs, const char *const *stringArgs, size_t numStringArgs, activator_t *activator); Runs an ACS script by its string name. Only one instance of the script will run at @@ -213,6 +213,8 @@ void ACS_Tick(void); Strings should be transformed into ACSVM string IDs. numArgs: Number of input arguments. + stringArgs: Array of input string arguments. + numStringArgs: Number of input string arguments. activator: Container for information on what activated this script. @@ -220,11 +222,11 @@ void ACS_Tick(void); true if we were able to run the script, otherwise false. --------------------------------------------------*/ -boolean ACS_Execute(const char *name, const INT32 *args, size_t numArgs, activator_t *activator); +boolean ACS_Execute(const char *name, const INT32 *args, size_t numArgs, const char *const *stringArgs, size_t numStringArgs, activator_t *activator); /*-------------------------------------------------- - boolean ACS_ExecuteAlways(const char *name, const INT32 *args, size_t numArgs, activator_t *activator); + boolean ACS_ExecuteAlways(const INT32 *args, size_t numArgs, const char *const *stringArgs, size_t numStringArgs, activator_t *activator) Runs an ACS script by its string name. If the script is already running, this method @@ -237,6 +239,8 @@ boolean ACS_Execute(const char *name, const INT32 *args, size_t numArgs, activat Strings should be transformed into ACSVM string IDs. numArgs: Number of input arguments. + stringArgs: Array of input string arguments. + numStringArgs: Number of input string arguments. activator: Container for information on what activated this script. @@ -244,11 +248,11 @@ boolean ACS_Execute(const char *name, const INT32 *args, size_t numArgs, activat true if we were able to run the script, otherwise false. --------------------------------------------------*/ -boolean ACS_ExecuteAlways(const char *name, const INT32 *args, size_t numArgs, activator_t *activator); +boolean ACS_ExecuteAlways(const char *name, const INT32 *args, size_t numArgs, const char *const *stringArgs, size_t numStringArgs, activator_t *activator); /*-------------------------------------------------- - INT32 ACS_ExecuteResult(const char *name, const INT32 *args, size_t numArgs, activator_t *activator); + INT32 ACS_ExecuteResult(const char *name, const INT32 *args, size_t numArgs, activator_t *activator) Runs an ACS script by its string name. Will return the scripts special result diff --git a/src/p_spec.c b/src/p_spec.c index 599ee327f..49fa5f441 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4307,40 +4307,24 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha case 475: // ACS_Execute { - INT32 newArgs[NUM_SCRIPT_ARGS-1] = {0}; - INT32 i; - if (!stringargs[0]) { CONS_Debug(DBG_GAMELOGIC, "Special type 475: No script name given\n"); return false; } - for (i = 1; i < NUM_SCRIPT_ARGS; i++) - { - newArgs[i - 1] = args[i]; - } - - ACS_Execute(stringargs[0], newArgs, NUM_SCRIPT_ARGS-1, activator); + ACS_Execute(stringargs[0], &args[1], NUM_SCRIPT_ARGS - 1, (const char* const*)&stringargs[1], NUM_SCRIPT_STRINGARGS - 1, activator); } break; case 476: // ACS_ExecuteAlways { - INT32 newArgs[NUM_SCRIPT_ARGS-1] = {0}; - INT32 i; - if (!stringargs[0]) { CONS_Debug(DBG_GAMELOGIC, "Special type 475: No script name given\n"); return false; } - for (i = 1; i < NUM_SCRIPT_ARGS; i++) - { - newArgs[i - 1] = args[i]; - } - - ACS_ExecuteAlways(stringargs[0], newArgs, NUM_SCRIPT_ARGS-1, activator); + ACS_ExecuteAlways(stringargs[0], &args[1], NUM_SCRIPT_ARGS - 1, (const char* const*)&stringargs[1], NUM_SCRIPT_STRINGARGS - 1, activator); } break; case 477: // ACS_Suspend