ACS_Execute, ACS_ExecuteAlways: handle map stringargs

This commit is contained in:
James R 2023-10-07 14:36:20 -07:00
parent e4fde7735e
commit adb3eb7463
3 changed files with 82 additions and 37 deletions

View file

@ -11,11 +11,14 @@
/// \file interface.cpp /// \file interface.cpp
/// \brief Action Code Script: Interface for the rest of SRB2's game logic /// \brief Action Code Script: Interface for the rest of SRB2's game logic
#include <algorithm>
#include <cstddef> #include <cstddef>
#include <istream> #include <istream>
#include <ostream> #include <ostream>
#include <vector> #include <vector>
#include <tcb/span.hpp>
#include "acsvm.hpp" #include "acsvm.hpp"
#include "interface.h" #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<ACSVM::Word> ACS_MixArgs(tcb::span<const INT32> args, tcb::span<const char* const> 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<ACSVM::Word> ACS_MixArgs(tcb::span<const INT32> args, tcb::span<const char* const> stringArgs)
{ {
Environment *env = &ACSEnv; std::vector<ACSVM::Word> argV;
size_t first = std::min(args.size(), stringArgs.size());
ACSVM::GlobalScope *const global = env->getGlobalScope(0); auto new_string = [env = &ACSEnv](const char* str) -> ACSVM::Word { return ~env->getString(str, strlen(str))->idx; };
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}; 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)); for (size_t i = first; i < args.size(); ++i)
return map->scriptStart(script, scope, {reinterpret_cast<const ACSVM::Word *>(args), numArgs, &info}); {
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. 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; Environment *env = &ACSEnv;
@ -383,7 +418,29 @@ boolean ACS_ExecuteAlways(const char *name, const INT32 *args, size_t numArgs, a
ThreadInfo info{activator}; ThreadInfo info{activator};
ACSVM::String *script = env->getString(name, strlen(name)); ACSVM::String *script = env->getString(name, strlen(name));
return map->scriptStartForced(script, scope, {reinterpret_cast<const ACSVM::Word *>(args), numArgs, &info}); std::vector<ACSVM::Word> 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<ACSVM::Word> argV = ACS_MixArgs(tcb::span {args, numArgs}, tcb::span {stringArgs, numStringArgs});
return map->scriptStartForced(script, scope, {argV.data(), argV.size(), &info});
} }
/*-------------------------------------------------- /*--------------------------------------------------

View file

@ -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. Runs an ACS script by its string name.
Only one instance of the script will run at Only one instance of the script will run at
@ -213,6 +213,8 @@ void ACS_Tick(void);
Strings should be transformed into Strings should be transformed into
ACSVM string IDs. ACSVM string IDs.
numArgs: Number of input arguments. numArgs: Number of input arguments.
stringArgs: Array of input string arguments.
numStringArgs: Number of input string arguments.
activator: Container for information on what activator: Container for information on what
activated this script. activated this script.
@ -220,11 +222,11 @@ void ACS_Tick(void);
true if we were able to run the script, otherwise false. 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. Runs an ACS script by its string name.
If the script is already running, this method 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 Strings should be transformed into
ACSVM string IDs. ACSVM string IDs.
numArgs: Number of input arguments. numArgs: Number of input arguments.
stringArgs: Array of input string arguments.
numStringArgs: Number of input string arguments.
activator: Container for information on what activator: Container for information on what
activated this script. 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. 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. Runs an ACS script by its string name.
Will return the scripts special result Will return the scripts special result

View file

@ -4307,40 +4307,24 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha
case 475: // ACS_Execute case 475: // ACS_Execute
{ {
INT32 newArgs[NUM_SCRIPT_ARGS-1] = {0};
INT32 i;
if (!stringargs[0]) if (!stringargs[0])
{ {
CONS_Debug(DBG_GAMELOGIC, "Special type 475: No script name given\n"); CONS_Debug(DBG_GAMELOGIC, "Special type 475: No script name given\n");
return false; return false;
} }
for (i = 1; i < NUM_SCRIPT_ARGS; i++) ACS_Execute(stringargs[0], &args[1], NUM_SCRIPT_ARGS - 1, (const char* const*)&stringargs[1], NUM_SCRIPT_STRINGARGS - 1, activator);
{
newArgs[i - 1] = args[i];
}
ACS_Execute(stringargs[0], newArgs, NUM_SCRIPT_ARGS-1, activator);
} }
break; break;
case 476: // ACS_ExecuteAlways case 476: // ACS_ExecuteAlways
{ {
INT32 newArgs[NUM_SCRIPT_ARGS-1] = {0};
INT32 i;
if (!stringargs[0]) if (!stringargs[0])
{ {
CONS_Debug(DBG_GAMELOGIC, "Special type 475: No script name given\n"); CONS_Debug(DBG_GAMELOGIC, "Special type 475: No script name given\n");
return false; return false;
} }
for (i = 1; i < NUM_SCRIPT_ARGS; i++) ACS_ExecuteAlways(stringargs[0], &args[1], NUM_SCRIPT_ARGS - 1, (const char* const*)&stringargs[1], NUM_SCRIPT_STRINGARGS - 1, activator);
{
newArgs[i - 1] = args[i];
}
ACS_ExecuteAlways(stringargs[0], newArgs, NUM_SCRIPT_ARGS-1, activator);
} }
break; break;
case 477: // ACS_Suspend case 477: // ACS_Suspend