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); } //