mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Instead of being specific to each level, Spray Cans are stored in a list on gamedata that will be stepped along each Spray Can you collect. They are only assigned to a level on collection - which prevents you from farming the same easy location for every colour in the game. In addition, this new system is one step short of dehardcoding them entirely. Now only Spray Cans specifically asked for by the existence of UC_SPRAYCAN will be put in the list, and if a secondary parameter is either "Yes" or "True", it will be put at the head of the list. This could technically support custom skincolours one day, but the author of this commit doesn't care to do the last bit of work necessary to make it happen. There's a slight extra overhead in that skincolor_t now also holds a `cache_spraycan` (renamed from `cachedcan`, which maps had previously) Currently, there's no safeguard against grabbing it on a custom course - you'll lose the Spray Can as soon as you load a fresh game again - but I consider that easy to fix (tomorrow) and necessary before merger, because the author of this commit does NOT want complaints on release because we forgot to protect users who keep on losing their skincolors.
743 lines
20 KiB
C
743 lines
20 KiB
C
// SONIC ROBO BLAST 2
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright (C) 1998-2000 by DooM Legacy Team.
|
|
// Copyright (C) 1999-2020 by Sonic Team Junior.
|
|
//
|
|
// This program is free software distributed under the
|
|
// terms of the GNU General Public License, version 2.
|
|
// See the 'LICENSE' file for more details.
|
|
//-----------------------------------------------------------------------------
|
|
/// \file deh_lua.c
|
|
/// \brief Lua SOC library
|
|
|
|
#include "g_game.h"
|
|
#include "s_sound.h"
|
|
#include "z_zone.h"
|
|
#include "k_menu.h"
|
|
#include "m_misc.h"
|
|
#include "p_local.h"
|
|
#include "st_stuff.h"
|
|
#include "fastcmp.h"
|
|
#include "lua_script.h"
|
|
#include "lua_libs.h"
|
|
|
|
#include "dehacked.h"
|
|
#include "deh_lua.h"
|
|
#include "deh_tables.h"
|
|
#include "deh_soc.h" // freeslotusage
|
|
|
|
// freeslot takes a name (string only!)
|
|
// and allocates it to the appropriate free slot.
|
|
// Returns the slot number allocated for it or nil if failed.
|
|
// ex. freeslot("MT_MYTHING","S_MYSTATE1","S_MYSTATE2")
|
|
// TODO: Error checking! @.@; There's currently no way to know which ones failed and why!
|
|
//
|
|
static inline int lib_freeslot(lua_State *L)
|
|
{
|
|
int n = lua_gettop(L);
|
|
int r = 0; // args returned
|
|
char *s, *type,*word;
|
|
|
|
if (!lua_lumploading)
|
|
return luaL_error(L, "This function cannot be called from within a hook or coroutine!");
|
|
|
|
if (!deh_loaded)
|
|
initfreeslots();
|
|
|
|
deh_loaded = true;
|
|
|
|
while (n-- > 0)
|
|
{
|
|
s = Z_StrDup(luaL_checkstring(L,1));
|
|
type = strtok(s, "_");
|
|
if (type)
|
|
strupr(type);
|
|
else {
|
|
Z_Free(s);
|
|
return luaL_error(L, "Unknown enum type in '%s'\n", luaL_checkstring(L, 1));
|
|
}
|
|
|
|
word = strtok(NULL, "\n");
|
|
if (word)
|
|
strupr(word);
|
|
else {
|
|
Z_Free(s);
|
|
return luaL_error(L, "Missing enum name in '%s'\n", luaL_checkstring(L, 1));
|
|
}
|
|
if (fastcmp(type, "SFX")) {
|
|
sfxenum_t sfx;
|
|
strlwr(word);
|
|
CONS_Printf("Sound sfx_%s allocated.\n",word);
|
|
sfx = S_AddSoundFx(word, false, 0, false);
|
|
if (sfx != sfx_None) {
|
|
lua_pushinteger(L, sfx);
|
|
r++;
|
|
} else
|
|
CONS_Alert(CONS_WARNING, "Ran out of free SFX slots!\n");
|
|
}
|
|
else if (fastcmp(type, "SPR"))
|
|
{
|
|
char wad;
|
|
spritenum_t j;
|
|
lua_getfield(L, LUA_REGISTRYINDEX, "WAD");
|
|
wad = (char)lua_tointeger(L, -1);
|
|
lua_pop(L, 1);
|
|
for (j = SPR_FIRSTFREESLOT; j <= SPR_LASTFREESLOT; j++)
|
|
{
|
|
if (used_spr[(j-SPR_FIRSTFREESLOT)/8] & (1<<(j%8)))
|
|
{
|
|
if (!sprnames[j][4] && memcmp(sprnames[j],word,4)==0)
|
|
sprnames[j][4] = wad;
|
|
continue; // Already allocated, next.
|
|
}
|
|
// Found a free slot!
|
|
CONS_Printf("Sprite SPR_%s allocated.\n",word);
|
|
strncpy(sprnames[j],word,4);
|
|
//sprnames[j][4] = 0;
|
|
used_spr[(j-SPR_FIRSTFREESLOT)/8] |= 1<<(j%8); // Okay, this sprite slot has been named now.
|
|
lua_pushinteger(L, j);
|
|
r++;
|
|
break;
|
|
}
|
|
if (j > SPR_LASTFREESLOT)
|
|
CONS_Alert(CONS_WARNING, "Ran out of free sprite slots!\n");
|
|
}
|
|
else if (fastcmp(type, "S"))
|
|
{
|
|
statenum_t i;
|
|
for (i = 0; i < NUMSTATEFREESLOTS; i++)
|
|
if (!FREE_STATES[i]) {
|
|
CONS_Printf("State S_%s allocated.\n",word);
|
|
FREE_STATES[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL);
|
|
strcpy(FREE_STATES[i],word);
|
|
freeslotusage[0][0]++;
|
|
lua_pushinteger(L, S_FIRSTFREESLOT + i);
|
|
r++;
|
|
break;
|
|
}
|
|
if (i == NUMSTATEFREESLOTS)
|
|
CONS_Alert(CONS_WARNING, "Ran out of free State slots!\n");
|
|
}
|
|
else if (fastcmp(type, "MT"))
|
|
{
|
|
mobjtype_t i;
|
|
for (i = 0; i < NUMMOBJFREESLOTS; i++)
|
|
if (!FREE_MOBJS[i]) {
|
|
CONS_Printf("MobjType MT_%s allocated.\n",word);
|
|
FREE_MOBJS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL);
|
|
strcpy(FREE_MOBJS[i],word);
|
|
freeslotusage[1][0]++;
|
|
lua_pushinteger(L, MT_FIRSTFREESLOT + i);
|
|
r++;
|
|
break;
|
|
}
|
|
if (i == NUMMOBJFREESLOTS)
|
|
CONS_Alert(CONS_WARNING, "Ran out of free MobjType slots!\n");
|
|
}
|
|
else if (fastcmp(type, "SKINCOLOR"))
|
|
{
|
|
skincolornum_t i;
|
|
for (i = 0; i < NUMCOLORFREESLOTS; i++)
|
|
if (!FREE_SKINCOLORS[i]) {
|
|
CONS_Printf("Skincolor SKINCOLOR_%s allocated.\n",word);
|
|
FREE_SKINCOLORS[i] = Z_Malloc(strlen(word)+1, PU_STATIC, NULL);
|
|
strcpy(FREE_SKINCOLORS[i],word);
|
|
skincolors[i].cache_spraycan = UINT16_MAX;
|
|
numskincolors++;
|
|
lua_pushinteger(L, SKINCOLOR_FIRSTFREESLOT + i);
|
|
r++;
|
|
break;
|
|
}
|
|
if (i == NUMCOLORFREESLOTS)
|
|
CONS_Alert(CONS_WARNING, "Ran out of free skincolor slots!\n");
|
|
}
|
|
else if (fastcmp(type, "SPR2"))
|
|
{
|
|
// Search if we already have an SPR2 by that name...
|
|
playersprite_t i;
|
|
for (i = SPR2_FIRSTFREESLOT; i < free_spr2; i++)
|
|
if (memcmp(spr2names[i],word,4) == 0)
|
|
break;
|
|
// We don't, so allocate a new one.
|
|
if (i >= free_spr2) {
|
|
if (free_spr2 < NUMPLAYERSPRITES)
|
|
{
|
|
CONS_Printf("Sprite SPR2_%s allocated.\n",word);
|
|
strncpy(spr2names[free_spr2],word,4);
|
|
spr2defaults[free_spr2] = 0;
|
|
lua_pushinteger(L, free_spr2);
|
|
r++;
|
|
spr2names[free_spr2++][4] = 0;
|
|
} else
|
|
CONS_Alert(CONS_WARNING, "Ran out of free SPR2 slots!\n");
|
|
}
|
|
}
|
|
else if (fastcmp(type, "TOL"))
|
|
{
|
|
// Search if we already have a typeoflevel by that name...
|
|
int i;
|
|
for (i = 0; TYPEOFLEVEL[i].name; i++)
|
|
if (fastcmp(word, TYPEOFLEVEL[i].name))
|
|
break;
|
|
|
|
// We don't, so allocate a new one.
|
|
if (TYPEOFLEVEL[i].name == NULL) {
|
|
if (lastcustomtol == (UINT32)MAXTOL) // Unless you have way too many, since they're flags.
|
|
CONS_Alert(CONS_WARNING, "Ran out of free typeoflevel slots!\n");
|
|
else {
|
|
CONS_Printf("TypeOfLevel TOL_%s allocated.\n",word);
|
|
G_AddTOL(lastcustomtol, word);
|
|
lua_pushinteger(L, lastcustomtol);
|
|
lastcustomtol <<= 1;
|
|
r++;
|
|
}
|
|
}
|
|
}
|
|
else if (fastcmp(type, "PRECIP"))
|
|
{
|
|
// Search if we already have a PRECIP by that name...
|
|
preciptype_t i;
|
|
for (i = PRECIP_FIRSTFREESLOT; i < precip_freeslot; i++)
|
|
if (fastcmp(word, precipprops[i].name))
|
|
break;
|
|
|
|
// We don't, so allocate a new one.
|
|
if (i >= precip_freeslot) {
|
|
if (precip_freeslot < MAXPRECIP)
|
|
{
|
|
CONS_Printf("Weather PRECIP_%s allocated.\n",word);
|
|
precipprops[i].name = Z_StrDup(word);
|
|
lua_pushinteger(L, precip_freeslot);
|
|
r++;
|
|
precip_freeslot++;
|
|
} else
|
|
CONS_Alert(CONS_WARNING, "Ran out of free PRECIP slots!\n");
|
|
}
|
|
}
|
|
Z_Free(s);
|
|
lua_remove(L, 1);
|
|
continue;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
// Wrapper for ALL A_Action functions.
|
|
// Arguments: mobj_t actor, int var1, int var2
|
|
static int action_call(lua_State *L)
|
|
{
|
|
//actionf_t *action = lua_touserdata(L,lua_upvalueindex(1));
|
|
actionf_t *action = *((actionf_t **)luaL_checkudata(L, 1, META_ACTION));
|
|
mobj_t *actor = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
|
|
var1 = (INT32)luaL_optinteger(L, 3, 0);
|
|
var2 = (INT32)luaL_optinteger(L, 4, 0);
|
|
if (!actor)
|
|
return LUA_ErrInvalid(L, "mobj_t");
|
|
action->acp1(actor);
|
|
return 0;
|
|
}
|
|
|
|
// Hardcoded A_Action name to call for super() or NULL if super() would be invalid.
|
|
// Set in lua_infolib.
|
|
const char *superactions[MAXRECURSION];
|
|
UINT8 superstack = 0;
|
|
|
|
static int lib_dummysuper(lua_State *L)
|
|
{
|
|
return luaL_error(L, "Can't call super() outside of hardcode-replacing A_Action functions being called by state changes!"); // convoluted, I know. @_@;;
|
|
}
|
|
|
|
static inline int lib_getenum(lua_State *L)
|
|
{
|
|
const char *word, *p;
|
|
fixed_t i;
|
|
boolean mathlib = lua_toboolean(L, lua_upvalueindex(1));
|
|
if (lua_type(L,2) != LUA_TSTRING)
|
|
return 0;
|
|
word = lua_tostring(L,2);
|
|
if (strlen(word) == 1) { // Assume sprite frame if length 1.
|
|
if (*word >= 'A' && *word <= '~')
|
|
{
|
|
lua_pushinteger(L, *word-'A');
|
|
return 1;
|
|
}
|
|
if (mathlib) return luaL_error(L, "constant '%s' could not be parsed.\n", word);
|
|
return 0;
|
|
}
|
|
else if (fastncmp("MF_", word, 3)) {
|
|
p = word+3;
|
|
for (i = 0; MOBJFLAG_LIST[i]; i++)
|
|
if (fastcmp(p, MOBJFLAG_LIST[i])) {
|
|
lua_pushinteger(L, ((lua_Integer)1<<i));
|
|
return 1;
|
|
}
|
|
if (mathlib) return luaL_error(L, "mobjflag '%s' could not be found.\n", word);
|
|
return 0;
|
|
}
|
|
else if (fastncmp("MF2_", word, 4)) {
|
|
p = word+4;
|
|
for (i = 0; MOBJFLAG2_LIST[i]; i++)
|
|
if (fastcmp(p, MOBJFLAG2_LIST[i])) {
|
|
lua_pushinteger(L, ((lua_Integer)1<<i));
|
|
return 1;
|
|
}
|
|
if (mathlib) return luaL_error(L, "mobjflag2 '%s' could not be found.\n", word);
|
|
return 0;
|
|
}
|
|
else if (fastncmp("MFE_", word, 4)) {
|
|
p = word+4;
|
|
for (i = 0; MOBJEFLAG_LIST[i]; i++)
|
|
if (fastcmp(p, MOBJEFLAG_LIST[i])) {
|
|
lua_pushinteger(L, ((lua_Integer)1<<i));
|
|
return 1;
|
|
}
|
|
if (mathlib) return luaL_error(L, "mobjeflag '%s' could not be found.\n", word);
|
|
return 0;
|
|
}
|
|
else if (fastncmp("MTF_", word, 4)) {
|
|
p = word+4;
|
|
for (i = 0; i < 4; i++)
|
|
if (MAPTHINGFLAG_LIST[i] && fastcmp(p, MAPTHINGFLAG_LIST[i])) {
|
|
lua_pushinteger(L, ((lua_Integer)1<<i));
|
|
return 1;
|
|
}
|
|
if (mathlib) return luaL_error(L, "mapthingflag '%s' could not be found.\n", word);
|
|
return 0;
|
|
}
|
|
else if (fastncmp("PF_", word, 3)) {
|
|
p = word+3;
|
|
for (i = 0; PLAYERFLAG_LIST[i]; i++)
|
|
if (fastcmp(p, PLAYERFLAG_LIST[i])) {
|
|
lua_pushinteger(L, ((lua_Integer)1<<i));
|
|
return 1;
|
|
}
|
|
if (mathlib) return luaL_error(L, "playerflag '%s' could not be found.\n", word);
|
|
return 0;
|
|
}
|
|
else if (fastncmp("GT_", word, 3)) {
|
|
p = word;
|
|
i = 0;
|
|
while (gametypes[i] != NULL)
|
|
{
|
|
if (fastcmp(p, gametypes[i]->constant))
|
|
{
|
|
lua_pushinteger(L, i);
|
|
return 1;
|
|
}
|
|
i++;
|
|
}
|
|
if (mathlib) return luaL_error(L, "gametype '%s' could not be found.\n", word);
|
|
return 0;
|
|
}
|
|
else if (fastncmp("GTR_", word, 4)) {
|
|
p = word+4;
|
|
for (i = 0; GAMETYPERULE_LIST[i]; i++)
|
|
if (fastcmp(p, GAMETYPERULE_LIST[i])) {
|
|
lua_pushinteger(L, ((lua_Integer)1<<i));
|
|
return 1;
|
|
}
|
|
if (mathlib) return luaL_error(L, "game type rule '%s' could not be found.\n", word);
|
|
return 0;
|
|
}
|
|
else if (fastncmp("TOL_", word, 4)) {
|
|
p = word+4;
|
|
for (i = 0; TYPEOFLEVEL[i].name; i++)
|
|
if (fastcmp(p, TYPEOFLEVEL[i].name)) {
|
|
lua_pushinteger(L, TYPEOFLEVEL[i].flag);
|
|
return 1;
|
|
}
|
|
if (mathlib) return luaL_error(L, "typeoflevel '%s' could not be found.\n", word);
|
|
return 0;
|
|
}
|
|
else if (fastncmp("ML_", word, 3)) {
|
|
p = word+3;
|
|
for (i = 0; ML_LIST[i]; i++)
|
|
if (fastcmp(p, ML_LIST[i])) {
|
|
lua_pushinteger(L, ((lua_Integer)1<<i));
|
|
return 1;
|
|
}
|
|
// Aliases
|
|
if (fastcmp(p, "EFFECT1"))
|
|
{
|
|
lua_pushinteger(L, (lua_Integer)ML_SKEWTD);
|
|
return 1;
|
|
}
|
|
if (fastcmp(p, "EFFECT2"))
|
|
{
|
|
lua_pushinteger(L, (lua_Integer)ML_NOSKEW);
|
|
return 1;
|
|
}
|
|
if (fastcmp(p, "EFFECT3"))
|
|
{
|
|
lua_pushinteger(L, (lua_Integer)ML_MIDPEG);
|
|
return 1;
|
|
}
|
|
if (fastcmp(p, "EFFECT4"))
|
|
{
|
|
lua_pushinteger(L, (lua_Integer)ML_MIDSOLID);
|
|
return 1;
|
|
}
|
|
if (fastcmp(p, "EFFECT5"))
|
|
{
|
|
lua_pushinteger(L, (lua_Integer)ML_WRAPMIDTEX);
|
|
return 1;
|
|
}
|
|
if (mathlib) return luaL_error(L, "linedef flag '%s' could not be found.\n", word);
|
|
return 0;
|
|
}
|
|
else if (fastncmp("MSF_", word, 4)) {
|
|
p = word + 4;
|
|
for (i = 0; MSF_LIST[i]; i++)
|
|
if (fastcmp(p, MSF_LIST[i])) {
|
|
lua_pushinteger(L, ((lua_Integer)1 << i));
|
|
return 1;
|
|
}
|
|
if (fastcmp(p, "FLIPSPECIAL_BOTH"))
|
|
{
|
|
lua_pushinteger(L, (lua_Integer)MSF_FLIPSPECIAL_BOTH);
|
|
return 1;
|
|
}
|
|
if (mathlib) return luaL_error(L, "sector flag '%s' could not be found.\n", word);
|
|
return 0;
|
|
}
|
|
else if (fastncmp("SSF_", word, 4)) {
|
|
p = word + 4;
|
|
for (i = 0; SSF_LIST[i]; i++)
|
|
if (fastcmp(p, SSF_LIST[i])) {
|
|
lua_pushinteger(L, ((lua_Integer)1 << i));
|
|
return 1;
|
|
}
|
|
if (mathlib) return luaL_error(L, "sector special flag '%s' could not be found.\n", word);
|
|
return 0;
|
|
}
|
|
else if (fastncmp("SD_", word, 3)) {
|
|
p = word + 3;
|
|
for (i = 0; SD_LIST[i]; i++)
|
|
if (fastcmp(p, SD_LIST[i])) {
|
|
lua_pushinteger(L, i);
|
|
return 1;
|
|
}
|
|
if (mathlib) return luaL_error(L, "sector damagetype '%s' could not be found.\n", word);
|
|
return 0;
|
|
}
|
|
else if (fastncmp("TO_", word, 3)) {
|
|
p = word + 3;
|
|
for (i = 0; TO_LIST[i]; i++)
|
|
if (fastcmp(p, TO_LIST[i])) {
|
|
lua_pushinteger(L, i);
|
|
return 1;
|
|
}
|
|
if (mathlib) return luaL_error(L, "sector triggerer '%s' could not be found.\n", word);
|
|
return 0;
|
|
}
|
|
else if (fastncmp("S_",word,2)) {
|
|
p = word+2;
|
|
for (i = 0; i < NUMSTATEFREESLOTS; i++) {
|
|
if (!FREE_STATES[i])
|
|
break;
|
|
if (fastcmp(p, FREE_STATES[i])) {
|
|
lua_pushinteger(L, S_FIRSTFREESLOT+i);
|
|
return 1;
|
|
}
|
|
}
|
|
for (i = 0; i < S_FIRSTFREESLOT; i++)
|
|
if (fastcmp(p, STATE_LIST[i]+2)) {
|
|
lua_pushinteger(L, i);
|
|
return 1;
|
|
}
|
|
return luaL_error(L, "state '%s' does not exist.\n", word);
|
|
}
|
|
else if (fastncmp("MT_",word,3)) {
|
|
p = word+3;
|
|
for (i = 0; i < NUMMOBJFREESLOTS; i++) {
|
|
if (!FREE_MOBJS[i])
|
|
break;
|
|
if (fastcmp(p, FREE_MOBJS[i])) {
|
|
lua_pushinteger(L, MT_FIRSTFREESLOT+i);
|
|
return 1;
|
|
}
|
|
}
|
|
for (i = 0; i < MT_FIRSTFREESLOT; i++)
|
|
if (fastcmp(p, MOBJTYPE_LIST[i]+3)) {
|
|
lua_pushinteger(L, i);
|
|
return 1;
|
|
}
|
|
return luaL_error(L, "mobjtype '%s' does not exist.\n", word);
|
|
}
|
|
else if (fastncmp("SPR_",word,4)) {
|
|
p = word+4;
|
|
for (i = 0; i < NUMSPRITES; i++)
|
|
if (!sprnames[i][4] && fastncmp(p,sprnames[i],4)) {
|
|
lua_pushinteger(L, i);
|
|
return 1;
|
|
}
|
|
if (mathlib) return luaL_error(L, "sprite '%s' could not be found.\n", word);
|
|
return 0;
|
|
}
|
|
else if (fastncmp("SPR2_",word,5)) {
|
|
p = word+5;
|
|
for (i = 0; i < (fixed_t)free_spr2; i++)
|
|
if (!spr2names[i][4])
|
|
{
|
|
// special 3-char cases, e.g. SPR2_RUN
|
|
// the spr2names entry will have "_" on the end, as in "RUN_"
|
|
if (spr2names[i][3] == '_' && !p[3]) {
|
|
if (fastncmp(p,spr2names[i],3)) {
|
|
lua_pushinteger(L, i);
|
|
return 1;
|
|
}
|
|
}
|
|
else if (fastncmp(p,spr2names[i],4)) {
|
|
lua_pushinteger(L, i);
|
|
return 1;
|
|
}
|
|
}
|
|
if (mathlib) return luaL_error(L, "player sprite '%s' could not be found.\n", word);
|
|
return 0;
|
|
}
|
|
else if (fastncmp("sfx_",word,4)) {
|
|
p = word+4;
|
|
for (i = 0; i < NUMSFX; i++)
|
|
if (S_sfx[i].name && fastcmp(p, S_sfx[i].name)) {
|
|
lua_pushinteger(L, i);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
else if (mathlib && fastncmp("SFX_",word,4)) { // SOCs are ALL CAPS!
|
|
p = word+4;
|
|
for (i = 0; i < NUMSFX; i++)
|
|
if (S_sfx[i].name && fasticmp(p, S_sfx[i].name)) {
|
|
lua_pushinteger(L, i);
|
|
return 1;
|
|
}
|
|
return luaL_error(L, "sfx '%s' could not be found.\n", word);
|
|
}
|
|
else if (mathlib && fastncmp("DS",word,2)) {
|
|
p = word+2;
|
|
for (i = 0; i < NUMSFX; i++)
|
|
if (S_sfx[i].name && fasticmp(p, S_sfx[i].name)) {
|
|
lua_pushinteger(L, i);
|
|
return 1;
|
|
}
|
|
if (mathlib) return luaL_error(L, "sfx '%s' could not be found.\n", word);
|
|
return 0;
|
|
}
|
|
else if (!mathlib && fastncmp("khud_",word,5)) {
|
|
p = word+5;
|
|
for (i = 0; i < NUMKARTHUD; i++)
|
|
if (fasticmp(p, KARTHUD_LIST[i])) {
|
|
lua_pushinteger(L, i);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
else if (mathlib && fastncmp("KHUD_",word,5)) { // SOCs are ALL CAPS!
|
|
p = word+5;
|
|
for (i = 0; i < NUMKARTHUD; i++)
|
|
if (fastcmp(p, KARTHUD_LIST[i])) {
|
|
lua_pushinteger(L, i);
|
|
return 1;
|
|
}
|
|
return luaL_error(L, "karthud '%s' could not be found.\n", word);
|
|
}
|
|
else if (fastncmp("SKINCOLOR_",word,10)) {
|
|
p = word+10;
|
|
for (i = 0; i < NUMCOLORFREESLOTS; i++) {
|
|
if (!FREE_SKINCOLORS[i])
|
|
break;
|
|
if (fastcmp(p, FREE_SKINCOLORS[i])) {
|
|
lua_pushinteger(L, SKINCOLOR_FIRSTFREESLOT+i);
|
|
return 1;
|
|
}
|
|
}
|
|
for (i = 0; i < SKINCOLOR_FIRSTFREESLOT; i++)
|
|
if (fastcmp(p, COLOR_ENUMS[i])) {
|
|
lua_pushinteger(L, i);
|
|
return 1;
|
|
}
|
|
return luaL_error(L, "skincolor '%s' could not be found.\n", word);
|
|
}
|
|
else if (fastncmp("PRECIP_",word,7)) {
|
|
p = word+7;
|
|
for (i = 0; i < MAXPRECIP; i++)
|
|
{
|
|
if (precipprops[i].name == NULL)
|
|
break;
|
|
|
|
if (fastcmp(p, precipprops[i].name))
|
|
{
|
|
lua_pushinteger(L, PRECIP_NONE + i);
|
|
return 1;
|
|
}
|
|
}
|
|
return luaL_error(L, "weather type '%s' does not exist.\n", word);
|
|
}
|
|
else if (!mathlib && fastncmp("A_",word,2)) {
|
|
char *caps;
|
|
// Try to get a Lua action first.
|
|
/// \todo Push a closure that sets superactions[] and superstack.
|
|
lua_getfield(L, LUA_REGISTRYINDEX, LREG_ACTIONS);
|
|
// actions are stored in all uppercase.
|
|
caps = Z_StrDup(word);
|
|
strupr(caps);
|
|
lua_getfield(L, -1, caps);
|
|
Z_Free(caps);
|
|
if (!lua_isnil(L, -1))
|
|
return 1; // Success! :D That was easy.
|
|
// Welp, that failed.
|
|
lua_pop(L, 2); // pop nil and LREG_ACTIONS
|
|
|
|
// Hardcoded actions as callable Lua functions!
|
|
// Retrieving them from this metatable allows them to be case-insensitive!
|
|
for (i = 0; actionpointers[i].name; i++)
|
|
if (fasticmp(word, actionpointers[i].name)) {
|
|
// We push the actionf_t* itself as userdata!
|
|
LUA_PushUserdata(L, &actionpointers[i].action, META_ACTION);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
else if (!mathlib && fastcmp("super",word))
|
|
{
|
|
if (!superstack)
|
|
{
|
|
lua_pushcfunction(L, lib_dummysuper);
|
|
return 1;
|
|
}
|
|
for (i = 0; actionpointers[i].name; i++)
|
|
if (fasticmp(superactions[superstack-1], actionpointers[i].name)) {
|
|
LUA_PushUserdata(L, &actionpointers[i].action, META_ACTION);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; INT_CONST[i].n; i++)
|
|
if (fastcmp(word,INT_CONST[i].n)) {
|
|
lua_pushinteger(L, INT_CONST[i].v);
|
|
return 1;
|
|
}
|
|
|
|
if (mathlib) return luaL_error(L, "constant '%s' could not be parsed.\n", word);
|
|
|
|
// DYNAMIC variables too!!
|
|
// Try not to add anything that would break netgames or timeattack replays here.
|
|
// You know, like consoleplayer, displayplayer, secondarydisplayplayer, or gametime.
|
|
return LUA_PushGlobals(L, word);
|
|
}
|
|
|
|
int LUA_EnumLib(lua_State *L)
|
|
{
|
|
if (lua_gettop(L) == 0)
|
|
lua_pushboolean(L, 0);
|
|
|
|
// Set the global metatable
|
|
lua_createtable(L, 0, 1);
|
|
lua_pushvalue(L, 1); // boolean passed to LUA_EnumLib as first argument.
|
|
lua_pushcclosure(L, lib_getenum, 1);
|
|
lua_setfield(L, -2, "__index");
|
|
lua_setmetatable(L, LUA_GLOBALSINDEX);
|
|
return 0;
|
|
}
|
|
|
|
// getActionName(action) -> return action's string name
|
|
static int lib_getActionName(lua_State *L)
|
|
{
|
|
if (lua_isuserdata(L, 1)) // arg 1 is built-in action, expect action userdata
|
|
{
|
|
actionf_t *action = *((actionf_t **)luaL_checkudata(L, 1, META_ACTION));
|
|
const char *name = NULL;
|
|
if (!action)
|
|
return luaL_error(L, "not a valid action?");
|
|
name = LUA_GetActionName(action);
|
|
if (!name) // that can't be right?
|
|
return luaL_error(L, "no name string could be found for this action");
|
|
lua_pushstring(L, name);
|
|
return 1;
|
|
}
|
|
else if (lua_isfunction(L, 1)) // arg 1 is a function (either C or Lua)
|
|
{
|
|
lua_settop(L, 1); // set top of stack to 1 (removing any extra args, which there shouldn't be)
|
|
// get the name for this action, if possible.
|
|
lua_getfield(L, LUA_REGISTRYINDEX, LREG_ACTIONS);
|
|
lua_pushnil(L);
|
|
// Lua stack at this point:
|
|
// 1 ... -2 -1
|
|
// arg ... LREG_ACTIONS nil
|
|
while (lua_next(L, -2))
|
|
{
|
|
// Lua stack at this point:
|
|
// 1 ... -3 -2 -1
|
|
// arg ... LREG_ACTIONS "A_ACTION" function
|
|
if (lua_rawequal(L, -1, 1)) // is this the same as the arg?
|
|
{
|
|
// make sure the key (i.e. "A_ACTION") is a string first
|
|
// (note: we don't use lua_isstring because it also returns true for numbers)
|
|
if (lua_type(L, -2) == LUA_TSTRING)
|
|
{
|
|
lua_pushvalue(L, -2); // push "A_ACTION" string to top of stack
|
|
return 1;
|
|
}
|
|
lua_pop(L, 2); // pop the name and function
|
|
break; // probably should have succeeded but we didn't, so end the loop
|
|
}
|
|
lua_pop(L, 1);
|
|
}
|
|
lua_pop(L, 1); // pop LREG_ACTIONS
|
|
return 0; // return nothing (don't error)
|
|
}
|
|
|
|
return luaL_typerror(L, 1, "action userdata or Lua function");
|
|
}
|
|
|
|
|
|
|
|
int LUA_SOCLib(lua_State *L)
|
|
{
|
|
lua_register(L,"freeslot",lib_freeslot);
|
|
lua_register(L,"getActionName",lib_getActionName);
|
|
|
|
luaL_newmetatable(L, META_ACTION);
|
|
lua_pushcfunction(L, action_call);
|
|
lua_setfield(L, -2, "__call");
|
|
lua_pop(L, 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
const char *LUA_GetActionName(void *action)
|
|
{
|
|
actionf_t *act = (actionf_t *)action;
|
|
size_t z;
|
|
for (z = 0; actionpointers[z].name; z++)
|
|
{
|
|
if (actionpointers[z].action.acv == act->acv)
|
|
return actionpointers[z].name;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void LUA_SetActionByName(void *state, const char *actiontocompare)
|
|
{
|
|
state_t *st = (state_t *)state;
|
|
size_t z;
|
|
for (z = 0; actionpointers[z].name; z++)
|
|
{
|
|
if (fasticmp(actiontocompare, actionpointers[z].name))
|
|
{
|
|
st->action = actionpointers[z].action;
|
|
st->action.acv = actionpointers[z].action.acv; // assign
|
|
st->action.acp1 = actionpointers[z].action.acp1;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
size_t LUA_GetActionNumByName(const char *actiontocompare)
|
|
{
|
|
size_t z;
|
|
for (z = 0; actionpointers[z].name; z++)
|
|
if (fasticmp(actiontocompare, actionpointers[z].name))
|
|
return z;
|
|
return z;
|
|
}
|