Add ACS functions that can replicate line triggers

PlayerTeam, PlayerRings, PlayerScore, CountEnemies, CountPushables, HaveUnlockableTrigger, HaveUnlockable, PlayerSkin, GetObjectDye, PlayerEmeralds, PlayerLap, LowestLap, and EncoreMode
This commit is contained in:
Sally Coolatta 2022-12-31 16:02:55 -05:00
parent a0adb05c9b
commit a602530811
5 changed files with 503 additions and 0 deletions

View file

@ -726,6 +726,50 @@ keywords
- sound: The name of the sound effect.\n
- volume: The volume to play it at, from 0 to 255.";
PlayerTeam = "int PlayerTeam(void)\n
Returns the team ID of the activating player.";
PlayerRings = "int PlayerRings(void)\n
Returns the number of rings that the activating player has.";
PlayerScore = "int PlayerScore(void)\n
Returns the number of points that the activating player has\n
gotten in the current round.";
CountEnemies = "int CountEnemies(int tag)\n
Returns the number of enemies touching the tagged sectors.\n
- tag: The sector tag to search in.";
CountPushables = "int CountPushables(int tag)\n
Returns the number of pushable objects touching the tagged sectors.\n
- tag: The sector tag to search in.";
HaveUnlockableTrigger = "bool HaveUnlockableTrigger(int id)\n
Returns whenever or not a unlockable trigger flag has been activated.\n
- id: The ID of the unlockable trigger, from 0 to 31.";
HaveUnlockable = "bool HaveUnlockable(int id)\n
Returns whenever or not an unlockable has been unlocked.\n
- id: The ID of the unlockable, from 0 to MAXUNLOCKABLES-1.";
PlayerSkin = "str PlayerSkin(void)\n
Returns the name of the activating player's skin.";
GetObjectDye = "str GetObjectDye(void)\n
Returns the name of the activating object's dye color.";
PlayerEmeralds = "int PlayerEmeralds(void)\n
Returns the number of Chaos Emeralds the activating player has collected.";
PlayerLap = "int PlayerLap(void)\n
Returns the activating player's lap count.";
LowestLap = "int LowestLap(void)\n
Returns the lap count of the player who is farthest behind.";
EncoreMode = "bool EncoreMode(void)\n
Returns whenever or not the map is being played in Encore Mode.";
Print = "void Print(<type>:<expression>, [...])\n
Displays a message to the center of the screen.\n
Expression types are as follows:\n

View file

@ -167,6 +167,17 @@ special
int -7:GetSideUDMFInt(3, int, int, str),
fixed -8:GetSideUDMFFixed(3, int, int, str),
*/
// Reimplementations of trigger linedefs.
int -300:CountEnemies(1, int),
int -301:CountPushables(1, int),
bool -302:HaveUnlockableTrigger(1, int),
bool -303:HaveUnlockable(1, int),
str -304:PlayerSkin(0),
str -305:GetObjectDye(0),
int -306:PlayerEmeralds(0),
int -307:PlayerLap(0),
int -308:LowestLap(0),
bool -309:EncoreMode(0),
// 0 to 56: Implemented by ACSVM
void { 2 }:__suspend(void),
@ -205,6 +216,11 @@ special
void {100 }:ThingSound(int, str, int),
void {101 }:EndPrintBold(void),
int {119 }:PlayerTeam(void),
int {120 }:PlayerRings(void),
int {122 }:PlayerScore(void),
int {136 }:FixedMul(int, int), // 136 to 137: Implemented by ACSVM
int {137 }:FixedDiv(int, int),

View file

@ -33,6 +33,9 @@ extern "C" {
#include "../hu_stuff.h"
#include "../s_sound.h"
#include "../r_textures.h"
#include "../m_cond.h"
#include "../r_skins.h"
#include "../k_battle.h"
}
#include <ACSVM/Code.hpp>
@ -202,6 +205,101 @@ static bool ACS_ActivatorIsLocal(ACSVM::Thread *thread)
return false;
}
/*--------------------------------------------------
static UINT32 ACS_SectorThingCounter(sector_t *sec, bool (*filter)(mobj_t *))
Helper function for CallFunc_CountEnemies
and CallFunc_CountPushables. Counts a number
of things in the specified sector.
Input Arguments:-
sec: The sector to search in.
filter: Filter function, total count is increased when
this function returns true.
Return:-
Numbers of things matching the filter found.
--------------------------------------------------*/
static UINT32 ACS_SectorThingCounter(sector_t *sec, bool (*filter)(mobj_t *))
{
msecnode_t *node = sec->touching_thinglist; // things touching this sector
UINT32 count = 0;
while (node)
{
mobj_t *mo = node->m_thing;
if (mo->z > sec->ceilingheight
|| mo->z + mo->height < sec->floorheight)
{
continue;
}
if (filter(mo) == true)
{
count++;
}
node = node->m_thinglist_next;
}
return count;
}
/*--------------------------------------------------
static UINT32 ACS_SectorTagThingCounter(mtag_t tag, bool (*filter)(mobj_t *))
Helper function for CallFunc_CountEnemies
and CallFunc_CountPushables. Counts a number
of things in the tagged sectors.
Input Arguments:-
tag: The sector tag to search in.
filter: Filter function, total count is increased when
this function returns true.
Return:-
Numbers of things matching the filter found.
--------------------------------------------------*/
static UINT32 ACS_SectorTagThingCounter(mtag_t tag, bool (*filter)(mobj_t *))
{
INT32 secnum = -1;
UINT32 count = 0;
size_t i;
TAG_ITER_SECTORS(tag, secnum)
{
sector_t *sec = &sectors[secnum];
boolean FOFsector = false;
// Check the lines of this sector, to see if it is a FOF control sector.
for (i = 0; i < sec->linecount; i++)
{
INT32 targetsecnum = -1;
if (sec->lines[i]->special < 100 || sec->lines[i]->special >= 300)
{
continue;
}
FOFsector = true;
TAG_ITER_SECTORS(sec->lines[i]->args[0], targetsecnum)
{
sector_t *targetsec = &sectors[targetsecnum];
count += ACS_SectorThingCounter(targetsec, filter);
}
}
if (FOFsector == false)
{
count += ACS_SectorThingCounter(sec, filter);
}
}
return count;
}
/*--------------------------------------------------
bool CallFunc_Random(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
@ -839,6 +937,78 @@ bool CallFunc_EndPrintBold(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM
return false;
}
/*--------------------------------------------------
bool CallFunc_PlayerTeam(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Returns the activating player's team ID.
--------------------------------------------------*/
bool CallFunc_PlayerTeam(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
auto info = &static_cast<Thread *>(thread)->info;
UINT8 teamID = 0;
(void)argV;
(void)argC;
if ((info != NULL)
&& (info->mo != NULL && P_MobjWasRemoved(info->mo) == false)
&& (info->mo->player != NULL))
{
teamID = info->mo->player->ctfteam;
}
thread->dataStk.push(teamID);
return false;
}
/*--------------------------------------------------
bool CallFunc_PlayerRings(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Returns the activating player's ring count.
--------------------------------------------------*/
bool CallFunc_PlayerRings(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
auto info = &static_cast<Thread *>(thread)->info;
SINT8 rings = 0;
(void)argV;
(void)argC;
if ((info != NULL)
&& (info->mo != NULL && P_MobjWasRemoved(info->mo) == false)
&& (info->mo->player != NULL))
{
rings = info->mo->player->rings;
}
thread->dataStk.push(rings);
return false;
}
/*--------------------------------------------------
bool CallFunc_PlayerScore(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Returns the activating player's ring count.
--------------------------------------------------*/
bool CallFunc_PlayerScore(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
auto info = &static_cast<Thread *>(thread)->info;
UINT32 score = 0;
(void)argV;
(void)argC;
if ((info != NULL)
&& (info->mo != NULL && P_MobjWasRemoved(info->mo) == false)
&& (info->mo->player != NULL))
{
score = info->mo->player->roundscore;
}
thread->dataStk.push(score);
return false;
}
/*--------------------------------------------------
bool CallFunc_EndLog(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
@ -859,3 +1029,232 @@ bool CallFunc_EndLog(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word
thread->printBuf.drop();
return false;
}
/*--------------------------------------------------
bool CallFunc_CountEnemies(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Returns the number of enemies in the tagged sectors.
--------------------------------------------------*/
bool ACS_EnemyFilter(mobj_t *mo)
{
return ((mo->flags & (MF_ENEMY|MF_BOSS)) && mo->health > 0);
}
bool CallFunc_CountEnemies(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
mtag_t tag = 0;
UINT32 count = 0;
(void)argC;
tag = argV[0];
count = ACS_SectorTagThingCounter(tag, ACS_EnemyFilter);
thread->dataStk.push(count);
return false;
}
/*--------------------------------------------------
bool CallFunc_CountPushables(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Returns the number of pushables in the tagged sectors.
--------------------------------------------------*/
bool ACS_PushableFilter(mobj_t *mo)
{
return ((mo->flags & MF_PUSHABLE)
|| ((mo->info->flags & MF_PUSHABLE) && mo->fuse));
}
bool CallFunc_CountPushables(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
mtag_t tag = 0;
UINT32 count = 0;
(void)argC;
tag = argV[0];
count = ACS_SectorTagThingCounter(tag, ACS_PushableFilter);
thread->dataStk.push(count);
return false;
}
/*--------------------------------------------------
bool CallFunc_HaveUnlockableTrigger(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Returns if an unlockable trigger has been gotten.
--------------------------------------------------*/
bool CallFunc_HaveUnlockableTrigger(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
UINT8 id = 0;
bool unlocked = false;
(void)argC;
id = argV[0];
if (id < 0 || id > 31) // limited by 32 bit variable
{
CONS_Printf("Bad unlockable trigger ID %d\n", id);
}
else
{
unlocked = (unlocktriggers & (1 << id));
}
thread->dataStk.push(unlocked);
return false;
}
/*--------------------------------------------------
bool CallFunc_HaveUnlockable(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Returns if an unlockable has been gotten.
--------------------------------------------------*/
bool CallFunc_HaveUnlockable(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
UINT8 id = 0;
bool unlocked = false;
(void)argC;
id = argV[0];
if (id < 0 || id >= MAXUNLOCKABLES)
{
CONS_Printf("Bad unlockable ID %d\n", id);
}
else
{
unlocked = M_CheckNetUnlockByID(id);
}
thread->dataStk.push(unlocked);
return false;
}
/*--------------------------------------------------
bool CallFunc_PlayerSkin(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Returns the activating player's skin name.
--------------------------------------------------*/
bool CallFunc_PlayerSkin(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
Environment *env = &ACSEnv;
auto info = &static_cast<Thread *>(thread)->info;
(void)argV;
(void)argC;
if ((info != NULL)
&& (info->mo != NULL && P_MobjWasRemoved(info->mo) == false)
&& (info->mo->player != NULL))
{
UINT8 skin = info->mo->player->skin;
thread->dataStk.push(~env->getString( skins[skin].name )->idx);
return false;
}
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 *>(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->dye : info->mo->color;
}
thread->dataStk.push(~env->getString( skincolors[dye].name )->idx);
return false;
}
/*--------------------------------------------------
bool CallFunc_PlayerEmeralds(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Returns the activating player's number of Chaos Emeralds.
--------------------------------------------------*/
bool CallFunc_PlayerEmeralds(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
auto info = &static_cast<Thread *>(thread)->info;
UINT8 count = 0;
(void)argV;
(void)argC;
if ((info != NULL)
&& (info->mo != NULL && P_MobjWasRemoved(info->mo) == false)
&& (info->mo->player != NULL))
{
count = K_NumEmeralds(info->mo->player);
}
thread->dataStk.push(count);
return false;
}
/*--------------------------------------------------
bool CallFunc_PlayerLap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Returns the activating player's current lap.
--------------------------------------------------*/
bool CallFunc_PlayerLap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
auto info = &static_cast<Thread *>(thread)->info;
UINT8 laps = 0;
(void)argV;
(void)argC;
if ((info != NULL)
&& (info->mo != NULL && P_MobjWasRemoved(info->mo) == false)
&& (info->mo->player != NULL))
{
laps = info->mo->player->laps;
}
thread->dataStk.push(laps);
return false;
}
/*--------------------------------------------------
bool CallFunc_LowestLap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Returns the lowest lap of all of the players in-game.
--------------------------------------------------*/
bool CallFunc_LowestLap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
(void)argV;
(void)argC;
thread->dataStk.push(P_FindLowestLap());
return false;
}
/*--------------------------------------------------
bool CallFunc_EncoreMode(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Returns if the map is in Encore Mode.
--------------------------------------------------*/
bool CallFunc_EncoreMode(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
(void)argV;
(void)argC;
thread->dataStk.push(encoremode);
return false;
}

View file

@ -65,6 +65,20 @@ bool CallFunc_SetLineTexture(ACSVM::Thread *thread, const ACSVM::Word *argV, ACS
bool CallFunc_SetLineSpecial(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_ThingSound(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_EndPrintBold(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_PlayerTeam(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_PlayerRings(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_PlayerScore(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_EndLog(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_CountEnemies(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_CountPushables(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_HaveUnlockableTrigger(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_HaveUnlockable(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_PlayerSkin(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_PlayerEmeralds(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_PlayerLap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_LowestLap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_EncoreMode(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
#endif // __SRB2_ACS_CALL_FUNCS_HPP__

View file

@ -95,6 +95,12 @@ Environment::Environment()
addCodeDataACS0( 99, {"", 7, addCallFunc(CallFunc_SetLineSpecial)});
addCodeDataACS0(100, {"", 3, addCallFunc(CallFunc_ThingSound)});
addCodeDataACS0(101, {"", 0, addCallFunc(CallFunc_EndPrintBold)});
addCodeDataACS0(119, {"", 0, addCallFunc(CallFunc_PlayerTeam)});
addCodeDataACS0(120, {"", 0, addCallFunc(CallFunc_PlayerRings)});
addCodeDataACS0(122, {"", 0, addCallFunc(CallFunc_PlayerScore)});
// 136 to 137: Implemented by ACSVM
// 157: Implemented by ACSVM
@ -124,6 +130,30 @@ Environment::Environment()
// 349 to 361: Implemented by ACSVM
// 363 to 380: Implemented by ACSVM
// Now for new style functions.
// This style is preferred for added functions
// that aren't mimicing one from Hexen's or ZDoom's
// ACS implementations.
//addFuncDataACS0( 1, addCallFunc(CallFunc_GetLineUDMFInt));
//addFuncDataACS0( 2, addCallFunc(CallFunc_GetLineUDMFFixed));
//addFuncDataACS0( 3, addCallFunc(CallFunc_GetThingUDMFInt));
//addFuncDataACS0( 4, addCallFunc(CallFunc_GetThingUDMFFixed));
//addFuncDataACS0( 5, addCallFunc(CallFunc_GetSectorUDMFInt));
//addFuncDataACS0( 6, addCallFunc(CallFunc_GetSectorUDMFFixed));
//addFuncDataACS0( 7, addCallFunc(CallFunc_GetSideUDMFInt));
//addFuncDataACS0( 8, addCallFunc(CallFunc_GetSideUDMFFixed));
addFuncDataACS0( 300, addCallFunc(CallFunc_CountEnemies));
addFuncDataACS0( 301, addCallFunc(CallFunc_CountPushables));
addFuncDataACS0( 302, addCallFunc(CallFunc_HaveUnlockableTrigger));
addFuncDataACS0( 303, addCallFunc(CallFunc_HaveUnlockable));
addFuncDataACS0( 304, addCallFunc(CallFunc_PlayerSkin));
addFuncDataACS0( 305, addCallFunc(CallFunc_GetObjectDye));
addFuncDataACS0( 306, addCallFunc(CallFunc_PlayerEmeralds));
addFuncDataACS0( 307, addCallFunc(CallFunc_PlayerLap));
addFuncDataACS0( 308, addCallFunc(CallFunc_LowestLap));
addFuncDataACS0( 309, addCallFunc(CallFunc_EncoreMode));
}
ACSVM::Thread *Environment::allocThread()