Add ThingCount

Hexen implements this as ThingCount(int, int), and ZDoom adds ThingCountName(str, int). I decided on simplifying down to ThingCount(str, int).
This commit is contained in:
Sally Coolatta 2022-10-07 20:19:51 -04:00
parent 1d373d2c81
commit a315482aa4
4 changed files with 180 additions and 7 deletions

View file

@ -205,7 +205,7 @@ special
void { 55, 56}:Delay(int),
int { 57, 58}:Random(int, int),
fixed { 57, 58}:RandomFixed(fixed, fixed),
int { 59, 60}:ThingCount(int, int),
int { 59, 60}:ThingCount(str, int),
void { 61, 62}:TagWait(int),
void { 63, 64}:PolyWait(int),
void { 65, 66}:ChangeFloor(int, str),

View file

@ -27,6 +27,93 @@
#include "r_state.h"
#include "p_polyobj.h"
#include "taglist.h"
#include "p_local.h"
#include "deh_tables.h"
#include "fastcmp.h"
/*--------------------------------------------------
static bool ACS_GetMobjTypeFromString(const char *word, mobjtype_t *type)
Helper function for ACS_CF_ThingCount. Gets
an object type from a string.
Input Arguments:-
word: The mobj class string.
type: Variable to store the result in.
Return:-
true if successful, otherwise false.
--------------------------------------------------*/
static bool ACS_GetMobjTypeFromString(const char *word, mobjtype_t *type)
{
mobjtype_t i;
if (fastncmp("MT_", word, 3))
{
// take off the MT_
word += 3;
}
for (i = 0; i < NUMMOBJFREESLOTS; i++)
{
if (!FREE_MOBJS[i])
{
break;
}
if (fastcmp(word, FREE_MOBJS[i]))
{
*type = MT_FIRSTFREESLOT+i;
return true;
}
}
for (i = 0; i < MT_FIRSTFREESLOT; i++)
{
if (fastcmp(word, MOBJTYPE_LIST[i]+3))
{
*type = i;
return true;
}
}
return false;
}
/*--------------------------------------------------
static bool ACS_CountThing(mobj_t *mobj, mobjtype_t type)
Helper function for ACS_CF_ThingCount.
Returns whenever or not to add this thing
to the thing count.
Input Arguments:-
mobj: The mobj we want to count.
type: Type exclusion.
Return:-
true if successful, otherwise false.
--------------------------------------------------*/
static bool ACS_CountThing(mobj_t *mobj, mobjtype_t type)
{
if (type == MT_NULL || mobj->type == type)
{
// Don't count dead monsters
if (mobj->info->spawnhealth > 0 && mobj->health <= 0)
{
// Note: Hexen checks for COUNTKILL.
// SRB2 does not have an equivalent, so I'm checking
// spawnhealth. Feel free to replace this condition
// with literally anything else.
return false;
}
// Count this object.
return true;
}
return false;
}
/*--------------------------------------------------
bool ACS_CF_Random(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC)
@ -40,13 +127,92 @@ bool ACS_CF_Random(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC
(void)argC;
low = (INT32)argV[0];
high = (INT32)argV[1];
low = argV[0];
high = argV[1];
ACSVM_Thread_DataStk_Push(thread, P_RandomRange(PR_ACS, low, high));
return false;
}
/*--------------------------------------------------
bool ACS_CF_ThingCount(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC)
Counts the number of things of a particular
type and tid. Both fields are optional;
no type means indescriminate against type,
no tid means search thru all thinkers.
--------------------------------------------------*/
bool ACS_CF_ThingCount(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC)
{
ACSVM_MapScope *map = NULL;
ACSVM_String *str = NULL;
const char *className = NULL;
size_t classLen = 0;
mobjtype_t type = MT_NULL;
mtag_t tid = 0;
size_t count = 0;
(void)argC;
map = ACSVM_Thread_GetScopeMap(thread);
str = ACSVM_MapScope_GetString(map, argV[0]);
className = ACSVM_String_GetStr(str);
classLen = ACSVM_String_GetLen(str);
if (classLen > 0)
{
bool success = ACS_GetMobjTypeFromString(className, &type);
if (success == false)
{
// Exit early.
CONS_Alert(CONS_WARNING,
"Couldn't find object type \"%s\" for ThingCount.\n",
className
);
return false;
}
}
tid = argV[1];
if (tid != 0)
{
// TODO: Even in SRB2 next's UDMF, tag lists
// still aren't attached to mobj_t, only
// mapthing_t. Fix this.
}
else
{
// Search thinkers instead of tag lists.
thinker_t *th = NULL;
mobj_t *mobj = NULL;
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
{
continue;
}
mobj = (mobj_t *)th;
if (ACS_CountThing(mobj, type) == true)
{
++count;
}
}
}
ACSVM_Thread_DataStk_Push(thread, count);
return false;
}
/*--------------------------------------------------
bool ACS_CF_TagWait(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC)
@ -99,7 +265,7 @@ bool ACS_CF_ChangeFloor(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word
const char *texName = NULL;
INT32 secnum = -1;
INT32 tag = 0;
mtag_t tag = 0;
(void)argC;
@ -130,7 +296,7 @@ bool ACS_CF_ChangeCeiling(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Wo
const char *texName = NULL;
INT32 secnum = -1;
INT32 tag = 0;
mtag_t tag = 0;
(void)argC;

View file

@ -202,7 +202,12 @@ static void ACS_EnvConstruct(ACSVM_Environment *env)
// Not that we're adding any modules to it, though. :p
ACSVM_GlobalScope_SetActive(global, true);
// Add the data & function pointers
// Add the data & function pointers.
// Starting with raw ACS0 codes. I'm using this classic-style
// format here to have a blueprint for what needs implementing,
// but it'd also be fine to move these to new style.
// See also:
// - https://doomwiki.org/wiki/ACS0_instruction_set
// - https://github.com/DavidPH/ACSVM/blob/master/ACSVM/CodeData.hpp
@ -211,7 +216,8 @@ static void ACS_EnvConstruct(ACSVM_Environment *env)
// 0 to 56: Implemented by ACSVM
ACS_AddCodeDataCallFunc(env, 57, "", 2, ACS_CF_Random);
ACS_AddCodeDataCallFunc(env, 58, "WW", 0, ACS_CF_Random);
ACS_AddCodeDataCallFunc(env, 59, "", 2, ACS_CF_ThingCount);
ACS_AddCodeDataCallFunc(env, 60, "WW", 0, ACS_CF_ThingCount);
ACS_AddCodeDataCallFunc(env, 61, "", 1, ACS_CF_TagWait);
ACS_AddCodeDataCallFunc(env, 62, "W", 0, ACS_CF_TagWait);
ACS_AddCodeDataCallFunc(env, 63, "", 1, ACS_CF_PolyWait);

View file

@ -127,6 +127,7 @@ void ACS_Tick(void);
--------------------------------------------------*/
bool ACS_CF_Random(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC);
bool ACS_CF_ThingCount(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC);
bool ACS_CF_TagWait(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC);
bool ACS_CF_PolyWait(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC);
bool ACS_CF_ChangeFloor(ACSVM_Thread *thread, ACSVM_Word const *argV, ACSVM_Word argC);