2020-09-08 17:08:08 +00:00
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
2021-05-07 16:04:30 +00:00
// Copyright (C) 2020-2021 by Iestyn "Monster Iestyn" Jealous.
// Copyright (C) 2020-2021 by Sonic Team Junior.
2020-09-08 17:08:08 +00:00
//
// 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_polyobjlib.c
/// \brief polyobject library for Lua scripting
# include "doomdef.h"
2020-09-08 17:55:16 +00:00
# include "fastcmp.h"
2020-09-08 17:08:08 +00:00
# include "p_local.h"
# include "p_polyobj.h"
# include "lua_script.h"
# include "lua_libs.h"
2020-09-09 18:38:56 +00:00
# include "lua_hud.h" // hud_running errors
# define NOHUD if (hud_running)\
return luaL_error ( L , " HUD rendering code should not call this function! " ) ;
2020-09-08 17:08:08 +00:00
2020-09-08 17:29:10 +00:00
enum polyobj_e {
2020-09-09 17:09:32 +00:00
// properties
2020-09-08 17:29:10 +00:00
polyobj_valid = 0 ,
2020-09-08 20:42:51 +00:00
polyobj_id ,
polyobj_parent ,
2020-09-09 20:15:02 +00:00
polyobj_vertices ,
polyobj_lines ,
2020-09-09 16:06:36 +00:00
polyobj_sector ,
2020-09-08 20:42:51 +00:00
polyobj_angle ,
polyobj_damage ,
polyobj_thrust ,
2020-09-08 21:10:11 +00:00
polyobj_flags ,
polyobj_translucency ,
2020-09-09 17:09:32 +00:00
polyobj_triggertag ,
2020-09-09 18:38:56 +00:00
// special functions - utility
2020-09-09 17:09:32 +00:00
polyobj_pointInside ,
polyobj_mobjTouching ,
2020-09-09 18:38:56 +00:00
polyobj_mobjInside ,
// special functions - manipulation
polyobj_moveXY ,
polyobj_rotate
2020-09-08 17:29:10 +00:00
} ;
static const char * const polyobj_opt [ ] = {
2020-09-09 17:09:32 +00:00
// properties
2020-09-08 17:29:10 +00:00
" valid " ,
2020-09-08 20:42:51 +00:00
" id " ,
" parent " ,
2020-09-09 20:15:02 +00:00
" vertices " ,
" lines " ,
2020-09-09 16:06:36 +00:00
" sector " ,
2020-09-08 20:42:51 +00:00
" angle " ,
" damage " ,
" thrust " ,
" flags " ,
2020-09-08 21:10:11 +00:00
" translucency " ,
" triggertag " ,
2020-09-09 18:38:56 +00:00
// special functions - utility
2020-09-09 17:09:32 +00:00
" pointInside " ,
" mobjTouching " ,
" mobjInside " ,
2020-09-09 18:38:56 +00:00
// special functions - manipulation
" moveXY " ,
" rotate " ,
2020-09-08 17:29:10 +00:00
NULL } ;
2020-09-09 20:15:02 +00:00
static const char * const valid_opt [ ] = { " valid " , NULL } ;
////////////////////////
// polyobj.vertices[] //
////////////////////////
// polyobj.vertices, i -> polyobj.vertices[i]
// polyobj.vertices.valid, for validity checking
//
// see sectorlines_get in lua_maplib.c
//
static int polyobjvertices_get ( lua_State * L )
{
vertex_t * * * polyverts = * ( ( vertex_t * * * * ) luaL_checkudata ( L , 1 , META_POLYOBJVERTICES ) ) ;
size_t i ;
size_t numofverts = 0 ;
lua_settop ( L , 2 ) ;
if ( ! lua_isnumber ( L , 2 ) )
{
int field = luaL_checkoption ( L , 2 , NULL , valid_opt ) ;
if ( ! polyverts | | ! ( * polyverts ) )
{
if ( field = = 0 ) {
lua_pushboolean ( L , 0 ) ;
return 1 ;
}
return luaL_error ( L , " accessed polyobj_t.vertices doesn't exist anymore. " ) ;
} else if ( field = = 0 ) {
lua_pushboolean ( L , 1 ) ;
return 1 ;
}
}
2020-10-15 23:17:51 +00:00
numofverts = * ( size_t * ) FIELDFROM ( polyobj_t , polyverts , vertices , /* -> */ numVertices ) ;
2020-09-09 20:15:02 +00:00
if ( ! numofverts )
return luaL_error ( L , " no vertices found! " ) ;
i = ( size_t ) lua_tointeger ( L , 2 ) ;
if ( i > = numofverts )
return 0 ;
LUA_PushUserdata ( L , ( * polyverts ) [ i ] , META_VERTEX ) ;
return 1 ;
}
// #(polyobj.vertices) -> polyobj.numVertices
static int polyobjvertices_num ( lua_State * L )
{
vertex_t * * * polyverts = * ( ( vertex_t * * * * ) luaL_checkudata ( L , 1 , META_POLYOBJVERTICES ) ) ;
size_t numofverts = 0 ;
if ( ! polyverts | | ! ( * polyverts ) )
return luaL_error ( L , " accessed polyobj_t.vertices doesn't exist anymore. " ) ;
2020-10-15 23:17:51 +00:00
numofverts = * ( size_t * ) FIELDFROM ( polyobj_t , polyverts , vertices , /* -> */ numVertices ) ;
2020-09-09 20:15:02 +00:00
lua_pushinteger ( L , numofverts ) ;
return 1 ;
}
/////////////////////
// polyobj.lines[] //
/////////////////////
// polyobj.lines, i -> polyobj.lines[i]
// polyobj.lines.valid, for validity checking
//
// see sectorlines_get in lua_maplib.c
//
static int polyobjlines_get ( lua_State * L )
{
line_t * * * polylines = * ( ( line_t * * * * ) luaL_checkudata ( L , 1 , META_POLYOBJLINES ) ) ;
size_t i ;
size_t numoflines = 0 ;
lua_settop ( L , 2 ) ;
if ( ! lua_isnumber ( L , 2 ) )
{
int field = luaL_checkoption ( L , 2 , NULL , valid_opt ) ;
if ( ! polylines | | ! ( * polylines ) )
{
if ( field = = 0 ) {
lua_pushboolean ( L , 0 ) ;
return 1 ;
}
return luaL_error ( L , " accessed polyobj_t.lines doesn't exist anymore. " ) ;
} else if ( field = = 0 ) {
lua_pushboolean ( L , 1 ) ;
return 1 ;
}
}
2020-10-15 23:17:51 +00:00
numoflines = * ( size_t * ) FIELDFROM ( polyobj_t , polylines , lines , /* -> */ numLines ) ;
2020-09-09 20:15:02 +00:00
if ( ! numoflines )
return luaL_error ( L , " no lines found! " ) ;
i = ( size_t ) lua_tointeger ( L , 2 ) ;
if ( i > = numoflines )
return 0 ;
LUA_PushUserdata ( L , ( * polylines ) [ i ] , META_LINE ) ;
return 1 ;
}
// #(polyobj.lines) -> polyobj.numLines
static int polyobjlines_num ( lua_State * L )
{
line_t * * * polylines = * ( ( line_t * * * * ) luaL_checkudata ( L , 1 , META_POLYOBJLINES ) ) ;
size_t numoflines = 0 ;
if ( ! polylines | | ! ( * polylines ) )
return luaL_error ( L , " accessed polyobj_t.lines doesn't exist anymore. " ) ;
2020-10-15 23:17:51 +00:00
numoflines = * ( size_t * ) FIELDFROM ( polyobj_t , polylines , lines , /* -> */ numLines ) ;
2020-09-09 20:15:02 +00:00
lua_pushinteger ( L , numoflines ) ;
return 1 ;
}
/////////////////////////////////
// polyobj_t function wrappers //
/////////////////////////////////
2020-09-09 18:38:56 +00:00
// special functions - utility
2020-09-09 17:09:32 +00:00
static int lib_polyobj_PointInside ( lua_State * L )
{
polyobj_t * po = * ( ( polyobj_t * * ) luaL_checkudata ( L , 1 , META_POLYOBJ ) ) ;
fixed_t x = luaL_checkfixed ( L , 2 ) ;
fixed_t y = luaL_checkfixed ( L , 3 ) ;
INLEVEL
if ( ! po )
return LUA_ErrInvalid ( L , " polyobj_t " ) ;
lua_pushboolean ( L , P_PointInsidePolyobj ( po , x , y ) ) ;
return 1 ;
}
static int lib_polyobj_MobjTouching ( lua_State * L )
{
polyobj_t * po = * ( ( polyobj_t * * ) luaL_checkudata ( L , 1 , META_POLYOBJ ) ) ;
mobj_t * mo = * ( ( mobj_t * * ) luaL_checkudata ( L , 2 , META_MOBJ ) ) ;
INLEVEL
if ( ! po )
return LUA_ErrInvalid ( L , " polyobj_t " ) ;
if ( ! mo )
return LUA_ErrInvalid ( L , " mobj_t " ) ;
lua_pushboolean ( L , P_MobjTouchingPolyobj ( po , mo ) ) ;
return 1 ;
}
static int lib_polyobj_MobjInside ( lua_State * L )
{
polyobj_t * po = * ( ( polyobj_t * * ) luaL_checkudata ( L , 1 , META_POLYOBJ ) ) ;
mobj_t * mo = * ( ( mobj_t * * ) luaL_checkudata ( L , 2 , META_MOBJ ) ) ;
INLEVEL
if ( ! po )
return LUA_ErrInvalid ( L , " polyobj_t " ) ;
if ( ! mo )
return LUA_ErrInvalid ( L , " mobj_t " ) ;
lua_pushboolean ( L , P_MobjInsidePolyobj ( po , mo ) ) ;
return 1 ;
}
2020-09-09 18:38:56 +00:00
// special functions - manipulation
static int lib_polyobj_moveXY ( lua_State * L )
{
polyobj_t * po = * ( ( polyobj_t * * ) luaL_checkudata ( L , 1 , META_POLYOBJ ) ) ;
fixed_t x = luaL_checkfixed ( L , 2 ) ;
fixed_t y = luaL_checkfixed ( L , 3 ) ;
boolean checkmobjs = lua_opttrueboolean ( L , 4 ) ;
NOHUD
INLEVEL
if ( ! po )
return LUA_ErrInvalid ( L , " polyobj_t " ) ;
lua_pushboolean ( L , Polyobj_moveXY ( po , x , y , checkmobjs ) ) ;
return 1 ;
}
static int lib_polyobj_rotate ( lua_State * L )
{
polyobj_t * po = * ( ( polyobj_t * * ) luaL_checkudata ( L , 1 , META_POLYOBJ ) ) ;
angle_t delta = luaL_checkangle ( L , 2 ) ;
2021-07-04 10:54:48 +00:00
boolean turnplayers = lua_opttrueboolean ( L , 3 ) ;
boolean turnothers = lua_opttrueboolean ( L , 4 ) ;
boolean checkmobjs = lua_opttrueboolean ( L , 5 ) ;
2020-09-09 18:38:56 +00:00
NOHUD
INLEVEL
if ( ! po )
return LUA_ErrInvalid ( L , " polyobj_t " ) ;
2021-07-04 10:54:48 +00:00
lua_pushboolean ( L , Polyobj_rotate ( po , delta , turnplayers , turnothers , checkmobjs ) ) ;
2020-09-09 18:38:56 +00:00
return 1 ;
}
2020-09-09 20:15:02 +00:00
///////////////
// polyobj_t //
///////////////
2020-09-08 17:29:10 +00:00
static int polyobj_get ( lua_State * L )
{
polyobj_t * polyobj = * ( ( polyobj_t * * ) luaL_checkudata ( L , 1 , META_POLYOBJ ) ) ;
enum polyobj_e field = luaL_checkoption ( L , 2 , NULL , polyobj_opt ) ;
if ( ! polyobj ) {
if ( field = = polyobj_valid ) {
lua_pushboolean ( L , false ) ;
return 1 ;
}
return LUA_ErrInvalid ( L , " polyobj_t " ) ;
}
switch ( field )
{
2020-09-09 17:09:32 +00:00
// properties
2020-09-08 17:29:10 +00:00
case polyobj_valid :
lua_pushboolean ( L , true ) ;
break ;
2020-09-08 20:42:51 +00:00
case polyobj_id :
lua_pushinteger ( L , polyobj - > id ) ;
break ;
case polyobj_parent :
lua_pushinteger ( L , polyobj - > parent ) ;
break ;
2020-09-09 20:15:02 +00:00
case polyobj_vertices : // vertices
LUA_PushUserdata ( L , & polyobj - > vertices , META_POLYOBJVERTICES ) ; // push the address of the "vertices" member in the struct, to allow our hacks to work
break ;
case polyobj_lines : // lines
LUA_PushUserdata ( L , & polyobj - > lines , META_POLYOBJLINES ) ; // push the address of the "lines" member in the struct, to allow our hacks to work
break ;
2020-09-09 16:06:36 +00:00
case polyobj_sector : // shortcut that exists only in Lua!
LUA_PushUserdata ( L , polyobj - > lines [ 0 ] - > backsector , META_SECTOR ) ;
break ;
2020-09-08 20:42:51 +00:00
case polyobj_angle :
lua_pushangle ( L , polyobj - > angle ) ;
break ;
case polyobj_damage :
lua_pushinteger ( L , polyobj - > damage ) ;
break ;
case polyobj_thrust :
lua_pushfixed ( L , polyobj - > thrust ) ;
break ;
case polyobj_flags :
lua_pushinteger ( L , polyobj - > flags ) ;
break ;
2020-09-08 21:10:11 +00:00
case polyobj_translucency :
lua_pushinteger ( L , polyobj - > translucency ) ;
break ;
case polyobj_triggertag :
lua_pushinteger ( L , polyobj - > triggertag ) ;
break ;
2020-09-09 18:38:56 +00:00
// special functions - utility
2020-09-09 17:09:32 +00:00
case polyobj_pointInside :
lua_pushcfunction ( L , lib_polyobj_PointInside ) ;
break ;
case polyobj_mobjTouching :
lua_pushcfunction ( L , lib_polyobj_MobjTouching ) ;
break ;
case polyobj_mobjInside :
lua_pushcfunction ( L , lib_polyobj_MobjInside ) ;
break ;
2020-09-09 18:38:56 +00:00
// special functions - manipulation
case polyobj_moveXY :
lua_pushcfunction ( L , lib_polyobj_moveXY ) ;
break ;
case polyobj_rotate :
lua_pushcfunction ( L , lib_polyobj_rotate ) ;
break ;
2020-09-08 17:29:10 +00:00
}
return 1 ;
2020-09-08 20:42:51 +00:00
}
2020-09-08 17:29:10 +00:00
static int polyobj_set ( lua_State * L )
{
2020-09-13 20:38:16 +00:00
polyobj_t * polyobj = * ( ( polyobj_t * * ) luaL_checkudata ( L , 1 , META_POLYOBJ ) ) ;
enum polyobj_e field = luaL_checkoption ( L , 2 , NULL , polyobj_opt ) ;
if ( ! polyobj )
return LUA_ErrInvalid ( L , " polyobj_t " ) ;
if ( hud_running )
return luaL_error ( L , " Do not alter polyobj_t in HUD rendering code! " ) ;
switch ( field )
{
default :
return luaL_error ( L , LUA_QL ( " polyobj_t " ) " field " LUA_QS " cannot be modified. " , polyobj_opt [ field ] ) ;
case polyobj_angle :
return luaL_error ( L , LUA_QL ( " polyobj_t " ) " field " LUA_QS " should not be set directly. Use the function " LUA_QL ( " polyobj:rotate(angle) " ) " instead. " , polyobj_opt [ field ] ) ;
case polyobj_parent :
polyobj - > parent = luaL_checkinteger ( L , 3 ) ;
break ;
case polyobj_flags :
polyobj - > flags = luaL_checkinteger ( L , 3 ) ;
break ;
case polyobj_translucency :
polyobj - > translucency = luaL_checkinteger ( L , 3 ) ;
break ;
}
return 0 ;
2020-09-08 17:29:10 +00:00
}
2020-09-08 20:42:51 +00:00
static int polyobj_num ( lua_State * L )
{
polyobj_t * polyobj = * ( ( polyobj_t * * ) luaL_checkudata ( L , 1 , META_POLYOBJ ) ) ;
if ( ! polyobj )
return luaL_error ( L , " accessed polyobj_t doesn't exist anymore. " ) ;
lua_pushinteger ( L , polyobj - PolyObjects ) ;
return 1 ;
}
2020-09-09 20:15:02 +00:00
///////////////////
// PolyObjects[] //
///////////////////
2020-09-08 17:29:10 +00:00
static int lib_iteratePolyObjects ( lua_State * L )
{
INT32 i = - 1 ;
if ( lua_gettop ( L ) < 2 )
{
//return luaL_error(L, "Don't call PolyObjects.iterate() directly, use it as 'for polyobj in PolyObjects.iterate do <block> end'.");
lua_pushcfunction ( L , lib_iteratePolyObjects ) ;
return 1 ;
}
lua_settop ( L , 2 ) ;
lua_remove ( L , 1 ) ; // state is unused.
if ( ! lua_isnil ( L , 1 ) )
i = ( INT32 ) ( * ( ( polyobj_t * * ) luaL_checkudata ( L , 1 , META_POLYOBJ ) ) - PolyObjects ) ;
for ( i + + ; i < numPolyObjects ; i + + )
{
LUA_PushUserdata ( L , & PolyObjects [ i ] , META_POLYOBJ ) ;
return 1 ;
}
return 0 ;
}
2020-09-08 20:42:51 +00:00
static int lib_PolyObject_getfornum ( lua_State * L )
{
INT32 id = ( INT32 ) luaL_checkinteger ( L , 1 ) ;
if ( ! numPolyObjects )
return 0 ; // if there's no PolyObjects then bail out here
LUA_PushUserdata ( L , Polyobj_GetForNum ( id ) , META_POLYOBJ ) ;
return 1 ;
}
2020-09-08 17:29:10 +00:00
static int lib_getPolyObject ( lua_State * L )
{
const char * field ;
INT32 i ;
// find PolyObject by number
if ( lua_type ( L , 2 ) = = LUA_TNUMBER )
{
i = luaL_checkinteger ( L , 2 ) ;
if ( i < 0 | | i > = numPolyObjects )
2021-02-15 12:37:25 +00:00
return luaL_error ( L , " polyobjects[] index %d out of range (0 - %d) " , i, numPolyObjects-1) ;
2020-09-08 17:29:10 +00:00
LUA_PushUserdata ( L , & PolyObjects [ i ] , META_POLYOBJ ) ;
return 1 ;
}
field = luaL_checkstring ( L , 2 ) ;
// special function iterate
if ( fastcmp ( field , " iterate " ) )
{
lua_pushcfunction ( L , lib_iteratePolyObjects ) ;
return 1 ;
}
2020-09-08 20:42:51 +00:00
// find PolyObject by ID
else if ( fastcmp ( field , " GetForNum " ) ) // name could probably be better
{
lua_pushcfunction ( L , lib_PolyObject_getfornum ) ;
return 1 ;
}
2020-09-08 17:29:10 +00:00
return 0 ;
}
static int lib_numPolyObjects ( lua_State * L )
{
lua_pushinteger ( L , numPolyObjects ) ;
return 1 ;
}
2020-09-08 17:08:08 +00:00
int LUA_PolyObjLib ( lua_State * L )
{
2020-09-09 20:15:02 +00:00
luaL_newmetatable ( L , META_POLYOBJVERTICES ) ;
lua_pushcfunction ( L , polyobjvertices_get ) ;
lua_setfield ( L , - 2 , " __index " ) ;
lua_pushcfunction ( L , polyobjvertices_num ) ;
lua_setfield ( L , - 2 , " __len " ) ;
lua_pop ( L , 1 ) ;
luaL_newmetatable ( L , META_POLYOBJLINES ) ;
lua_pushcfunction ( L , polyobjlines_get ) ;
lua_setfield ( L , - 2 , " __index " ) ;
lua_pushcfunction ( L , polyobjlines_num ) ;
lua_setfield ( L , - 2 , " __len " ) ;
lua_pop ( L , 1 ) ;
2020-09-08 17:29:10 +00:00
luaL_newmetatable ( L , META_POLYOBJ ) ;
lua_pushcfunction ( L , polyobj_get ) ;
lua_setfield ( L , - 2 , " __index " ) ;
lua_pushcfunction ( L , polyobj_set ) ;
lua_setfield ( L , - 2 , " __newindex " ) ;
2020-09-08 20:42:51 +00:00
lua_pushcfunction ( L , polyobj_num ) ;
lua_setfield ( L , - 2 , " __len " ) ;
2020-09-08 17:29:10 +00:00
lua_pop ( L , 1 ) ;
lua_newuserdata ( L , 0 ) ;
lua_createtable ( L , 0 , 2 ) ;
lua_pushcfunction ( L , lib_getPolyObject ) ;
lua_setfield ( L , - 2 , " __index " ) ;
lua_pushcfunction ( L , lib_numPolyObjects ) ;
lua_setfield ( L , - 2 , " __len " ) ;
lua_setmetatable ( L , - 2 ) ;
2021-02-15 12:37:25 +00:00
lua_setglobal ( L , " polyobjects " ) ;
2020-09-08 17:08:08 +00:00
return 0 ;
}