Allow ACS to call linedef specials as functions

A handful need adjusted to move more stuff off of linedef and into args, but otherwise works well.
This commit is contained in:
Sally Coolatta 2022-11-14 21:43:01 -05:00
parent 62bda51d89
commit 4c7519dffb
5 changed files with 667 additions and 396 deletions

View file

@ -76,93 +76,88 @@
// Ideally would implement as many as possible.
special
int 400:Floor_SetHeightTexture(2,3), // tag, height[, texture]
int 401:Ceiling_SetHeightTexture(2,3), // tag, height[, texture]
int 402:Light_ChangeToValue(2), // tag, value
int 403:Floor_Move(3,5), // tag, height, speed[, texture, script]
int 404:Ceiling_Move(3,5), // tag, height, speed[, texture, script]
int 405:Floor_MoveByOffset(3,4), // tag, offset, speed[, instant]
int 400:Floor_SetHeightTexture(3),
int 407:Ceiling_MoveByOffset(3,4), // tag, offset, speed[, instant]
int 402:Light_Copy(2),
int 403:Floor_Move(5),
int 409:Sector_ChangeTag(2), // old tag, new tag
int 410:Line_ChangeFrontSectorTag(2), // line tag, new tag
int 405:Floor_MoveByOffset(5),
int 411:Sector_StopMovement(1), // tag
int 412:Thing_Teleport(2, 5), // thing tag, sector tag[, silent, keep angle, keep speed]. Relative teleport is now a separate function.
int 408:Sector_SetFlats(2),
int 409:Sector_ChangeTag(3),
int 410:Line_ChangeFrontSectorTag(2),
// TODO: split all these damn features up into separate functions, instead of optional variables
int 413:Level_SetMusic(1, 12), // name[, track, loop, local, reload reset, force reset, position, position is offset, fade out time, fade in time, fade out vol, fade in vol]
int 411:Sector_StopMovement(1),
int 412:Thing_Teleport(5),
int 413:Level_SetMusic(1, 7),
int 414:Thing_PlaySound(4),
int 415:Console_Execute(1),
int 416:Light_Flicker(5),
int 417:Light_Pulse(5),
int 418:Light_BlinkUnsynced(6),
int 419:Light_Blink(6),
int 420:Light_Fade(4),
int 421:Light_Stop(1),
int 422:Player_CutAwayView(2, 3),
int 423:Level_SetSky(1, 2),
int 424:Level_SetWeather(1, 2),
int 425:Thing_SetState(1),
int 426:Thing_Stop(0, 1),
int 427:Player_AddScore(1),
int 428:FOF_StartMovement(2, 5),
int 429:Sector_Crush(4),
int 414:Thing_PlaySound(1, 3), // name[, local, origin enum]. Doing it from a sector is now a separate function.
// int 415:Console_Execute(1), // script id
int 416:Light_Flicker(2, 4), // tag, value a[, value b, frequency]
int 417:Light_Pulse(2, 4), // tag, value a[, value b, frequency]
int 418:Light_BlinkUnsynced(4, 5), // tag, low time, hi time, value a[, value b]
int 419:Light_Blink(4, 5), // tag, low time, hi time, value a[, value b]
int 420:Light_Fade(3, 5), // tag, value, speed[, speed is tics, no interrupt]
int 421:Light_Stop(1), // tag
int 422:Player_CutAwayView(2, 3), // tid, tics[, pitch]
int 423:Level_SetSky(1, 2), // texture[, global]
int 424:Level_SetWeather(1, 2), // effect[, global]
int 425:Thing_SetState(1), // string
int 426:Thing_Stop(0, 1), // [sector]
int 427:Player_AddScore(1), // amount
int 428:FOF_StartMovement(8, 9), // tag, bottom low, bottom hi, top low, top hi, speed, start delay, swap delay[, invert]
int 429:Ceiling_Crush(2, 3), // tag, speed[, constant]
int 430:Floor_Crush(2, 3), // tag, speed[, constant]
int 431:Sector_Crush(2, 3), // tag, speed[, constant]
// int 432:Thing_Set2D(1), // bool
int 433:Thing_SetFlip(1), // bool
// int 434:Player_CustomPower(?),
int 435:Scroll_Change(3), // tag, dir, speed
int 436:FOF_Shatter(2), // target, control
int 437:Player_DisableControl(1, 2), // time[, allowjump]
int 438:Thing_SetScale(1), // size
int 439:Line_CopyTextures(1, 2), // tag[, existing]
// int 432:Thing_Set2D(1),
int 433:Thing_SetFlip(1),
// int 434:Player_CustomPower(2),
int 435:Scroll_Change(2),
int 436:FOF_Shatter(2),
int 437:Player_DisableControl(1, 2),
int 438:Thing_SetScale(1),
int 439:Line_CopyTextures(1, 3),
// int 440:Level_StartMetalSonicRace(0),
int 441:SetUnlockableTrigger(1), // ID
int 442:Sector_NextThingState(2, 3), // tag, type[, state]
int 443:Lua_Execute(1), // script
int 444:Earthquake(1, 2), // tics[, intensity]
int 445:FOF_SetExists(2, 3), // target, control[, exists]
int 446:FOF_Crumble(2, 3), // target, control[, options]
int 447:Sector_SetColormap(2, 8), // tag, light[, fade, extra, flags, force light, force fade, force extra]
int 448:SetSkyboxViewpoint(1, 2), // viewpoint ID[, global]. Center point is now a separate function
int 449:SetBossActive(1, 2), // boss ID[, active?]
int 450:ACS_ExecuteAlways(1,4), // script[, arg1, arg2, arg3]
int 451:ACS_ExecuteRandomAlways(2,5), // script low, script high[, arg1, arg2, arg3]
int 452:FOF_SetAlpha(3, 5), // target, control, alpha[, add, update flags]
int 453:FOF_Fade(4, 5), // target, control, alpha, time[, options]
int 454:FOF_StopFade(2, 3), // target, control[, interrupt]
// int 455:Sector_FadeColormap(?), // TODO
int 456:Sector_StopColormapFade(1), // tag
int 457:Thing_StartTracking(5), // tag, tolerance, time, script, continue
int 441:SetUnlockableTrigger(1),
int 442:Sector_NextThingState(4),
int 443:Lua_Execute(1, 8),
int 444:Earthquake(1, 3),
int 445:FOF_SetExists(2, 3),
int 446:FOF_Crumble(2, 3),
int 447:Sector_SetColormap(2, 3),
int 448:SetSkyboxViewpoint(3, 4),
int 449:SetBossActive(1, 2),
int 450:Line_Execute(1),
int 451:Line_ExecuteRandom(2),
int 452:FOF_SetAlpha(4),
int 453:FOF_Fade(5),
int 454:FOF_StopFade(2, 3),
int 455:Sector_FadeColormap(4),
int 456:Sector_StopColormapFade(1),
int 457:Thing_StartTracking(3, 5),
int 458:Thing_StopTracking(0),
int 459:Prompt_Open(1, 3), // prompt[, allow control, close script]. Closing is now a separate function.
int 460:Player_AddRings(1, 2), // amount[, freq]
int 461:Thing_Spawn(4, 5), // type, x, y, z[, angle]. Randomized coordinates can be handled by code.
int 459:Prompt_Execute(4),
int 460:Player_AddRings(2, 3),
int 461:Thing_Spawn(5, 9),
int 462:Level_Stopwatch(0),
int 463:Thing_Dye(1), // color
// int 464:TriggerEggCapsule(1, 2), // capsule ID[, end level]
// int 464:TriggerEggCapsule(1, 2),
int 466:Level_SetFailed(0, 1), // [success?]
int 466:Level_SetFailed(1),
int 480:Polyobj_DoorSlide(5), // po, speed, angle, dist, delay
int 481:Polyobj_DoorSwing(4), // po, speed, angle, delay
int 482:Polyobj_Move(4), // po, speed, angle, dist
int 483:Polyobj_OR_Move(4), // po, speed, angle, dist
int 484:Polyobj_RotateRight(3), // po, speed, angle
int 485:Polyobj_OR_RotateRight(3), // po, speed, angle
int 486:Polyobj_RotateLeft(3), // po, speed, angle
int 487:Polyobj_OR_RotateLeft(3), // po, speed, angle
int 488:Polyobj_MoveByWaypoints(4), // po, speed, sequence[, options]
int 489:Polyobj_InvisibleIntangible(1, 2), // po[, just visibility]
int 490:Polyobj_VisibleTangible(1, 2), // po[, just visibility]
int 491:Polyobj_SetAlpha(2, 3), // po, alpha[, add]
int 492:Polyobj_FadeAlpha(2, 3), // po, alpha, speed[, options]
int 480:Polyobj_DoorSlide(5),
int 481:Polyobj_DoorSwing(4),
int 482:Polyobj_Move(4),
int 483:Polyobj_OR_Move(4),
int 484:Polyobj_RotateRight(3),
int 485:Polyobj_OR_RotateRight(3),
int 486:Polyobj_RotateLeft(3),
int 487:Polyobj_OR_RotateLeft(3),
int 488:Polyobj_MoveByWaypoints(4),
int 489:Polyobj_InvisibleIntangible(1, 2),
int 490:Polyobj_VisibleTangible(1, 2),
int 491:Polyobj_SetAlpha(2, 3),
int 492:Polyobj_FadeAlpha(2, 3),
int 499:Sector_ToggleWaypoints(0, 1), // [enable?]
int 499:Sector_ToggleWaypoints(1, 2),
// internal functions have negative values
int -1:GetLineUDMFInt(2, int, str),

View file

@ -174,7 +174,7 @@ static bool ACS_CountThing(mobj_t *mobj, mobjtype_t type)
--------------------------------------------------*/
static bool ACS_ActivatorIsLocal(ACSVM_Thread *thread)
{
acs_threadinfo_t *info = (acs_threadinfo_t *)ACSVM_Thread_GetInfo(thread);
activator_t *info = (activator_t *)ACSVM_Thread_GetInfo(thread);
if ((info != NULL)
&& (info->mo != NULL && P_MobjWasRemoved(info->mo) == false)
@ -394,7 +394,7 @@ bool ACS_CF_ChangeCeiling(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Wo
--------------------------------------------------*/
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);
activator_t *info = (activator_t *)ACSVM_Thread_GetInfo(thread);
(void)argV;
(void)argC;
@ -411,7 +411,7 @@ bool ACS_CF_LineSide(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word ar
--------------------------------------------------*/
bool ACS_CF_ClearLineSpecial(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC)
{
acs_threadinfo_t *info = (acs_threadinfo_t *)ACSVM_Thread_GetInfo(thread);
activator_t *info = (activator_t *)ACSVM_Thread_GetInfo(thread);
(void)argV;
(void)argC;
@ -537,7 +537,7 @@ bool ACS_CF_Timer(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC)
--------------------------------------------------*/
bool ACS_CF_SectorSound(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC)
{
acs_threadinfo_t *info = (acs_threadinfo_t *)ACSVM_Thread_GetInfo(thread);
activator_t *info = (activator_t *)ACSVM_Thread_GetInfo(thread);
ACSVM_MapScope *map = NULL;
ACSVM_String *str = NULL;
@ -711,7 +711,7 @@ bool ACS_CF_SetLineTexture(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_W
--------------------------------------------------*/
bool ACS_CF_SetLineSpecial(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC)
{
acs_threadinfo_t *info = (acs_threadinfo_t *)ACSVM_Thread_GetInfo(thread);
activator_t *info = (activator_t *)ACSVM_Thread_GetInfo(thread);
mtag_t tag = 0;
INT32 spec = 0;

View file

@ -416,6 +416,85 @@ static bool ACS_EnvCheckTag(ACSVM_Environment const *env, ACSVM_Word type, ACSVM
return true;
}
/*--------------------------------------------------
static ACSVM_Word ACS_EnvCallSpecial(ACSVM_Environment const *env, ACSVM_Thread *thread, ACSVM_Word spec, ACSVM_Word const *argV, ACSVM_Word argC)
ACSVM Environment hook. Activates a special
function straight from the script rather than
a linedef.
Input Arguments:-
env - The ACS environment data.
thread - The thread that is executing the special.
spec - The special ID to execute.
argV - Array containing the arguments given from the script.
argC - The number of entries in argV.
Return:-
1 when successful, otherwise 0.
--------------------------------------------------*/
static ACSVM_Word ACS_EnvCallSpecial(ACSVM_Environment *env, ACSVM_Thread *thread, ACSVM_Word spec, ACSVM_Word const *argV, ACSVM_Word argC)
{
activator_t *info = ACSVM_Thread_GetInfo(thread);
ACSVM_MapScope *map = ACSVM_Thread_GetScopeMap(thread);
INT32 args[NUMLINEARGS] = {0};
char *stringargs[NUMLINESTRINGARGS] = {0};
size_t numStringArgs = 0;
size_t i = 0;
(void)env;
// This needs manually set, as ACS just uses indicies in the
// compiled string table and not actual strings, and SRB2 has
// separate args and stringargs, so there's no way to
// properly distinguish them.
switch (spec)
{
case 442:
numStringArgs = 2;
break;
case 413:
case 414:
case 415:
case 423:
case 425:
case 443:
case 459:
case 461:
case 463:
case 469:
numStringArgs = 1;
break;
default:
break;
}
for (; i < numStringArgs; i++)
{
ACSVM_String *strPtr = ACSVM_MapScope_GetString(map, argV[i]);
const char *str = ACSVM_String_GetStr(strPtr);
size_t strLen = ACSVM_String_GetLen(strPtr);
stringargs[i] = Z_Malloc(strLen + 1, PU_STATIC, NULL);
M_Memcpy(stringargs[i], str, strLen + 1);
}
for (; i < min(argC, NUMLINEARGS); i++)
{
args[i - numStringArgs] = argV[i];
}
P_ProcessSpecial(info, spec, args, stringargs);
for (i = 0; i < numStringArgs; i++)
{
Z_Free(stringargs[i]);
}
return 1;
}
/*--------------------------------------------------
static void ACS_ThrDestruct(ACSVM_Thread *thread)
@ -430,7 +509,7 @@ static bool ACS_EnvCheckTag(ACSVM_Environment const *env, ACSVM_Word type, ACSVM
--------------------------------------------------*/
static void ACS_ThrDestruct(ACSVM_Thread *thread)
{
acs_threadinfo_t *info = ACSVM_Thread_GetInfo(thread);
activator_t *info = ACSVM_Thread_GetInfo(thread);
if (info != NULL)
{
@ -453,7 +532,7 @@ static void ACS_ThrDestruct(ACSVM_Thread *thread)
--------------------------------------------------*/
static void ACS_ThrStart(ACSVM_Thread *thread, void *data)
{
acs_threadinfo_t *activator = NULL;
activator_t *activator = NULL;
ACSVM_Thread_SetResult(thread, 1);
@ -461,11 +540,11 @@ static void ACS_ThrStart(ACSVM_Thread *thread, void *data)
{
// Create an empty one, to reduce NULL checks.
// Might not be necessary.
activator = Z_Calloc(sizeof(acs_threadinfo_t), PU_STATIC, NULL);
activator = Z_Calloc(sizeof(activator_t), PU_STATIC, NULL);
}
else
{
activator = (acs_threadinfo_t *)data;
activator = (activator_t *)data;
}
ACSVM_Thread_SetInfo(thread, activator);
@ -512,6 +591,7 @@ void ACS_Init(void)
funcs.ctor = ACS_EnvConstruct;
funcs.loadModule = ACS_EnvLoadModule;
funcs.checkTag = ACS_EnvCheckTag;
funcs.callSpecImpl = ACS_EnvCallSpecial;
funcs.allocThread = ACS_EnvAllocThread;
ACSenv = ACSVM_AllocEnvironment(&funcs, NULL);
@ -657,13 +737,13 @@ void ACS_RunPlayerEnterScript(player_t *player)
ACSVM_HubScope *hub = NULL;
ACSVM_MapScope *map = NULL;
acs_threadinfo_t *activator = NULL;
activator_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);
activator = Z_Calloc(sizeof(activator_t), PU_STATIC, NULL);
P_SetTarget(&activator->mo, player->mo);
@ -721,13 +801,13 @@ void ACS_RunLapScript(mobj_t *mo, line_t *line)
ACSVM_HubScope *hub = NULL;
ACSVM_MapScope *map = NULL;
acs_threadinfo_t *activator = NULL;
activator_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);
activator = Z_Calloc(sizeof(activator_t), PU_STATIC, NULL);
P_SetTarget(&activator->mo, mo);
activator->line = line;

View file

@ -55,12 +55,33 @@ typedef enum
//
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;
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.
boolean fromLineSpecial; // Called from P_ProcessLineSpecial.
} activator_t;
/*--------------------------------------------------
void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char **stringargs);
Runs a numbered special action. Can be called
by both linedefs and ACS scripts.
Input Arguments:-
activator - Struct containing information on what activated this special.
special - Special ID.
args - Array of the args.
stringargs - Array of the string args.
Return:-
N/A
--------------------------------------------------*/
void P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, char **stringargs);
/*--------------------------------------------------
ACSVM_Environment *ACS_GetEnvironment(void);

File diff suppressed because it is too large Load diff