From 5521284fa07403d189e6afe83a359d871fcb2e62 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Wed, 26 Apr 2023 02:16:19 -0400 Subject: [PATCH] ACS: Implement Line and Side get/set functions Additionally, these all now support tag 0 as getting/setting properties from the activator. --- src/acs/call-funcs.cpp | 533 +++++++++++++++++++++++++++++++++++++++- src/acs/call-funcs.hpp | 4 + src/acs/environment.cpp | 8 +- 3 files changed, 535 insertions(+), 10 deletions(-) diff --git a/src/acs/call-funcs.cpp b/src/acs/call-funcs.cpp index 85887e4c7..deced2df6 100644 --- a/src/acs/call-funcs.cpp +++ b/src/acs/call-funcs.cpp @@ -801,7 +801,17 @@ bool CallFunc_SetLineTexture(ACSVM::Thread *thread, const ACSVM::Word *argV, ACS TAG_ITER_LINES(tag, lineId) { line_t *line = &lines[lineId]; - side_t *side = &sides[line->sidenum[sideId]]; + side_t *side = NULL; + + if (line->sidenum[sideId] != 0xffff) + { + side = &sides[line->sidenum[sideId]]; + } + + if (side == NULL) + { + continue; + } switch (texPos) { @@ -1479,6 +1489,470 @@ bool CallFunc_SetLineRenderStyle(ACSVM::Thread *thread, const ACSVM::Word *argV, return false; } +/*-------------------------------------------------- + bool CallFunc_Get/SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Generic line property management. +--------------------------------------------------*/ +enum +{ + LINE_PROP_FLAGS, + LINE_PROP_ALPHA, + LINE_PROP_BLENDMODE, + LINE_PROP_ACTIVATION, + LINE_PROP_ACTION, + LINE_PROP_ARG0, + LINE_PROP_ARG1, + LINE_PROP_ARG2, + LINE_PROP_ARG3, + LINE_PROP_ARG4, + LINE_PROP_ARG5, + LINE_PROP_ARG6, + LINE_PROP_ARG7, + LINE_PROP_ARG8, + LINE_PROP_ARG9, + LINE_PROP_ARG0STR, + LINE_PROP_ARG1STR, + LINE_PROP__MAX +}; + +static INT32 NextLine(mtag_t tag, INT32 lineID, INT32 activatorID) +{ + if (tag == 0) + { + // 0 grabs the activator. + + if (lineID != 0) + { + // Don't do more than once. + return -1; + } + + return activatorID; + } + + return Tag_Iterate_Lines(tag, lineID); +} + +bool CallFunc_GetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + auto info = &static_cast(thread)->info; + Environment *env = &ACSEnv; + + mtag_t tag = 0; + INT32 lineID = 0; + INT32 activatorID = -1; + line_t *line = NULL; + + INT32 property = LINE_PROP__MAX; + INT32 value = 0; + + tag = argV[0]; + + if (info != NULL && info->line != NULL) + { + activatorID = info->line - lines; + } + + if ((lineID = NextLine(tag, lineID, activatorID)) != -1) + { + line = &lines[ lineID ]; + } + + property = argV[1]; + + if (line != NULL) + { + +#define PROP_INT(x, y) \ + case x: \ + { \ + value = static_cast( line->y ); \ + break; \ + } + +#define PROP_STR(x, y) \ + case x: \ + { \ + value = static_cast( ~env->getString( line->y )->idx ); \ + break; \ + } + + switch (property) + { + PROP_INT(LINE_PROP_FLAGS, flags) + PROP_INT(LINE_PROP_ALPHA, alpha) + PROP_INT(LINE_PROP_BLENDMODE, blendmode) + PROP_INT(LINE_PROP_ACTIVATION, activation) + PROP_INT(LINE_PROP_ACTION, special) + PROP_INT(LINE_PROP_ARG0, args[0]) + PROP_INT(LINE_PROP_ARG1, args[1]) + PROP_INT(LINE_PROP_ARG2, args[2]) + PROP_INT(LINE_PROP_ARG3, args[3]) + PROP_INT(LINE_PROP_ARG4, args[4]) + PROP_INT(LINE_PROP_ARG5, args[5]) + PROP_INT(LINE_PROP_ARG6, args[6]) + PROP_INT(LINE_PROP_ARG7, args[7]) + PROP_INT(LINE_PROP_ARG8, args[8]) + PROP_INT(LINE_PROP_ARG9, args[9]) + PROP_STR(LINE_PROP_ARG0STR, stringargs[0]) + PROP_STR(LINE_PROP_ARG1STR, stringargs[1]) + default: + { + CONS_Alert(CONS_WARNING, "GetLineProperty type %d out of range (expected 0 - %d).\n", property, LINE_PROP__MAX-1); + break; + } + } + +#undef PROP_STR +#undef PROP_INT + + } + + thread->dataStk.push(value); + return false; +} + +bool CallFunc_SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + auto info = &static_cast(thread)->info; + //Environment *env = &ACSEnv; + + mtag_t tag = 0; + INT32 lineID = 0; + INT32 activatorID = -1; + line_t *line = NULL; + + INT32 property = LINE_PROP__MAX; + INT32 value = 0; + + tag = argV[0]; + + if (info != NULL && info->line != NULL) + { + activatorID = info->line - lines; + } + + if ((lineID = NextLine(tag, lineID, activatorID)) != -1) + { + line = &lines[ lineID ]; + } + + property = argV[1]; + value = argV[2]; + + while (line != NULL) + { + +#define PROP_READONLY(x, y) \ + case x: \ + { \ + CONS_Alert(CONS_WARNING, "SetLineProperty type '%s' cannot be written to.\n", "y"); \ + break; \ + } + +#define PROP_INT(x, y) \ + case x: \ + { \ + line->y = static_cast< decltype(line->y) >(value); \ + break; \ + } + +#define PROP_STR(x, y) \ + case x: \ + { \ + ACSVM::String *str = thread->scopeMap->getString( value ); \ + if (str->len == 0) \ + { \ + Z_Free(line->y); \ + line->y = NULL; \ + } \ + else \ + { \ + line->y = static_cast(Z_Realloc(line->y, str->len + 1, PU_LEVEL, NULL)); \ + M_Memcpy(line->y, str->str, str->len + 1); \ + line->y[str->len] = '\0'; \ + } \ + break; \ + } + + switch (property) + { + PROP_INT(LINE_PROP_FLAGS, flags) + PROP_INT(LINE_PROP_ALPHA, alpha) + PROP_INT(LINE_PROP_BLENDMODE, blendmode) + PROP_INT(LINE_PROP_ACTIVATION, activation) + PROP_INT(LINE_PROP_ACTION, special) + PROP_INT(LINE_PROP_ARG0, args[0]) + PROP_INT(LINE_PROP_ARG1, args[1]) + PROP_INT(LINE_PROP_ARG2, args[2]) + PROP_INT(LINE_PROP_ARG3, args[3]) + PROP_INT(LINE_PROP_ARG4, args[4]) + PROP_INT(LINE_PROP_ARG5, args[5]) + PROP_INT(LINE_PROP_ARG6, args[6]) + PROP_INT(LINE_PROP_ARG7, args[7]) + PROP_INT(LINE_PROP_ARG8, args[8]) + PROP_INT(LINE_PROP_ARG9, args[9]) + PROP_STR(LINE_PROP_ARG0STR, stringargs[0]) + PROP_STR(LINE_PROP_ARG1STR, stringargs[1]) + default: + { + CONS_Alert(CONS_WARNING, "SetLineProperty type %d out of range (expected 0 - %d).\n", property, LINE_PROP__MAX-1); + break; + } + } + + if ((lineID = NextLine(tag, lineID, activatorID)) != -1) + { + line = &lines[ lineID ]; + } + else + { + line = NULL; + } + +#undef PROP_STR +#undef PROP_INT +#undef PROP_READONLY + + } + + return false; +} + +/*-------------------------------------------------- + bool CallFunc_Get/SetSideProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) + + Generic side property management. +--------------------------------------------------*/ +enum +{ + SIDE_PROP_XOFFSET, + SIDE_PROP_YOFFSET, + SIDE_PROP_TOPTEXTURE, + SIDE_PROP_BOTTOMTEXTURE, + SIDE_PROP_MIDTEXTURE, + SIDE_PROP__MAX +}; + +bool CallFunc_GetSideProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + auto info = &static_cast(thread)->info; + Environment *env = &ACSEnv; + + mtag_t tag = 0; + INT32 lineID = 0; + INT32 activatorID = -1; + line_t *line = NULL; + + UINT8 sideID = 0; + side_t *side = NULL; + + INT32 property = SIDE_PROP__MAX; + INT32 value = 0; + + tag = argV[0]; + + if (info != NULL && info->line != NULL) + { + activatorID = info->line - lines; + } + + if ((lineID = NextLine(tag, lineID, activatorID)) != -1) + { + line = &lines[ lineID ]; + } + + sideID = argV[1]; + if (sideID < 0 || sideID > 1) + { + sideID = info->side; + } + + if (line != NULL && line->sidenum[sideID] != 0xffff) + { + side = &sides[line->sidenum[sideID]]; + } + + property = argV[2]; + + if (side != NULL) + { + +#define PROP_INT(x, y) \ + case x: \ + { \ + value = static_cast( side->y ); \ + break; \ + } + +#define PROP_STR(x, y) \ + case x: \ + { \ + value = static_cast( ~env->getString( side->y )->idx ); \ + break; \ + } + +#define PROP_TEXTURE(x, y) \ + case x: \ + { \ + value = static_cast( ~env->getString( textures[ side->y ]->name )->idx ); \ + break; \ + } + + switch (property) + { + PROP_INT(SIDE_PROP_XOFFSET, textureoffset) + PROP_INT(SIDE_PROP_YOFFSET, rowoffset) + PROP_TEXTURE(SIDE_PROP_TOPTEXTURE, toptexture) + PROP_TEXTURE(SIDE_PROP_BOTTOMTEXTURE, bottomtexture) + PROP_TEXTURE(SIDE_PROP_MIDTEXTURE, midtexture) + default: + { + CONS_Alert(CONS_WARNING, "GetSideProperty type %d out of range (expected 0 - %d).\n", property, SIDE_PROP__MAX-1); + break; + } + } + +#undef PROP_TEXTURE +#undef PROP_STR +#undef PROP_INT + + } + + thread->dataStk.push(value); + return false; +} + +bool CallFunc_SetSideProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) +{ + auto info = &static_cast(thread)->info; + //Environment *env = &ACSEnv; + + mtag_t tag = 0; + INT32 lineID = 0; + INT32 activatorID = -1; + line_t *line = NULL; + + UINT8 sideID = 0; + side_t *side = NULL; + + INT32 property = SIDE_PROP__MAX; + INT32 value = 0; + + tag = argV[0]; + + if (info != NULL && info->line != NULL) + { + activatorID = info->line - lines; + } + + if ((lineID = NextLine(tag, lineID, activatorID)) != -1) + { + line = &lines[ lineID ]; + } + + sideID = argV[1]; + if (sideID < 0 || sideID > 1) + { + sideID = info->side; + } + + if (line != NULL && line->sidenum[sideID] != 0xffff) + { + side = &sides[line->sidenum[sideID]]; + } + + property = argV[2]; + value = argV[3]; + + while (line != NULL) + { + if (side != NULL) + { + +#define PROP_READONLY(x, y) \ + case x: \ + { \ + CONS_Alert(CONS_WARNING, "SetSideProperty type '%s' cannot be written to.\n", "y"); \ + break; \ + } + +#define PROP_INT(x, y) \ + case x: \ + { \ + side->y = static_cast< decltype(side->y) >(value); \ + break; \ + } + +#define PROP_STR(x, y) \ + case x: \ + { \ + ACSVM::String *str = thread->scopeMap->getString( value ); \ + if (str->len == 0) \ + { \ + Z_Free(side->y); \ + side->y = NULL; \ + } \ + else \ + { \ + side->y = static_cast(Z_Realloc(side->y, str->len + 1, PU_LEVEL, NULL)); \ + M_Memcpy(side->y, str->str, str->len + 1); \ + side->y[str->len] = '\0'; \ + } \ + break; \ + } + +#define PROP_TEXTURE(x, y) \ + case x: \ + { \ + side->y = R_TextureNumForName( thread->scopeMap->getString( value )->str ); \ + break; \ + } + + switch (property) + { + PROP_INT(SIDE_PROP_XOFFSET, textureoffset) + PROP_INT(SIDE_PROP_YOFFSET, rowoffset) + PROP_TEXTURE(SIDE_PROP_TOPTEXTURE, toptexture) + PROP_TEXTURE(SIDE_PROP_BOTTOMTEXTURE, bottomtexture) + PROP_TEXTURE(SIDE_PROP_MIDTEXTURE, midtexture) + default: + { + CONS_Alert(CONS_WARNING, "SetSideProperty type %d out of range (expected 0 - %d).\n", property, SIDE_PROP__MAX-1); + break; + } + } + } + + if ((lineID = NextLine(tag, lineID, activatorID)) != -1) + { + line = &lines[ lineID ]; + } + else + { + line = NULL; + } + + if (line != NULL && line->sidenum[sideID] != 0xffff) + { + side = &sides[line->sidenum[sideID]]; + } + else + { + side = NULL; + } + +#undef PROP_TEXTURE +#undef PROP_STR +#undef PROP_INT +#undef PROP_READONLY + + } + + return false; +} + /*-------------------------------------------------- bool CallFunc_Get/SetSectorProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) @@ -1516,19 +1990,45 @@ enum SECTOR_PROP__MAX }; +static INT32 NextSector(mtag_t tag, INT32 sectorID, INT32 activatorID) +{ + if (tag == 0) + { + // 0 grabs the activator. + + if (sectorID != 0) + { + // Don't do more than once. + return -1; + } + + return activatorID; + } + + return Tag_Iterate_Sectors(tag, sectorID); +} + bool CallFunc_GetSectorProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) { + auto info = &static_cast(thread)->info; Environment *env = &ACSEnv; mtag_t tag = 0; - INT32 sectorID = -1; + INT32 sectorID = 0; + INT32 activatorID = -1; sector_t *sector = NULL; INT32 property = SECTOR_PROP__MAX; INT32 value = 0; tag = argV[0]; - if ((sectorID = Tag_Iterate_Sectors(tag, 0)) != -1) + + if (info != NULL && info->sector != NULL) + { + activatorID = info->sector - sectors; + } + + if ((sectorID = NextSector(tag, sectorID, activatorID)) != -1) { sector = §ors[ sectorID ]; } @@ -1607,22 +2107,34 @@ bool CallFunc_GetSectorProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, bool CallFunc_SetSectorProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC) { + auto info = &static_cast(thread)->info; //Environment *env = &ACSEnv; mtag_t tag = 0; - INT32 sectorID = -1; + INT32 sectorID = 0; + INT32 activatorID = -1; sector_t *sector = NULL; INT32 property = SECTOR_PROP__MAX; INT32 value = 0; tag = argV[0]; + + if (info != NULL && info->sector != NULL) + { + activatorID = info->sector - sectors; + } + + if ((sectorID = NextSector(tag, sectorID, activatorID)) != -1) + { + sector = §ors[ sectorID ]; + } + property = argV[1]; value = argV[2]; - TAG_ITER_SECTORS(tag, sectorID) + while (sector != NULL) { - sector = §ors[sectorID]; #define PROP_READONLY(x, y) \ case x: \ @@ -1699,6 +2211,15 @@ bool CallFunc_SetSectorProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, } } + if ((sectorID = NextSector(tag, sectorID, activatorID)) != -1) + { + sector = §ors[ sectorID ]; + } + else + { + sector = NULL; + } + #undef PROP_FLAT #undef PROP_STR #undef PROP_INT diff --git a/src/acs/call-funcs.hpp b/src/acs/call-funcs.hpp index d49cb0702..154ee1fbd 100644 --- a/src/acs/call-funcs.hpp +++ b/src/acs/call-funcs.hpp @@ -83,6 +83,10 @@ bool CallFunc_PodiumFinish(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM bool CallFunc_SetLineRenderStyle(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_GetSideProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); +bool CallFunc_SetSideProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_GetSectorProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); bool CallFunc_SetSectorProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC); diff --git a/src/acs/environment.cpp b/src/acs/environment.cpp index 28821ccc8..0840da59a 100644 --- a/src/acs/environment.cpp +++ b/src/acs/environment.cpp @@ -128,14 +128,14 @@ Environment::Environment() // This style is preferred for added functions // that aren't mimicing one from Hexen's or ZDoom's // ACS implementations. - //addFuncDataACS0( 1, addCallFunc(CallFunc_GetLineProperty)); - //addFuncDataACS0( 2, addCallFunc(CallFunc_SetLineProperty)); + addFuncDataACS0( 1, addCallFunc(CallFunc_GetLineProperty)); + addFuncDataACS0( 2, addCallFunc(CallFunc_SetLineProperty)); //addFuncDataACS0( 3, addCallFunc(CallFunc_GetLineUserProperty)); addFuncDataACS0( 4, addCallFunc(CallFunc_GetSectorProperty)); addFuncDataACS0( 5, addCallFunc(CallFunc_SetSectorProperty)); //addFuncDataACS0( 6, addCallFunc(CallFunc_GetSectorUserProperty)); - //addFuncDataACS0( 7, addCallFunc(CallFunc_GetSideProperty)); - //addFuncDataACS0( 8, addCallFunc(CallFunc_SetSideProperty)); + 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));