blankart/src/lua_itemlib.c
2026-01-01 14:45:23 -05:00

386 lines
8.9 KiB
C

// BLANKART
//-----------------------------------------------------------------------------
// Copyright (C) 2026 by BlanKart Team.
// Copyright (C) 2014-2025 by Sonic Team Junior.
// Copyright (C) 2016 by John "JTE" Muniz.
//
// 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 lua_itemlib.c
/// \brief item structures library for Lua scripting
#include "doomdef.h"
#include "k_items.h"
#include "lua_script.h"
#include "lua_libs.h"
#include "lua_hud.h" // hud_running errors
#include "lua_hook.h" // hook_cmd_running errors
enum itemvars
{
itemvars_equipstyle,
itemvars_equipstylealt,
itemvars_flags,
itemvars_flagsalt,
//itemvars_graphics, // see K_GetItemGraphics
itemvars_altcvar,
itemvars_altenabled,
};
static const char *const itemvars_opt[] = {
"equipstyle",
"equipstylealt",
"flags",
"flagsalt",
//"graphics",
"altcvar",
"altenabled",
NULL
};
static int item_get(lua_State *L)
{
kartitem_t *item = *((kartitem_t**)luaL_checkudata(L, 1, META_KARTITEM));
enum itemvars field = luaL_checkoption(L, 2, NULL, itemvars_opt);
// items are always valid, only added, never removed
I_Assert(item != NULL);
switch (field)
{
case itemvars_equipstyle:
lua_pushinteger(L, item->equipstyle[0]);
break;
case itemvars_equipstylealt:
lua_pushinteger(L, item->equipstyle[1]);
break;
case itemvars_flags:
lua_pushinteger(L, item->flags[0]);
break;
case itemvars_flagsalt:
lua_pushinteger(L, item->flags[1]);
break;
case itemvars_altcvar:
LUA_PushUserdata(L, item->altcvar, META_CVAR);
break;
case itemvars_altenabled:
lua_pushboolean(L, item->altenabled);
break;
default:
return luaL_error(L, LUA_QL("kartitem_t") " has no field named " LUA_QS, itemvars_opt[field]);
}
return 1;
}
static int item_set(lua_State *L)
{
return luaL_error(L, LUA_QL("kartitem_t") " struct cannot be edited by Lua.");
}
static int item_num(lua_State *L)
{
kartitem_t *item = *((kartitem_t**)luaL_checkudata(L, 1, META_KARTITEM));
// items are always valid, only added, never removed
I_Assert(item != NULL);
lua_pushinteger(L, item - kartitems);
return 1;
}
enum resultvars
{
resultvars_type,
resultvars_amount,
resultvars_displayname,
resultvars_isalt,
resultvars_flags,
//resultvars_odds,
//resultvars_uniqueodds,
resultvars_basecooldown,
resultvars_cooldown,
};
static const char *const resultvars_opt[] = {
"type",
"amount",
"displayname",
"isalt",
"flags",
//"odds",
//"uniqueodds",
"basecooldown",
"cooldown",
NULL
};
static int result_get(lua_State *L)
{
kartresult_t *result = *((kartresult_t**)luaL_checkudata(L, 1, META_KARTRESULT));
enum resultvars field = luaL_checkoption(L, 2, NULL, resultvars_opt);
// results are always valid, only added, never removed
I_Assert(result != NULL);
switch (field)
{
case resultvars_type:
lua_pushinteger(L, result->type);
break;
case resultvars_amount:
lua_pushinteger(L, result->amount);
break;
case resultvars_displayname:
lua_pushstring(L, result->displayname);
break;
case resultvars_isalt:
lua_pushboolean(L, result->isalt);
break;
case resultvars_flags:
lua_pushinteger(L, result->flags);
break;
//case resultvars_odds:
//i don't have time for this shit
//break;
//case resultvars_uniqueodds:
//break;
case resultvars_basecooldown:
lua_pushinteger(L, result->basecooldown);
break;
case resultvars_cooldown:
lua_pushinteger(L, result->cooldown);
break;
default:
return luaL_error(L, LUA_QL("kartresult_t") " has no field named " LUA_QS, resultvars_opt[field]);
}
return 1;
}
static int result_set(lua_State *L)
{
kartresult_t *result = *((kartresult_t**)luaL_checkudata(L, 1, META_KARTRESULT));
enum resultvars field = luaL_checkoption(L, 2, NULL, resultvars_opt);
if (hud_running)
return luaL_error(L, "Do not alter kartresult_t in HUD rendering code!");
if (hook_cmd_running)
return luaL_error(L, "Do not alter kartresult_t in BuildCMD code!");
// results are always valid, only added, never removed
I_Assert(result != NULL);
switch (field)
{
case resultvars_type:
case resultvars_amount:
case resultvars_displayname:
case resultvars_isalt:
case resultvars_flags:
case resultvars_basecooldown:
return luaL_error(L, LUA_QL("kartresult_t") " field " LUA_QS " should not be set directly.", resultvars_opt[field]);
case resultvars_cooldown:
result->cooldown = luaL_checkinteger(L, 3);
break;
default:
return luaL_error(L, LUA_QL("kartresult_t") " has no field named " LUA_QS, resultvars_opt[field]);
}
return 0;
}
static int result_num(lua_State *L)
{
kartresult_t *result = *((kartresult_t**)luaL_checkudata(L, 1, META_KARTRESULT));
// results are always valid, only added, never removed
I_Assert(result != NULL);
lua_pushinteger(L, result - kartresults);
return 1;
}
static int graphics_get(lua_State *L)
{
kartitemgraphics_t *graphics = *((kartitemgraphics_t**)luaL_checkudata(L, 1, META_KARTITEMGRAPHICS));
INT32 index = luaL_checkinteger(L, 2);
if (index < 0 || index >= graphics->numpatches)
return luaL_error(L, "patch index %d out of range (0 - %d)", index, graphics->numpatches-1);
LUA_PushUserdata(L, graphics->patches[index], META_PATCH);
return 1;
}
static int graphics_set(lua_State *L)
{
return luaL_error(L, LUA_QL("kartitemgraphics_t") " struct cannot be edited by Lua.");
}
static int graphics_num(lua_State *L)
{
kartitemgraphics_t *graphics = *((kartitemgraphics_t**)luaL_checkudata(L, 1, META_KARTITEMGRAPHICS));
lua_pushinteger(L, graphics->numpatches);
return 1;
}
static int lib_iterateKartItems(lua_State *L)
{
INT32 i;
if (lua_gettop(L) < 2)
{
lua_pushcfunction(L, lib_iterateKartItems);
return 1;
}
lua_settop(L, 2);
lua_remove(L, 1); // state is unused.
if (!lua_isnil(L, 1))
i = (*(kartitem_t **)luaL_checkudata(L, 1, META_KARTITEM)) - kartitems + 1;
else
i = 1;
if (i >= 1 && i < numkartitems)
{
LUA_PushUserdata(L, &kartitems[i], META_KARTITEM);
return 1;
}
return 0;
}
static int lib_iterateKartResults(lua_State *L)
{
INT32 i;
if (lua_gettop(L) < 2)
{
lua_pushcfunction(L, lib_iterateKartResults);
return 1;
}
lua_settop(L, 2);
lua_remove(L, 1); // state is unused.
if (!lua_isnil(L, 1))
i = (*(kartresult_t **)luaL_checkudata(L, 1, META_KARTRESULT)) - kartresults + 1;
else
i = 0;
if (i >= 0 && i < numkartresults)
{
LUA_PushUserdata(L, &kartresults[i], META_KARTRESULT);
return 1;
}
return 0;
}
static int lib_getKartItem(lua_State *L)
{
if (lua_type(L, 2) == LUA_TNUMBER)
{
INT32 i = luaL_checkinteger(L, 2);
if (i < 1 || i >= numkartitems)
return luaL_error(L, "kartitem index %d out of range (1 - %d)", i, numkartitems-1);
LUA_PushUserdata(L, &kartitems[i], META_KARTITEM);
return 1;
}
const char *field = luaL_checkstring(L, 2);
if (fastcmp(field, "iterate"))
{
lua_pushcfunction(L, lib_iterateKartItems);
return 1;
}
return 0;
}
static int lib_numKartItems(lua_State *L)
{
lua_pushinteger(L, numkartitems);
return 1;
}
static int lib_getKartResult(lua_State *L)
{
if (lua_type(L, 2) == LUA_TNUMBER)
{
INT32 i = luaL_checkinteger(L, 2);
if (i < 0 || i >= numkartresults)
return luaL_error(L, "kartresult index %d out of range (0 - %d)", i, numkartresults-1);
LUA_PushUserdata(L, &kartresults[i], META_KARTRESULT);
return 1;
}
const char *field = luaL_checkstring(L, 2);
if (fastcmp(field, "iterate"))
{
lua_pushcfunction(L, lib_iterateKartResults);
return 1;
}
return 0;
}
static int lib_numKartResults(lua_State *L)
{
lua_pushinteger(L, numkartresults);
return 1;
}
int LUA_ItemLib(lua_State *L)
{
luaL_newmetatable(L, META_KARTITEM);
lua_pushcfunction(L, item_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, item_set);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, item_num);
lua_setfield(L, -2, "__len");
lua_pop(L, 1);
luaL_newmetatable(L, META_KARTRESULT);
lua_pushcfunction(L, result_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, result_set);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, result_num);
lua_setfield(L, -2, "__len");
lua_pop(L, 1);
luaL_newmetatable(L, META_KARTITEMGRAPHICS);
lua_pushcfunction(L, graphics_get);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, graphics_set);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, graphics_num);
lua_setfield(L, -2, "__len");
lua_pop(L, 1);
lua_newuserdata(L, 0);
lua_createtable(L, 0, 2);
lua_pushcfunction(L, lib_getKartItem);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, lib_numKartItems);
lua_setfield(L, -2, "__len");
lua_setmetatable(L, -2);
lua_setglobal(L, "kartitems");
lua_newuserdata(L, 0);
lua_createtable(L, 0, 2);
lua_pushcfunction(L, lib_getKartResult);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, lib_numKartResults);
lua_setfield(L, -2, "__len");
lua_setmetatable(L, -2);
lua_setglobal(L, "kartresults");
return 0;
}