From 6b4d193fdf26a3b1190b7e1c57c583de4da17442 Mon Sep 17 00:00:00 2001 From: Lactozilla Date: Mon, 29 Apr 2024 19:17:50 -0300 Subject: [PATCH] Changes: Added Spawn Added GetActorX, GetActorY, GetActorZ Added GetActorVelX, GetActorVelY, GetActorVelZ Added GetActorAngle, GetActorPitch, GetActorRoll Added GetActorFloorZ, GetActorFloorTexture, GetActorLightLevel Added CheckActorState, CheckActorFlag, GetActorClass Added SetActorPosition, SetActorVelocity Added SetActorAngle, SetActorPitch, SetActorRoll Added SetActorState, SetActorFlag, SetActorClass Changed GetThingDye to GetActorDye Changed DyeThing to SetActorDye Added GiveRings, GiveSpheres, GiveLives, GiveScore, DropFlag, TossFlag, DropEmeralds, TossEmeralds Added PlayerHoldingFlag, PlayerIsIt, PlayerFinished Fixed SetActorProperty and GetActorProperty Removed AwardScore, AwardRings Removed actor properties: X, Y, Z, type, angle, pitch, roll, floorz, ceilingz, momx, momy, momz, state, flags, flags2, eflags Reorganized script types Made GAMEOVER scripts run when players die --- extras/acs/srb2defs.acs | 101 +-- extras/acs/srb2special.acs | 32 +- src/acs/call-funcs.cpp | 1609 ++++++++++++++++++++++++++++++------ src/acs/call-funcs.hpp | 45 +- src/acs/environment.cpp | 49 +- src/acs/thread.hpp | 18 +- src/g_game.c | 2 - src/p_inter.c | 2 + src/p_local.h | 3 +- src/p_mobj.c | 34 + src/p_user.c | 1 + 11 files changed, 1562 insertions(+), 334 deletions(-) diff --git a/extras/acs/srb2defs.acs b/extras/acs/srb2defs.acs index b09ac93fd..bfb3324dc 100644 --- a/extras/acs/srb2defs.acs +++ b/extras/acs/srb2defs.acs @@ -31,62 +31,46 @@ // Actor properties you can get/set -#define APROP_X 0 -#define APROP_Y 1 -#define APROP_Z 2 -#define APROP_Type 3 -#define APROP_Angle 4 -#define APROP_Pitch 5 -#define APROP_Roll 6 -#define APROP_SpriteRoll 7 -#define APROP_Frame 8 -#define APROP_Sprite 9 -#define APROP_Sprite2 10 -#define APROP_RenderFlags 11 -#define APROP_SpriteXScale 12 -#define APROP_SpriteYScale 13 -#define APROP_SpriteXOffset 14 -#define APROP_SpriteYOffset 15 -#define APROP_FloorZ 16 -#define APROP_CeilingZ 17 -#define APROP_Radius 18 -#define APROP_Height 19 -#define APROP_MomX 20 -#define APROP_MomY 21 -#define APROP_MomZ 22 -#define APROP_Tics 23 -#define APROP_State 24 -#define APROP_Flags 25 -#define APROP_Flags2 26 -#define APROP_ExtraFlags 27 -#define APROP_Skin 28 -#define APROP_Color 29 -#define APROP_Health 30 -#define APROP_MoveDir 31 -#define APROP_MoveCount 32 -#define APROP_ReactionTime 33 -#define APROP_Threshold 34 -#define APROP_LastLook 35 -#define APROP_Friction 36 -#define APROP_MoveFactor 37 -#define APROP_Fuse 38 -#define APROP_WaterTop 39 -#define APROP_WaterBottom 40 -#define APROP_Scale 41 -#define APROP_DestScale 42 -#define APROP_ScaleSpeed 43 -#define APROP_ExtraValue1 44 -#define APROP_ExtraValue2 45 -#define APROP_CustomVal 46 -#define APROP_CustomValMem 47 -#define APROP_Colorized 48 -#define APROP_Mirrored 49 -#define APROP_ShadowScale 50 -#define APROP_DispOffset 51 -#define APROP_Target 52 -#define APROP_Tracer 53 -#define APROP_HNext 54 -#define APROP_HPrev 55 +#define APROP_Frame 0 +#define APROP_Sprite 1 +#define APROP_Sprite2 2 +#define APROP_RenderFlags 3 +#define APROP_SpriteXScale 4 +#define APROP_SpriteYScale 5 +#define APROP_SpriteXOffset 6 +#define APROP_SpriteYOffset 7 +#define APROP_SpriteRoll 8 +#define APROP_Radius 9 +#define APROP_Height 10 +#define APROP_Tics 11 +#define APROP_Skin 12 +#define APROP_Color 13 +#define APROP_Health 14 +#define APROP_MoveDir 15 +#define APROP_MoveCount 16 +#define APROP_ReactionTime 17 +#define APROP_Threshold 18 +#define APROP_LastLook 19 +#define APROP_Friction 20 +#define APROP_MoveFactor 21 +#define APROP_Fuse 22 +#define APROP_WaterTop 23 +#define APROP_WaterBottom 24 +#define APROP_Scale 25 +#define APROP_DestScale 26 +#define APROP_ScaleSpeed 27 +#define APROP_ExtraValue1 28 +#define APROP_ExtraValue2 29 +#define APROP_CustomVal 30 +#define APROP_CustomValMem 31 +#define APROP_Colorized 32 +#define APROP_Mirrored 33 +#define APROP_ShadowScale 34 +#define APROP_DispOffset 35 +#define APROP_Target 36 +#define APROP_Tracer 37 +#define APROP_HNext 38 +#define APROP_HPrev 39 // Line properties @@ -237,6 +221,11 @@ #define TEAM_RED 1 #define TEAM_BLUE 2 +// Team flags + +#define TEAMFLAG_RED (1 << 0) +#define TEAMFLAG_BLUE (1 << 1) + // Weapons #define WEAPON_AUTO 0 diff --git a/extras/acs/srb2special.acs b/extras/acs/srb2special.acs index 17b64d09a..1fb3056c0 100644 --- a/extras/acs/srb2special.acs +++ b/extras/acs/srb2special.acs @@ -7,13 +7,25 @@ special -5:SetSectorProperty(3), -7:GetSideProperty(2), -8:SetSideProperty(3), - -10:GetThingProperty(2), - -11:SetThingProperty(3), -100:strcmp(2,3), -101:strcasecmp(2,3), -120:PlayerRings(0), -122:PlayerScore(0), -123:PlayerSuper(0), + -200:GetActorVelX(1), + -201:GetActorVelY(1), + -202:GetActorVelZ(1), + -203:GetActorRoll(1), + -204:GetActorFloorTexture(1), + -205:CheckActorState(2), + -206:CheckActorFlag(2), + -207:GetActorClass(1), + -208:GetActorDye(1), + -209:SetActorVelocity(4,5), + -210:SetActorRoll(2), + -211:SetActorFlag(2,3), + -212:SetActorClass(2), + -213:SetActorDye(2), -300:CountEnemies(2), -301:CountPushables(2), -302:HasUnlockable(1), @@ -30,11 +42,8 @@ special -313:NiGHTSAttack(0), -314:ModeAttacking(0), -315:LowestLap(0), - -320:GetThingDye(0), - -321:DyeThing(1), -322:Teleport(2,3), -323:SetViewpoint(1,2), - // -324:Thing_Spawn(1), // NOTE: would it be better to implement Spawn? (https://zdoom.org/wiki/Spawn) -325:Thing_TrackAngle(4,6), -326:Thing_StopTrackingAngle(1), -327:CheckPowerUp(1), @@ -44,6 +53,17 @@ special -331:TakeAmmo(2), -332:DoSuperTransformation(0,1), -333:DoSuperDetransformation(0), + -334:GiveRings(1), + -335:GiveSpheres(1), + -336:GiveLives(1), + -337:GiveScore(1), + -338:DropFlag(0), + -339:TossFlag(0), + -340:DropEmeralds(0), + -341:TossEmeralds(0), + -342:PlayerHoldingFlag(2), + -343:PlayerIsIt(1), + -344:PlayerFinished(1), -500:CameraWait(1), -503:SetLineRenderStyle(3), -504:MapWarp(2), @@ -84,7 +104,6 @@ special 420:Light_Fade(3,6), 421:StopLightingEffect(1), 424:Weather_Change(1,2), - 427:AwardScore(1), 428:Plat_StartMovement(1,2), 429:Sector_Crush(1,2), 432:Switch2DMode(0,1), @@ -109,7 +128,6 @@ special 454:FOF_StopFading(2), 455:Colormap_Fade(3,4), 456:Colormap_StopFading(1), - 460:AwardRings(1,2), 462:StopTimer(0), 464:TriggerEggCapsule(1,2), 466:SetLevelFailureState(1), diff --git a/src/acs/call-funcs.cpp b/src/acs/call-funcs.cpp index 132066bd4..04b9fd015 100644 --- a/src/acs/call-funcs.cpp +++ b/src/acs/call-funcs.cpp @@ -61,6 +61,8 @@ using namespace srb2::acs; +#define NO_RETURN(thread) thread->dataStk.push(0) + /*-------------------------------------------------- static bool ACS_GetMobjTypeFromString(const char *word, mobjtype_t *type) @@ -309,6 +311,88 @@ static bool ACS_GetColorFromString(const char *word, skincolornum_t *type) return false; } +/*-------------------------------------------------- + static bool ACS_CheckActorFlag(mobj_t *mobj, mobjtype_t type) + + Helper function for CallFunc_SetObjectFlag and CallFunc_CheckObjectFlag. + + Input Arguments:- + flag: The name of the flag to check. + result: Which flag to give to the actor. + type: Variable to store which flag set the actor flag was found it. + + Return:- + true if the flag exists, otherwise false. +--------------------------------------------------*/ +static bool ACS_CheckActorFlag(const char *flag, UINT32 *result, unsigned *type) +{ + if (result) + *result = 0; + if (type) + *type = 0; + + // Could be optimized but I don't care right now. First check regular flags + for (unsigned i = 0; MOBJFLAG_LIST[i]; i++) + { + if (fastcmp(flag, MOBJFLAG_LIST[i])) + { + if (result) + *result = (1 << i); + if (type) + *type = 1; + return true; + } + } + + // Now check flags2 + for (unsigned i = 0; MOBJFLAG2_LIST[i]; i++) + { + if (fastcmp(flag, MOBJFLAG2_LIST[i])) + { + if (result) + *result = (1 << i); + if (type) + *type = 2; + return true; + } + } + + // Finally, check extra flags + for (unsigned i = 0; MOBJEFLAG_LIST[i]; i++) + { + if (fastcmp(flag, MOBJEFLAG_LIST[i])) + { + if (result) + *result = (1 << i); + if (type) + *type = 3; + return true; + } + } + + return false; +} + +/*-------------------------------------------------- + static angle_t ACS_FixedToAngle(int angle) + + Converts a fixed-point angle to a Doom angle. +--------------------------------------------------*/ +static angle_t ACS_FixedToAngle(fixed_t angle) +{ + return FixedAngle(angle * 360); +} + +/*-------------------------------------------------- + static void ACS_AngleToFixed(ACSVM::Thread *thread, angle_t angle) + + Converts a Doom angle to a fixed-point angle. +--------------------------------------------------*/ +static fixed_t ACS_AngleToFixed(angle_t angle) +{ + return FixedDiv(AngleFixed(angle), 360*FRACUNIT); +} + /*-------------------------------------------------- static bool ACS_CountThing(mobj_t *mobj, mobjtype_t type) @@ -553,11 +637,11 @@ bool CallFunc_ThingCount(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM:: { // Exit early. CONS_Alert(CONS_WARNING, - "Couldn't find object type \"%s\" for ThingCount.\n", + "Couldn't find actor class \"%s\" for ThingCount.\n", className ); - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -670,7 +754,7 @@ bool CallFunc_CameraWait(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM:: ACS_TAGTYPE_CAMERA }; - thread->dataStk.push(0); + NO_RETURN(thread); return true; // Execution interrupted } @@ -917,7 +1001,7 @@ bool CallFunc_SectorSound(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM: sfxName ); - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -976,7 +1060,7 @@ bool CallFunc_AmbientSound(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM sfxName ); - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -1116,7 +1200,7 @@ bool CallFunc_ChangeSky(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::W P_SetupLevelSky(argV[0], argV[1]); - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -1164,7 +1248,7 @@ bool CallFunc_ThingSound(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM:: sfxName ); - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -1514,7 +1598,7 @@ bool CallFunc_HasUnlockable(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSV if (id >= MAXUNLOCKABLES) { - CONS_Printf("Bad unlockable ID %d\n", id); + CONS_Alert(CONS_WARNING, "HasUnlockable: Bad unlockable ID %d.\n", id); } else { @@ -1574,7 +1658,7 @@ bool CallFunc_PlayerSkin(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM:: return false; } - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -1626,54 +1710,6 @@ bool CallFunc_PlayerExiting(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSV return false; } -/*-------------------------------------------------- - bool CallFunc_SetObjectDye(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) - - Dyes the activating object. ---------------------------------------------------*/ -bool CallFunc_SetObjectDye(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) -{ - auto info = &static_cast(thread)->info; - - (void)argC; - - if ((info != NULL) - && (info->mo != NULL && P_MobjWasRemoved(info->mo) == false)) - { - var1 = 0; - var2 = argV[0]; - A_Dye(info->mo); - } - - thread->dataStk.push(0); - - return false; -} - -/*-------------------------------------------------- - bool CallFunc_GetObjectDye(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) - - Returns the activating object's current dye. ---------------------------------------------------*/ -bool CallFunc_GetObjectDye(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) -{ - Environment *env = &ACSEnv; - auto info = &static_cast(thread)->info; - UINT16 dye = SKINCOLOR_NONE; - - (void)argV; - (void)argC; - - if ((info != NULL) - && (info->mo != NULL && P_MobjWasRemoved(info->mo) == false)) - { - dye = (info->mo->player != NULL) ? info->mo->player->powers[pw_dye] : info->mo->color; - } - - thread->dataStk.push(~env->getString( skincolors[dye].name )->idx); - return false; -} - /*-------------------------------------------------- bool CallFunc_Teleport(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) @@ -1694,7 +1730,7 @@ bool CallFunc_Teleport(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Wo S_StartSound(dest, sfx_mixup); // Play the 'bowrwoosh!' sound } - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -1713,7 +1749,7 @@ bool CallFunc_SetViewpoint(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM mobj_t *altview = P_FindMobjFromTID(argV[0], NULL, info->mo); if (!altview) { - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -1730,7 +1766,7 @@ bool CallFunc_SetViewpoint(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM player_t *player = info->mo->player; if (!player) { - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -1750,7 +1786,64 @@ bool CallFunc_SetViewpoint(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM } } - thread->dataStk.push(0); + NO_RETURN(thread); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_SpawnObject(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Spawns an actor. +--------------------------------------------------*/ +bool CallFunc_SpawnObject(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + ACSVM::String *str = thread->scopeMap->getString( argV[0] ); + if (!str->str || str->len == 0) + { + CONS_Alert(CONS_WARNING, "Spawn actor class was not provided.\n"); + + NO_RETURN(thread); + + return false; + } + + const char *className = str->str; + + mobjtype_t mobjType = MT_NULL; + + if (ACS_GetMobjTypeFromString(className, &mobjType) == false) + { + CONS_Alert(CONS_WARNING, + "Couldn't find actor class \"%s\" for Spawn.\n", + className + ); + } + else + { + fixed_t x = argV[1]; + fixed_t y = argV[2]; + fixed_t z = argV[3]; + + mobj_t *mobj = P_SpawnMobj(x, y, z, mobjType); + if (!P_MobjWasRemoved(mobj)) + { + if (argC >= 5) + P_SetThingTID(mobj, argV[4]); + + if (argC >= 6) + mobj->angle = ACS_FixedToAngle(argV[5]); + } + else + { + CONS_Alert(CONS_WARNING, + "Spawn: Couldn't spawn actor class \"%s\".\n", + className + ); + } + } + + NO_RETURN(thread); return false; } @@ -1779,7 +1872,7 @@ bool CallFunc_TrackObjectAngle(ACSVM::Thread *thread, const ACSVM::Word *argV, A mobj->cusval = mobj->cvmem = failuredelay; // cusval = tics to allow failure before line trigger; cvmem = decrement timer } - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -1801,7 +1894,7 @@ bool CallFunc_StopTrackingObjectAngle(ACSVM::Thread *thread, const ACSVM::Word * mobj->lastlook = mobj->cvmem = mobj->cusval = mobj->extravalue1 = mobj->extravalue2 = 0; } - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -2011,7 +2104,827 @@ bool CallFunc_SetLineRenderStyle(ACSVM::Thread *thread, const ACSVM::Word *argV, line->alpha = alpha; } - thread->dataStk.push(0); + NO_RETURN(thread); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_GetObjectX(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Returns the X position of an actor. +--------------------------------------------------*/ +bool CallFunc_GetObjectX(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + auto info = &static_cast(thread)->info; + + fixed_t value = 0; + + mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo); + if (mobj != NULL && P_MobjWasRemoved(mobj) == false) + { + value = mobj->x; + } + + thread->dataStk.push(value); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_GetObjectY(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Returns the Y position of an actor. +--------------------------------------------------*/ +bool CallFunc_GetObjectY(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + auto info = &static_cast(thread)->info; + + fixed_t value = 0; + + mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo); + if (mobj != NULL && P_MobjWasRemoved(mobj) == false) + { + value = mobj->y; + } + + thread->dataStk.push(value); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_GetObjectZ(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Returns the Z position of an actor. +--------------------------------------------------*/ +bool CallFunc_GetObjectZ(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + auto info = &static_cast(thread)->info; + + fixed_t value = 0; + + mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo); + if (mobj != NULL && P_MobjWasRemoved(mobj) == false) + { + value = mobj->z; + } + + thread->dataStk.push(value); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_GetObjectVelX(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Returns the X velocity of an actor. +--------------------------------------------------*/ +bool CallFunc_GetObjectVelX(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + auto info = &static_cast(thread)->info; + + fixed_t value = 0; + + mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo); + if (mobj != NULL && P_MobjWasRemoved(mobj) == false) + { + value = mobj->momx; + } + + thread->dataStk.push(value); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_GetObjectVelY(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Returns the Y velocity of an actor. +--------------------------------------------------*/ +bool CallFunc_GetObjectVelY(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + auto info = &static_cast(thread)->info; + + fixed_t value = 0; + + mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo); + if (mobj != NULL && P_MobjWasRemoved(mobj) == false) + { + value = mobj->momy; + } + + thread->dataStk.push(value); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_GetObjectVelZ(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Returns the Z velocity of an actor. +--------------------------------------------------*/ +bool CallFunc_GetObjectVelZ(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + auto info = &static_cast(thread)->info; + + fixed_t value = 0; + + mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo); + if (mobj != NULL && P_MobjWasRemoved(mobj) == false) + { + value = mobj->momz; + } + + thread->dataStk.push(value); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_GetObjectAngle(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Returns the yaw of an actor. +--------------------------------------------------*/ +bool CallFunc_GetObjectAngle(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + auto info = &static_cast(thread)->info; + + fixed_t value = 0; + + mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo); + if (mobj != NULL && P_MobjWasRemoved(mobj) == false) + { + value = ACS_AngleToFixed(mobj->angle); + } + + thread->dataStk.push(value); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_GetObjectRoll(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Returns the roll of an actor. +--------------------------------------------------*/ +bool CallFunc_GetObjectRoll(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + auto info = &static_cast(thread)->info; + + fixed_t value = 0; + + mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo); + if (mobj != NULL && P_MobjWasRemoved(mobj) == false) + { + value = ACS_AngleToFixed(mobj->roll); + } + + thread->dataStk.push(value); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_GetObjectPitch(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Returns the pitch of an actor. +--------------------------------------------------*/ +bool CallFunc_GetObjectPitch(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + auto info = &static_cast(thread)->info; + + fixed_t value = 0; + + mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo); + if (mobj != NULL && P_MobjWasRemoved(mobj) == false) + { + value = ACS_AngleToFixed(mobj->pitch); + } + + thread->dataStk.push(value); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_GetObjectFloorZ(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Returns the highest floor point underneath the actor. +--------------------------------------------------*/ +bool CallFunc_GetObjectFloorZ(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + auto info = &static_cast(thread)->info; + + fixed_t value = 0; + + mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo); + if (mobj != NULL && P_MobjWasRemoved(mobj) == false) + { + value = ACS_AngleToFixed(mobj->pitch); + } + + thread->dataStk.push(value); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_GetObjectCeilingZ(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Returns the lowest ceiling point above the actor. +--------------------------------------------------*/ +bool CallFunc_GetObjectCeilingZ(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + auto info = &static_cast(thread)->info; + + fixed_t value = 0; + + mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo); + if (mobj != NULL && P_MobjWasRemoved(mobj) == false) + { + value = mobj->ceilingz; + } + + thread->dataStk.push(value); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_GetObjectFloorTexture(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Returns the texture of the floor where the actor is currently on. +--------------------------------------------------*/ +bool CallFunc_GetObjectFloorTexture(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + Environment *env = &ACSEnv; + auto info = &static_cast(thread)->info; + + INT32 floorpic = 0; + + mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo); + if (mobj != NULL && P_MobjWasRemoved(mobj) == false) + { + INT32 picnum = P_FloorPicAtPos(mobj->x, mobj->y, mobj->z, mobj->height); + if (picnum != -1) + { + floorpic = ~env->getString( levelflats[picnum].name )->idx; + } + } + + thread->dataStk.push(floorpic); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_GetObjectLightLevel(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Returns the light level of the place where the actor is currently in. +--------------------------------------------------*/ +bool CallFunc_GetObjectLightLevel(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + auto info = &static_cast(thread)->info; + + INT32 lightlevel = 0; + + mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo); + if (mobj != NULL && P_MobjWasRemoved(mobj) == false) + { + lightlevel = P_GetLightLevelFromSectorAt(mobj->subsector->sector, mobj->x, mobj->y, mobj->z); + } + + thread->dataStk.push(lightlevel); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_CheckObjectState(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Checks if the actor with the matching TID is in the specified state. If said TID is zero, this checks the activator. +--------------------------------------------------*/ +bool CallFunc_CheckObjectState(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + auto info = &static_cast(thread)->info; + + bool inState = false; + + mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo); + if (mobj != NULL && P_MobjWasRemoved(mobj) == false) + { + statenum_t stateNum = S_NULL; + bool success = ACS_GetStateFromString(thread->scopeMap->getString( argV[1] )->str, &stateNum); + if (success == true) + { + if (mobj->state == &states[stateNum]) + { + inState = true; + } + } + } + + thread->dataStk.push(inState); + return false; +} + +/*-------------------------------------------------- + bool CallFunc_CheckObjectFlag(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Checks if the actor with the matching TID has a specific flag. If said TID is zero, this checks the activator. +--------------------------------------------------*/ +bool CallFunc_CheckObjectFlag(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + auto info = &static_cast(thread)->info; + + (void)argC; + + mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo); + + const char *flagName = thread->scopeMap->getString( argV[1] )->str; + + bool hasFlag = false; + + if (mobj != NULL && P_MobjWasRemoved(mobj) == false) + { + if (ACS_CheckActorFlag(flagName, NULL, NULL) == true) + { + hasFlag = true; + } + else + { + CONS_Alert(CONS_WARNING, "CheckActorFlag: no actor flag named \"%s\".\n", flagName); + } + } + + thread->dataStk.push(hasFlag); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_GetObjectClass(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Returns the class name of the actor. +--------------------------------------------------*/ +bool CallFunc_GetObjectClass(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + Environment *env = &ACSEnv; + auto info = &static_cast(thread)->info; + + INT32 mobjClass = 0; + + mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo); + if (mobj != NULL && P_MobjWasRemoved(mobj) == false) + { + if (mobj->type >= MT_FIRSTFREESLOT) + { + std::string prefix = "MT_"; + std::string full = prefix + FREE_MOBJS[mobj->type - MT_FIRSTFREESLOT]; + mobjClass = static_cast( ~env->getString( full.c_str() )->idx ); + } + else + { + mobjClass = static_cast( ~env->getString( MOBJTYPE_LIST[ mobj->type ] )->idx ); + } + } + + thread->dataStk.push(mobjClass); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_GetObjectDye(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Returns the actor's dye. +--------------------------------------------------*/ +bool CallFunc_GetObjectDye(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + Environment *env = &ACSEnv; + auto info = &static_cast(thread)->info; + UINT16 dye = SKINCOLOR_NONE; + + (void)argC; + + mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo); + + if (mobj != NULL && P_MobjWasRemoved(mobj) == false) + { + dye = (mobj->player != NULL) ? mobj->player->powers[pw_dye] : mobj->color; + } + + thread->dataStk.push(~env->getString( skincolors[dye].name )->idx); + return false; +} + +/*-------------------------------------------------- + bool CallFunc_SetObjectPosition(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Sets the position of the actor with the matching TID. If said TID is zero, this affects the activator. +--------------------------------------------------*/ +bool CallFunc_SetObjectPosition(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + // SetActorPosition's signature makes the 'fog' parameter required. Sad! + // So we just ignore it. + auto info = &static_cast(thread)->info; + bool success = false; + + (void)argC; + + mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo); + + fixed_t x = argV[1]; + fixed_t y = argV[2]; + fixed_t z = argV[3]; + + if (mobj != NULL && P_MobjWasRemoved(mobj) == false && P_CheckPosition(mobj, x, y) == true) + { + fixed_t floorz = P_FloorzAtPos(x, y, z, mobj->height); + fixed_t ceilingz = P_CeilingzAtPos(x, y, z, mobj->height); + if (z >= floorz && (z + mobj->height) <= ceilingz) + { + P_SetOrigin(mobj, x, y, z); + success = true; + } + } + + thread->dataStk.push(success); + return false; +} + +/*-------------------------------------------------- + bool CallFunc_SetObjectVelocity(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Sets the velocity of every actor with the matching TID. If said TID is zero, this affects the activator. +--------------------------------------------------*/ +bool CallFunc_SetObjectVelocity(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + auto info = &static_cast(thread)->info; + + fixed_t velX = argV[1]; + fixed_t velY = argV[2]; + fixed_t velZ = argV[3]; + + bool add = argC >= 5 ? (argV[4] != 0) : false; + + mobj_t *mobj = nullptr; + + while ((mobj = P_FindMobjFromTID(argV[0], mobj, info->mo)) != nullptr) + { + if (add) + { + mobj->momx += velX; + mobj->momy += velY; + mobj->momz += velZ; + } + else + { + mobj->momx = velX; + mobj->momy = velY; + mobj->momz = velZ; + } + } + + NO_RETURN(thread); + return false; +} + +/*-------------------------------------------------- + bool CallFunc_SetObjectAngle(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Sets the angle of every actor with the matching TID. If said TID is zero, this affects the activator. +--------------------------------------------------*/ +bool CallFunc_SetObjectAngle(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + auto info = &static_cast(thread)->info; + + (void)argC; + + angle_t angle = ACS_FixedToAngle(argV[1]); + + mobj_t *mobj = nullptr; + + while ((mobj = P_FindMobjFromTID(argV[0], mobj, info->mo)) != nullptr) + { + mobj->angle = angle; + } + + NO_RETURN(thread); + return false; +} + +/*-------------------------------------------------- + bool CallFunc_SetObjectRoll(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Sets the roll of every actor with the matching TID. If said TID is zero, this affects the activator. +--------------------------------------------------*/ +bool CallFunc_SetObjectRoll(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + auto info = &static_cast(thread)->info; + + (void)argC; + + angle_t roll = ACS_FixedToAngle(argV[1]); + + mobj_t *mobj = nullptr; + + while ((mobj = P_FindMobjFromTID(argV[0], mobj, info->mo)) != nullptr) + { + mobj->roll = roll; + } + + NO_RETURN(thread); + return false; +} + +/*-------------------------------------------------- + bool CallFunc_SetObjectPitch(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Sets the pitch of every actor with the matching TID. If said TID is zero, this affects the activator. +--------------------------------------------------*/ +bool CallFunc_SetObjectPitch(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + auto info = &static_cast(thread)->info; + + (void)argC; + + angle_t pitch = ACS_FixedToAngle(argV[1]); + + mobj_t *mobj = nullptr; + + while ((mobj = P_FindMobjFromTID(argV[0], mobj, info->mo)) != nullptr) + { + mobj->pitch = pitch; + } + + NO_RETURN(thread); + return false; +} + +/*-------------------------------------------------- + bool CallFunc_SetObjectState(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Sets the state of every actor with the matching TID. If said TID is zero, this affects the activator. +--------------------------------------------------*/ +bool CallFunc_SetObjectState(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + auto info = &static_cast(thread)->info; + + (void)argC; + + int count = 0; + + mobj_t *mobj = nullptr; + + while ((mobj = P_FindMobjFromTID(argV[0], mobj, info->mo)) != nullptr) + { + statenum_t newState = S_NULL; + bool success = ACS_GetStateFromString(thread->scopeMap->getString( argV[1] )->str, &newState); + if (success == true) + { + P_SetMobjState(mobj, newState); + count++; + } + } + + thread->dataStk.push(count); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_SetObjectFlag(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Toggles a flag for every actor with the matching TID. If said TID is zero, this affects the activator. +--------------------------------------------------*/ +bool CallFunc_SetObjectFlag(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + auto info = &static_cast(thread)->info; + + (void)argC; + + int count = 0; + + mobj_t *mobj = nullptr; + + const char *flagName = thread->scopeMap->getString( argV[1] )->str; + + bool add = !!argV[2]; + + while ((mobj = P_FindMobjFromTID(argV[0], mobj, info->mo)) != nullptr) + { + UINT32 flags = 0; + unsigned type = 0; + + if (ACS_CheckActorFlag(flagName, &flags, &type) == false) + { + CONS_Alert(CONS_WARNING, "SetActorFlag: no actor flag named \"%s\".\n", flagName); + break; + } + + // flags + if (type == 1) + { + if (add) + { + if ((flags & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (mobj->flags & (MF_NOBLOCKMAP|MF_NOSECTOR))) + { + P_UnsetThingPosition(mobj); + mobj->flags |= static_cast(flags); + if ((flags & MF_NOSECTOR) && sector_list) + { + P_DelSeclist(sector_list); + sector_list = NULL; + } + mobj->snext = NULL, mobj->sprev = NULL; + P_SetThingPosition(mobj); + } + else + { + mobj->flags |= static_cast(flags); + } + } + else + { + mobj->flags &= static_cast(~flags); + } + } + // flags2 + else if (type == 2) + { + if (add) + mobj->flags2 |= static_cast(flags); + else + mobj->flags2 &= static_cast(~flags); + } + // eflags + else if (type == 3) + { + if (add) + mobj->eflags |= static_cast(flags); + else + mobj->eflags &= static_cast(~flags); + } + + count++; + } + + thread->dataStk.push(count); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_SetObjectClass(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Sets the class of the actor with the matching TID. If said TID is zero, this affects the activator. +--------------------------------------------------*/ +bool CallFunc_SetObjectClass(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + auto info = &static_cast(thread)->info; + + (void)argC; + + ACSVM::String *str = thread->scopeMap->getString( argV[1] ); + if (!str->str || str->len == 0) + { + CONS_Alert(CONS_WARNING, "SetActorClass actor class was not provided.\n"); + + NO_RETURN(thread); + + return false; + } + + const char *className = str->str; + + mobjtype_t mobjType = MT_NULL; + + mobj_t *mobj = P_FindMobjFromTID(argV[0], NULL, info->mo); + + if (mobj != NULL && P_MobjWasRemoved(mobj) == false) + { + bool success = ACS_GetMobjTypeFromString(className, &mobjType); + + if (success == false) + { + // Exit early. + CONS_Alert(CONS_WARNING, + "Couldn't find actor class \"%s\" for SetActorClass.\n", + className + ); + + NO_RETURN(thread); + + return false; + } + + mobj->type = mobjType; + mobj->info = &mobjinfo[mobjType]; + } + + NO_RETURN(thread); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_SetObjectDye(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Dyes every actor with the matching TID. If said TID is zero, this affects the activator. +--------------------------------------------------*/ +bool CallFunc_SetObjectDye(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + auto info = &static_cast(thread)->info; + + mobj_t *mobj = nullptr; + + while ((mobj = P_FindMobjFromTID(argV[0], mobj, info->mo)) != nullptr) + { + var1 = 0; + var2 = argV[1]; + A_Dye(info->mo); + } + + NO_RETURN(thread); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_SetObjectSpecial(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Sets the special and arguments of every actor with the matching TID. If said TID is zero, this affects the activator. +--------------------------------------------------*/ +bool CallFunc_SetObjectSpecial(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + ACSVM::MapScope *map = thread->scopeMap; + + auto info = &static_cast(thread)->info; + + mobj_t *mobj = nullptr; + + while ((mobj = P_FindMobjFromTID(argV[0], mobj, info->mo)) != nullptr) + { + mobj->special = argV[1]; + + for (int i = 0; i < std::min((int)(argC - 2), NUM_SCRIPT_ARGS); i++) + { + mobj->script_args[i] = (INT32)argV[i + 2]; + } + + for (int i = 0; i < std::min((int)(argC - 2), NUM_SCRIPT_STRINGARGS); i++) + { + ACSVM::String *strPtr = map->getString(argV[i + 2]); + + size_t len = strPtr->len; + + if (len == 0) + { + Z_Free(mobj->script_stringargs[i]); + mobj->script_stringargs[i] = NULL; + continue; + } + + mobj->script_stringargs[i] = static_cast(Z_Realloc(mobj->script_stringargs[i], len + 1, PU_STATIC, nullptr)); + M_Memcpy(mobj->script_stringargs[i], strPtr->str, len + 1); + } + } + + NO_RETURN(thread); return false; } @@ -2031,8 +2944,6 @@ bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Wor const char *levelName = NULL; size_t levelLen = 0; - INT16 nextmap = 0; - (void)argC; map = thread->scopeMap; @@ -2046,28 +2957,32 @@ bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Wor { CONS_Alert(CONS_WARNING, "MapWarp level name was not provided.\n"); } - - if (levelName[0] == 'M' && levelName[1] == 'A' && levelName[2] == 'P' && levelName[5] == '\0') - { - nextmap = (INT16)M_MapNumber(levelName[3], levelName[4]); - } - - if (nextmap == 0) - { - CONS_Alert(CONS_WARNING, "MapWarp level %s is not valid or loaded.\n", levelName); - } else { - nextmapoverride = nextmap; + INT16 nextmap = 0; - if (argV[1] == 0) - skipstats = 1; + if (levelName[0] == 'M' && levelName[1] == 'A' && levelName[2] == 'P' && levelName[5] == '\0') + { + nextmap = (INT16)M_MapNumber(levelName[3], levelName[4]); + } - if (server) - SendNetXCmd(XD_EXITLEVEL, NULL, 0); + if (nextmap == 0) + { + CONS_Alert(CONS_WARNING, "MapWarp level %s is not valid or loaded.\n", levelName); + } + else + { + nextmapoverride = nextmap; + + if (argV[1] == 0) + skipstats = 1; + + if (server) + SendNetXCmd(XD_EXITLEVEL, NULL, 0); + } } - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -2152,7 +3067,7 @@ bool CallFunc_RemoveBot(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::W } } - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -2175,7 +3090,7 @@ bool CallFunc_ExitLevel(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::W if (server) SendNetXCmd(XD_EXITLEVEL, NULL, 0); - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -2195,7 +3110,7 @@ bool CallFunc_MusicPlay(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::W if (argC > 1 && argV[1] && !ACS_ActivatorIsLocal(thread)) { - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -2203,7 +3118,7 @@ bool CallFunc_MusicPlay(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::W S_StopMusic(); S_ChangeMusicInternal(map->getString(argV[0])->str, true); - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -2219,14 +3134,14 @@ bool CallFunc_MusicStopAll(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM if (argC > 0 && argV[0] && !ACS_ActivatorIsLocal(thread)) { - thread->dataStk.push(0); + NO_RETURN(thread); return false; } S_StopMusic(); - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -2243,7 +3158,7 @@ bool CallFunc_MusicRestore(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0); - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -2262,7 +3177,7 @@ bool CallFunc_MusicDim(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Wo S_FadeOutStopMusic(fade); - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -2506,7 +3421,7 @@ bool CallFunc_SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, AC } - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -2821,7 +3736,7 @@ bool CallFunc_SetSideProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, AC } - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -3108,7 +4023,7 @@ bool CallFunc_SetSectorProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, } - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -3120,14 +4035,6 @@ bool CallFunc_SetSectorProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, --------------------------------------------------*/ enum { - THING_PROP_X, - THING_PROP_Y, - THING_PROP_Z, - THING_PROP_TYPE, - THING_PROP_ANGLE, - THING_PROP_PITCH, - THING_PROP_ROLL, - THING_PROP_SPRITEROLL, THING_PROP_FRAME, THING_PROP_SPRITE, THING_PROP_SPRITE2, @@ -3136,18 +4043,10 @@ enum THING_PROP_SPRITEYSCALE, THING_PROP_SPRITEXOFFSET, THING_PROP_SPRITEYOFFSET, - THING_PROP_FLOORZ, - THING_PROP_CEILINGZ, + THING_PROP_SPRITEROLL, THING_PROP_RADIUS, THING_PROP_HEIGHT, - THING_PROP_MOMX, - THING_PROP_MOMY, - THING_PROP_MOMZ, THING_PROP_TICS, - THING_PROP_STATE, - THING_PROP_FLAGS, - THING_PROP_FLAGS2, - THING_PROP_EFLAGS, THING_PROP_SKIN, THING_PROP_COLOR, THING_PROP_HEALTH, @@ -3221,22 +4120,6 @@ bool CallFunc_GetThingProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, A break; \ } -#define PROP_TYPE(x, y) \ - case x: \ - { \ - if (mobj->y >= MT_FIRSTFREESLOT) \ - { \ - std::string prefix = "MT_"; \ - std::string full = prefix + FREE_MOBJS[mobj->y - MT_FIRSTFREESLOT]; \ - value = static_cast( ~env->getString( full.c_str() )->idx ); \ - } \ - else \ - { \ - value = static_cast( ~env->getString( MOBJTYPE_LIST[ mobj->y ] )->idx ); \ - } \ - break; \ - } - #define PROP_SPR(x, y) \ case x: \ { \ @@ -3251,23 +4134,6 @@ bool CallFunc_GetThingProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, A break; \ } -#define PROP_STATE(x, y) \ - case x: \ - { \ - statenum_t stateID = static_cast(mobj->y - states); \ - if (stateID >= S_FIRSTFREESLOT) \ - { \ - std::string prefix = "S_"; \ - std::string full = prefix + FREE_STATES[stateID - S_FIRSTFREESLOT]; \ - value = static_cast( ~env->getString( full.c_str() )->idx ); \ - } \ - else \ - { \ - value = static_cast( ~env->getString( STATE_LIST[ stateID ] )->idx ); \ - } \ - break; \ - } - #define PROP_SKIN(x, y) \ case x: \ { \ @@ -3298,14 +4164,6 @@ bool CallFunc_GetThingProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, A switch (property) { - PROP_INT(THING_PROP_X, x) - PROP_INT(THING_PROP_Y, y) - PROP_INT(THING_PROP_Z, z) - PROP_TYPE(THING_PROP_TYPE, type) - PROP_ANGLE(THING_PROP_ANGLE, angle) - PROP_ANGLE(THING_PROP_PITCH, pitch) - PROP_ANGLE(THING_PROP_ROLL, roll) - PROP_ANGLE(THING_PROP_SPRITEROLL, spriteroll) PROP_INT(THING_PROP_FRAME, frame) PROP_SPR(THING_PROP_SPRITE, sprite) PROP_SPR2(THING_PROP_SPRITE2, sprite2) @@ -3314,18 +4172,10 @@ bool CallFunc_GetThingProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, A PROP_INT(THING_PROP_SPRITEYSCALE, spriteyscale) PROP_INT(THING_PROP_SPRITEXOFFSET, spritexoffset) PROP_INT(THING_PROP_SPRITEYOFFSET, spriteyoffset) - PROP_INT(THING_PROP_FLOORZ, floorz) - PROP_INT(THING_PROP_CEILINGZ, ceilingz) + PROP_ANGLE(THING_PROP_SPRITEROLL, spriteroll) PROP_INT(THING_PROP_RADIUS, radius) PROP_INT(THING_PROP_HEIGHT, height) - PROP_INT(THING_PROP_MOMX, momx) - PROP_INT(THING_PROP_MOMY, momy) - PROP_INT(THING_PROP_MOMZ, momz) PROP_INT(THING_PROP_TICS, tics) - PROP_STATE(THING_PROP_STATE, state) - PROP_INT(THING_PROP_FLAGS, flags) - PROP_INT(THING_PROP_FLAGS2, flags2) - PROP_INT(THING_PROP_EFLAGS, eflags) PROP_SKIN(THING_PROP_SKIN, skin) PROP_COLOR(THING_PROP_COLOR, color) PROP_INT(THING_PROP_HEALTH, health) @@ -3364,10 +4214,8 @@ bool CallFunc_GetThingProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, A #undef PROP_MOBJ #undef PROP_COLOR #undef PROP_SKIN -#undef PROP_STATE #undef PROP_SPR2 #undef PROP_SPR -#undef PROP_TYPE #undef PROP_ANGLE #undef PROP_STR #undef PROP_INT @@ -3439,23 +4287,6 @@ bool CallFunc_SetThingProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, A break; \ } -#define PROP_TYPE(x, y) \ - case x: \ - { \ - if (mobj->player == NULL) \ - { \ - mobjtype_t newType = mobj->y; \ - bool success = ACS_GetMobjTypeFromString(thread->scopeMap->getString( value )->str, &newType); \ - if (success == true) \ - { \ - mobj->y = newType; \ - mobj->info = &mobjinfo[newType]; \ - P_SetScale(mobj, mobj->scale, false); \ - } \ - } \ - break; \ - } - #define PROP_SPR(x, y) \ case x: \ { \ @@ -3480,18 +4311,6 @@ bool CallFunc_SetThingProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, A break; \ } -#define PROP_STATE(x, y) \ - case x: \ - { \ - statenum_t newState = static_cast(mobj->y - states); \ - bool success = ACS_GetStateFromString(thread->scopeMap->getString( value )->str, &newState); \ - if (success == true) \ - { \ - P_SetMobjState(mobj, newState); \ - } \ - break; \ - } - #define PROP_SKIN(x, y) \ case x: \ { \ @@ -3531,38 +4350,8 @@ bool CallFunc_SetThingProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, A break; \ } -#define PROP_FLAGS(x, y) \ - case x: \ - { \ - if ((value & (MF_NOBLOCKMAP|MF_NOSECTOR)) != (mobj->y & (MF_NOBLOCKMAP|MF_NOSECTOR))) \ - { \ - P_UnsetThingPosition(mobj); \ - mobj->y = value; \ - if ((value & MF_NOSECTOR) && sector_list) \ - { \ - P_DelSeclist(sector_list); \ - sector_list = NULL; \ - } \ - mobj->snext = NULL, mobj->sprev = NULL; \ - P_SetThingPosition(mobj); \ - } \ - else \ - { \ - mobj->y = value; \ - } \ - break; \ - } - switch (property) { - PROP_READONLY(THING_PROP_X, x) - PROP_READONLY(THING_PROP_Y, y) - PROP_READONLY(THING_PROP_Z, z) - PROP_TYPE(THING_PROP_TYPE, type) - PROP_ANGLE(THING_PROP_ANGLE, angle) - PROP_ANGLE(THING_PROP_PITCH, pitch) - PROP_ANGLE(THING_PROP_ROLL, roll) - PROP_ANGLE(THING_PROP_SPRITEROLL, spriteroll) PROP_INT(THING_PROP_FRAME, frame) PROP_SPR(THING_PROP_SPRITE, sprite) PROP_SPR2(THING_PROP_SPRITE2, sprite2) @@ -3571,18 +4360,10 @@ bool CallFunc_SetThingProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, A PROP_INT(THING_PROP_SPRITEYSCALE, spriteyscale) PROP_INT(THING_PROP_SPRITEXOFFSET, spritexoffset) PROP_INT(THING_PROP_SPRITEYOFFSET, spriteyoffset) - PROP_INT(THING_PROP_FLOORZ, floorz) - PROP_INT(THING_PROP_CEILINGZ, ceilingz) + PROP_ANGLE(THING_PROP_SPRITEROLL, spriteroll) PROP_READONLY(THING_PROP_RADIUS, radius) PROP_READONLY(THING_PROP_HEIGHT, height) - PROP_INT(THING_PROP_MOMX, momx) - PROP_INT(THING_PROP_MOMY, momy) - PROP_INT(THING_PROP_MOMZ, momz) PROP_INT(THING_PROP_TICS, tics) - PROP_STATE(THING_PROP_STATE, state) - PROP_FLAGS(THING_PROP_FLAGS, flags) - PROP_INT(THING_PROP_FLAGS2, flags2) - PROP_INT(THING_PROP_EFLAGS, eflags) PROP_SKIN(THING_PROP_SKIN, skin) PROP_COLOR(THING_PROP_COLOR, color) PROP_INT(THING_PROP_HEALTH, health) @@ -3620,15 +4401,12 @@ bool CallFunc_SetThingProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, A mobj = P_FindMobjFromTID(tag, mobj, info->mo); -#undef PROP_FLAGS #undef PROP_SCALE #undef PROP_MOBJ #undef PROP_COLOR #undef PROP_SKIN -#undef PROP_STATE #undef PROP_SPR2 #undef PROP_SPR -#undef PROP_TYPE #undef PROP_ANGLE #undef PROP_STR #undef PROP_INT @@ -3636,7 +4414,7 @@ bool CallFunc_SetThingProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, A } - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -3826,7 +4604,7 @@ bool CallFunc_GivePowerUp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM: } } - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -3963,7 +4741,7 @@ bool CallFunc_GiveAmmo(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Wo CONS_Alert(CONS_WARNING, "GiveAmmo weapon %d out of range (expected 0 - %d).\n", weapon, WEAPON__MAX-1); } - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -4009,7 +4787,7 @@ bool CallFunc_TakeAmmo(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Wo CONS_Alert(CONS_WARNING, "TakeAmmo weapon %d out of range (expected 0 - %d).\n", weapon, WEAPON__MAX-1); } - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -4040,7 +4818,7 @@ bool CallFunc_DoSuperTransformation(ACSVM::Thread *thread, const ACSVM::Word *ar } } - thread->dataStk.push(0); + NO_RETURN(thread); return false; } @@ -4072,29 +4850,354 @@ bool CallFunc_DoSuperDetransformation(ACSVM::Thread *thread, const ACSVM::Word * } } - thread->dataStk.push(0); + NO_RETURN(thread); return false; } /*-------------------------------------------------- - static angle_t ACS_GetAngle(int angle) + bool CallFunc_GiveRings(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) - Converts a fixed-point angle to a Doom angle. + Awards a specific amount of rings to the activator. --------------------------------------------------*/ -static angle_t ACS_GetAngle(int angle) +bool CallFunc_GiveRings(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) { - return FixedAngle(angle * 360); + (void)argC; + + auto info = &static_cast(thread)->info; + + INT32 numRings = argV[0]; + + if ((info != NULL) + && (info->mo != NULL && P_MobjWasRemoved(info->mo) == false) + && (info->mo->player != NULL)) + { + P_GivePlayerRings(info->mo->player, numRings); + } + else + { + for (UINT8 i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + P_GivePlayerRings(&players[i], numRings); + } + } + + NO_RETURN(thread); + + return false; } /*-------------------------------------------------- - static void ACS_PushAngle(ACSVM::Thread *thread, angle_t angle) + bool CallFunc_GiveSpheres(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) - Pushes an angle to the stack (really a fixed-point number.) + Awards a specific amount of spheres to the activator. --------------------------------------------------*/ -static void ACS_PushAngle(ACSVM::Thread *thread, angle_t angle) +bool CallFunc_GiveSpheres(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) { - thread->dataStk.push(FixedDiv(AngleFixed(angle), 360*FRACUNIT)); + (void)argC; + + auto info = &static_cast(thread)->info; + + INT32 numSpheres = argV[0]; + + if ((info != NULL) + && (info->mo != NULL && P_MobjWasRemoved(info->mo) == false) + && (info->mo->player != NULL)) + { + P_GivePlayerSpheres(info->mo->player, numSpheres); + } + else + { + for (UINT8 i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + P_GivePlayerSpheres(&players[i], numSpheres); + } + } + + NO_RETURN(thread); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_GiveLives(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Awards a specific amount of lives to the activator. +--------------------------------------------------*/ +bool CallFunc_GiveLives(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + auto info = &static_cast(thread)->info; + + INT32 numLives = argV[0]; + + if ((info != NULL) + && (info->mo != NULL && P_MobjWasRemoved(info->mo) == false) + && (info->mo->player != NULL)) + { + P_GivePlayerLives(info->mo->player, numLives); + } + else + { + for (UINT8 i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + P_GivePlayerLives(&players[i], numLives); + } + } + + NO_RETURN(thread); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_GiveScore(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Awards score to the activator. +--------------------------------------------------*/ +bool CallFunc_GiveScore(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + auto info = &static_cast(thread)->info; + + INT32 score = argV[0]; + + if ((info != NULL) + && (info->mo != NULL && P_MobjWasRemoved(info->mo) == false) + && (info->mo->player != NULL)) + { + P_AddPlayerScore(info->mo->player, score); + } + else + { + for (UINT8 i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + P_AddPlayerScore(&players[i], score); + } + } + + NO_RETURN(thread); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_DropFlag(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Makes the activator drop their flag (or all players if there was no activator.) +--------------------------------------------------*/ +bool CallFunc_DropFlag(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + (void)argV; + + auto info = &static_cast(thread)->info; + + if ((info != NULL) + && (info->mo != NULL && P_MobjWasRemoved(info->mo) == false) + && (info->mo->player != NULL)) + { + P_PlayerFlagBurst(info->mo->player, false); + } + else + { + for (UINT8 i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + P_PlayerFlagBurst(&players[i], false); + } + } + + NO_RETURN(thread); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_TossFlag(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Makes the activator toss their flag (or all players if there was no activator.) +--------------------------------------------------*/ +bool CallFunc_TossFlag(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + (void)argV; + + auto info = &static_cast(thread)->info; + + if ((info != NULL) + && (info->mo != NULL && P_MobjWasRemoved(info->mo) == false) + && (info->mo->player != NULL)) + { + P_PlayerFlagBurst(info->mo->player, true); + } + else + { + for (UINT8 i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + P_PlayerFlagBurst(&players[i], true); + } + } + + NO_RETURN(thread); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_DropEmeralds(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Makes the activator drop their emeralds (or all players if there was no activator.) +--------------------------------------------------*/ +bool CallFunc_DropEmeralds(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + (void)argV; + + auto info = &static_cast(thread)->info; + + if ((info != NULL) + && (info->mo != NULL && P_MobjWasRemoved(info->mo) == false) + && (info->mo->player != NULL)) + { + P_PlayerEmeraldBurst(info->mo->player, false); + } + else + { + for (UINT8 i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + P_PlayerEmeraldBurst(&players[i], false); + } + } + + NO_RETURN(thread); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_TossEmeralds(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Makes the activator toss their emeralds (or all players if there was no activator.) +--------------------------------------------------*/ +bool CallFunc_TossEmeralds(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + (void)argV; + + auto info = &static_cast(thread)->info; + + if ((info != NULL) + && (info->mo != NULL && P_MobjWasRemoved(info->mo) == false) + && (info->mo->player != NULL)) + { + P_PlayerEmeraldBurst(info->mo->player, true); + } + else + { + for (UINT8 i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + P_PlayerEmeraldBurst(&players[i], true); + } + } + + NO_RETURN(thread); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_PlayerHoldingFlag(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Checks if the given player is holding a flag. +--------------------------------------------------*/ +bool CallFunc_PlayerHoldingFlag(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + INT32 playernum = argV[0]; + INT32 gotflag = argV[1]; + + bool isHoldingFlag = false; + + if (playernum < 0 || playernum >= MAXPLAYERS) + { + CONS_Alert(CONS_WARNING, "PlayerHoldingFlag player %d out of range (expected 0 - %d).\n", playernum, MAXPLAYERS-1); + } + else + { + if (players[playernum].gotflag & gotflag) + isHoldingFlag = true; + } + + thread->dataStk.push(isHoldingFlag); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_PlayerIsIt(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Checks if the given player is it. +--------------------------------------------------*/ +bool CallFunc_PlayerIsIt(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + INT32 playernum = argV[0]; + + bool isIt = false; + + if (playernum < 0 || playernum >= MAXPLAYERS) + { + CONS_Alert(CONS_WARNING, "PlayerIsIt player %d out of range (expected 0 - %d).\n", playernum, MAXPLAYERS-1); + } + else + { + if (players[playernum].pflags & PF_TAGIT) + isIt = true; + } + + thread->dataStk.push(isIt); + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_PlayerFinished(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Checks if the activator finished the level. +--------------------------------------------------*/ +bool CallFunc_PlayerFinished(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + (void)argC; + + INT32 playernum = argV[0]; + + bool finished = false; + + if (playernum < 0 || playernum >= MAXPLAYERS) + { + CONS_Alert(CONS_WARNING, "PlayerFinished player %d out of range (expected 0 - %d).\n", playernum, MAXPLAYERS-1); + } + else + { + if (players[playernum].pflags & PF_FINISHED) + finished = true; + } + + thread->dataStk.push(finished); + + return false; } /*-------------------------------------------------- @@ -4105,7 +5208,7 @@ static void ACS_PushAngle(ACSVM::Thread *thread, angle_t angle) bool CallFunc_Sin(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) { (void)argC; - ACS_PushAngle(thread, FINESINE((ACS_GetAngle(argV[0])>>ANGLETOFINESHIFT) & FINEMASK)); + thread->dataStk.push(ACS_AngleToFixed(FINESINE((ACS_FixedToAngle(argV[0])>>ANGLETOFINESHIFT) & FINEMASK))); return false; } @@ -4117,7 +5220,7 @@ bool CallFunc_Sin(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word ar bool CallFunc_Cos(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) { (void)argC; - ACS_PushAngle(thread, FINECOSINE((ACS_GetAngle(argV[0])>>ANGLETOFINESHIFT) & FINEMASK)); + thread->dataStk.push(ACS_AngleToFixed(FINECOSINE((ACS_FixedToAngle(argV[0])>>ANGLETOFINESHIFT) & FINEMASK))); return false; } @@ -4129,7 +5232,7 @@ bool CallFunc_Cos(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word ar bool CallFunc_Tan(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) { (void)argC; - ACS_PushAngle(thread, FINETANGENT(((ACS_GetAngle(argV[0])+ANGLE_90)>>ANGLETOFINESHIFT) & 4095)); + thread->dataStk.push(ACS_AngleToFixed(FINETANGENT(((ACS_FixedToAngle(argV[0])+ANGLE_90)>>ANGLETOFINESHIFT) & 4095))); return false; } @@ -4141,7 +5244,7 @@ bool CallFunc_Tan(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word ar bool CallFunc_Arcsin(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) { (void)argC; - ACS_PushAngle(thread, -FixedAcos(argV[0]) + ANGLE_90); + thread->dataStk.push(ACS_AngleToFixed(-FixedAcos(argV[0]) + ANGLE_90)); return false; } @@ -4153,7 +5256,7 @@ bool CallFunc_Arcsin(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word bool CallFunc_Arccos(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) { (void)argC; - ACS_PushAngle(thread, FixedAcos(argV[0])); + thread->dataStk.push(ACS_AngleToFixed(FixedAcos(argV[0]))); return false; } @@ -4240,7 +5343,7 @@ bool CallFunc_Round(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word bool CallFunc_InvAngle(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) { (void)argC; - ACS_PushAngle(thread, InvAngle(ACS_GetAngle(argV[0]))); + thread->dataStk.push(ACS_AngleToFixed(InvAngle(ACS_FixedToAngle(argV[0])))); return false; } diff --git a/src/acs/call-funcs.hpp b/src/acs/call-funcs.hpp index 7fe0269b8..2aa9af756 100644 --- a/src/acs/call-funcs.hpp +++ b/src/acs/call-funcs.hpp @@ -78,10 +78,9 @@ bool CallFunc_SkinUnlocked(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM bool CallFunc_PlayerSkin(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_PlayerBot(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_PlayerExiting(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); -bool CallFunc_SetObjectDye(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); -bool CallFunc_GetObjectDye(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_Teleport(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_SetViewpoint(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_SpawnObject(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_TrackObjectAngle(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_StopTrackingObjectAngle(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_PlayerEmeralds(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); @@ -96,6 +95,36 @@ bool CallFunc_NiGHTSAttack(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM bool CallFunc_SetLineRenderStyle(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +// Some useful actor functions. +bool CallFunc_GetObjectX(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GetObjectY(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GetObjectZ(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GetObjectVelX(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GetObjectVelY(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GetObjectVelZ(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GetObjectAngle(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GetObjectRoll(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GetObjectPitch(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GetObjectFloorZ(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GetObjectCeilingZ(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GetObjectFloorTexture(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GetObjectLightLevel(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_CheckObjectState(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_CheckObjectFlag(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GetObjectClass(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GetObjectDye(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); + +bool CallFunc_SetObjectPosition(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_SetObjectVelocity(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_SetObjectAngle(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_SetObjectRoll(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_SetObjectPitch(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_SetObjectState(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_SetObjectFlag(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_SetObjectClass(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_SetObjectDye(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_SetObjectSpecial(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); + bool CallFunc_MapWarp(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_AddBot(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_RemoveBot(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); @@ -124,6 +153,18 @@ bool CallFunc_TakeAmmo(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Wo bool CallFunc_DoSuperTransformation(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_DoSuperDetransformation(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GiveRings(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GiveSpheres(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GiveLives(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GiveScore(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_DropFlag(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_TossFlag(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_DropEmeralds(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_TossEmeralds(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_PlayerHoldingFlag(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_PlayerIsIt(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_PlayerFinished(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); + bool CallFunc_Sin(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_Cos(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_Tan(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); diff --git a/src/acs/environment.cpp b/src/acs/environment.cpp index f9c850c45..4cb29333f 100644 --- a/src/acs/environment.cpp +++ b/src/acs/environment.cpp @@ -98,6 +98,7 @@ Environment::Environment() addCodeDataACS0(119, {"", 0, addCallFunc(CallFunc_PlayerTeam)}); // 136 to 137: Implemented by ACSVM + addCodeDataACS0(149, {"", 6, addCallFunc(CallFunc_SpawnObject)}); // 157: Implemented by ACSVM @@ -105,29 +106,43 @@ Environment::Environment() addCodeDataACS0(174, {"BB", 0, addCallFunc(CallFunc_Random)}); // 175 to 179: Implemented by ACSVM + addCodeDataACS0(180, {"", 7, addCallFunc(CallFunc_SetObjectSpecial)}); + // 181 to 189: Implemented by ACSVM + addCodeDataACS0(196, {"", 1, addCallFunc(CallFunc_GetObjectX)}); + addCodeDataACS0(197, {"", 1, addCallFunc(CallFunc_GetObjectY)}); + addCodeDataACS0(198, {"", 1, addCallFunc(CallFunc_GetObjectZ)}); // 203 to 217: Implemented by ACSVM addCodeDataACS0(220, {"", 2, addCallFunc(CallFunc_Sin)}); addCodeDataACS0(221, {"", 2, addCallFunc(CallFunc_Cos)}); // 225 to 243: Implemented by ACSVM - + addCodeDataACS0(245, {"", 3, addCallFunc(CallFunc_SetThingProperty)}); + addCodeDataACS0(246, {"", 2, addCallFunc(CallFunc_GetThingProperty)}); addCodeDataACS0(247, {"", 0, addCallFunc(CallFunc_PlayerNumber)}); addCodeDataACS0(248, {"", 0, addCallFunc(CallFunc_ActivatorTID)}); // 253: Implemented by ACSVM // 256 to 257: Implemented by ACSVM + addCodeDataACS0(259, {"", 1, addCallFunc(CallFunc_GetObjectFloorZ)}); // 263: Implemented by ACSVM + addCodeDataACS0(260, {"", 1, addCallFunc(CallFunc_GetObjectAngle)}); addCodeDataACS0(266, {"", 2, addCallFunc(CallFunc_ChangeSky)}); // reimplements linedef type 423 addCodeDataACS0(270, {"", 0, addCallFunc(CallFunc_EndLog)}); // 273 to 275: Implemented by ACSVM + addCodeDataACS0(276, {"", 2, addCallFunc(CallFunc_SetObjectAngle)}); + addCodeDataACS0(282, {"", 1, addCallFunc(CallFunc_GetObjectCeilingZ)}); // 291 to 325: Implemented by ACSVM // 330: Implemented by ACSVM + addCodeDataACS0(331, {"", 1, addCallFunc(CallFunc_GetObjectPitch)}); + addCodeDataACS0(332, {"", 1, addCallFunc(CallFunc_SetObjectPitch)}); + addCodeDataACS0(334, {"", 1, addCallFunc(CallFunc_SetObjectState)}); + addCodeDataACS0(340, {"", 1, addCallFunc(CallFunc_GetObjectLightLevel)}); // 349 to 361: Implemented by ACSVM @@ -146,8 +161,6 @@ Environment::Environment() addFuncDataACS0( 7, addCallFunc(CallFunc_GetSideProperty)); addFuncDataACS0( 8, addCallFunc(CallFunc_SetSideProperty)); // addFuncDataACS0( 9, addCallFunc(CallFunc_GetSideUserProperty)); - addFuncDataACS0( 10, addCallFunc(CallFunc_GetThingProperty)); - addFuncDataACS0( 11, addCallFunc(CallFunc_SetThingProperty)); // addFuncDataACS0( 12, addCallFunc(CallFunc_GetThingUserProperty)); // addFuncDataACS0( 13, addCallFunc(CallFunc_GetPlayerProperty)); // addFuncDataACS0( 14, addCallFunc(CallFunc_SetPlayerProperty)); @@ -161,6 +174,22 @@ Environment::Environment() addFuncDataACS0( 122, addCallFunc(CallFunc_PlayerScore)); addFuncDataACS0( 123, addCallFunc(CallFunc_PlayerSuper)); + addFuncDataACS0( 200, addCallFunc(CallFunc_GetObjectVelX)); + addFuncDataACS0( 201, addCallFunc(CallFunc_GetObjectVelY)); + addFuncDataACS0( 202, addCallFunc(CallFunc_GetObjectVelZ)); + addFuncDataACS0( 203, addCallFunc(CallFunc_GetObjectRoll)); + addFuncDataACS0( 204, addCallFunc(CallFunc_GetObjectFloorTexture)); + addFuncDataACS0( 205, addCallFunc(CallFunc_CheckObjectState)); + addFuncDataACS0( 206, addCallFunc(CallFunc_CheckObjectFlag)); + addFuncDataACS0( 207, addCallFunc(CallFunc_GetObjectClass)); + addFuncDataACS0( 208, addCallFunc(CallFunc_GetObjectDye)); + + addFuncDataACS0( 209, addCallFunc(CallFunc_SetObjectVelocity)); + addFuncDataACS0( 210, addCallFunc(CallFunc_SetObjectRoll)); + addFuncDataACS0( 211, addCallFunc(CallFunc_SetObjectFlag)); + addFuncDataACS0( 212, addCallFunc(CallFunc_SetObjectClass)); + addFuncDataACS0( 213, addCallFunc(CallFunc_SetObjectDye)); + addFuncDataACS0( 300, addCallFunc(CallFunc_CountEnemies)); addFuncDataACS0( 301, addCallFunc(CallFunc_CountPushables)); addFuncDataACS0( 302, addCallFunc(CallFunc_HasUnlockable)); @@ -177,11 +206,8 @@ Environment::Environment() addFuncDataACS0( 313, addCallFunc(CallFunc_NiGHTSAttack)); addFuncDataACS0( 314, addCallFunc(CallFunc_ModeAttacking)); addFuncDataACS0( 315, addCallFunc(CallFunc_LowestLap)); - addFuncDataACS0( 320, addCallFunc(CallFunc_GetObjectDye)); - addFuncDataACS0( 321, addCallFunc(CallFunc_SetObjectDye)); addFuncDataACS0( 322, addCallFunc(CallFunc_Teleport)); addFuncDataACS0( 323, addCallFunc(CallFunc_SetViewpoint)); - // addFuncDataACS0( 324, addCallFunc(CallFunc_SpawnObject)); addFuncDataACS0( 325, addCallFunc(CallFunc_TrackObjectAngle)); addFuncDataACS0( 326, addCallFunc(CallFunc_StopTrackingObjectAngle)); addFuncDataACS0( 327, addCallFunc(CallFunc_CheckPowerUp)); @@ -191,6 +217,17 @@ Environment::Environment() addFuncDataACS0( 331, addCallFunc(CallFunc_TakeAmmo)); addFuncDataACS0( 332, addCallFunc(CallFunc_DoSuperTransformation)); addFuncDataACS0( 333, addCallFunc(CallFunc_DoSuperDetransformation)); + addFuncDataACS0( 334, addCallFunc(CallFunc_GiveRings)); + addFuncDataACS0( 335, addCallFunc(CallFunc_GiveSpheres)); + addFuncDataACS0( 336, addCallFunc(CallFunc_GiveLives)); + addFuncDataACS0( 337, addCallFunc(CallFunc_GiveScore)); + addFuncDataACS0( 338, addCallFunc(CallFunc_DropFlag)); + addFuncDataACS0( 339, addCallFunc(CallFunc_TossFlag)); + addFuncDataACS0( 340, addCallFunc(CallFunc_DropEmeralds)); + addFuncDataACS0( 341, addCallFunc(CallFunc_TossEmeralds)); + addFuncDataACS0( 342, addCallFunc(CallFunc_PlayerHoldingFlag)); + addFuncDataACS0( 343, addCallFunc(CallFunc_PlayerIsIt)); + addFuncDataACS0( 344, addCallFunc(CallFunc_PlayerFinished)); addFuncDataACS0( 500, addCallFunc(CallFunc_CameraWait)); addFuncDataACS0( 503, addCallFunc(CallFunc_SetLineRenderStyle)); diff --git a/src/acs/thread.hpp b/src/acs/thread.hpp index 1b52780fe..589eed3ae 100644 --- a/src/acs/thread.hpp +++ b/src/acs/thread.hpp @@ -35,12 +35,16 @@ namespace srb2::acs { // enum acs_scriptType_e { - ACS_ST_OPEN = 1, // OPEN: Runs once when the level starts. - ACS_ST_RESPAWN = 2, // RESPAWN: Runs when a player respawns. - ACS_ST_DEATH = 3, // DEATH: Runs when a player dies. - ACS_ST_ENTER = 4, // ENTER: Runs when a player enters the game; both on start of the level, and when un-spectating. - ACS_ST_GAMEOVER = 5, // GAMEOVER: Runs when the level ends due to a losing condition and no player has an extra life. - ACS_ST_FINISH = 6, // FINISH: Runs when a player finishes + ACS_ST_OPEN = 1, // OPEN: Runs once when the level starts. + ACS_ST_RESPAWN = 2, // RESPAWN: Runs when a player respawns. + ACS_ST_DEATH = 3, // DEATH: Runs when a player dies. + ACS_ST_ENTER = 4, // ENTER: Runs when a player enters the game; both on start of the level, and when un-spectating. + ACS_ST_PICKUP = 5, // PICKUP: Runs when a player picks up a flag. (Skulltag) + ACS_ST_BLUERETURN = 6, // BLUERETURN: Runs when the blue flag returns to its base. (Skulltag) + ACS_ST_REDRETURN = 7, // REDRETURN: Runs when the red flag returns to its base. (Skulltag) + ACS_ST_EVENT = 16, // EVENT: Runs when certain game events happen. (Zandronum) + ACS_ST_GAMEOVER = 19, // GAMEOVER: Runs when the player gets a game over. (SRB2) + ACS_ST_FINISH = 20 // FINISH: Runs when a player finishes the level. (SRB2) }; // @@ -50,7 +54,7 @@ enum acs_tagType_e { ACS_TAGTYPE_POLYOBJ, ACS_TAGTYPE_SECTOR, - ACS_TAGTYPE_CAMERA, + ACS_TAGTYPE_CAMERA }; class ThreadInfo : public ACSVM::ThreadInfo diff --git a/src/g_game.c b/src/g_game.c index 7d1a47c22..8a180a032 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -4290,8 +4290,6 @@ static void G_DoStartContinue(void) G_PlayerFinishLevel(consoleplayer); // take away cards and stuff - ACS_RunGameOverScript(); - F_StartContinue(); gameaction = ga_nothing; } diff --git a/src/p_inter.c b/src/p_inter.c index f8923c7a1..3ff12e62a 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2728,6 +2728,8 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget if (!usedCheats && cursaveslot > 0) G_SaveGameOver((UINT32)cursaveslot, (target->player->continues <= 0)); } + + ACS_RunGameOverScript(); } } target->player->playerstate = PST_DEAD; diff --git a/src/p_local.h b/src/p_local.h index 54c9fabb8..698867e33 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -314,7 +314,6 @@ boolean P_CheckSkyHit(mobj_t *mo, line_t *line); void P_PushableThinker(mobj_t *mobj); void P_SceneryThinker(mobj_t *mobj); - fixed_t P_MobjFloorZ(sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, fixed_t radius, line_t *line, boolean lowest, boolean perfect); fixed_t P_MobjCeilingZ(sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t y, fixed_t radius, line_t *line, boolean lowest, boolean perfect); #define P_GetFloorZ(mobj, sector, x, y, line) P_MobjFloorZ(sector, NULL, x, y, mobj->radius, line, false, false) @@ -324,6 +323,8 @@ fixed_t P_MobjCeilingZ(sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t #define P_GetSpecialBottomZ(mobj, src, bound) P_MobjFloorZ(src, bound, mobj->x, mobj->y, mobj->radius, NULL, src != bound, true) #define P_GetSpecialTopZ(mobj, src, bound) P_MobjCeilingZ(src, bound, mobj->x, mobj->y, mobj->radius, NULL, src == bound, true) +INT32 P_FloorPicAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height); + #define P_CameraGetFloorZ(mobj, sector, x, y, line) P_MobjFloorZ(sector, NULL, x, y, mobj->radius, line, false, false) #define P_CameraGetCeilingZ(mobj, sector, x, y, line) P_MobjCeilingZ(sector, NULL, x, y, mobj->radius, line, true, false) #define P_CameraGetFOFTopZ(mobj, sector, fof, x, y, line) P_MobjCeilingZ(sectors + fof->secnum, sector, x, y, mobj->radius, line, false, false) diff --git a/src/p_mobj.c b/src/p_mobj.c index 65adb530b..df3ae2586 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1260,6 +1260,40 @@ fixed_t P_MobjCeilingZ(sector_t *sector, sector_t *boundsec, fixed_t x, fixed_t return sector->ceilingheight; } +INT32 P_FloorPicAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height) +{ + sector_t *sector = R_PointInSubsector(x, y)->sector; + + INT32 floorpic = sector->floorpic; + + if (sector->ffloors) + { + ffloor_t *best = NULL; + fixed_t thingtop = z + height; + + for (ffloor_t *rover = sector->ffloors; rover; rover = rover->next) + { + if (!(rover->fofflags & FOF_EXISTS)) + continue; + + fixed_t topheight = P_GetFFloorTopZAt(rover, x, y); + fixed_t bottomheight = P_GetFFloorBottomZAt(rover, x, y); + + fixed_t delta1 = z - (bottomheight + ((topheight - bottomheight)/2)); + fixed_t delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2)); + if (topheight > P_GetFFloorTopZAt(best, x, y) && abs(delta1) < abs(delta2)) + { + best = rover; + } + } + + if (best) + floorpic = *best->toppic; + } + + return floorpic; +} + static void P_PlayerFlip(mobj_t *mo) { if (!mo->player) diff --git a/src/p_user.c b/src/p_user.c index 949f3f244..d08a5ee18 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2315,6 +2315,7 @@ void P_DoPlayerFinish(player_t *player) player->powers[pw_underwater] = 0; player->powers[pw_spacetime] = 0; P_RestoreMusic(player); + ACS_RunPlayerFinishScript(player); } //