2014-03-30 08:55:06 +00:00
# include "quakedef.h"
# ifdef VM_LUA
# include "pr_common.h"
# include "hash.h"
2018-04-15 02:48:23 +00:00
# define LUA_MALLOC_TAG 0x55780128
2014-03-30 08:55:06 +00:00
# define luagloballist \
globalentity ( true , self ) \
globalentity ( true , other ) \
globalentity ( true , world ) \
globalfloat ( true , time ) \
globalfloat ( true , frametime ) \
globalentity ( false , newmis ) \
globalfloat ( false , force_retouch ) \
globalstring ( true , mapname ) \
globalfloat ( false , deathmatch ) \
globalfloat ( false , coop ) \
globalfloat ( false , teamplay ) \
globalfloat ( true , serverflags ) \
globalfloat ( false , dimension_send ) \
globalfloat ( false , physics_mode ) \
globalfloat ( true , total_secrets ) \
globalfloat ( true , total_monsters ) \
globalfloat ( true , found_secrets ) \
globalfloat ( true , killed_monsters ) \
globalvec ( true , v_forward ) \
globalvec ( true , v_up ) \
globalvec ( true , v_right ) \
globalfloat ( true , trace_allsolid ) \
globalfloat ( true , trace_startsolid ) \
globalfloat ( true , trace_fraction ) \
globalvec ( true , trace_endpos ) \
globalvec ( true , trace_plane_normal ) \
globalfloat ( true , trace_plane_dist ) \
globalentity ( true , trace_ent ) \
globalfloat ( true , trace_inopen ) \
globalfloat ( true , trace_inwater ) \
2016-07-21 19:27:59 +00:00
globalfloat ( false , trace_endcontentsf ) \
2016-07-12 00:40:13 +00:00
globalint ( false , trace_endcontentsi ) \
2016-07-21 19:27:59 +00:00
globalfloat ( false , trace_surfaceflagsf ) \
2016-07-12 00:40:13 +00:00
globalint ( false , trace_surfaceflagsi ) \
2014-03-30 08:55:06 +00:00
globalfloat ( false , cycle_wrapped ) \
globalentity ( false , msg_entity ) \
globalfunc ( false , main ) \
globalfunc ( true , StartFrame ) \
globalfunc ( true , PlayerPreThink ) \
globalfunc ( true , PlayerPostThink ) \
globalfunc ( true , ClientKill ) \
globalfunc ( true , ClientConnect ) \
globalfunc ( true , PutClientInServer ) \
globalfunc ( true , ClientDisconnect ) \
globalfunc ( false , SetNewParms ) \
2018-04-06 17:21:15 +00:00
globalfunc ( false , SetChangeParms ) \
globalfloat ( false , dimension_default ) \
globalvec ( false , global_gravitydir )
2014-03-30 08:55:06 +00:00
//any globals or functions that the server might want access to need to be known also.
# define luaextragloballist \
globalstring ( true , startspot ) \
2018-04-06 17:21:15 +00:00
globalfunc ( true , ClientReEnter )
2014-03-30 08:55:06 +00:00
typedef struct
{
# define globalentity(required, name) int name;
# define globalint(required, name) int name;
# define globalfloat(required, name) float name;
# define globalstring(required, name) string_t name;
# define globalvec(required, name) vec3_t name;
# define globalfunc(required, name) int name;
luagloballist
luaextragloballist
# undef globalentity
# undef globalint
# undef globalfloat
# undef globalstring
# undef globalvec
# undef globalfunc
2018-04-06 17:21:15 +00:00
float parm [ NUM_SPAWN_PARMS ] ;
2014-03-30 08:55:06 +00:00
} luaglobalvars_t ;
typedef struct
{
int type ;
2018-04-15 02:48:23 +00:00
qintptr_t offset ;
2014-03-30 08:55:06 +00:00
char * name ;
bucket_t buck ;
} luafld_t ;
2018-04-06 17:21:15 +00:00
//#define LIBLUA_STATIC
# ifdef LIBLUA_STATIC
# ifdef _MSC_VER
# pragma comment(lib, "liblua.lib")
# endif
# include <lua.h>
//#include <lualib.h>
# include <lauxlib.h>
# else
2014-03-30 08:55:06 +00:00
typedef struct lua_State lua_State ;
typedef void * ( QDECL * lua_Alloc ) ( void * ud , void * ptr , size_t osize , size_t nsize ) ;
typedef const char * ( QDECL * lua_Reader ) ( lua_State * L , void * data , size_t * size ) ;
typedef int ( QDECL * lua_CFunction ) ( lua_State * L ) ;
typedef double lua_Number ;
2018-04-06 17:21:15 +00:00
typedef long long lua_Integer ;
# define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL)
# define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL)
# define lua_pop(L,n) lua_settop(L, -(n)-1)
# define lua_pushstring(L,s) lua_pushfstring(L,"%s",s)
//#define lua_remove(L,idx) (lua_rotate(L, (idx), -1), lua_pop(L, 1))
# define lua_replace(L,idx) (lua_copy(L, -1, (idx)), lua_pop(L, 1))
# define lua_pushglobaltable(L) (lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS))
# define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
# define LUA_TNONE (-1)
# define LUA_TNIL 0
# define LUA_TBOOLEAN 1
# define LUA_TLIGHTUSERDATA 2
# define LUA_TNUMBER 3
# define LUA_TSTRING 4
# define LUA_TTABLE 5
# define LUA_TFUNCTION 6
# define LUA_TUSERDATA 7
# define LUA_TTHREAD 8
# define LUA_NUMTAGS 9
# define LUA_RIDX_GLOBALS 2
# define LUA_REGISTRYINDEX (-1000000 - 1000)
# define lua_newstate lua.newstate
# define lua_atpanic lua.atpanic
# define lua_close lua.close
# define lua_load lua.load
# define lua_pcallk lua.pcallk
# define lua_callk lua.callk
# define lua_getfield lua.getfield
# define lua_setfield lua.setfield
# define lua_gettable lua.gettable
# define lua_settable lua.settable
# define lua_getglobal lua.getglobal
# define lua_setglobal lua.setglobal
# define lua_error lua.error
# define lua_type lua.type
# define lua_typename lua.typename
# define lua_rawget lua.rawget
# define lua_rawgeti lua.rawgeti
# define lua_rawgetp lua.rawgetp
# define lua_rawset lua.rawset
# define lua_createtable lua.createtable
# define lua_setmetatable lua.setmetatable
# define lua_newuserdata lua.newuserdata
# define lua_copy lua.copy
# define lua_gettop lua.gettop
# define lua_settop lua.settop
# define lua_pushboolean lua.pushboolean
# define lua_pushnil lua.pushnil
# define lua_pushnumber lua.pushnumber
# define lua_pushinteger lua.pushinteger
# define lua_pushvalue lua.pushvalue
# define lua_pushcclosure lua.pushcclosure
# define lua_pushfstring lua.pushfstring
# define lua_pushliteral lua_pushstring
# define lua_pushlightuserdata lua.pushlightuserdata
# define lua_tolstring lua.tolstring
# define lua_toboolean lua.toboolean
# define lua_tonumberx lua.tonumberx
# define lua_tointegerx lua.tointegerx
# define lua_topointer lua.topointer
# define lua_touserdata lua.touserdata
# define lua_touserdata lua.touserdata
# define lua_next lua.next
//#define lua_remove lua.remove
# define luaL_callmeta lua.Lcallmeta
# define luaL_newmetatable lua.Lnewmetatable
# define lua_newtable(L) lua_createtable(L,0,0)
# define lua_pushcfunction(L,f) lua_pushcclosure(L,f,0)
# define lua_isnil(L,i) (lua_type(L,i)==LUA_TNIL)
# define lua_tostring(L,i) lua_tolstring(L,i,NULL)
# define lua_tonumber(L,i) lua_tonumberx(L,i,NULL)
# define lua_tointeger(L,i) lua_tointegerx(L,i,NULL)
# endif
2014-03-30 08:55:06 +00:00
//I'm using this struct for all the global stuff.
static struct
{
lua_State * ctx ;
char readbuf [ 1024 ] ;
pubprogfuncs_t progfuncs ;
progexterns_t progfuncsparms ;
edict_t * * edicttable ;
unsigned int maxedicts ;
2018-04-06 17:21:15 +00:00
2014-03-30 08:55:06 +00:00
luaglobalvars_t globals ; //internal global structure
hashtable_t globalfields ; //name->luafld_t
luafld_t globflds [ 1024 ] ; //fld->offset+type
2018-04-06 17:21:15 +00:00
2014-03-30 08:55:06 +00:00
hashtable_t entityfields ; //name->luafld_t
luafld_t entflds [ 1024 ] ; //fld->offset+type
2018-04-06 17:21:15 +00:00
size_t numflds ;
2014-03-30 08:55:06 +00:00
2018-04-06 17:21:15 +00:00
# ifndef LIBLUA_STATIC
2014-03-30 08:55:06 +00:00
qboolean triedlib ;
2017-12-28 16:24:50 +00:00
dllhandle_t * lib ;
2014-03-30 08:55:06 +00:00
2017-10-12 12:02:25 +00:00
lua_State * ( QDECL * newstate ) ( lua_Alloc f , void * ud ) ;
lua_CFunction ( QDECL * atpanic ) ( lua_State * L , lua_CFunction panicf ) ;
2014-03-30 08:55:06 +00:00
void ( QDECL * close ) ( lua_State * L ) ;
int ( QDECL * load ) ( lua_State * L , lua_Reader reader , void * dt , const char * chunkname , const char * mode ) ;
int ( QDECL * pcallk ) ( lua_State * L , int nargs , int nresults , int errfunc , int ctx , lua_CFunction k ) ;
void ( QDECL * callk ) ( lua_State * L , int nargs , int nresults , int ctx , lua_CFunction k ) ;
void ( QDECL * getfield ) ( lua_State * L , int idx , const char * k ) ;
void ( QDECL * setfield ) ( lua_State * L , int idx , const char * k ) ;
void ( QDECL * gettable ) ( lua_State * L , int idx ) ;
void ( QDECL * settable ) ( lua_State * L , int idx ) ;
void ( QDECL * getglobal ) ( lua_State * L , const char * var ) ;
void ( QDECL * setglobal ) ( lua_State * L , const char * var ) ;
int ( QDECL * error ) ( lua_State * L ) ;
int ( QDECL * type ) ( lua_State * L , int idx ) ;
const char * ( QDECL * typename ) ( lua_State * L , int tp ) ;
2018-04-06 17:21:15 +00:00
int ( QDECL * rawget ) ( lua_State * L , int idx ) ;
int ( QDECL * rawgeti ) ( lua_State * L , int idx , lua_Integer n ) ;
int ( QDECL * rawgetp ) ( lua_State * L , int idx , const void * p ) ;
2014-03-30 08:55:06 +00:00
void ( QDECL * rawset ) ( lua_State * L , int idx ) ;
void ( QDECL * createtable ) ( lua_State * L , int narr , int nrec ) ;
int ( QDECL * setmetatable ) ( lua_State * L , int objindex ) ;
void * ( QDECL * newuserdata ) ( lua_State * L , size_t usize ) ;
2018-04-06 17:21:15 +00:00
void ( QDECL * copy ) ( lua_State * L , int fromidx , int toidx ) ; //added in 5.3
// void (QDECL *replace) (lua_State *L, int idx); //removed in 5.3
2014-03-30 08:55:06 +00:00
int ( QDECL * gettop ) ( lua_State * L ) ;
int ( QDECL * settop ) ( lua_State * L , int idx ) ;
void ( QDECL * pushboolean ) ( lua_State * L , int b ) ;
void ( QDECL * pushnil ) ( lua_State * L ) ;
void ( QDECL * pushnumber ) ( lua_State * L , lua_Number n ) ;
void ( QDECL * pushinteger ) ( lua_State * L , lua_Integer n ) ;
void ( QDECL * pushvalue ) ( lua_State * L , int idx ) ;
void ( QDECL * pushcclosure ) ( lua_State * L , lua_CFunction fn , int n ) ;
const char * ( QDECL * pushfstring ) ( lua_State * L , const char * fmt , . . . ) ;
void ( QDECL * pushlightuserdata ) ( lua_State * L , void * p ) ;
const char * ( QDECL * tolstring ) ( lua_State * L , int idx , size_t * len ) ;
int ( QDECL * toboolean ) ( lua_State * L , int idx ) ;
lua_Number ( QDECL * tonumberx ) ( lua_State * L , int idx , int * isnum ) ;
lua_Integer ( QDECL * tointegerx ) ( lua_State * L , int idx , int * isnum ) ;
const void * ( QDECL * topointer ) ( lua_State * L , int idx ) ;
void * ( QDECL * touserdata ) ( lua_State * L , int idx ) ;
2018-04-06 17:21:15 +00:00
int ( QDECL * next ) ( lua_State * L , int idx ) ;
// void (QDECL *remove) (lua_State *L, int idx);
2014-03-30 08:55:06 +00:00
int ( QDECL * Lcallmeta ) ( lua_State * L , int obj , const char * e ) ;
int ( QDECL * Lnewmetatable ) ( lua_State * L , const char * tname ) ;
2018-04-06 17:21:15 +00:00
# endif
2017-10-12 12:02:25 +00:00
} lua ;
2014-03-30 08:55:06 +00:00
static qboolean init_lua ( void )
{
2018-04-06 17:21:15 +00:00
# ifndef LIBLUA_STATIC
2014-03-30 08:55:06 +00:00
if ( ! lua . triedlib )
{
dllfunction_t luafuncs [ ] =
{
{ ( void * ) & lua . newstate , " lua_newstate " } ,
{ ( void * ) & lua . atpanic , " lua_atpanic " } ,
{ ( void * ) & lua . close , " lua_close " } ,
{ ( void * ) & lua . load , " lua_load " } ,
{ ( void * ) & lua . pcallk , " lua_pcallk " } ,
{ ( void * ) & lua . callk , " lua_callk " } ,
{ ( void * ) & lua . getfield , " lua_getfield " } ,
{ ( void * ) & lua . setfield , " lua_setfield " } ,
{ ( void * ) & lua . gettable , " lua_gettable " } ,
{ ( void * ) & lua . settable , " lua_settable " } ,
{ ( void * ) & lua . getglobal , " lua_getglobal " } ,
{ ( void * ) & lua . setglobal , " lua_setglobal " } ,
{ ( void * ) & lua . error , " lua_error " } ,
{ ( void * ) & lua . type , " lua_type " } ,
{ ( void * ) & lua . typename , " lua_typename " } ,
{ ( void * ) & lua . rawget , " lua_rawget " } ,
2018-04-06 17:21:15 +00:00
{ ( void * ) & lua . rawgeti , " lua_rawgeti " } ,
{ ( void * ) & lua . rawgetp , " lua_rawgetp " } ,
2014-03-30 08:55:06 +00:00
{ ( void * ) & lua . rawset , " lua_rawset " } ,
{ ( void * ) & lua . createtable , " lua_createtable " } ,
{ ( void * ) & lua . setmetatable , " lua_setmetatable " } ,
{ ( void * ) & lua . newuserdata , " lua_newuserdata " } ,
2018-04-06 17:21:15 +00:00
{ ( void * ) & lua . copy , " lua_copy " } ,
// {(void*)&lua.replace, "lua_replace"},
2014-03-30 08:55:06 +00:00
{ ( void * ) & lua . gettop , " lua_gettop " } ,
{ ( void * ) & lua . settop , " lua_settop " } ,
{ ( void * ) & lua . pushboolean , " lua_pushboolean " } ,
{ ( void * ) & lua . pushnil , " lua_pushnil " } ,
{ ( void * ) & lua . pushnumber , " lua_pushnumber " } ,
{ ( void * ) & lua . pushinteger , " lua_pushinteger " } ,
{ ( void * ) & lua . pushvalue , " lua_pushvalue " } ,
{ ( void * ) & lua . pushcclosure , " lua_pushcclosure " } ,
{ ( void * ) & lua . pushfstring , " lua_pushfstring " } ,
{ ( void * ) & lua . pushlightuserdata , " lua_pushlightuserdata " } ,
{ ( void * ) & lua . tolstring , " lua_tolstring " } ,
{ ( void * ) & lua . toboolean , " lua_toboolean " } ,
{ ( void * ) & lua . tonumberx , " lua_tonumberx " } ,
{ ( void * ) & lua . tointegerx , " lua_tointegerx " } ,
{ ( void * ) & lua . topointer , " lua_topointer " } ,
{ ( void * ) & lua . touserdata , " lua_touserdata " } ,
2018-04-06 17:21:15 +00:00
{ ( void * ) & lua . next , " lua_next " } ,
// {(void*)&lua.remove, "lua_remove"},
2014-03-30 08:55:06 +00:00
{ ( void * ) & lua . Lcallmeta , " luaL_callmeta " } ,
{ ( void * ) & lua . Lnewmetatable , " luaL_newmetatable " } ,
{ NULL , NULL }
} ;
lua . triedlib = true ;
2018-04-06 17:21:15 +00:00
lua . lib = Sys_LoadLibrary ( " lua53 " , luafuncs ) ;
2014-03-30 08:55:06 +00:00
}
if ( ! lua . lib )
return false ;
2018-04-06 17:21:15 +00:00
# endif
2014-03-30 08:55:06 +00:00
return true ;
}
2018-04-06 17:21:15 +00:00
char * QDECL Lua_AddString ( pubprogfuncs_t * prinst , const char * val , int minlength , pbool demarkup ) ;
static void lua_pushedict ( lua_State * L , struct edict_s * ent )
{
lua_rawgetp ( L , LUA_REGISTRYINDEX , ent ) ;
}
2018-04-08 14:24:50 +00:00
/*
2018-04-06 17:21:15 +00:00
static void lua_debugstack ( lua_State * L )
{
int idx ;
int top = lua_gettop ( L ) ;
for ( idx = 1 ; idx < = top ; idx + + )
{
if ( luaL_callmeta ( L , idx , " __tostring " ) )
{
Con_Printf ( " Stack%i: %s \n " , idx , lua_tolstring ( L , - 1 , NULL ) ) ;
lua_pop ( L , 1 ) ;
}
else
{
int t = lua_type ( L , idx ) ;
switch ( t )
{
case LUA_TNUMBER :
Con_Printf ( " Stack%i: %g \n " , idx , lua_tonumber ( L , idx ) ) ;
break ;
case LUA_TSTRING :
Con_Printf ( " Stack%i: %s \n " , idx , lua_tolstring ( L , idx , NULL ) ) ;
break ;
case LUA_TBOOLEAN :
Con_Printf ( " Stack%i: %s \n " , idx , ( lua_toboolean ( L , idx ) ? " true " : " false " ) ) ;
break ;
case LUA_TNIL :
Con_Printf ( " Stack%i: %s \n " , idx , " nil " ) ;
break ;
case LUA_TTABLE :
//special check for things that look like vectors.
lua_getfield ( L , idx , " x " ) ;
lua_getfield ( L , idx , " y " ) ;
lua_getfield ( L , idx , " z " ) ;
if ( lua_type ( L , - 3 ) = = LUA_TNUMBER & & lua_type ( L , - 2 ) = = LUA_TNUMBER & & lua_type ( L , - 1 ) = = LUA_TNUMBER )
{
Con_Printf ( " Stack%i: '%f %f %f' \n " , idx , lua_tonumberx ( L , - 3 , NULL ) , lua_tonumberx ( L , - 2 , NULL ) , lua_tonumberx ( L , - 1 , NULL ) ) ;
lua_pop ( L , 3 ) ;
break ;
}
lua_pop ( L , 3 ) ;
default :
Con_Printf ( " Stack%i: %s: %p \n " , idx , lua_typename ( L , lua_type ( L , idx ) ) , lua_topointer ( L , idx ) ) ;
break ;
}
}
}
}
2018-04-08 14:24:50 +00:00
*/
2014-03-30 08:55:06 +00:00
static void * my_lua_alloc ( void * ud , void * ptr , size_t osize , size_t nsize )
{
if ( nsize = = 0 )
{
free ( ptr ) ;
return NULL ;
}
else
return realloc ( ptr , nsize ) ;
}
const char * my_lua_Reader ( lua_State * L , void * data , size_t * size )
{
vfsfile_t * f = data ;
* size = VFS_READ ( f , lua . readbuf , sizeof ( lua . readbuf ) ) ;
return lua . readbuf ;
}
//replace lua's standard 'print' function to use the console instead of stdout. intended to use the same linebreak rules.
2018-04-06 17:21:15 +00:00
static int bi_lua_print ( lua_State * L )
2014-03-30 08:55:06 +00:00
{
//the problem is that we can only really accept strings here.
//so lets just use the tostring function to make sure things are actually readable as strings.
2018-04-06 17:21:15 +00:00
int args = lua_gettop ( L ) ;
2014-03-30 08:55:06 +00:00
int i ;
const char * s ;
2018-04-06 17:21:15 +00:00
lua_getglobal ( L , " tostring " ) ;
2014-03-30 08:55:06 +00:00
//args now start at 1
for ( i = 1 ; i < = args ; i + + )
{
2018-04-06 17:21:15 +00:00
lua_pushvalue ( L , - 1 ) ;
lua_pushvalue ( L , i ) ;
lua_pcall ( L , 1 , 1 , 0 ) ; //pops args+func
s = lua_tolstring ( L , - 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
if ( s = = NULL )
s = " ? " ;
if ( i > 1 ) Con_Printf ( " \t " ) ;
Con_Printf ( " %s " , s ) ;
2018-04-06 17:21:15 +00:00
lua_pop ( L , 1 ) ; //pop our lstring
2014-03-30 08:55:06 +00:00
} ;
2018-04-06 17:21:15 +00:00
lua_pop ( L , 1 ) ; //pop the cached tostring.
2014-03-30 08:55:06 +00:00
Con_Printf ( " \n " ) ;
return 0 ;
} ;
//more like quakec's print
2018-04-06 17:21:15 +00:00
static int bi_lua_conprint ( lua_State * L )
2014-03-30 08:55:06 +00:00
{
//the problem is that we can only really accept strings here.
//so lets just use the tostring function to make sure things are actually readable as strings.
2018-04-06 17:21:15 +00:00
int args = lua_gettop ( L ) ;
2014-03-30 08:55:06 +00:00
int i ;
const char * s ;
2018-04-06 17:21:15 +00:00
lua_getglobal ( L , " tostring " ) ;
2014-03-30 08:55:06 +00:00
//args start at stack index 1
for ( i = 1 ; i < = args ; i + + )
{
2018-04-06 17:21:15 +00:00
lua_pushvalue ( L , - 1 ) ; //dupe the tostring
lua_pushvalue ( L , i ) ; //dupe the argument
lua_pcall ( L , 1 , 1 , 0 ) ; //pops args+func, pushes the string result
s = lua_tolstring ( L , - 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
if ( s = = NULL )
s = " ? " ;
Con_Printf ( " %s " , s ) ;
2018-04-06 17:21:15 +00:00
lua_pop ( L , 1 ) ; //pop our lstring
2014-03-30 08:55:06 +00:00
} ;
2018-04-06 17:21:15 +00:00
lua_pop ( L , 1 ) ; //pop the cached tostring.
2014-03-30 08:55:06 +00:00
return 0 ;
} ;
static int bi_lua_dprint ( lua_State * L )
{
if ( ! developer . ival )
return 0 ;
2018-04-06 17:21:15 +00:00
return bi_lua_conprint ( L ) ;
2014-03-30 08:55:06 +00:00
}
//taken from lua's baselib.c, with dependancies reduced a little.
2018-04-06 17:21:15 +00:00
static int bi_lua_tostring ( lua_State * L )
2014-03-30 08:55:06 +00:00
{
2018-04-06 17:21:15 +00:00
// if (lua_type(L, 1) == LUA_TNONE)
2014-03-30 08:55:06 +00:00
// luaL_argerror(L, narg, "value expected");
2018-04-06 17:21:15 +00:00
if ( luaL_callmeta ( L , 1 , " __tostring " ) )
2014-03-30 08:55:06 +00:00
return 1 ;
2018-04-06 17:21:15 +00:00
switch ( lua_type ( L , 1 ) )
2014-03-30 08:55:06 +00:00
{
case LUA_TNUMBER :
2018-04-06 17:21:15 +00:00
lua_pushfstring ( L , lua_tolstring ( L , 1 , NULL ) ) ;
2014-03-30 08:55:06 +00:00
break ;
case LUA_TSTRING :
2018-04-06 17:21:15 +00:00
lua_pushvalue ( L , 1 ) ;
2014-03-30 08:55:06 +00:00
break ;
case LUA_TBOOLEAN :
2018-04-06 17:21:15 +00:00
lua_pushstring ( L , ( lua_toboolean ( L , 1 ) ? " true " : " false " ) ) ;
2014-03-30 08:55:06 +00:00
break ;
case LUA_TNIL :
2018-04-06 17:21:15 +00:00
lua_pushstring ( L , " nil " ) ;
2014-03-30 08:55:06 +00:00
break ;
case LUA_TTABLE :
//special check for things that look like vectors.
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " x " ) ;
lua_getfield ( L , 1 , " y " ) ;
lua_getfield ( L , 1 , " z " ) ;
if ( lua_type ( L , - 3 ) = = LUA_TNUMBER & & lua_type ( L , - 2 ) = = LUA_TNUMBER & & lua_type ( L , - 1 ) = = LUA_TNUMBER )
2014-03-30 08:55:06 +00:00
{
2018-04-06 17:21:15 +00:00
lua_pushfstring ( L , " '%g %g %g' " , lua_tonumberx ( L , - 3 , NULL ) , lua_tonumberx ( L , - 2 , NULL ) , lua_tonumberx ( L , - 1 , NULL ) ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
//fallthrough
default :
2018-04-06 17:21:15 +00:00
lua_pushfstring ( L , " %s: %p " , lua_typename ( L , lua_type ( L , 1 ) ) , lua_topointer ( L , 1 ) ) ;
2014-03-30 08:55:06 +00:00
break ;
}
return 1 ;
}
2018-04-06 17:21:15 +00:00
# define bi_lua_vtos bi_lua_tostring
# define bi_lua_ftos bi_lua_tostring
2014-03-30 08:55:06 +00:00
2018-04-08 14:24:50 +00:00
//taken from lua's baselib.c, with dependancies reduced a little.
static int bi_lua_tonumber ( lua_State * L )
{
// if (lua_type(L, 1) == LUA_TNONE)
// luaL_argerror(L, narg, "value expected");
if ( luaL_callmeta ( L , 1 , " __tonumber " ) )
return 1 ;
switch ( lua_type ( L , 1 ) )
{
case LUA_TSTRING :
lua_pushnumber ( L , atof ( lua_tostring ( L , 1 ) ) ) ;
break ;
case LUA_TNUMBER :
lua_pushvalue ( L , 1 ) ;
break ;
case LUA_TBOOLEAN :
lua_pushnumber ( L , lua_toboolean ( L , 1 ) ) ;
break ;
case LUA_TNIL :
lua_pushnumber ( L , 0 ) ;
break ;
case LUA_TTABLE :
//special check for things that look like vectors.
lua_getfield ( L , 1 , " x " ) ;
lua_getfield ( L , 1 , " y " ) ;
lua_getfield ( L , 1 , " z " ) ;
if ( lua_type ( L , - 3 ) = = LUA_TNUMBER & & lua_type ( L , - 2 ) = = LUA_TNUMBER & & lua_type ( L , - 1 ) = = LUA_TNUMBER )
{
vec3_t v = { lua_tonumberx ( L , - 3 , NULL ) , lua_tonumberx ( L , - 2 , NULL ) , lua_tonumberx ( L , - 1 , NULL ) } ;
lua_pushnumber ( L , DotProduct ( v , v ) ) ;
return 1 ;
}
lua_getfield ( L , 1 , " entnum " ) ;
if ( lua_type ( L , - 1 ) = = LUA_TNUMBER )
return 1 ;
//fallthrough
default :
lua_pushfstring ( L , " %s: %p " , lua_typename ( L , lua_type ( L , 1 ) ) , lua_topointer ( L , 1 ) ) ;
break ;
}
return 1 ;
}
# define bi_lua_stof bi_lua_tonumber
2014-03-30 08:55:06 +00:00
static int my_lua_panic ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
const char * s = lua_tolstring ( L , - 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
Sys_Error ( " lua error: %s " , s ) ;
}
static int my_lua_entity_eq ( lua_State * L )
{
//table1=1
//table2=2
unsigned int entnum1 , entnum2 ;
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
entnum1 = lua_tointegerx ( L , - 1 , NULL ) ;
lua_getfield ( L , 2 , " entnum " ) ;
entnum2 = lua_tointegerx ( L , - 1 , NULL ) ;
lua_pop ( L , 2 ) ;
2014-03-30 08:55:06 +00:00
2018-04-06 17:21:15 +00:00
lua_pushboolean ( L , entnum1 = = entnum2 ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int my_lua_entity_tostring ( lua_State * L )
{
//table=1
unsigned int entnum ;
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
entnum = lua_tointegerx ( L , - 1 , NULL ) ;
lua_pop ( L , 1 ) ;
lua_pushstring ( L , va ( " entity: %u " , entnum ) ) ;
return 1 ;
}
2014-03-30 08:55:06 +00:00
2018-04-06 17:21:15 +00:00
static int my_lua_vec3_tostring ( lua_State * L )
{
//table=1
lua_Number x , y , z ;
lua_getfield ( L , 1 , " x " ) ;
x = lua_tonumber ( L , - 1 ) ;
lua_getfield ( L , 1 , " y " ) ;
y = lua_tonumber ( L , - 1 ) ;
lua_getfield ( L , 1 , " z " ) ;
z = lua_tonumber ( L , - 1 ) ;
lua_pop ( L , 3 ) ;
lua_pushstring ( L , va ( " '%g %g %g' " , x , y , z ) ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
2018-04-06 17:21:15 +00:00
static qboolean lua_readvector ( lua_State * L , int idx , float * result )
2014-03-30 08:55:06 +00:00
{
2018-04-06 17:21:15 +00:00
switch ( lua_type ( L , idx ) )
2014-03-30 08:55:06 +00:00
{
case LUA_TSTRING :
{
//we parse strings primnarily for easy .ent(or bsp) loading support.
2018-04-06 17:21:15 +00:00
const char * str = lua_tolstring ( L , idx , NULL ) ;
2014-03-30 08:55:06 +00:00
str = COM_Parse ( str ) ;
result [ 0 ] = atof ( com_token ) ;
str = COM_Parse ( str ) ;
result [ 1 ] = atof ( com_token ) ;
str = COM_Parse ( str ) ;
result [ 2 ] = atof ( com_token ) ;
}
2018-04-06 17:21:15 +00:00
return true ;
2014-03-30 08:55:06 +00:00
case LUA_TTABLE :
2018-04-06 17:21:15 +00:00
lua_getfield ( L , idx , " x " ) ;
result [ 0 ] = lua_tonumberx ( L , - 1 , NULL ) ;
lua_getfield ( L , idx , " y " ) ;
result [ 1 ] = lua_tonumberx ( L , - 1 , NULL ) ;
lua_getfield ( L , idx , " z " ) ;
result [ 2 ] = lua_tonumberx ( L , - 1 , NULL ) ;
lua_pop ( L , 3 ) ;
return true ;
case LUA_TNUMBER :
result [ 0 ] =
result [ 1 ] =
result [ 2 ] = lua_tonumber ( L , idx ) ;
2014-03-30 08:55:06 +00:00
break ;
case LUA_TNIL :
result [ 0 ] = 0 ;
result [ 1 ] = 0 ;
result [ 2 ] = 0 ;
break ;
default :
2018-04-06 17:21:15 +00:00
Con_Printf ( " Expected vector, got %s \n " , lua_typename ( L , lua_type ( L , idx ) ) ) ;
result [ 0 ] = 0 ;
result [ 1 ] = 0 ;
result [ 2 ] = 0 ;
break ;
2014-03-30 08:55:06 +00:00
}
2018-04-06 17:21:15 +00:00
return false ;
}
static void lua_pushvector ( lua_State * L , vec_t x , vec_t y , vec_t z )
{
lua_newtable ( L ) ;
//FIXME: should provide a metatable with a __tostring
lua_pushnumber ( L , x ) ;
lua_setfield ( L , - 2 , " x " ) ;
lua_pushnumber ( L , y ) ;
lua_setfield ( L , - 2 , " y " ) ;
lua_pushnumber ( L , z ) ;
lua_setfield ( L , - 2 , " z " ) ;
luaL_getmetatable ( L , " vec3_t " ) ;
lua_setmetatable ( L , - 2 ) ;
}
static int my_lua_vec3_eq ( lua_State * L )
{
vec3_t a , b ;
lua_readvector ( L , 1 , a ) ;
lua_readvector ( L , 2 , b ) ;
lua_pushboolean ( L , a [ 0 ] = = b [ 0 ] & & a [ 1 ] = = b [ 1 ] & & a [ 2 ] = = b [ 2 ] ) ;
return 1 ;
}
static int my_lua_vec3_sub ( lua_State * L )
{
vec3_t a , b ;
lua_readvector ( L , 1 , a ) ;
lua_readvector ( L , 2 , b ) ;
lua_pushvector ( L , a [ 0 ] - b [ 0 ] , a [ 1 ] - b [ 1 ] , a [ 2 ] - b [ 2 ] ) ;
return 1 ;
}
static int my_lua_vec3_mul ( lua_State * L )
{
vec3_t a , b ;
if ( lua_readvector ( L , 1 , a ) + lua_readvector ( L , 2 , b ) = = 2 )
lua_pushnumber ( L , DotProduct ( a , b ) ) ; //vec*vec is a dotproduct
else
lua_pushvector ( L , a [ 0 ] * b [ 0 ] , a [ 1 ] * b [ 1 ] , a [ 2 ] * b [ 2 ] ) ; //one arg is a scaler. woot.
return 1 ;
}
static int my_lua_vec3_add ( lua_State * L )
{
vec3_t a , b ;
lua_readvector ( L , 1 , a ) ;
lua_readvector ( L , 2 , b ) ;
lua_pushvector ( L , a [ 0 ] + b [ 0 ] , a [ 1 ] + b [ 1 ] , a [ 2 ] + b [ 2 ] ) ;
return 1 ;
}
static int my_lua_vec3_len ( lua_State * L )
{
vec3_t a ;
lua_readvector ( L , 1 , a ) ;
lua_pushnumber ( L , VectorLength ( a ) ) ;
return 1 ;
2014-03-30 08:55:06 +00:00
}
static int my_lua_entity_set ( lua_State * L ) //__newindex
{
// Con_Printf("lua_entity_set: ");
// my_lua_print(L);
//table=1
//key=2
//value=3
2018-04-06 17:21:15 +00:00
if ( lua_type ( L , 2 ) = = LUA_TSTRING )
2014-03-30 08:55:06 +00:00
{
2018-04-06 17:21:15 +00:00
const char * s = lua_tolstring ( L , 2 , NULL ) ;
2014-03-30 08:55:06 +00:00
luafld_t * fld = Hash_GetInsensitive ( & lua . entityfields , s ) ;
eval_t * eval ;
unsigned int entnum ;
2018-04-06 17:21:15 +00:00
if ( fld & & fld - > offset > = 0 )
2014-03-30 08:55:06 +00:00
{
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
entnum = lua_tointegerx ( L , - 1 , NULL ) ;
lua_pop ( L , 1 ) ;
2017-12-28 16:24:50 +00:00
if ( entnum < lua . maxedicts & & lua . edicttable [ entnum ] & & ! ED_ISFREE ( lua . edicttable [ entnum ] ) )
2014-03-30 08:55:06 +00:00
{
eval = ( eval_t * ) ( ( char * ) lua . edicttable [ entnum ] - > v + fld - > offset ) ;
switch ( fld - > type )
{
case ev_float :
2018-04-06 17:21:15 +00:00
eval - > _float = lua_tonumberx ( L , 3 , NULL ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
case ev_vector :
lua_readvector ( L , 3 , eval - > _vector ) ;
return 0 ;
case ev_integer :
2018-04-06 17:21:15 +00:00
eval - > _int = lua_tointegerx ( L , 3 , NULL ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
case ev_function :
2018-04-06 17:21:15 +00:00
if ( lua_type ( L , 3 ) = = LUA_TNIL )
2014-03-30 08:55:06 +00:00
eval - > function = 0 ; //so the engine can distinguish between nil and not.
else
eval - > function = fld - > offset | ( ( entnum + 1 ) < < 10 ) ;
2018-04-06 17:21:15 +00:00
lua_pushlightuserdata ( L , ( void * ) ( qintptr_t ) fld - > offset ) ; //execute only knows a function id, so we need to translate the store to match.
lua_replace ( L , 2 ) ;
lua_rawset ( L , 1 ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
case ev_string :
2018-04-06 17:21:15 +00:00
if ( lua_type ( L , 3 ) = = LUA_TNIL )
2014-03-30 08:55:06 +00:00
eval - > string = 0 ; //so the engine can distinguish between nil and not.
else
eval - > string = fld - > offset | ( ( entnum + 1 ) < < 10 ) ;
2018-04-06 17:21:15 +00:00
lua_pushlightuserdata ( L , ( void * ) ( qintptr_t ) fld - > offset ) ; //execute only knows a string id, so we need to translate the store to match.
lua_replace ( L , 2 ) ;
lua_rawset ( L , 1 ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
case ev_entity :
//read the table's entnum field so we know which one its meant to be.
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 3 , " entnum " ) ;
eval - > edict = lua_tointegerx ( L , - 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
}
}
}
}
2018-04-06 17:21:15 +00:00
lua_rawset ( L , 1 ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
}
static int my_lua_entity_get ( lua_State * L ) //__index
{
// Con_Printf("lua_entity_get: ");
// my_lua_print(L);
//table=1
//key=2
2018-04-06 17:21:15 +00:00
if ( lua_type ( L , 2 ) = = LUA_TSTRING )
2014-03-30 08:55:06 +00:00
{
2018-04-06 17:21:15 +00:00
const char * s = lua_tolstring ( L , 2 , NULL ) ;
2014-03-30 08:55:06 +00:00
luafld_t * fld = Hash_GetInsensitive ( & lua . entityfields , s ) ;
eval_t * eval ;
int entnum ;
if ( fld )
{
2018-04-06 17:21:15 +00:00
if ( fld - > offset < 0 )
{ //negative offsets are not real fields, but are just there to ensure that no nils appear
lua_rawget ( L , 1 ) ;
if ( lua_isnil ( L , - 1 ) )
{
lua_pop ( L , 1 ) ;
switch ( fld - > type )
{
case ev_float :
lua_pushnumber ( L , 0 ) ;
return 1 ;
case ev_integer :
lua_pushinteger ( L , 0 ) ;
return 1 ;
case ev_vector :
lua_pushvector ( L , 0 , 0 , 0 ) ;
break ;
case ev_function :
default : //no idea
lua_pushnil ( L ) ;
break ;
case ev_string :
lua_pushliteral ( L , " " ) ;
break ;
case ev_entity :
lua_pushedict ( L , lua . edicttable [ 0 ] ) ;
break ;
}
}
return 1 ;
}
lua_getfield ( L , 1 , " entnum " ) ;
entnum = lua_tointegerx ( L , - 1 , NULL ) ;
lua_pop ( L , 1 ) ;
2014-03-30 08:55:06 +00:00
if ( entnum < lua . maxedicts & & lua . edicttable [ entnum ] ) // && !lua.edicttable[entnum]->isfree)
{
eval = ( eval_t * ) ( ( char * ) lua . edicttable [ entnum ] - > v + fld - > offset ) ;
switch ( fld - > type )
{
case ev_float :
2018-04-06 17:21:15 +00:00
lua_pushnumber ( L , eval - > _float ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
case ev_integer :
2018-04-06 17:21:15 +00:00
lua_pushinteger ( L , eval - > _int ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
case ev_vector :
2018-04-06 17:21:15 +00:00
lua_pushvector ( L , eval - > _vector [ 0 ] , eval - > _vector [ 1 ] , eval - > _vector [ 2 ] ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
case ev_function :
case ev_string :
2018-04-06 17:21:15 +00:00
lua_pushlightuserdata ( L , ( void * ) ( qintptr_t ) ( eval - > function & 1023 ) ) ; //execute only knows a function id, so we need to translate the store to match.
lua_replace ( L , 2 ) ;
lua_rawget ( L , 1 ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
case ev_entity :
//return the table for the entity via the lua registry.
2018-04-06 17:21:15 +00:00
lua_pushlightuserdata ( lua . ctx , lua . edicttable [ eval - > edict ] ) ;
lua_gettable ( lua . ctx , LUA_REGISTRYINDEX ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
}
}
}
//make sure it exists so we don't get called constantly if code loops through stuff that wasn't set.
2018-04-06 17:21:15 +00:00
// lua_pushstring(L, "nil");
lua_rawget ( L , 1 ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int my_lua_global_set ( lua_State * L ) //__newindex
{
// Con_Printf("my_lua_global_set: ");
// my_lua_print(L);
//table=1
//key=2
//value=3
2018-04-06 17:21:15 +00:00
if ( lua_type ( L , 2 ) = = LUA_TSTRING )
2014-03-30 08:55:06 +00:00
{
2018-04-06 17:21:15 +00:00
const char * s = lua_tolstring ( L , 2 , NULL ) ;
2014-03-30 08:55:06 +00:00
luafld_t * fld = Hash_GetInsensitive ( & lua . globalfields , s ) ;
eval_t * eval ;
if ( fld )
{
eval = ( eval_t * ) ( ( char * ) & lua . globals + fld - > offset ) ;
switch ( fld - > type )
{
case ev_float :
2018-04-06 17:21:15 +00:00
eval - > _float = lua_tonumberx ( L , 3 , NULL ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
case ev_vector :
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 3 , " x " ) ;
eval - > _vector [ 0 ] = lua_tonumberx ( L , - 1 , NULL ) ;
lua_getfield ( L , 3 , " y " ) ;
eval - > _vector [ 1 ] = lua_tonumberx ( L , - 1 , NULL ) ;
lua_getfield ( L , 3 , " z " ) ;
eval - > _vector [ 2 ] = lua_tonumberx ( L , - 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
case ev_integer :
2018-04-06 17:21:15 +00:00
eval - > _int = lua_tointegerx ( L , 3 , NULL ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
case ev_function :
2018-04-06 17:21:15 +00:00
if ( lua_type ( L , 3 ) = = LUA_TNIL )
2014-03-30 08:55:06 +00:00
eval - > function = 0 ; //so the engine can distinguish between nil and not.
else
eval - > function = fld - > offset ;
2018-04-06 17:21:15 +00:00
lua_pushlightuserdata ( L , ( void * ) fld - > offset ) ; //execute only knows a function id, so we need to translate the store to match.
lua_replace ( L , 2 ) ;
lua_rawset ( L , 1 ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
case ev_string :
2018-04-06 17:21:15 +00:00
if ( lua_type ( L , 3 ) = = LUA_TNIL )
2014-03-30 08:55:06 +00:00
eval - > string = 0 ; //so the engine can distinguish between nil and not.
else
eval - > string = fld - > offset ;
2018-04-06 17:21:15 +00:00
lua_pushlightuserdata ( L , ( void * ) fld - > offset ) ; //execute only knows a string id, so we need to translate the store to match.
lua_replace ( L , 2 ) ;
lua_rawset ( L , 1 ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
case ev_entity :
//read the table's entnum field so we know which one its meant to be.
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 3 , " entnum " ) ;
eval - > edict = lua_tointegerx ( L , - 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
}
}
}
2018-04-06 17:21:15 +00:00
lua_rawset ( L , 1 ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
}
static int my_lua_global_get ( lua_State * L ) //__index
{
// Con_Printf("my_lua_global_get: ");
// my_lua_print(L);
//table=1
//key=2
2018-04-06 17:21:15 +00:00
if ( lua_type ( L , 2 ) = = LUA_TSTRING )
2014-03-30 08:55:06 +00:00
{
2018-04-06 17:21:15 +00:00
const char * s = lua_tolstring ( L , 2 , NULL ) ;
2014-03-30 08:55:06 +00:00
luafld_t * fld = Hash_GetInsensitive ( & lua . globalfields , s ) ;
eval_t * eval ;
if ( fld )
{
eval = ( eval_t * ) ( ( char * ) & lua . globals + fld - > offset ) ;
switch ( fld - > type )
{
case ev_float :
2018-04-06 17:21:15 +00:00
lua_pushnumber ( L , eval - > _float ) ;
return 1 ;
case ev_integer :
lua_pushinteger ( L , eval - > _int ) ;
return 1 ;
case ev_vector :
lua_pushvector ( L , eval - > _vector [ 0 ] , eval - > _vector [ 1 ] , eval - > _vector [ 2 ] ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
case ev_function :
2018-04-06 17:21:15 +00:00
lua_pushlightuserdata ( L , ( void * ) ( qintptr_t ) eval - > function ) ; //execute only knows a function id, so we need to translate the store to match.
lua_replace ( L , 2 ) ;
lua_rawget ( L , 1 ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
case ev_entity :
2018-04-06 17:21:15 +00:00
lua_pushedict ( L , lua . edicttable [ eval - > edict ] ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
}
}
//make sure it exists so we don't get called constantly if code loops through stuff that wasn't set.
2018-04-06 17:21:15 +00:00
// lua_pushstring(L, "nil");
lua_rawget ( L , 1 ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_setmodel ( lua_State * L )
{
int entnum ;
edict_t * e ;
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
entnum = lua_tointegerx ( L , - 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
e = ( entnum > = lua . maxedicts ) ? NULL : lua . edicttable [ entnum ] ;
2018-04-06 17:21:15 +00:00
PF_setmodel_Internal ( & lua . progfuncs , e , lua_tolstring ( L , 2 , NULL ) ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
}
static int bi_lua_precache_model ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
PF_precache_model_Internal ( & lua . progfuncs , lua_tolstring ( L , 1 , NULL ) , false ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
}
2018-04-06 17:21:15 +00:00
# define bi_lua_precache_model2 bi_lua_precache_model
2014-03-30 08:55:06 +00:00
static int bi_lua_precache_sound ( lua_State * L )
{
2023-06-25 15:04:40 +00:00
PF_precache_sound_Internal ( & lua . progfuncs , lua_tolstring ( L , 1 , NULL ) , false ) ;
2018-04-06 17:21:15 +00:00
return 0 ;
}
# define bi_lua_precache_sound2 bi_lua_precache_sound
static int bi_lua_precache_file ( lua_State * L )
{
2014-03-30 08:55:06 +00:00
return 0 ;
}
static int bi_lua_lightstyle ( lua_State * L )
{
2014-06-25 03:53:11 +00:00
vec3_t rgb ;
2018-04-06 17:21:15 +00:00
if ( lua_gettop ( L ) > = 3 )
lua_readvector ( L , 3 , rgb ) ;
else
VectorSet ( rgb , 1 , 1 , 1 ) ;
PF_applylightstyle ( lua_tointegerx ( L , 1 , NULL ) , lua_tolstring ( L , 2 , NULL ) , rgb ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
}
static int bi_lua_spawn ( lua_State * L )
{
2017-12-28 16:24:50 +00:00
edict_t * e = lua . progfuncs . EntAlloc ( & lua . progfuncs , false , 0 ) ;
2014-03-30 08:55:06 +00:00
if ( e )
2018-04-06 17:21:15 +00:00
lua_pushedict ( L , e ) ;
2014-03-30 08:55:06 +00:00
else
2018-04-06 17:21:15 +00:00
lua_pushnil ( L ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_remove ( lua_State * L )
{
int entnum ;
edict_t * e ;
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
entnum = lua_tointegerx ( L , - 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
e = ( entnum > = lua . maxedicts ) ? NULL : lua . edicttable [ entnum ] ;
if ( e )
2023-06-25 15:04:40 +00:00
lua . progfuncs . EntFree ( & lua . progfuncs , e , false ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
}
static int bi_lua_setorigin ( lua_State * L )
{
edict_t * e ;
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
e = EDICT_NUM_UB ( ( & lua . progfuncs ) , lua_tointegerx ( L , - 1 , NULL ) ) ;
2014-03-30 08:55:06 +00:00
lua_readvector ( L , 2 , e - > v - > origin ) ;
World_LinkEdict ( & sv . world , ( wedict_t * ) e , false ) ;
return 0 ;
}
static int bi_lua_setsize ( lua_State * L )
{
edict_t * e ;
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
e = EDICT_NUM_UB ( ( & lua . progfuncs ) , lua_tointegerx ( L , - 1 , NULL ) ) ;
2014-03-30 08:55:06 +00:00
lua_readvector ( L , 2 , e - > v - > mins ) ;
lua_readvector ( L , 3 , e - > v - > maxs ) ;
VectorSubtract ( e - > v - > maxs , e - > v - > mins , e - > v - > size ) ;
World_LinkEdict ( & sv . world , ( wedict_t * ) e , false ) ;
return 0 ;
}
static int bi_lua_localcmd ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
const char * str = lua_tolstring ( lua . ctx , 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
Cbuf_AddText ( str , RESTRICT_INSECURE ) ;
return 0 ;
}
static int bi_lua_changelevel ( lua_State * L )
{
const char * s , * spot ;
// make sure we don't issue two changelevels (unless the last one failed)
if ( sv . mapchangelocked )
return 0 ;
sv . mapchangelocked = true ;
2018-04-06 17:21:15 +00:00
if ( lua_type ( L , 2 ) = = LUA_TSTRING ) //and not nil or none
2014-03-30 08:55:06 +00:00
{
2018-04-06 17:21:15 +00:00
s = lua_tolstring ( lua . ctx , 1 , NULL ) ;
spot = lua_tolstring ( lua . ctx , 2 , NULL ) ;
2014-03-30 08:55:06 +00:00
Cbuf_AddText ( va ( " \n changelevel %s %s \n " , s , spot ) , RESTRICT_LOCAL ) ;
}
else
{
2018-04-06 17:21:15 +00:00
s = lua_tolstring ( lua . ctx , 1 , NULL ) ;
Cbuf_AddText ( va ( " \n changelevel %s \n " , s ) , RESTRICT_LOCAL ) ;
2014-03-30 08:55:06 +00:00
}
return 0 ;
}
static int bi_lua_stuffcmd ( lua_State * L )
{
int entnum ;
const char * str ;
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
entnum = lua_tointegerx ( L , - 1 , NULL ) ;
str = lua_tolstring ( L , 2 , NULL ) ;
2014-03-30 08:55:06 +00:00
2015-10-27 15:20:15 +00:00
PF_stuffcmd_Internal ( entnum , str , 0 ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
}
static int bi_lua_centerprint ( lua_State * L )
{
int entnum ;
const char * str ;
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
entnum = lua_tointegerx ( L , - 1 , NULL ) ;
str = lua_tolstring ( L , 2 , NULL ) ;
if ( ! str )
str = " " ;
2014-03-30 08:55:06 +00:00
PF_centerprint_Internal ( entnum , false , str ) ;
return 0 ;
}
static int bi_lua_getinfokey ( lua_State * L )
{
int entnum ;
const char * key ;
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
entnum = lua_tointegerx ( L , - 1 , NULL ) ;
key = lua_tolstring ( L , 2 , NULL ) ;
2014-03-30 08:55:06 +00:00
key = PF_infokey_Internal ( entnum , key ) ;
2018-04-06 17:21:15 +00:00
lua_pushstring ( L , key ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
2018-04-06 17:21:15 +00:00
# define bi_lua_infokey bi_lua_getinfokey
2014-03-30 08:55:06 +00:00
static int bi_lua_setinfokey ( lua_State * L )
{
int entnum ;
const char * key ;
const char * value ;
int result ;
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
entnum = lua_tointegerx ( L , - 1 , NULL ) ;
key = lua_tolstring ( L , 2 , NULL ) ;
value = lua_tolstring ( L , 3 , NULL ) ;
2014-03-30 08:55:06 +00:00
2018-07-05 16:21:44 +00:00
result = PF_ForceInfoKey_Internal ( entnum , key , value , strlen ( value ) ) ;
2018-04-06 17:21:15 +00:00
lua_pushinteger ( L , result ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_ambientsound ( lua_State * L )
{
vec3_t pos ;
2018-04-06 17:21:15 +00:00
const char * samp = lua_tolstring ( L , 2 , NULL ) ;
float vol = lua_tonumberx ( L , 3 , NULL ) ;
float attenuation = lua_tonumberx ( L , 4 , NULL ) ;
2014-03-30 08:55:06 +00:00
lua_readvector ( L , 1 , pos ) ;
PF_ambientsound_Internal ( pos , samp , vol , attenuation ) ;
return 0 ;
}
static int bi_lua_sound ( lua_State * L )
{
int entnum ;
2018-04-06 17:21:15 +00:00
float channel = lua_tonumberx ( L , 2 , NULL ) ;
const char * samp = lua_tolstring ( L , 3 , NULL ) ;
float volume = lua_tonumberx ( L , 4 , NULL ) ;
float attenuation = lua_tonumberx ( L , 5 , NULL ) ;
2014-03-30 08:55:06 +00:00
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
entnum = lua_tointegerx ( L , - 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
//note: channel & 256 == reliable
2018-04-06 17:21:15 +00:00
SVQ1_StartSound ( NULL , ( wedict_t * ) EDICT_NUM_UB ( ( & lua . progfuncs ) , entnum ) , channel , samp , volume * 255 , attenuation , 0 , 0 , 0 ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
}
static int bi_lua_pointcontents ( lua_State * L )
{
vec3_t pos ;
lua_readvector ( L , 1 , pos ) ;
2018-04-06 17:21:15 +00:00
lua_pushinteger ( L , sv . world . worldmodel - > funcs . PointContents ( sv . world . worldmodel , NULL , pos ) ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_setspawnparms ( lua_State * L )
{
globalvars_t pr_globals ;
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
pr_globals . param [ 0 ] . i = lua_tointegerx ( L , - 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
PF_setspawnparms ( & lua . progfuncs , & pr_globals ) ;
return 0 ;
}
static int bi_lua_makestatic ( lua_State * L )
{
globalvars_t pr_globals ;
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
pr_globals . param [ 0 ] . i = lua_tointegerx ( L , - 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
PF_makestatic ( & lua . progfuncs , & pr_globals ) ;
return 0 ;
}
static int bi_lua_droptofloor ( lua_State * L )
{
extern cvar_t pr_droptofloorunits ;
wedict_t * ent ;
vec3_t end ;
vec3_t start ;
trace_t trace ;
const float * gravitydir ;
2017-12-28 16:24:50 +00:00
static const vec3_t standardgravity = { 0 , 0 , - 1 } ;
2014-03-30 08:55:06 +00:00
pubprogfuncs_t * prinst = & lua . progfuncs ;
world_t * world = prinst - > parms - > user ;
ent = PROG_TO_WEDICT ( ( & lua . progfuncs ) , pr_global_struct - > self ) ;
if ( ent - > xv - > gravitydir [ 2 ] | | ent - > xv - > gravitydir [ 1 ] | | ent - > xv - > gravitydir [ 0 ] )
gravitydir = ent - > xv - > gravitydir ;
else
gravitydir = standardgravity ;
VectorCopy ( ent - > v - > origin , end ) ;
if ( pr_droptofloorunits . value > 0 )
VectorMA ( end , pr_droptofloorunits . value , gravitydir , end ) ;
else
VectorMA ( end , 256 , gravitydir , end ) ;
VectorCopy ( ent - > v - > origin , start ) ;
trace = World_Move ( world , start , ent - > v - > mins , ent - > v - > maxs , end , MOVE_NORMAL , ent ) ;
if ( trace . fraction = = 1 | | trace . allsolid )
2018-04-06 17:21:15 +00:00
lua_pushboolean ( L , false ) ;
2014-03-30 08:55:06 +00:00
else
{
VectorCopy ( trace . endpos , ent - > v - > origin ) ;
World_LinkEdict ( world , ent , false ) ;
ent - > v - > flags = ( int ) ent - > v - > flags | FL_ONGROUND ;
ent - > v - > groundentity = EDICT_TO_PROG ( prinst , trace . ent ) ;
2018-04-06 17:21:15 +00:00
lua_pushboolean ( L , true ) ;
2014-03-30 08:55:06 +00:00
}
return 1 ;
}
static int bi_lua_checkbottom ( lua_State * L )
{
qboolean okay ;
int entnum ;
2017-12-28 16:24:50 +00:00
vec3_t up = { 0 , 0 , 1 } ;
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
entnum = lua_tointegerx ( L , - 1 , NULL ) ;
okay = World_CheckBottom ( & sv . world , ( wedict_t * ) EDICT_NUM_UB ( ( & lua . progfuncs ) , entnum ) , up ) ;
lua_pushboolean ( L , okay ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
2018-04-06 17:21:15 +00:00
static int bi_lua_bprint_qw ( lua_State * L )
{
int level = lua_tointegerx ( L , 1 , NULL ) ;
const char * str = lua_tolstring ( L , 2 , NULL ) ;
SV_BroadcastPrintf ( level , " %s " , str ) ;
return 0 ;
}
static int bi_lua_bprint_nq ( lua_State * L )
2014-03-30 08:55:06 +00:00
{
2018-04-06 17:21:15 +00:00
int level = PRINT_HIGH ;
const char * str = lua_tolstring ( L , 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
SV_BroadcastPrintf ( level , " %s " , str ) ;
return 0 ;
}
2018-04-06 17:21:15 +00:00
static int bi_lua_sprint_qw ( lua_State * L )
{
int entnum ;
int level = lua_tointegerx ( L , 2 , NULL ) ;
const char * str = lua_tolstring ( L , 3 , NULL ) ;
lua_getfield ( L , 1 , " entnum " ) ;
entnum = lua_tointegerx ( L , - 1 , NULL ) ;
if ( entnum < 1 | | entnum > sv . allocated_client_slots )
{
Con_TPrintf ( " tried to sprint to a non-client \n " ) ;
return 0 ;
}
SV_ClientPrintf ( & svs . clients [ entnum - 1 ] , level , " %s " , str ) ;
return 0 ;
}
static int bi_lua_sprint_nq ( lua_State * L )
2014-03-30 08:55:06 +00:00
{
int entnum ;
2018-04-06 17:21:15 +00:00
int level = PRINT_HIGH ;
const char * str = lua_tolstring ( L , 2 , NULL ) ;
2014-03-30 08:55:06 +00:00
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
entnum = lua_tointegerx ( L , - 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
if ( entnum < 1 | | entnum > sv . allocated_client_slots )
{
Con_TPrintf ( " tried to sprint to a non-client \n " ) ;
return 0 ;
}
SV_ClientPrintf ( & svs . clients [ entnum - 1 ] , level , " %s " , str ) ;
return 0 ;
}
static int bi_lua_cvar_set ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
const char * name = lua_tolstring ( L , 1 , NULL ) ;
const char * str = lua_tolstring ( L , 2 , NULL ) ;
2014-03-30 08:55:06 +00:00
cvar_t * var = Cvar_FindVar ( name ) ;
if ( var )
Cvar_Set ( var , str ) ;
return 0 ;
}
static int bi_lua_cvar_get ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
const char * name = lua_tolstring ( L , 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
cvar_t * var = Cvar_FindVar ( name ) ;
if ( var )
2018-04-06 17:21:15 +00:00
lua_pushstring ( L , var - > string ) ;
2014-03-30 08:55:06 +00:00
else
2018-04-06 17:21:15 +00:00
lua_pushnil ( L ) ;
return 1 ;
}
static int bi_lua_cvar ( lua_State * L ) //useless get[float]
{
const char * name = lua_tolstring ( L , 1 , NULL ) ;
cvar_t * var = Cvar_FindVar ( name ) ;
if ( var )
lua_pushnumber ( L , var - > value ) ;
else
lua_pushnil ( L ) ;
return 1 ;
2014-03-30 08:55:06 +00:00
}
2018-04-06 17:21:15 +00:00
static int pushset_trace_globals ( lua_State * L , trace_t * trace )
2014-03-30 08:55:06 +00:00
{
pr_global_struct - > trace_allsolid = trace - > allsolid ;
pr_global_struct - > trace_startsolid = trace - > startsolid ;
pr_global_struct - > trace_fraction = trace - > fraction ;
pr_global_struct - > trace_inwater = trace - > inwater ;
pr_global_struct - > trace_inopen = trace - > inopen ;
2017-12-28 16:24:50 +00:00
pr_global_struct - > trace_surfaceflagsf = trace - > surface ? trace - > surface - > flags : 0 ;
2016-07-12 00:40:13 +00:00
pr_global_struct - > trace_surfaceflagsi = trace - > surface ? trace - > surface - > flags : 0 ;
2017-12-28 16:24:50 +00:00
// if (pr_global_struct->trace_surfacename)
// prinst->SetStringField(prinst, NULL, &pr_global_struct->trace_surfacename, tr->surface?tr->surface->name:"", true);
pr_global_struct - > trace_endcontentsf = trace - > contents ;
2016-07-12 00:40:13 +00:00
pr_global_struct - > trace_endcontentsi = trace - > contents ;
2014-03-30 08:55:06 +00:00
// if (trace.fraction != 1)
// VectorMA (trace->endpos, 4, trace->plane.normal, P_VEC(trace_endpos));
// else
VectorCopy ( trace - > endpos , P_VEC ( trace_endpos ) ) ;
VectorCopy ( trace - > plane . normal , P_VEC ( trace_plane_normal ) ) ;
pr_global_struct - > trace_plane_dist = trace - > plane . dist ;
pr_global_struct - > trace_ent = trace - > ent ? ( ( wedict_t * ) trace - > ent ) - > entnum : 0 ;
2018-04-06 17:21:15 +00:00
lua_newtable ( L ) ;
lua_pushnumber ( L , trace - > fraction ) ;
lua_setfield ( L , - 2 , " fraction " ) ;
lua_pushvector ( L , trace - > endpos [ 0 ] , trace - > endpos [ 1 ] , trace - > endpos [ 2 ] ) ;
lua_setfield ( L , - 2 , " endpos " ) ;
if ( trace - > ent )
lua_pushedict ( L , trace - > ent ) ;
else
lua_pushedict ( L , lua . edicttable [ 0 ] ) ;
lua_setfield ( L , - 2 , " ent " ) ;
lua_pushboolean ( L , trace - > allsolid ) ;
lua_setfield ( L , - 2 , " allsolid " ) ;
lua_pushboolean ( L , trace - > startsolid ) ;
lua_setfield ( L , - 2 , " startsolid " ) ;
lua_pushboolean ( L , trace - > inwater ) ;
lua_setfield ( L , - 2 , " inwater " ) ;
lua_pushboolean ( L , trace - > inopen ) ;
lua_setfield ( L , - 2 , " inopen " ) ;
lua_newtable ( L ) ;
lua_pushnumber ( L , trace - > plane . dist ) ;
lua_setfield ( L , - 2 , " dist " ) ;
lua_pushvector ( L , trace - > plane . normal [ 0 ] , trace - > plane . normal [ 1 ] , trace - > plane . normal [ 2 ] ) ;
lua_setfield ( L , - 2 , " normal " ) ;
lua_setfield ( L , - 2 , " plane " ) ;
return 1 ;
2014-03-30 08:55:06 +00:00
}
static int bi_lua_traceline ( lua_State * L )
{
vec3_t v1 , v2 ;
trace_t trace ;
int nomonsters ;
wedict_t * ent ;
lua_readvector ( L , 1 , v1 ) ;
lua_readvector ( L , 2 , v2 ) ;
2018-04-06 17:21:15 +00:00
nomonsters = lua_tointegerx ( L , 3 , NULL ) ;
lua_getfield ( L , 4 , " entnum " ) ;
ent = ( wedict_t * ) EDICT_NUM_UB ( ( & lua . progfuncs ) , lua_tointegerx ( L , - 1 , NULL ) ) ;
2014-03-30 08:55:06 +00:00
2016-07-12 00:40:13 +00:00
trace = World_Move ( & sv . world , v1 , vec3_origin , vec3_origin , v2 , nomonsters | MOVE_IGNOREHULL , ( wedict_t * ) ent ) ;
2014-03-30 08:55:06 +00:00
2018-04-06 17:21:15 +00:00
return pushset_trace_globals ( L , & trace ) ;
2014-03-30 08:55:06 +00:00
}
static int bi_lua_tracebox ( lua_State * L )
{
vec3_t v1 , v2 , mins , maxs ;
trace_t trace ;
int nomonsters ;
wedict_t * ent ;
lua_readvector ( L , 1 , v1 ) ;
lua_readvector ( L , 2 , v2 ) ;
lua_readvector ( L , 3 , mins ) ;
lua_readvector ( L , 4 , maxs ) ;
2018-04-06 17:21:15 +00:00
nomonsters = lua_tointegerx ( L , 5 , NULL ) ;
lua_getfield ( L , 6 , " entnum " ) ;
ent = ( wedict_t * ) EDICT_NUM_UB ( ( & lua . progfuncs ) , lua_tointegerx ( L , - 1 , NULL ) ) ;
2014-03-30 08:55:06 +00:00
2016-07-12 00:40:13 +00:00
trace = World_Move ( & sv . world , v1 , mins , maxs , v2 , nomonsters | MOVE_IGNOREHULL , ( wedict_t * ) ent ) ;
2014-03-30 08:55:06 +00:00
2018-04-06 17:21:15 +00:00
return pushset_trace_globals ( L , & trace ) ;
2014-03-30 08:55:06 +00:00
}
static int bi_lua_walkmove ( lua_State * L )
{
pubprogfuncs_t * prinst = & lua . progfuncs ;
world_t * world = prinst - > parms - > user ;
wedict_t * ent ;
float yaw , dist ;
vec3_t move ;
int oldself ;
2017-12-28 16:24:50 +00:00
vec3_t axis [ 3 ] ;
2014-03-30 08:55:06 +00:00
ent = PROG_TO_WEDICT ( prinst , * world - > g . self ) ;
2018-04-06 17:21:15 +00:00
yaw = lua_tonumberx ( L , 1 , NULL ) ;
dist = lua_tonumberx ( L , 2 , NULL ) ;
2014-03-30 08:55:06 +00:00
if ( ! ( ( int ) ent - > v - > flags & ( FL_ONGROUND | FL_FLY | FL_SWIM ) ) )
{
2018-04-06 17:21:15 +00:00
lua_pushboolean ( L , false ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
2014-06-21 17:58:17 +00:00
World_GetEntGravityAxis ( ent , axis ) ;
2014-03-30 08:55:06 +00:00
yaw = yaw * M_PI * 2 / 360 ;
2014-06-21 17:58:17 +00:00
VectorScale ( axis [ 0 ] , cos ( yaw ) * dist , move ) ;
VectorMA ( move , sin ( yaw ) * dist , axis [ 1 ] , move ) ;
2014-03-30 08:55:06 +00:00
// save program state, because World_movestep may call other progs
oldself = * world - > g . self ;
2018-10-17 00:43:04 +00:00
lua_pushboolean ( L , World_movestep ( world , ent , move , axis , true , false , NULL ) ) ;
2014-03-30 08:55:06 +00:00
// restore program state
* world - > g . self = oldself ;
return 1 ;
}
static int bi_lua_movetogoal ( lua_State * L )
{
pubprogfuncs_t * prinst = & lua . progfuncs ;
world_t * world = prinst - > parms - > user ;
wedict_t * ent ;
float dist ;
ent = PROG_TO_WEDICT ( prinst , * world - > g . self ) ;
2018-04-06 17:21:15 +00:00
dist = lua_tonumberx ( L , 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
World_MoveToGoal ( world , ent , dist ) ;
return 0 ;
}
static int bi_lua_nextent ( lua_State * L )
{
world_t * world = & sv . world ;
int i ;
wedict_t * ent ;
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
i = lua_tointegerx ( L , - 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
while ( 1 )
{
i + + ;
if ( i = = world - > num_edicts )
{
ent = world - > edicts ;
break ;
}
2018-04-06 17:21:15 +00:00
ent = ( wedict_t * ) lua . edicttable [ i ] ;
2017-12-28 16:24:50 +00:00
if ( ! ED_ISFREE ( ent ) )
2014-03-30 08:55:06 +00:00
{
break ;
}
}
2018-04-06 17:21:15 +00:00
lua_pushedict ( L , ( struct edict_s * ) ent ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_nextclient ( lua_State * L )
{
world_t * world = & sv . world ;
int i ;
wedict_t * ent ;
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
i = lua_tointegerx ( L , - 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
while ( 1 )
{
i + + ;
if ( i = = sv . allocated_client_slots )
{
ent = world - > edicts ;
break ;
}
2018-04-06 17:21:15 +00:00
ent = WEDICT_NUM_UB ( world - > progs , i ) ;
2017-12-28 16:24:50 +00:00
if ( ! ED_ISFREE ( ent ) )
2014-03-30 08:55:06 +00:00
{
break ;
}
}
2018-04-06 17:21:15 +00:00
lua_pushlightuserdata ( L , ent ) ;
lua_gettable ( L , LUA_REGISTRYINDEX ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_checkclient ( lua_State * L )
{
pubprogfuncs_t * prinst = & lua . progfuncs ;
wedict_t * ent ;
2018-04-06 17:21:15 +00:00
ent = WEDICT_NUM_PB ( prinst , PF_checkclient_Internal ( prinst ) ) ;
lua_pushlightuserdata ( L , ent ) ;
lua_gettable ( L , LUA_REGISTRYINDEX ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_random ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
lua_pushnumber ( L , ( rand ( ) & 0x7fff ) / ( ( float ) 0x8000 ) ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_makevectors ( lua_State * L )
{
vec3_t angles ;
//this is annoying as fuck in lua, what with it writing globals and stuff.
//perhaps we should support f,u,l=makevectors(ang)... meh, cba.
lua_readvector ( L , 1 , angles ) ;
AngleVectors ( angles , pr_global_struct - > v_forward , pr_global_struct - > v_right , pr_global_struct - > v_up ) ;
2018-04-06 17:21:15 +00:00
# if 1
//globals suck, and lua allows multi-return.
lua_pushvector ( L , ( pr_global_struct - > v_forward ) [ 0 ] , ( pr_global_struct - > v_forward ) [ 1 ] , ( pr_global_struct - > v_forward ) [ 2 ] ) ;
lua_pushvector ( L , ( pr_global_struct - > v_right ) [ 0 ] , ( pr_global_struct - > v_right ) [ 1 ] , ( pr_global_struct - > v_right ) [ 2 ] ) ;
lua_pushvector ( L , ( pr_global_struct - > v_up ) [ 0 ] , ( pr_global_struct - > v_up ) [ 1 ] , ( pr_global_struct - > v_up ) [ 2 ] ) ;
return 3 ;
# else
2014-03-30 08:55:06 +00:00
return 0 ;
2018-04-06 17:21:15 +00:00
# endif
}
static int bi_lua_normalize ( lua_State * L )
{
vec3_t v ;
lua_readvector ( L , 1 , v ) ;
VectorNormalize ( v ) ;
lua_pushvector ( L , v [ 0 ] , v [ 1 ] , v [ 2 ] ) ;
return 1 ;
2014-03-30 08:55:06 +00:00
}
static int bi_lua_vectoangles ( lua_State * L )
{
vec3_t forward ;
vec3_t up ;
float * uv = NULL ;
vec3_t ret ;
lua_readvector ( L , 1 , forward ) ;
2018-04-06 17:21:15 +00:00
if ( lua_type ( L , 2 ) ! = LUA_TNONE )
2014-03-30 08:55:06 +00:00
{
lua_readvector ( L , 1 , up ) ;
uv = up ;
}
2017-12-28 16:24:50 +00:00
VectorAngles ( forward , uv , ret , true ) ;
2014-03-30 08:55:06 +00:00
2018-04-06 17:21:15 +00:00
lua_pushvector ( L , ret [ 0 ] , ret [ 1 ] , ret [ 2 ] ) ;
return 1 ;
}
static int bi_lua_vectoyaw ( lua_State * L )
{
vec3_t forward ;
vec3_t up ;
float * uv = NULL ;
vec3_t ret ;
lua_readvector ( L , 1 , forward ) ;
if ( lua_type ( L , 2 ) ! = LUA_TNONE )
{
lua_readvector ( L , 1 , up ) ;
uv = up ;
}
VectorAngles ( forward , uv , ret , true ) ;
lua_pushnumber ( L , ret [ 1 ] ) ;
return 1 ;
}
void QCBUILTIN PF_aim ( pubprogfuncs_t * prinst , struct globalvars_s * pr_globals ) ;
static int bi_lua_aim ( lua_State * L )
{ //aim builtin is for keyboard users, if they still exist.
globalvars_t pr_globals ;
lua_getfield ( L , 1 , " entnum " ) ;
pr_globals . param [ 0 ] . i = lua_tointeger ( L , - 1 ) ;
pr_globals . param [ 1 ] . f = lua_tonumber ( L , 2 ) ; //speed
PF_aim ( & lua . progfuncs , & pr_globals ) ;
lua_pushvector ( L , pr_globals . ret . vec [ 0 ] , pr_globals . ret . vec [ 1 ] , pr_globals . ret . vec [ 2 ] ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_tokenize ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
const char * instring = lua_tolstring ( L , 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
int argc = 0 ;
2018-04-06 17:21:15 +00:00
lua_newtable ( L ) ;
2014-03-30 08:55:06 +00:00
while ( NULL ! = ( instring = COM_Parse ( instring ) ) )
{
//lua is traditionally 1-based
//for i=1,t.argc do
2018-04-06 17:21:15 +00:00
lua_pushinteger ( L , + + argc ) ;
lua_pushstring ( L , com_token ) ;
lua_settable ( L , - 3 ) ;
2014-03-30 08:55:06 +00:00
if ( argc = = 1 )
{
while ( * instring = = ' ' | | * instring = = ' \t ' )
instring + + ;
2018-04-06 17:21:15 +00:00
lua_pushstring ( L , instring ) ;
lua_setfield ( L , - 2 , " args " ) ; //args is all-but-the-first
2014-03-30 08:55:06 +00:00
}
}
2018-04-06 17:21:15 +00:00
lua_pushinteger ( L , argc ) ;
lua_setfield ( L , - 2 , " argc " ) ; //argc is the count.
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_findradiuschain ( lua_State * L )
{
extern cvar_t sv_gameplayfix_blowupfallenzombies ;
world_t * world = & sv . world ;
edict_t * ent , * chain ;
float rad ;
vec3_t org ;
vec3_t eorg ;
int i , j ;
chain = ( edict_t * ) world - > edicts ;
lua_readvector ( L , 1 , org ) ;
2018-04-06 17:21:15 +00:00
rad = lua_tonumberx ( L , 2 , NULL ) ;
2014-03-30 08:55:06 +00:00
rad = rad * rad ;
for ( i = 1 ; i < world - > num_edicts ; i + + )
{
2018-04-06 17:21:15 +00:00
ent = EDICT_NUM_PB ( world - > progs , i ) ;
2017-12-28 16:24:50 +00:00
if ( ED_ISFREE ( ent ) )
2014-03-30 08:55:06 +00:00
continue ;
if ( ent - > v - > solid = = SOLID_NOT & & ( progstype ! = PROG_QW | | ! ( ( int ) ent - > v - > flags & FL_FINDABLE_NONSOLID ) ) & & ! sv_gameplayfix_blowupfallenzombies . value )
continue ;
for ( j = 0 ; j < 3 ; j + + )
eorg [ j ] = org [ j ] - ( ent - > v - > origin [ j ] + ( ent - > v - > mins [ j ] + ent - > v - > maxs [ j ] ) * 0.5 ) ;
if ( DotProduct ( eorg , eorg ) > rad )
continue ;
ent - > v - > chain = EDICT_TO_PROG ( world - > progs , chain ) ;
chain = ent ;
}
2018-04-06 17:21:15 +00:00
lua_pushlightuserdata ( L , chain ) ;
lua_gettable ( L , LUA_REGISTRYINDEX ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_findradiustable ( lua_State * L )
{
extern cvar_t sv_gameplayfix_blowupfallenzombies ;
world_t * world = & sv . world ;
edict_t * ent , * chain ;
float rad ;
vec3_t org ;
vec3_t eorg ;
int i , j ;
int results = 1 ; //lua arrays are 1-based
chain = ( edict_t * ) world - > edicts ;
lua_readvector ( L , 1 , org ) ;
2018-04-06 17:21:15 +00:00
rad = lua_tonumberx ( L , 2 , NULL ) ;
2014-03-30 08:55:06 +00:00
rad = rad * rad ;
2018-04-06 17:21:15 +00:00
lua_newtable ( L ) ; //our return value.
2014-03-30 08:55:06 +00:00
for ( i = 1 ; i < world - > num_edicts ; i + + )
{
2018-04-06 17:21:15 +00:00
ent = EDICT_NUM_PB ( world - > progs , i ) ;
2017-12-28 16:24:50 +00:00
if ( ED_ISFREE ( ent ) )
2014-03-30 08:55:06 +00:00
continue ;
if ( ent - > v - > solid = = SOLID_NOT & & ( progstype ! = PROG_QW | | ! ( ( int ) ent - > v - > flags & FL_FINDABLE_NONSOLID ) ) & & ! sv_gameplayfix_blowupfallenzombies . value )
continue ;
for ( j = 0 ; j < 3 ; j + + )
eorg [ j ] = org [ j ] - ( ent - > v - > origin [ j ] + ( ent - > v - > mins [ j ] + ent - > v - > maxs [ j ] ) * 0.5 ) ;
if ( DotProduct ( eorg , eorg ) > rad )
continue ;
2018-04-06 17:21:15 +00:00
lua_pushinteger ( L , + + results ) ;
lua_pushlightuserdata ( L , ent ) ;
lua_gettable ( L , LUA_REGISTRYINDEX ) ;
lua_settable ( L , - 3 ) ;
2014-03-30 08:55:06 +00:00
}
2018-04-06 17:21:15 +00:00
lua_pushlightuserdata ( L , chain ) ;
lua_gettable ( L , LUA_REGISTRYINDEX ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
# define bi_lua_findradius bi_lua_findradiuschain
2018-04-06 17:21:15 +00:00
static int bi_lua_find ( lua_State * L )
{
world_t * world = & sv . world ;
edict_t * ent ;
size_t i ;
const char * s ;
const char * match ;
lua_getfield ( L , 1 , " entnum " ) ;
i = lua_tointegerx ( L , - 1 , NULL ) + 1 ;
match = lua_tostring ( L , 3 ) ;
for ( ; i < world - > num_edicts ; i + + )
{
ent = EDICT_NUM_PB ( world - > progs , i ) ;
if ( ED_ISFREE ( ent ) )
continue ;
lua_pushedict ( L , ent ) ;
lua_pushvalue ( L , 2 ) ;
lua_gettable ( L , - 2 ) ;
s = lua_tostring ( L , - 1 ) ;
if ( ! s )
s = " " ;
if ( ! strcmp ( s , match ) ) //should probably do a lua comparison, but nils suck
{
lua_pop ( L , 2 ) ;
lua_pushedict ( L , ent ) ;
return 1 ;
}
lua_pop ( L , 2 ) ;
}
lua_pushedict ( L , EDICT_NUM_PB ( world - > progs , 0 ) ) ;
return 1 ;
}
2014-03-30 08:55:06 +00:00
static int bi_lua_multicast ( lua_State * L )
{
int dest ;
vec3_t org ;
2018-04-06 17:21:15 +00:00
dest = lua_tointegerx ( L , 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
lua_readvector ( L , 2 , org ) ;
NPP_Flush ( ) ;
SV_Multicast ( org , dest ) ;
return 0 ;
}
extern sizebuf_t csqcmsgbuffer ;
static int bi_lua_writechar ( lua_State * L )
{
globalvars_t pr_globals ;
pr_globals . param [ 0 ] . f = ( csqcmsgbuffer . maxsize ? MSG_CSQC : MSG_MULTICAST ) ;
2018-04-06 17:21:15 +00:00
pr_globals . param [ 1 ] . f = lua_tonumberx ( L , 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
PF_WriteChar ( & lua . progfuncs , & pr_globals ) ;
return 0 ;
}
static int bi_lua_writebyte ( lua_State * L )
{
globalvars_t pr_globals ;
pr_globals . param [ 0 ] . f = ( csqcmsgbuffer . maxsize ? MSG_CSQC : MSG_MULTICAST ) ;
2018-04-06 17:21:15 +00:00
pr_globals . param [ 1 ] . f = lua_tonumberx ( L , 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
PF_WriteByte ( & lua . progfuncs , & pr_globals ) ;
return 0 ;
}
static int bi_lua_writeshort ( lua_State * L )
{
globalvars_t pr_globals ;
pr_globals . param [ 0 ] . f = ( csqcmsgbuffer . maxsize ? MSG_CSQC : MSG_MULTICAST ) ;
2018-04-06 17:21:15 +00:00
pr_globals . param [ 1 ] . f = lua_tonumberx ( L , 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
PF_WriteShort ( & lua . progfuncs , & pr_globals ) ;
return 0 ;
}
static int bi_lua_writelong ( lua_State * L )
{
globalvars_t pr_globals ;
pr_globals . param [ 0 ] . f = ( csqcmsgbuffer . maxsize ? MSG_CSQC : MSG_MULTICAST ) ;
2018-04-06 17:21:15 +00:00
pr_globals . param [ 1 ] . f = lua_tonumberx ( L , 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
PF_WriteLong ( & lua . progfuncs , & pr_globals ) ;
return 0 ;
}
static int bi_lua_writeangle ( lua_State * L )
{
globalvars_t pr_globals ;
pr_globals . param [ 0 ] . f = ( csqcmsgbuffer . maxsize ? MSG_CSQC : MSG_MULTICAST ) ;
2018-04-06 17:21:15 +00:00
pr_globals . param [ 1 ] . f = lua_tonumberx ( L , 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
PF_WriteAngle ( & lua . progfuncs , & pr_globals ) ;
return 0 ;
}
static int bi_lua_writecoord ( lua_State * L )
{
globalvars_t pr_globals ;
pr_globals . param [ 0 ] . f = ( csqcmsgbuffer . maxsize ? MSG_CSQC : MSG_MULTICAST ) ;
2018-04-06 17:21:15 +00:00
pr_globals . param [ 1 ] . f = lua_tonumberx ( L , 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
PF_WriteCoord ( & lua . progfuncs , & pr_globals ) ;
return 0 ;
}
static int bi_lua_writestring ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
PF_WriteString_Internal ( ( csqcmsgbuffer . maxsize ? MSG_CSQC : MSG_MULTICAST ) , lua_tolstring ( L , 1 , NULL ) ) ;
2014-03-30 08:55:06 +00:00
return 0 ;
}
static int bi_lua_writeentity ( lua_State * L )
{
globalvars_t pr_globals ;
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
2014-03-30 08:55:06 +00:00
pr_globals . param [ 0 ] . f = ( csqcmsgbuffer . maxsize ? MSG_CSQC : MSG_MULTICAST ) ;
2018-04-06 17:21:15 +00:00
pr_globals . param [ 1 ] . i = lua_tointegerx ( L , - 1 , NULL ) ;
PF_WriteEntity ( & lua . progfuncs , & pr_globals ) ;
return 0 ;
}
static int bi_lua_WriteChar ( lua_State * L )
{
globalvars_t pr_globals ;
pr_globals . param [ 0 ] . f = lua_tonumberx ( L , 1 , NULL ) ;
pr_globals . param [ 1 ] . f = lua_tonumberx ( L , 2 , NULL ) ;
PF_WriteChar ( & lua . progfuncs , & pr_globals ) ;
return 0 ;
}
static int bi_lua_WriteByte ( lua_State * L )
{
globalvars_t pr_globals ;
pr_globals . param [ 0 ] . f = lua_tonumberx ( L , 1 , NULL ) ;
pr_globals . param [ 1 ] . f = lua_tonumberx ( L , 2 , NULL ) ;
PF_WriteByte ( & lua . progfuncs , & pr_globals ) ;
return 0 ;
}
static int bi_lua_WriteShort ( lua_State * L )
{
globalvars_t pr_globals ;
pr_globals . param [ 0 ] . f = lua_tonumberx ( L , 1 , NULL ) ;
pr_globals . param [ 1 ] . f = lua_tonumberx ( L , 2 , NULL ) ;
PF_WriteShort ( & lua . progfuncs , & pr_globals ) ;
return 0 ;
}
static int bi_lua_WriteLong ( lua_State * L )
{
globalvars_t pr_globals ;
pr_globals . param [ 0 ] . f = lua_tonumberx ( L , 1 , NULL ) ;
pr_globals . param [ 1 ] . f = lua_tonumberx ( L , 2 , NULL ) ;
PF_WriteLong ( & lua . progfuncs , & pr_globals ) ;
return 0 ;
}
static int bi_lua_WriteAngle ( lua_State * L )
{
globalvars_t pr_globals ;
pr_globals . param [ 0 ] . f = lua_tonumberx ( L , 1 , NULL ) ;
pr_globals . param [ 1 ] . f = lua_tonumberx ( L , 2 , NULL ) ;
PF_WriteAngle ( & lua . progfuncs , & pr_globals ) ;
return 0 ;
}
static int bi_lua_WriteCoord ( lua_State * L )
{
globalvars_t pr_globals ;
pr_globals . param [ 0 ] . f = lua_tonumberx ( L , 1 , NULL ) ;
pr_globals . param [ 1 ] . f = lua_tonumberx ( L , 2 , NULL ) ;
PF_WriteCoord ( & lua . progfuncs , & pr_globals ) ;
return 0 ;
}
static int bi_lua_WriteString ( lua_State * L )
{
PF_WriteString_Internal ( lua_tonumberx ( L , 1 , NULL ) , lua_tolstring ( L , 2 , NULL ) ) ;
return 0 ;
}
static int bi_lua_WriteEntity ( lua_State * L )
{
globalvars_t pr_globals ;
lua_getfield ( L , 2 , " entnum " ) ;
pr_globals . param [ 0 ] . f = lua_tonumberx ( L , 1 , NULL ) ;
pr_globals . param [ 1 ] . i = lua_tointegerx ( L , - 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
PF_WriteEntity ( & lua . progfuncs , & pr_globals ) ;
return 0 ;
}
2018-04-06 17:21:15 +00:00
void QCBUILTIN PF_particle ( pubprogfuncs_t * prinst , globalvars_t * pr_globals ) ;
static int bi_lua_particle ( lua_State * L )
{
globalvars_t pr_globals ;
lua_readvector ( L , 1 , pr_globals . param [ 0 ] . vec ) ;
lua_readvector ( L , 2 , pr_globals . param [ 1 ] . vec ) ;
pr_globals . param [ 2 ] . f = lua_tonumberx ( L , 3 , NULL ) ;
pr_globals . param [ 3 ] . f = lua_tonumberx ( L , 4 , NULL ) ;
PF_particle ( & lua . progfuncs , & pr_globals ) ;
return 0 ;
}
static int bi_lua_ChangeYaw ( lua_State * L )
{
PF_changeyaw ( & lua . progfuncs , NULL ) ;
return 0 ;
}
2014-03-30 08:55:06 +00:00
static int bi_lua_bitnot ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
lua_pushinteger ( L , ~ lua_tointegerx ( L , 1 , NULL ) ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_bitclear ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
lua_pushinteger ( L , lua_tointegerx ( L , 1 , NULL ) & ~ lua_tointegerx ( L , 2 , NULL ) ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_bitset ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
lua_pushnumber ( L , lua_tointegerx ( L , 1 , NULL ) | lua_tointegerx ( L , 2 , NULL ) ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
# define bi_lua_bitor bi_lua_bitset
static int bi_lua_bitand ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
lua_pushnumber ( L , lua_tointegerx ( L , 1 , NULL ) & lua_tointegerx ( L , 2 , NULL ) ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_bitxor ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
lua_pushnumber ( L , lua_tointegerx ( L , 1 , NULL ) ^ lua_tointegerx ( L , 2 , NULL ) ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_sin ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
lua_pushnumber ( L , sin ( lua_tonumberx ( L , 1 , NULL ) ) ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_cos ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
lua_pushnumber ( L , cos ( lua_tonumberx ( L , 1 , NULL ) ) ) ;
return 1 ;
}
static int bi_lua_tan ( lua_State * L )
{
lua_pushnumber ( L , tan ( lua_tonumberx ( L , 1 , NULL ) ) ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_atan2 ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
lua_pushnumber ( L , atan2 ( lua_tonumberx ( L , 1 , NULL ) , lua_tonumberx ( L , 2 , NULL ) ) ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_sqrt ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
lua_pushnumber ( L , sin ( lua_tonumberx ( L , 1 , NULL ) ) ) ;
return 1 ;
}
static int bi_lua_pow ( lua_State * L )
{
lua_pushnumber ( L , pow ( lua_tonumberx ( L , 1 , NULL ) , lua_tonumberx ( L , 2 , NULL ) ) ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_floor ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
lua_pushnumber ( L , floor ( lua_tonumberx ( L , 1 , NULL ) ) ) ;
return 1 ;
}
static int bi_lua_rint ( lua_State * L )
{ //C rounds towards 0, so bias away from 0 by 0.5 and we'll get the right rounded value.
lua_Number f = lua_tonumberx ( L , 1 , NULL ) ;
if ( f < 0 )
lua_pushinteger ( L , f - 0.5 ) ;
else
lua_pushinteger ( L , f + 0.5 ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_ceil ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
lua_pushnumber ( L , ceil ( lua_tonumberx ( L , 1 , NULL ) ) ) ;
return 1 ;
}
static int bi_lua_fabs ( lua_State * L )
{
lua_pushnumber ( L , fabs ( lua_tonumberx ( L , 1 , NULL ) ) ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_acos ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
lua_pushnumber ( L , acos ( lua_tonumberx ( L , 1 , NULL ) ) ) ;
return 1 ;
}
static int bi_lua_asin ( lua_State * L )
{
lua_pushnumber ( L , asin ( lua_tonumberx ( L , 1 , NULL ) ) ) ;
return 1 ;
}
static int bi_lua_atan ( lua_State * L )
{
lua_pushnumber ( L , atan ( lua_tonumberx ( L , 1 , NULL ) ) ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
typedef struct
{
lua_State * L ;
int idx ;
} luafsenum_t ;
2017-12-28 16:24:50 +00:00
static int QDECL lua_file_enumerate ( const char * fname , qofs_t fsize , time_t mtime , void * param , searchpathfuncs_t * spath )
2014-03-30 08:55:06 +00:00
{
luafsenum_t * e = param ;
2018-04-06 17:21:15 +00:00
lua_pushinteger ( e - > L , e - > idx + + ) ;
lua_pushfstring ( e - > L , " %s " , fname ) ;
lua_settable ( e - > L , - 3 ) ;
2014-03-30 08:55:06 +00:00
return true ;
}
static int bi_lua_getfilelist ( lua_State * L )
{
luafsenum_t e ;
2018-04-06 17:21:15 +00:00
const char * path = lua_tolstring ( L , 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
e . L = L ;
e . idx = 1 ; //lua arrays are 1-based.
2018-04-06 17:21:15 +00:00
lua_newtable ( L ) ; //our return value.
2014-03-30 08:55:06 +00:00
COM_EnumerateFiles ( path , lua_file_enumerate , & e ) ;
return 1 ;
}
static int bi_lua_fclose ( lua_State * L )
{
//both fclose and __gc.
//should we use a different function so that we can warn on dupe fcloses without bugging out on fclose+gc?
//meh, cba
2018-04-06 17:21:15 +00:00
vfsfile_t * * f = lua_touserdata ( L , 1 ) ;
2014-03-30 08:55:06 +00:00
if ( f & & * f ! = NULL )
{
VFS_CLOSE ( * f ) ;
* f = NULL ;
}
return 0 ;
}
static int bi_lua_fopen ( lua_State * L )
{
vfsfile_t * f ;
2018-04-06 17:21:15 +00:00
const char * fname = lua_tolstring ( L , 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
qboolean read = true ;
vfsfile_t * * ud ;
if ( read )
f = FS_OpenVFS ( fname , " rb " , FS_GAME ) ;
else
f = FS_OpenVFS ( fname , " wb " , FS_GAMEONLY ) ;
if ( ! f )
{
2018-04-06 17:21:15 +00:00
lua_pushnil ( L ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
2018-04-06 17:21:15 +00:00
ud = lua_newuserdata ( L , sizeof ( vfsfile_t * ) ) ;
2014-03-30 08:55:06 +00:00
* ud = f ;
2018-04-06 17:21:15 +00:00
lua_newtable ( L ) ;
lua_pushcclosure ( L , bi_lua_fclose , 0 ) ;
lua_setfield ( L , - 2 , " __gc " ) ;
lua_setmetatable ( L , - 2 ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_fgets ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
vfsfile_t * * f = lua_touserdata ( L , 1 ) ;
2014-03-30 08:55:06 +00:00
char line [ 8192 ] ;
char * r = NULL ;
if ( f & & * f )
r = VFS_GETS ( * f , line , sizeof ( line ) ) ;
if ( r )
2018-04-06 17:21:15 +00:00
lua_pushfstring ( L , " %s " , r ) ;
2014-03-30 08:55:06 +00:00
else
2018-04-06 17:21:15 +00:00
lua_pushnil ( L ) ;
2014-03-30 08:55:06 +00:00
return 1 ;
}
static int bi_lua_fputs ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
vfsfile_t * * f = lua_touserdata ( L , 1 ) ;
2014-03-30 08:55:06 +00:00
size_t l ;
2018-04-06 17:21:15 +00:00
const char * str = lua_tolstring ( L , 2 , & l ) ;
2014-03-30 08:55:06 +00:00
if ( f & & * f ! = NULL )
VFS_WRITE ( * f , str , l ) ;
return 0 ;
}
static int bi_lua_loadlua ( lua_State * L )
{
2018-04-06 17:21:15 +00:00
const char * fname = lua_tolstring ( L , 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
vfsfile_t * sourcefile = FS_OpenVFS ( fname , " rb " , FS_GAME ) ;
if ( ! sourcefile )
{
Con_Printf ( " Error trying to load %s \n " , fname ) ;
2018-04-06 17:21:15 +00:00
lua_pushnil ( L ) ;
}
else if ( 0 ! = lua_load ( L , my_lua_Reader , sourcefile , va ( " @%s " , fname ) , " bt " ) ) //load the file, embed it within a function and push it
{
Con_Printf ( " Error trying to parse %s: %s \n " , fname , lua_tolstring ( L , - 1 , NULL ) ) ;
lua_pushnil ( L ) ;
}
VFS_CLOSE ( sourcefile ) ;
return 1 ;
}
static int bi_lua_require ( lua_State * L )
{
const char * fname = lua_tolstring ( L , 1 , NULL ) ;
vfsfile_t * sourcefile ;
const char * usename ;
if ( ( sourcefile = FS_OpenVFS ( usename = fname , " rb " , FS_GAME ) ) )
;
else if ( ( sourcefile = FS_OpenVFS ( usename = va ( " %s.lua " , fname ) , " rb " , FS_GAME ) ) )
;
else
{
Con_Printf ( " Error trying to load %s \n " , fname ) ;
return 1 ;
2014-03-30 08:55:06 +00:00
}
2018-04-06 17:21:15 +00:00
if ( 0 ! = lua_load ( lua . ctx , my_lua_Reader , sourcefile , va ( " @%s " , usename ) , " bt " ) ) //load the file, embed it within a function and push it
2014-03-30 08:55:06 +00:00
{
2018-04-06 17:21:15 +00:00
//failed - it pushed an error code instead
Con_Printf ( " Error trying to parse %s: %s \n " , fname , lua_tolstring ( lua . ctx , - 1 , NULL ) ) ;
lua_pop ( lua . ctx , 1 ) ;
}
else
{
if ( lua_pcall ( lua . ctx , 0 , 0 , 0 ) ! = 0 ) //now call it, so its actually run.
{
const char * s = lua_tolstring ( lua . ctx , - 1 , NULL ) ;
Con_Printf ( CON_WARNING " %s \n " , s ) ;
lua_pop ( lua . ctx , 1 ) ;
}
2014-03-30 08:55:06 +00:00
}
VFS_CLOSE ( sourcefile ) ;
2018-04-06 17:21:15 +00:00
return 0 ;
}
static int bi_lua_vec3 ( lua_State * L )
{
float x = lua_tonumberx ( L , 1 , NULL ) ;
float y = lua_tonumberx ( L , 2 , NULL ) ;
float z = lua_tonumberx ( L , 3 , NULL ) ;
lua_pushvector ( L , x , y , z ) ;
return 1 ;
}
static int bi_lua_field ( lua_State * L )
{
const char * fname = lua_tostring ( L , 1 ) ;
const char * ftype = lua_tostring ( L , 2 ) ;
int t ;
size_t u ;
if ( ! strcmp ( ftype , " string " ) )
t = ev_string ;
else if ( ! strcmp ( ftype , " float " ) )
t = ev_float ;
else if ( ! strcmp ( ftype , " integer " ) )
t = ev_integer ;
else if ( ! strcmp ( ftype , " vector " ) )
t = ev_vector ;
else if ( ! strcmp ( ftype , " function " ) )
t = ev_function ;
else if ( ! strcmp ( ftype , " entity " ) )
t = ev_entity ;
else
{
Con_Printf ( " Unknown field type \n " ) ;
return 0 ;
}
if ( lua . numflds = = countof ( lua . entflds ) )
{
Con_Printf ( " Too many ent fields \n " ) ;
return 0 ;
}
//no dupes please.
for ( u = 0 ; u < lua . numflds ; u + + )
{
if ( ! strcmp ( lua . entflds [ u ] . name , fname ) )
return 0 ;
}
lua . entflds [ lua . numflds ] . offset = - 1 ; //if we don't know about it yet, then its an artificial field, and present just so that self.whatever returns something other than nil.
lua . entflds [ lua . numflds ] . name = Lua_AddString ( NULL , fname , 0 , false ) ;
lua . entflds [ lua . numflds ] . type = t ;
Hash_AddInsensitive ( & lua . entityfields , lua . entflds [ lua . numflds ] . name , & lua . entflds [ lua . numflds ] , & lua . entflds [ lua . numflds ] . buck ) ;
lua . numflds + + ;
return 0 ;
}
static int bi_lua_type ( lua_State * L )
{
const char * tn ;
int t = lua_type ( L , 1 ) ;
// luaL_argcheck(L, t != LUA_TNONE, 1, "value expected");
tn = lua_typename ( L , t ) ;
lua_pushstring ( L , tn ) ;
return 1 ;
}
static int bi_lua_logfrag ( lua_State * L )
{
//stub... noone cares
return 0 ;
}
/*static int bi_lua_entities(lua_State *L)
{
//stub... noone cares
return 0 ;
} */
# ifdef LIBLUA_STATIC
static int pairsmeta ( lua_State * L , const char * method , int iszero ,
lua_CFunction iter ) {
luaL_checkany ( L , 1 ) ;
if ( luaL_getmetafield ( L , 1 , method ) = = LUA_TNIL ) { /* no metamethod? */
lua_pushcfunction ( L , iter ) ; /* will return generator, */
lua_pushvalue ( L , 1 ) ; /* state, */
if ( iszero ) lua_pushinteger ( L , 0 ) ; /* and initial value */
else lua_pushnil ( L ) ;
}
else {
lua_pushvalue ( L , 1 ) ; /* argument 'self' to metamethod */
lua_call ( L , 1 , 3 ) ; /* get 3 values from metamethod */
}
return 3 ;
}
static int luaB_next ( lua_State * L ) {
luaL_checktype ( L , 1 , LUA_TTABLE ) ;
lua_settop ( L , 2 ) ; /* create a 2nd argument if there isn't one */
if ( lua_next ( L , 1 ) )
return 2 ;
else {
lua_pushnil ( L ) ;
return 1 ;
}
}
static int bi_lua_pairs ( lua_State * L ) {
return pairsmeta ( L , " __pairs " , 0 , luaB_next ) ;
}
# endif
static int bi_lua_objerror ( lua_State * L )
{
2018-04-15 02:48:23 +00:00
Con_Printf ( " \n " ) ;
2018-04-06 17:21:15 +00:00
lua_pushedict ( L , lua . edicttable [ lua . globals . self ] ) ;
lua_pushnil ( L ) ;
while ( lua_next ( L , - 2 ) )
{ //FIXME: this doesn't find vector fields
if ( lua_type ( L , - 2 ) = = LUA_TSTRING )
Con_Printf ( " %21s: " , lua_tostring ( L , - 2 ) ) ;
else if ( lua_type ( L , - 2 ) = = LUA_TLIGHTUSERDATA )
{
int i ;
const void * ud = lua_topointer ( L , - 2 ) ;
2018-04-15 02:48:23 +00:00
for ( i = 0 ; i < lua . numflds ; i + + )
if ( lua . entflds [ i ] . offset = = ( qintptr_t ) ud )
2018-04-06 17:21:15 +00:00
break ;
2018-04-15 02:48:23 +00:00
if ( i = = lua . numflds )
2018-04-06 17:21:15 +00:00
Con_Printf ( " %21s: " , lua_typename ( L , lua_type ( L , - 2 ) ) ) ;
else
Con_Printf ( " %21s: " , lua . entflds [ i ] . name ) ;
}
else
Con_Printf ( " %21s: " , lua_typename ( L , lua_type ( L , - 2 ) ) ) ;
if ( lua_type ( L , - 1 ) = = LUA_TSTRING )
Con_Printf ( " \" %s \" \n " , lua_tostring ( L , - 1 ) ) ;
else if ( lua_type ( L , - 1 ) = = LUA_TNUMBER )
Con_Printf ( " \" %g \" \n " , lua_tonumber ( L , - 1 ) ) ;
# ifdef LIBLUA_STATIC
else if ( lua_type ( L , - 1 ) = = LUA_TFUNCTION )
{
lua_Debug ar = { 0 } ;
lua_pushvalue ( L , - 1 ) ;
lua_getinfo ( L , " >nS " , & ar ) ;
Con_Printf ( " %s %s:%i \n " , ar . name , ar . source , ar . linedefined ) ;
}
# endif
else
Con_Printf ( " %s \n " , lua_typename ( L , lua_type ( L , - 1 ) ) ) ;
lua_pop ( L , 1 ) ;
}
lua_pop ( L , 1 ) ;
2018-04-15 02:48:23 +00:00
Con_Printf ( " objerror: %s \n " , lua_tostring ( L , 1 ) ) ;
2018-04-06 17:21:15 +00:00
return 0 ;
}
static int bi_lua_error ( lua_State * L )
{
SV_Error ( " Error: %s \n " , lua_tostring ( L , 1 ) ) ;
return 0 ;
}
static int bi_lua_qtrue ( lua_State * L )
{
//the truth is what you make it...
const char * s ;
switch ( lua_type ( L , 1 ) )
{
case LUA_TSTRING :
s = lua_tostring ( L , 1 ) ;
lua_pushboolean ( L , * s ! = 0 ) ; //empty string is considered false. WARNING: vanilla QC considered empty-but-not-null strings to be true
break ;
default :
2018-04-07 12:33:06 +00:00
// case LUA_TUSERDATA:
2018-04-06 17:21:15 +00:00
// case LUA_TTHREAD:
// case LUA_TLIGHTUSERDATA:
2018-04-07 12:33:06 +00:00
// case LUA_TNONE:
// case LUA_TNIL:
lua_pushboolean ( L , false ) ;
break ;
case LUA_TBOOLEAN :
lua_pushvalue ( L , 1 ) ;
break ;
case LUA_TNUMBER :
lua_pushboolean ( L , lua_tonumber ( L , 1 ) ! = 0 ) ;
break ;
case LUA_TFUNCTION : //functions are always considered true. otherwise they're nil and not functions.
lua_pushboolean ( L , true ) ;
break ;
case LUA_TTABLE :
//might be a vector or an entity.
2018-04-06 17:21:15 +00:00
lua_getfield ( L , 1 , " entnum " ) ;
if ( ! lua_isnil ( L , - 1 ) )
{ //okay, so its a table with a valid entnum field. must be an entity.
lua_pushboolean ( L , 0 ! = lua_tointegerx ( L , - 1 , NULL ) ) ; //true if its not 0/world
}
else
{ //assume that its a vector.
//note that this means that any table without x|y|z fields will be considered false.
vec3_t v ;
2018-04-07 12:33:06 +00:00
lua_readvector ( L , 1 , v ) ;
lua_pushboolean ( L , v [ 0 ] | | v [ 1 ] | | v [ 2 ] ) ;
}
break ;
2018-04-06 17:21:15 +00:00
}
2014-03-30 08:55:06 +00:00
return 1 ;
}
2018-04-06 17:21:15 +00:00
# define registerfunc(n) lua_pushcclosure(L, bi_lua_##n, 0); lua_setglobal(L, #n);
# define registerfuncn(n) registerfunc(n) //new crap
# define registerfuncd(n) registerfunc(n) //deprecated crap
2014-03-30 08:55:06 +00:00
static void my_lua_registerbuiltins ( lua_State * L )
2017-10-12 12:02:25 +00:00
{
2018-04-06 17:21:15 +00:00
lua_atpanic ( L , my_lua_panic ) ;
lua_pushglobaltable ( L ) ;
lua_setfield ( L , - 1 , " _G " ) ;
2017-10-12 12:02:25 +00:00
//standard lua library replacement
//this avoids the risk of including any way to access os.execute etc, or other file access.
2018-04-06 17:21:15 +00:00
registerfuncn ( tostring ) ; //standardish
2018-04-08 14:24:50 +00:00
registerfuncn ( tonumber ) ; //standardish
2018-04-06 17:21:15 +00:00
registerfuncn ( type ) ; //standardish
registerfuncn ( print ) ; //'standard' lua print, except prints to console. WARNING: this adds an implicit \n. Use conprint for the quake-style version.
registerfuncn ( require ) ; //'standard'ish, except uses quake's filesystem instead of reading random system paths.
# ifdef LIBLUA_STATIC
registerfuncn ( pairs ) ;
# endif
2018-04-08 14:24:50 +00:00
lua_pushnil ( L ) ; lua_setglobal ( L , " dofile " ) ; //violates our sandbox
lua_pushnil ( L ) ; lua_setglobal ( L , " loadfile " ) ; //violates our sandbox
2017-10-12 12:02:25 +00:00
2018-04-06 17:21:15 +00:00
lua_newtable ( L ) ;
lua_pushcclosure ( L , bi_lua_fabs , 0 ) ; lua_setfield ( L , - 2 , " abs " ) ;
lua_pushcclosure ( L , bi_lua_rint , 0 ) ; lua_setfield ( L , - 2 , " rint " ) ;
lua_pushcclosure ( L , bi_lua_ceil , 0 ) ; lua_setfield ( L , - 2 , " ceil " ) ;
lua_pushcclosure ( L , bi_lua_floor , 0 ) ; lua_setfield ( L , - 2 , " floor " ) ;
lua_pushcclosure ( L , bi_lua_sin , 0 ) ; lua_setfield ( L , - 2 , " sin " ) ;
lua_pushcclosure ( L , bi_lua_cos , 0 ) ; lua_setfield ( L , - 2 , " cos " ) ;
lua_pushcclosure ( L , bi_lua_tan , 0 ) ; lua_setfield ( L , - 2 , " tan " ) ;
lua_pushcclosure ( L , bi_lua_asin , 0 ) ; lua_setfield ( L , - 2 , " asin " ) ;
lua_pushcclosure ( L , bi_lua_acos , 0 ) ; lua_setfield ( L , - 2 , " acos " ) ;
lua_pushcclosure ( L , bi_lua_atan , 0 ) ; lua_setfield ( L , - 2 , " atan " ) ;
lua_pushcclosure ( L , bi_lua_atan2 , 0 ) ; lua_setfield ( L , - 2 , " atan2 " ) ;
lua_pushcclosure ( L , bi_lua_sqrt , 0 ) ; lua_setfield ( L , - 2 , " sqrt " ) ;
lua_pushcclosure ( L , bi_lua_pow , 0 ) ; lua_setfield ( L , - 2 , " pow " ) ;
lua_pushnumber ( L , M_PI ) ; lua_setfield ( L , - 2 , " pi " ) ;
lua_setglobal ( L , " math " ) ;
// registerfuncd(entities);
registerfuncd ( loadlua ) ; //should probably use 'require' instead.
registerfuncn ( vec3 ) ;
registerfuncn ( field ) ;
2018-10-17 00:43:04 +00:00
# undef qtrue
2018-04-06 17:21:15 +00:00
registerfuncn ( qtrue ) ; //for auto-converted code that tests for truth amongst a myriad of different custom types...
2017-10-12 12:02:25 +00:00
registerfunc ( setmodel ) ;
registerfunc ( precache_model ) ;
2018-04-06 17:21:15 +00:00
registerfuncd ( precache_model2 ) ; //pointless alternative name
2017-10-12 12:02:25 +00:00
registerfunc ( precache_sound ) ;
2018-04-06 17:21:15 +00:00
registerfuncd ( precache_sound2 ) ; //pointless alternative name
registerfuncd ( precache_file ) ; //empty pointless function...
2017-10-12 12:02:25 +00:00
registerfunc ( lightstyle ) ;
registerfunc ( spawn ) ;
registerfunc ( remove ) ;
2014-03-30 08:55:06 +00:00
registerfunc ( nextent ) ;
registerfunc ( nextclient ) ;
2017-10-12 12:02:25 +00:00
registerfunc ( makestatic ) ;
registerfunc ( setorigin ) ;
registerfunc ( setsize ) ;
2018-04-06 17:21:15 +00:00
registerfuncn ( conprint ) ; //dprint, without the developer
registerfunc ( bprint_qw ) ;
registerfunc ( sprint_qw ) ;
if ( progstype = = PROG_QW )
{
lua_pushcclosure ( L , bi_lua_conprint , 0 ) ; lua_setglobal ( L , " dprint " ) ; //ignores developer
lua_pushcclosure ( L , bi_lua_bprint_qw , 0 ) ; lua_setglobal ( L , " bprint " ) ; //an extra level arg
lua_pushcclosure ( L , bi_lua_sprint_qw , 0 ) ; lua_setglobal ( L , " sprint " ) ; //an extra level arg
}
else
{
lua_pushcclosure ( L , bi_lua_dprint , 0 ) ; lua_setglobal ( L , " dprint " ) ; //responds to developer
lua_pushcclosure ( L , bi_lua_bprint_nq , 0 ) ; lua_setglobal ( L , " bprint " ) ; //no level arg
lua_pushcclosure ( L , bi_lua_sprint_nq , 0 ) ; lua_setglobal ( L , " sprint " ) ; //no level arg
}
2014-03-30 08:55:06 +00:00
registerfunc ( centerprint ) ;
registerfunc ( ambientsound ) ;
registerfunc ( sound ) ;
registerfunc ( random ) ;
registerfunc ( checkclient ) ;
registerfunc ( stuffcmd ) ;
registerfunc ( localcmd ) ;
2018-04-06 17:21:15 +00:00
registerfuncd ( cvar ) ; //gets a float value, never a string.
registerfuncn ( cvar_get ) ;
2014-03-30 08:55:06 +00:00
registerfunc ( cvar_set ) ;
2018-04-06 17:21:15 +00:00
registerfuncd ( findradius ) ; //qc legacy compat. should probably warn when its called or sommit.
registerfuncn ( findradiuschain ) ; //renamed from qc. because qc's behaviour is annoying enough that we want to discourage its use.
registerfuncn ( findradiustable ) ; //findradius, but returns an array/table instead.
registerfunc ( objerror ) ;
registerfunc ( error ) ;
// registerfuncd(break); //won't implement
2014-03-30 08:55:06 +00:00
registerfunc ( traceline ) ;
2018-04-06 17:21:15 +00:00
registerfuncn ( tracebox ) ;
2014-03-30 08:55:06 +00:00
registerfunc ( walkmove ) ;
registerfunc ( movetogoal ) ;
registerfunc ( droptofloor ) ;
registerfunc ( checkbottom ) ;
registerfunc ( pointcontents ) ;
2018-04-06 17:21:15 +00:00
registerfuncd ( ChangeYaw ) ;
2014-03-30 08:55:06 +00:00
registerfunc ( setspawnparms ) ;
registerfunc ( changelevel ) ;
2018-04-06 17:21:15 +00:00
registerfunc ( logfrag ) ;
registerfuncd ( infokey ) ;
registerfuncn ( getinfokey ) ;
registerfuncn ( setinfokey ) ;
2014-03-30 08:55:06 +00:00
registerfunc ( multicast ) ;
2018-04-06 17:21:15 +00:00
registerfuncn ( writebyte ) ;
registerfuncn ( writechar ) ;
registerfuncn ( writeshort ) ;
registerfuncn ( writelong ) ;
registerfuncn ( writeangle ) ;
registerfuncn ( writecoord ) ;
registerfuncn ( writestring ) ;
registerfuncn ( writeentity ) ;
registerfuncd ( WriteByte ) ;
registerfuncd ( WriteChar ) ;
registerfuncd ( WriteShort ) ;
registerfuncd ( WriteLong ) ;
registerfuncd ( WriteAngle ) ;
registerfuncd ( WriteCoord ) ;
registerfuncd ( WriteString ) ;
registerfuncd ( WriteEntity ) ;
registerfuncd ( particle ) ;
registerfuncn ( bitnot ) ;
registerfuncn ( bitclear ) ;
registerfuncn ( bitset ) ;
registerfuncn ( bitor ) ;
registerfuncn ( bitand ) ;
registerfuncn ( bitxor ) ;
registerfuncn ( sin ) ;
registerfuncn ( cos ) ;
registerfuncn ( acos ) ;
registerfuncn ( asin ) ;
registerfuncn ( atan ) ;
registerfuncn ( atan2 ) ;
registerfuncn ( sqrt ) ;
registerfuncn ( pow ) ;
2014-03-30 08:55:06 +00:00
registerfunc ( floor ) ;
registerfunc ( ceil ) ;
2018-04-06 17:21:15 +00:00
registerfunc ( rint ) ;
registerfunc ( fabs ) ;
registerfuncn ( fopen ) ;
registerfuncn ( fclose ) ;
registerfuncn ( fgets ) ;
registerfuncn ( fputs ) ;
registerfuncn ( getfilelist ) ;
registerfuncd ( find ) ;
2014-03-30 08:55:06 +00:00
//registerfunc(strftime);
registerfunc ( tokenize ) ;
registerfunc ( makevectors ) ;
2018-04-06 17:21:15 +00:00
registerfunc ( normalize ) ;
2014-03-30 08:55:06 +00:00
registerfunc ( vectoangles ) ;
2018-04-06 17:21:15 +00:00
registerfunc ( vectoyaw ) ;
registerfuncd ( aim ) ; //original implementation nudges v_forward up or down so that keyboard players can still play.
registerfunc ( vtos ) ;
registerfunc ( ftos ) ;
2018-04-08 14:24:50 +00:00
registerfunc ( stof ) ;
2014-03-30 08:55:06 +00:00
//registerfunc(PRECACHE_VWEP_MODEL);
//registerfunc(SETPAUSE);
2017-10-12 12:02:25 +00:00
2018-04-06 17:21:15 +00:00
//set a metatable on the globals table
//this means that we can just directly use self.foo instead of blob.self.foo
lua_pushglobaltable ( L ) ;
if ( luaL_newmetatable ( L , " globals " ) )
{
lua_pushcclosure ( L , my_lua_global_set , 0 ) ; //for the luls.
lua_setfield ( L , - 2 , " __newindex " ) ;
lua_pushcclosure ( L , my_lua_global_get , 0 ) ; //for the luls.
lua_setfield ( L , - 2 , " __index " ) ;
}
lua_setmetatable ( L , - 2 ) ;
lua_pop ( L , 1 ) ;
2017-10-12 12:02:25 +00:00
2018-04-06 17:21:15 +00:00
if ( luaL_newmetatable ( L , " vec3_t " ) )
2017-10-12 12:02:25 +00:00
{
2018-04-06 17:21:15 +00:00
// lua_pushcclosure(L, my_lua_vec3_set, 0); //known writes should change the internal info so the engine can use the information.
// lua_setfield (L, -2, "__newindex");
// lua_pushcclosure(L, my_lua_vec3_get, 0); //we need to de-translate the engine's fields too.
// lua_setfield (L, -2, "__index");
lua_pushcclosure ( L , my_lua_vec3_tostring , 0 ) ; //cos its prettier than seeing 'table 0x5425729' all over the place
lua_setfield ( L , - 2 , " __tostring " ) ;
lua_pushcclosure ( L , my_lua_vec3_eq , 0 ) ; //for comparisons, you know?
lua_setfield ( L , - 2 , " __eq " ) ;
lua_pushcclosure ( L , my_lua_vec3_add , 0 ) ; //for comparisons, you know?
lua_setfield ( L , - 2 , " __add " ) ;
lua_pushcclosure ( L , my_lua_vec3_sub , 0 ) ; //for comparisons, you know?
lua_setfield ( L , - 2 , " __sub " ) ;
lua_pushcclosure ( L , my_lua_vec3_mul , 0 ) ; //for comparisons, you know?
lua_setfield ( L , - 2 , " __mul " ) ;
2017-10-12 12:02:25 +00:00
2018-04-06 17:21:15 +00:00
lua_pushcclosure ( L , my_lua_vec3_len , 0 ) ; //for comparisons, you know?
lua_setfield ( L , - 2 , " __len " ) ;
lua_pop ( L , 1 ) ;
2017-10-12 12:02:25 +00:00
}
2014-03-30 08:55:06 +00:00
}
static edict_t * QDECL Lua_EdictNum ( pubprogfuncs_t * pf , unsigned int num )
{
int newcount ;
if ( num > = lua . maxedicts )
{
newcount = num + 64 ;
lua . edicttable = realloc ( lua . edicttable , newcount * sizeof ( * lua . edicttable ) ) ;
while ( lua . maxedicts < newcount )
lua . edicttable [ lua . maxedicts + + ] = NULL ;
2018-04-06 17:21:15 +00:00
pf - > edicttable_length = lua . maxedicts ;
pf - > edicttable = lua . edicttable ;
2014-03-30 08:55:06 +00:00
}
return lua . edicttable [ num ] ;
}
static unsigned int QDECL Lua_NumForEdict ( pubprogfuncs_t * pf , edict_t * e )
{
return e - > entnum ;
}
static int QDECL Lua_EdictToProgs ( pubprogfuncs_t * pf , edict_t * e )
{
return e - > entnum ;
}
static edict_t * QDECL Lua_ProgsToEdict ( pubprogfuncs_t * pf , int num )
{
return Lua_EdictNum ( pf , num ) ;
}
void Lua_EntClear ( pubprogfuncs_t * pf , edict_t * e )
{
int num = e - > entnum ;
memset ( e - > v , 0 , sv . world . edict_size ) ;
2017-12-28 16:24:50 +00:00
e - > ereftype = ER_ENTITY ;
2014-03-30 08:55:06 +00:00
e - > entnum = num ;
}
edict_t * Lua_CreateEdict ( unsigned int num )
{
edict_t * e ;
e = lua . edicttable [ num ] = Z_Malloc ( sizeof ( edict_t ) + sv . world . edict_size ) ;
e - > v = ( stdentvars_t * ) ( e + 1 ) ;
# ifdef VM_Q1
e - > xv = ( extentvars_t * ) ( e - > v + 1 ) ;
# endif
e - > entnum = num ;
return e ;
}
2023-06-25 15:04:40 +00:00
static void QDECL Lua_EntRemove ( pubprogfuncs_t * pf , edict_t * e , qboolean instant )
2014-03-30 08:55:06 +00:00
{
lua_State * L = lua . ctx ;
if ( ! ED_CanFree ( e ) )
return ;
2017-12-28 16:24:50 +00:00
e - > ereftype = ER_FREE ;
2023-06-25 15:04:40 +00:00
e - > freetime = ( instant ? 0 : sv . time ) ; //can respawn instantly when asked.
2014-03-30 08:55:06 +00:00
//clear out the lua version of the entity, so that it can be garbage collected.
//should probably clear out its entnum field too, just in case.
2018-04-06 17:21:15 +00:00
lua_pushlightuserdata ( L , e ) ;
lua_pushnil ( L ) ;
lua_settable ( L , LUA_REGISTRYINDEX ) ;
2014-03-30 08:55:06 +00:00
}
static edict_t * Lua_DoRespawn ( pubprogfuncs_t * pf , edict_t * e , int num )
{
lua_State * L = lua . ctx ;
if ( ! e )
e = Lua_CreateEdict ( num ) ;
else
Lua_EntClear ( pf , e ) ;
ED_Spawned ( ( struct edict_s * ) e , false ) ;
//create a new table for the entity, give it a suitable metatable, and store it into the registry (avoiding GC and allowing us to actually hold on to it).
2018-04-06 17:21:15 +00:00
lua_pushlightuserdata ( L , lua . edicttable [ num ] ) ;
lua_newtable ( L ) ;
if ( luaL_newmetatable ( L , " entity " ) )
2017-10-12 12:02:25 +00:00
{
2018-04-06 17:21:15 +00:00
lua_pushcclosure ( L , my_lua_entity_set , 0 ) ; //known writes should change the internal info so the engine can use the information.
lua_setfield ( L , - 2 , " __newindex " ) ;
2017-10-12 12:02:25 +00:00
2018-04-06 17:21:15 +00:00
lua_pushcclosure ( L , my_lua_entity_get , 0 ) ; //we need to de-translate the engine's fields too.
lua_setfield ( L , - 2 , " __index " ) ;
2017-10-12 12:02:25 +00:00
2018-04-06 17:21:15 +00:00
lua_pushcclosure ( L , my_lua_entity_tostring , 0 ) ; //cos its prettier than seeing 'table 0x5425729' all over the place
lua_setfield ( L , - 2 , " __tostring " ) ;
2017-10-12 12:02:25 +00:00
2018-04-06 17:21:15 +00:00
lua_pushcclosure ( L , my_lua_entity_eq , 0 ) ; //for comparisons, you know?
lua_setfield ( L , - 2 , " __eq " ) ;
2017-10-12 12:02:25 +00:00
}
2018-04-06 17:21:15 +00:00
lua_setmetatable ( L , - 2 ) ;
lua_pushinteger ( L , num ) ;
lua_setfield ( L , - 2 , " entnum " ) ; //so we know which entity it is.
lua_settable ( L , LUA_REGISTRYINDEX ) ;
2014-03-30 08:55:06 +00:00
return e ;
}
2017-12-28 16:24:50 +00:00
static edict_t * QDECL Lua_EntAlloc ( pubprogfuncs_t * pf , pbool isobject , size_t extrasize )
2014-03-30 08:55:06 +00:00
{
int i ;
edict_t * e ;
for ( i = 0 ; i < sv . world . num_edicts ; i + + )
{
2018-04-06 17:21:15 +00:00
e = ( edict_t * ) EDICT_NUM_PB ( pf , i ) ;
2014-03-30 08:55:06 +00:00
// the first couple seconds of server time can involve a lot of
// freeing and allocating, so relax the replacement policy
2017-12-28 16:24:50 +00:00
if ( ! e | | ( ED_ISFREE ( e ) & & ( e - > freetime < 2 | | sv . time - e - > freetime > 0.5 ) ) )
2014-03-30 08:55:06 +00:00
{
e = Lua_DoRespawn ( pf , e , i ) ;
return ( struct edict_s * ) e ;
}
}
if ( i > = sv . world . max_edicts - 1 ) //try again, but use timed out ents.
{
for ( i = 0 ; i < sv . world . num_edicts ; i + + )
{
2018-04-06 17:21:15 +00:00
e = ( edict_t * ) EDICT_NUM_PB ( pf , i ) ;
2014-03-30 08:55:06 +00:00
// the first couple seconds of server time can involve a lot of
// freeing and allocating, so relax the replacement policy
2017-12-28 16:24:50 +00:00
if ( ! e | | ED_ISFREE ( e ) )
2014-03-30 08:55:06 +00:00
{
e = Lua_DoRespawn ( pf , e , i ) ;
return ( struct edict_s * ) e ;
}
}
if ( i > = sv . world . max_edicts - 1 )
{
Sys_Error ( " ED_Alloc: no free edicts " ) ;
}
}
sv . world . num_edicts + + ;
2018-04-06 17:21:15 +00:00
e = Lua_EdictNum ( pf , i ) ;
2014-03-30 08:55:06 +00:00
e = Lua_DoRespawn ( pf , e , i ) ;
return ( struct edict_s * ) e ;
}
2018-04-06 17:21:15 +00:00
/*static int QDECL Lua_LoadEnts(pubprogfuncs_t *pf, const char *mapstring, void *ctx, void (PDECL *callback) (pubprogfuncs_t *progfuncs, struct edict_s *ed, void *ctx, const char *entstart, const char *entend))
2014-03-30 08:55:06 +00:00
{
lua_State * L = lua . ctx ;
int i = 0 ;
2018-04-06 17:21:15 +00:00
lua_getglobal ( L , " LoadEnts " ) ;
lua_newtable ( L ) ;
2014-03-30 08:55:06 +00:00
while ( NULL ! = ( mapstring = COM_Parse ( mapstring ) ) )
{
2018-04-06 17:21:15 +00:00
lua_pushinteger ( L , i + + ) ;
lua_pushstring ( L , com_token ) ;
lua_settable ( L , - 3 ) ;
2014-03-30 08:55:06 +00:00
}
2018-04-06 17:21:15 +00:00
// lua_pushinteger(L, spawnflags);
2014-03-30 08:55:06 +00:00
2018-04-06 17:21:15 +00:00
if ( lua_pcall ( L , 2 , 0 , 0 ) ! = 0 )
2014-03-30 08:55:06 +00:00
{
2018-04-06 17:21:15 +00:00
const char * s = lua_tolstring ( L , - 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
Con_Printf ( CON_WARNING " %s \n " , s ) ;
2018-04-06 17:21:15 +00:00
lua_pop ( L , 1 ) ;
}
return sv . world . edict_size ;
} */
static const char * Lua_ParseEdict ( pubprogfuncs_t * progfuncs , const char * data , struct edict_s * ent )
{
lua_State * L = lua . ctx ;
// fdef_t *key;
pbool init ;
char keyname [ 256 ] ;
int n ;
int nest = 1 ;
char token [ 8192 ] ;
luafld_t * fld ;
// eval_t *val;
init = false ;
// go through all the dictionary pairs
while ( 1 )
{
// parse key
data = COM_ParseOut ( data , token , sizeof ( token ) ) ;
if ( token [ 0 ] = = ' } ' )
{
if ( - - nest )
continue ;
break ;
}
if ( token [ 0 ] = = ' { ' & & ! token [ 1 ] )
nest + + ;
if ( ! data )
{
Con_Printf ( " Lua_ParseEdict: EOF without closing brace \n " ) ;
return NULL ;
}
if ( nest > 1 )
continue ;
strncpy ( keyname , token , sizeof ( keyname ) - 1 ) ;
keyname [ sizeof ( keyname ) - 1 ] = 0 ;
// another hack to fix heynames with trailing spaces
n = strlen ( keyname ) ;
while ( n & & keyname [ n - 1 ] = = ' ' )
{
keyname [ n - 1 ] = 0 ;
n - - ;
}
// parse value
data = COM_ParseOut ( data , token , sizeof ( token ) ) ;
if ( ! data )
{
Con_Printf ( " Lua_ParseEdict: EOF without closing brace \n " ) ;
return NULL ;
}
if ( token [ 0 ] = = ' } ' )
{
Con_Printf ( " Lua_ParseEdict: closing brace without data \n " ) ;
return NULL ;
}
init = true ;
// keynames with a leading underscore are used for utility comments,
// and are immediately discarded by quake
if ( keyname [ 0 ] = = ' _ ' )
continue ;
if ( ! strcmp ( keyname , " angle " ) ) //Quake anglehack - we've got to leave it in cos it doesn't work for quake otherwise, and this is a QuakeC lib!
{
Q_snprintfz ( keyname , sizeof ( keyname ) , " angles " ) ; //change it from yaw to 3d angle
Q_snprintfz ( token , sizeof ( token ) , " 0 %f 0 " , atof ( token ) ) ; //change it from yaw to 3d angle
goto cont ;
}
/*
key = ED_FindField ( progfuncs , keyname ) ;
if ( ! key )
{
if ( ! strcmp ( keyname , " light " ) ) //Quake lighthack - allows a field name and a classname to go by the same thing in the level editor
if ( ( key = ED_FindField ( progfuncs , " light_lev " ) ) )
goto cont ;
if ( externs - > badfield & & externs - > badfield ( & progfuncs - > funcs , ( struct edict_s * ) ent , keyname , qcc_token ) )
continue ;
Con_DPrintf ( " '%s' is not a field \n " , keyname ) ;
continue ;
}
*/
cont :
fld = Hash_GetInsensitive ( & lua . entityfields , keyname ) ;
if ( fld & & fld - > type = = ev_float )
lua_pushnumber ( L , atof ( token ) ) ;
else if ( fld & & fld - > type = = ev_integer )
lua_pushinteger ( L , atoi ( token ) ) ;
else if ( fld & & fld - > type = = ev_vector )
{
char * e ;
float x , y , z ;
x = strtod ( token , & e ) ;
if ( * e = = ' ' )
e + + ;
y = strtod ( e , & e ) ;
if ( * e = = ' ' )
e + + ;
z = strtod ( e , & e ) ;
if ( * e = = ' ' )
e + + ;
lua_pushvector ( L , x , y , z ) ;
}
2018-04-15 02:48:23 +00:00
else if ( fld & & fld - > type = = ev_function )
lua_getglobal ( L , token ) ; //functions are nameless, except for how they're invoked. so this is only for evil mods...
else if ( fld & & fld - > type = = ev_entity )
{
int num = atoi ( token ) ;
lua_pushedict ( L , EDICT_NUM_UB ( ( & lua . progfuncs ) , num ) ) ;
}
2018-04-06 17:21:15 +00:00
else
lua_pushstring ( L , token ) ;
lua_setfield ( L , - 2 , keyname ) ;
/*if (!ED_ParseEpair (progfuncs, (char*)ent->fields - progfuncs->funcs.stringtable, key->ofs, key->type, qcc_token))
{
continue ;
// Sys_Error ("ED_ParseEdict: parse error on entities");
} */
2014-03-30 08:55:06 +00:00
}
2018-04-06 17:21:15 +00:00
if ( ! init )
ent - > ereftype = ER_FREE ;
return data ;
}
2023-06-25 15:04:40 +00:00
static int QDECL Lua_LoadEnts ( pubprogfuncs_t * pf , const char * mapstring , void * ctx ,
void ( PDECL * memoryreset ) ( pubprogfuncs_t * progfuncs , void * ctx ) ,
void ( PDECL * entspawned ) ( pubprogfuncs_t * progfuncs , struct edict_s * ed , void * ctx , const char * entstart , const char * entend ) ,
pbool ( PDECL * extendedterm ) ( pubprogfuncs_t * progfuncs , void * ctx , const char * * extline )
) //restore the entire progs state (or just add some more ents) (returns edicts ize)
2018-04-06 17:21:15 +00:00
{
lua_State * L = lua . ctx ;
struct edict_s * ed = NULL ;
const char * datastart = mapstring ;
lua_pushglobaltable ( L ) ;
while ( 1 )
{
datastart = mapstring ;
2023-06-25 15:04:40 +00:00
if ( extendedterm )
{
//skip simple leading whitespace
while ( * mapstring = = ' ' | | * mapstring = = ' \t ' | | * mapstring = = ' \r ' | | * mapstring = = ' \n ' )
mapstring + + ;
if ( mapstring [ 0 ] = = ' / ' & & mapstring [ 1 ] = = ' * ' ) //we are not reading lua here, so C-style comments are the proper form (otherwise ignored by COM_Parse, giving extensibility).
{ //looks like we have a hidden extension.
mapstring + = 2 ;
for ( ; ; )
{
//skip to end of line
if ( ! * mapstring )
break ; //unexpected EOF
else if ( mapstring [ 0 ] = = ' * ' & & mapstring [ 1 ] = = ' / ' )
{ //end of comment
mapstring + = 2 ;
break ;
}
else if ( * mapstring ! = ' \n ' )
{
mapstring + + ;
continue ;
}
mapstring + + ; //skip past the \n
while ( * mapstring = = ' ' | | * mapstring = = ' \t ' )
mapstring + + ; //skip leading indentation
if ( mapstring [ 0 ] = = ' * ' & & mapstring [ 1 ] = = ' / ' )
{ //end of comment
mapstring + = 2 ;
break ;
}
else if ( * mapstring = = ' / ' )
continue ; //embedded comment. ignore the line. not going to do nested comments, because those are not normally valid anyway, just C++-style inside C-style.
else if ( extendedterm ( pf , ctx , & mapstring ) )
; //found a term we recognised
else
; //unknown line, but this is a comment so whatever
}
continue ;
}
}
2018-04-06 17:21:15 +00:00
mapstring = COM_Parse ( mapstring ) ;
if ( ! strcmp ( com_token , " { " ) )
{
if ( ! ed ) //first entity
ed = EDICT_NUM_PB ( pf , 0 ) ;
else
ed = ED_Alloc ( pf , false , 0 ) ;
ed - > ereftype = ER_ENTITY ;
if ( pf - > parms - > entspawn )
pf - > parms - > entspawn ( ed , true ) ;
lua_pushedict ( L , ed ) ;
mapstring = Lua_ParseEdict ( pf , mapstring , ed ) ;
if ( 1 )
{ //we can't call the callback, as it would be unable to represent the function references.
int spawnflags , killonspawnflags = * ( int * ) ctx ; //lame. really lame
lua_getfield ( L , - 1 , " spawnflags " ) ; //push -1["classname"]...
spawnflags = lua_tointeger ( L , - 1 ) ;
lua_pop ( L , 1 ) ;
if ( spawnflags & killonspawnflags )
2023-06-25 15:04:40 +00:00
lua . progfuncs . EntFree ( & lua . progfuncs , ed , true ) ;
2018-04-06 17:21:15 +00:00
else
{
lua_getfield ( L , - 1 , " classname " ) ; //push -1["classname"]...
//-3:globaltable, -2:enttable, -1:classname string
lua_gettable ( L , - 3 ) ; //pop the classname and look it up inside the global table (to find the function in question)
lua . globals . self = ed - > entnum ;
if ( lua_pcall ( L , 0 , 0 , 0 ) ! = 0 )
{
const char * s = lua_tolstring ( L , - 1 , NULL ) ;
lua_getfield ( L , - 2 , " classname " ) ; //push -1["classname"]...
Con_Printf ( CON_WARNING " spawn func %s: %s \n " , lua_tolstring ( L , - 1 , NULL ) , s ) ;
lua_pop ( L , 2 ) ;
}
}
}
else
{
lua_pop ( L , 1 ) ;
2023-06-25 15:04:40 +00:00
entspawned ( pf , ed , ctx , datastart , mapstring ) ;
2018-04-06 17:21:15 +00:00
}
lua_pop ( L , 1 ) ; //pop ent table
}
else
break ; //unexpected token...
}
lua_pop ( L , 1 ) ;
2014-03-30 08:55:06 +00:00
return sv . world . edict_size ;
}
2018-10-17 00:43:04 +00:00
static eval_t * QDECL Lua_GetEdictFieldValue ( pubprogfuncs_t * pf , edict_t * e , const char * fieldname , etype_t type , evalc_t * cache )
2014-03-30 08:55:06 +00:00
{
eval_t * val ;
luafld_t * fld ;
fld = Hash_GetInsensitive ( & lua . entityfields , fieldname ) ;
if ( fld )
{
val = ( eval_t * ) ( ( char * ) e - > v + fld - > offset ) ;
return val ;
}
return NULL ;
}
static eval_t * QDECL Lua_FindGlobal ( pubprogfuncs_t * prinst , const char * name , progsnum_t num , etype_t * type )
{
eval_t * val ;
luafld_t * fld ;
fld = Hash_GetInsensitive ( & lua . globalfields , name ) ;
if ( fld )
{
val = ( eval_t * ) ( ( char * ) & lua . globals + fld - > offset ) ;
return val ;
}
Con_Printf ( " Lua_FindGlobal: %s \n " , name ) ;
return NULL ;
}
static func_t QDECL Lua_FindFunction ( pubprogfuncs_t * prinst , const char * name , progsnum_t num )
{
eval_t * val ;
luafld_t * fld ;
fld = Hash_GetInsensitive ( & lua . globalfields , name ) ;
if ( fld )
{
val = ( eval_t * ) ( ( char * ) & lua . globals + fld - > offset ) ;
return val - > function ;
}
Con_Printf ( " Lua_FindFunction: %s \n " , name ) ;
return 0 ;
}
static globalvars_t * QDECL Lua_Globals ( pubprogfuncs_t * prinst , int prnum )
{
// Con_Printf("Lua_Globals: called\n");
return NULL ;
}
char * QDECL Lua_AddString ( pubprogfuncs_t * prinst , const char * val , int minlength , pbool demarkup )
{
char * ptr ;
int len = strlen ( val ) + 1 ;
if ( len < minlength )
len = minlength ;
2018-04-15 02:48:23 +00:00
ptr = Z_TagMalloc ( len , LUA_MALLOC_TAG ) ;
2014-03-30 08:55:06 +00:00
strcpy ( ptr , val ) ;
return ptr ;
}
static string_t QDECL Lua_StringToProgs ( pubprogfuncs_t * prinst , const char * str )
{
Con_Printf ( " Lua_StringToProgs called instead of Lua_SetStringField \n " ) ;
return 0 ;
}
//passing NULL for ed means its setting a global.
static void QDECL Lua_SetStringField ( pubprogfuncs_t * prinst , edict_t * ed , string_t * fld , const char * str , pbool str_is_static )
{
lua_State * L = lua . ctx ;
string_t val ;
string_t base ;
if ( ed )
{
base = ( ed - > entnum + 1 ) < < 10 ;
val = ( char * ) fld - ( char * ) ed - > v ;
2018-04-06 17:21:15 +00:00
lua_pushedict ( lua . ctx , lua . edicttable [ ed - > entnum ] ) ;
2014-03-30 08:55:06 +00:00
}
else
{
base = 0 ;
val = ( char * ) fld - ( char * ) & lua . globals ;
//push the globals list
2018-04-06 17:21:15 +00:00
lua_pushglobaltable ( L ) ;
2014-03-30 08:55:06 +00:00
}
* fld = base | val ; //set the engine's value
//set the stuff so that lua can read it properly.
2018-04-06 17:21:15 +00:00
lua_pushlightuserdata ( L , ( void * ) ( qintptr_t ) val ) ;
lua_pushstring ( L , str ) ;
lua_rawset ( L , - 3 ) ;
2014-03-30 08:55:06 +00:00
//and pop the table
2018-04-06 17:21:15 +00:00
lua_pop ( L , 1 ) ;
2014-03-30 08:55:06 +00:00
}
static const char * ASMCALL QDECL Lua_StringToNative ( pubprogfuncs_t * prinst , string_t str )
{
const char * ret = " " ;
unsigned int entnum = str > > 10 ;
if ( str )
{
str & = 1023 ;
if ( ! entnum )
{
//okay, its the global table.
2018-04-06 17:21:15 +00:00
lua_pushglobaltable ( lua . ctx ) ;
2014-03-30 08:55:06 +00:00
}
else
{
entnum - = 1 ;
if ( entnum > = lua . maxedicts )
return ret ; //erk...
//get the entity's table
2018-04-06 17:21:15 +00:00
lua_pushlightuserdata ( lua . ctx , lua . edicttable [ entnum ] ) ;
lua_gettable ( lua . ctx , LUA_REGISTRYINDEX ) ;
2014-03-30 08:55:06 +00:00
}
//read the function from the table
2018-04-06 17:21:15 +00:00
lua_pushlightuserdata ( lua . ctx , ( void * ) ( qintptr_t ) str ) ;
lua_rawget ( lua . ctx , - 2 ) ;
ret = lua_tolstring ( lua . ctx , - 1 , NULL ) ;
lua_pop ( lua . ctx , 2 ) ; //pop the table+string.
2014-03-30 08:55:06 +00:00
//popping the string is 'safe' on the understanding that the string reference is still held by its containing table, so don't store the string anywhere.
}
return ret ;
}
2018-10-17 00:43:04 +00:00
static void Lua_Event_Touch ( world_t * w , wedict_t * s , wedict_t * o , trace_t * trace )
2014-03-30 08:55:06 +00:00
{
int oself = pr_global_struct - > self ;
int oother = pr_global_struct - > other ;
pr_global_struct - > self = EDICT_TO_PROG ( w - > progs , s ) ;
pr_global_struct - > other = EDICT_TO_PROG ( w - > progs , o ) ;
pr_global_struct - > time = w - > physicstime ;
2018-04-06 17:21:15 +00:00
# if 1
2014-03-30 08:55:06 +00:00
PR_ExecuteProgram ( w - > progs , s - > v - > touch ) ;
2018-04-06 17:21:15 +00:00
# else
lua_pushedict ( lua . ctx , s ) ;
//lua_pushliteral(lua.ctx, "touch");
lua_pushlightuserdata ( lua . ctx , ( void * ) ( ( char * ) & s - > v - > touch - ( char * ) s - > v ) ) ;
lua_rawget ( lua . ctx , - 2 ) ;
lua_replace ( lua . ctx , - 2 ) ;
if ( lua_pcall ( lua . ctx , 0 , 0 , 0 ) ! = 0 )
{
const char * e = lua_tolstring ( lua . ctx , - 1 , NULL ) ;
lua_pushedict ( lua . ctx , ( struct edict_s * ) s ) ;
lua_getfield ( lua . ctx , - 1 , " classname " ) ;
Con_Printf ( CON_WARNING " %s touch: %s \n " , lua_tostring ( lua . ctx , - 1 ) , e ) ;
lua_pop ( lua . ctx , 3 ) ; //error, enttable, classname
}
# endif
2014-03-30 08:55:06 +00:00
pr_global_struct - > self = oself ;
pr_global_struct - > other = oother ;
}
static void Lua_Event_Think ( world_t * w , wedict_t * s )
{
pr_global_struct - > self = EDICT_TO_PROG ( w - > progs , s ) ;
pr_global_struct - > other = EDICT_TO_PROG ( w - > progs , w - > edicts ) ;
2018-04-06 17:21:15 +00:00
#if 0
2014-03-30 08:55:06 +00:00
PR_ExecuteProgram ( w - > progs , s - > v - > think ) ;
2018-04-06 17:21:15 +00:00
# else
lua_pushedict ( lua . ctx , ( struct edict_s * ) s ) ;
// lua_pushliteral(lua.ctx, "think");
lua_pushlightuserdata ( lua . ctx , ( void * ) ( ( char * ) & s - > v - > think - ( char * ) s - > v ) ) ;
lua_rawget ( lua . ctx , - 2 ) ;
lua_replace ( lua . ctx , - 2 ) ;
if ( lua_pcall ( lua . ctx , 0 , 0 , 0 ) ! = 0 )
{
const char * e = lua_tolstring ( lua . ctx , - 1 , NULL ) ;
lua_pushedict ( lua . ctx , ( struct edict_s * ) s ) ;
lua_getfield ( lua . ctx , - 1 , " classname " ) ;
Con_Printf ( CON_WARNING " %s think: %s \n " , lua_tostring ( lua . ctx , - 1 ) , e ) ;
lua_pop ( lua . ctx , 3 ) ; //error, enttable, classname
}
# endif
2014-03-30 08:55:06 +00:00
}
static qboolean Lua_Event_ContentsTransition ( world_t * w , wedict_t * ent , int oldwatertype , int newwatertype )
{
2018-04-06 17:21:15 +00:00
return false ; //always do legacy behaviour, because I cba implementing anything else.
2014-03-30 08:55:06 +00:00
}
static void Lua_SetupGlobals ( world_t * world )
{
int flds ;
int bucks ;
comentvars_t * v = NULL ;
extentvars_t * xv = ( extentvars_t * ) ( v + 1 ) ;
memset ( & lua . globals , 0 , sizeof ( lua . globals ) ) ;
lua . globals . physics_mode = 2 ;
lua . globals . dimension_send = 255 ;
2015-06-04 06:15:14 +00:00
lua . globals . dimension_default = 255 ;
2018-04-06 17:21:15 +00:00
lua . globals . global_gravitydir [ 2 ] = - 1 ;
2014-03-30 08:55:06 +00:00
flds = 0 ;
bucks = 64 ;
Hash_InitTable ( & lua . globalfields , bucks , Z_Malloc ( Hash_BytesForBuckets ( bucks ) ) ) ;
//WARNING: global is not remapped yet...
//This code is written evilly, but works well enough
# define doglobal(n, t) \
pr_global_ptrs - > n = & lua . globals . n ; \
lua . globflds [ flds ] . offset = ( char * ) & lua . globals . n - ( char * ) & lua . globals ; \
lua . globflds [ flds ] . name = # n ; \
lua . globflds [ flds ] . type = t ; \
Hash_AddInsensitive ( & lua . globalfields , lua . globflds [ flds ] . name , & lua . globflds [ flds ] , & lua . globflds [ flds ] . buck ) ; \
flds + + ;
# define doglobal_v(o, f, t) \
lua . globflds [ flds ] . offset = ( char * ) & lua . globals . o - ( char * ) & lua . globals ; \
lua . globflds [ flds ] . name = # f ; \
lua . globflds [ flds ] . type = t ; \
Hash_AddInsensitive ( & lua . globalfields , lua . globflds [ flds ] . name , & lua . globflds [ flds ] , & lua . globflds [ flds ] . buck ) ; \
flds + + ;
# define globalentity(required, name) doglobal(name, ev_entity)
# define globalint(required, name) doglobal(name, ev_integer)
# define globalfloat(required, name) doglobal(name, ev_float)
# define globalstring(required, name) doglobal(name, ev_string)
# define globalvec(required, name) doglobal(name, ev_vector) doglobal_v(name[0], name##_x, ev_float) doglobal_v(name[1], name##_y, ev_float) doglobal_v(name[2], name##_z, ev_float)
# define globalfunc(required, name) doglobal(name, ev_function)
luagloballist
# undef doglobal
# define doglobal(n, t) doglobal_v(n,n,t)
luaextragloballist
2018-04-06 17:21:15 +00:00
# define parm(n)\
pr_global_ptrs - > spawnparamglobals [ n ] = & lua . globals . parm [ n ] ; \
lua . globflds [ flds ] . offset = ( char * ) & lua . globals . parm [ n ] - ( char * ) & lua . globals ; \
lua . globflds [ flds ] . name = " parm " # n ; \
lua . globflds [ flds ] . type = ev_float ; \
Hash_AddInsensitive ( & lua . globalfields , lua . globflds [ flds ] . name , & lua . globflds [ flds ] , & lua . globflds [ flds ] . buck ) ; \
2023-06-25 15:04:40 +00:00
flds + +
2018-04-06 17:21:15 +00:00
parm ( 0 ) ; parm ( 1 ) ; parm ( 2 ) ; parm ( 3 ) ; parm ( 4 ) ; parm ( 5 ) ; parm ( 6 ) ; parm ( 7 ) ;
parm ( 8 ) ; parm ( 9 ) ; parm ( 10 ) ; parm ( 11 ) ; parm ( 12 ) ; parm ( 13 ) ; parm ( 14 ) ; parm ( 15 ) ;
# undef parm
lua . numflds = 0 ;
2014-03-30 08:55:06 +00:00
bucks = 256 ;
Hash_InitTable ( & lua . entityfields , bucks , Z_Malloc ( Hash_BytesForBuckets ( bucks ) ) ) ;
# define doefield(n, t) \
2018-04-06 17:21:15 +00:00
lua . entflds [ lua . numflds ] . offset = ( char * ) & v - > n - ( char * ) v ; \
lua . entflds [ lua . numflds ] . name = # n ; \
lua . entflds [ lua . numflds ] . type = t ; \
Hash_AddInsensitive ( & lua . entityfields , lua . entflds [ lua . numflds ] . name , & lua . entflds [ lua . numflds ] , & lua . entflds [ lua . numflds ] . buck ) ; \
lua . numflds + + ;
2014-03-30 08:55:06 +00:00
# define doefield_v(o, f, t) \
2018-04-06 17:21:15 +00:00
lua . entflds [ lua . numflds ] . offset = ( char * ) & v - > o - ( char * ) v ; \
lua . entflds [ lua . numflds ] . name = # f ; \
lua . entflds [ lua . numflds ] . type = t ; \
Hash_AddInsensitive ( & lua . entityfields , lua . entflds [ lua . numflds ] . name , & lua . entflds [ lua . numflds ] , & lua . entflds [ lua . numflds ] . buck ) ; \
lua . numflds + + ;
2014-03-30 08:55:06 +00:00
# define comfieldentity(name,desc) doefield(name, ev_entity)
# define comfieldint(name,desc) doefield(name, ev_integer)
# define comfieldfloat(name,desc) doefield(name, ev_float)
# define comfieldstring(name,desc) doefield(name, ev_string)
# define comfieldvector(name,desc) doefield(name, ev_vector) doefield_v(name[0], name##_x, ev_float) doefield_v(name[1], name##_y, ev_float) doefield_v(name[2], name##_z, ev_float)
# define comfieldfunction(name,typestr,desc) doefield(name, ev_function)
comqcfields
# undef doefield
# undef doefield_v
# define doefield(n, t) \
2018-04-06 17:21:15 +00:00
lua . entflds [ lua . numflds ] . offset = ( char * ) & xv - > n - ( char * ) v ; \
lua . entflds [ lua . numflds ] . name = # n ; \
lua . entflds [ lua . numflds ] . type = t ; \
Hash_AddInsensitive ( & lua . entityfields , lua . entflds [ lua . numflds ] . name , & lua . entflds [ lua . numflds ] , & lua . entflds [ lua . numflds ] . buck ) ; \
lua . numflds + + ;
2014-03-30 08:55:06 +00:00
# define doefield_v(o, f, t) \
2018-04-06 17:21:15 +00:00
lua . entflds [ lua . numflds ] . offset = ( char * ) & xv - > o - ( char * ) v ; \
lua . entflds [ lua . numflds ] . name = # f ; \
lua . entflds [ lua . numflds ] . type = t ; \
Hash_AddInsensitive ( & lua . entityfields , lua . entflds [ lua . numflds ] . name , & lua . entflds [ lua . numflds ] , & lua . entflds [ lua . numflds ] . buck ) ; \
lua . numflds + + ;
2014-03-30 08:55:06 +00:00
comextqcfields
svextqcfields
PR_SV_FillWorldGlobals ( world ) ;
}
void QDECL Lua_ExecuteProgram ( pubprogfuncs_t * funcs , func_t func )
{
unsigned int entnum = func > > 10 ;
func & = 1023 ;
if ( ! entnum )
{
//okay, its the global table.
2018-04-06 17:21:15 +00:00
lua_pushglobaltable ( lua . ctx ) ;
2014-03-30 08:55:06 +00:00
}
else
{
entnum - = 1 ;
if ( entnum > = lua . maxedicts )
return ; //erk...
//get the entity's table
2018-04-06 17:21:15 +00:00
lua_pushlightuserdata ( lua . ctx , lua . edicttable [ entnum ] ) ;
lua_gettable ( lua . ctx , LUA_REGISTRYINDEX ) ;
2014-03-30 08:55:06 +00:00
}
//read the function from the table
2018-04-06 17:21:15 +00:00
lua_pushlightuserdata ( lua . ctx , ( void * ) ( qintptr_t ) func ) ;
lua_rawget ( lua . ctx , - 2 ) ;
2014-03-30 08:55:06 +00:00
//and now invoke it.
2018-04-06 17:21:15 +00:00
if ( lua_pcall ( lua . ctx , 0 , 0 , 0 ) ! = 0 )
2014-03-30 08:55:06 +00:00
{
2018-04-06 17:21:15 +00:00
const char * s = lua_tolstring ( lua . ctx , - 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
Con_Printf ( CON_WARNING " %s \n " , s ) ;
2018-04-06 17:21:15 +00:00
lua_pop ( lua . ctx , 1 ) ;
2014-03-30 08:55:06 +00:00
}
}
void PDECL Lua_CloseProgs ( pubprogfuncs_t * inst )
{
2018-04-06 17:21:15 +00:00
lua_close ( lua . ctx ) ;
2014-03-30 08:55:06 +00:00
free ( lua . edicttable ) ;
lua . edicttable = NULL ;
lua . maxedicts = 0 ;
2018-04-06 17:21:15 +00:00
memset ( & lua , 0 , sizeof ( lua ) ) ;
2018-04-15 02:48:23 +00:00
Z_FreeTags ( LUA_MALLOC_TAG ) ;
2018-04-06 17:21:15 +00:00
}
static void QDECL Lua_Get_FrameState ( world_t * w , wedict_t * ent , framestate_t * fstate )
{
memset ( fstate , 0 , sizeof ( * fstate ) ) ;
fstate - > g [ FS_REG ] . frame [ 0 ] = ent - > v - > frame ;
fstate - > g [ FS_REG ] . frametime [ 0 ] = ent - > xv - > frame1time ;
fstate - > g [ FS_REG ] . lerpweight [ 0 ] = 1 ;
fstate - > g [ FS_REG ] . endbone = 0x7fffffff ;
fstate - > g [ FST_BASE ] . frame [ 0 ] = ent - > xv - > baseframe ;
fstate - > g [ FST_BASE ] . frametime [ 0 ] = ent - > xv - > /*base*/ frame1time ;
fstate - > g [ FST_BASE ] . lerpweight [ 0 ] = 1 ;
fstate - > g [ FST_BASE ] . endbone = ent - > xv - > basebone ;
# if defined(SKELETALOBJECTS) || defined(RAGDOLL)
if ( ent - > xv - > skeletonindex )
skel_lookup ( w , ent - > xv - > skeletonindex , fstate ) ;
# endif
2014-03-30 08:55:06 +00:00
}
qboolean PR_LoadLua ( void )
{
world_t * world = & sv . world ;
pubprogfuncs_t * pf ;
2018-04-06 17:21:15 +00:00
vfsfile_t * sourcefile = NULL ;
if ( ( sourcefile = FS_OpenVFS ( " qwprogs.lua " , " rb " , FS_GAME ) ) )
progstype = PROG_QW ;
else if ( ( sourcefile = FS_OpenVFS ( " progs.lua " , " rb " , FS_GAME ) ) )
progstype = PROG_NQ ;
else
2014-03-30 08:55:06 +00:00
return false ;
if ( ! init_lua ( ) )
{
VFS_CLOSE ( sourcefile ) ;
Con_Printf ( " WARNING: Found progs.lua, but could load load lua library \n " ) ;
return false ;
}
pf = svprogfuncs = & lua . progfuncs ;
2023-06-25 15:04:40 +00:00
pf - > Shutdown = Lua_CloseProgs ;
2014-03-30 08:55:06 +00:00
pf - > AddString = Lua_AddString ;
2018-04-06 17:21:15 +00:00
pf - > EdictNum = Lua_EdictNum ;
pf - > NumForEdict = Lua_NumForEdict ;
2014-03-30 08:55:06 +00:00
pf - > EdictToProgs = Lua_EdictToProgs ;
pf - > ProgsToEdict = Lua_ProgsToEdict ;
pf - > EntAlloc = Lua_EntAlloc ;
pf - > EntFree = Lua_EntRemove ;
pf - > EntClear = Lua_EntClear ;
pf - > FindGlobal = Lua_FindGlobal ;
pf - > load_ents = Lua_LoadEnts ;
pf - > globals = Lua_Globals ;
pf - > GetEdictFieldValue = Lua_GetEdictFieldValue ;
pf - > SetStringField = Lua_SetStringField ;
pf - > StringToProgs = Lua_StringToProgs ;
pf - > StringToNative = Lua_StringToNative ;
pf - > ExecuteProgram = Lua_ExecuteProgram ;
pf - > FindFunction = Lua_FindFunction ;
world - > Event_Touch = Lua_Event_Touch ;
world - > Event_Think = Lua_Event_Think ;
world - > Event_Sound = SVQ1_StartSound ;
world - > Event_ContentsTransition = Lua_Event_ContentsTransition ;
world - > Get_CModel = SVPR_GetCModel ;
2018-04-06 17:21:15 +00:00
world - > Get_FrameState = Lua_Get_FrameState ;
2014-03-30 08:55:06 +00:00
world - > progs = pf ;
world - > progs - > parms = & lua . progfuncsparms ;
world - > progs - > parms - > user = world ;
2018-04-06 17:21:15 +00:00
world - > progs - > parms - > Printf = PR_Printf ;
world - > progs - > parms - > DPrintf = PR_DPrintf ;
2014-03-30 08:55:06 +00:00
world - > usesolidcorpse = true ;
Lua_SetupGlobals ( world ) ;
svs . numprogs = 0 ; //Why is this svs?
# ifdef VM_Q1
world - > edict_size = sizeof ( stdentvars_t ) + sizeof ( extentvars_t ) ;
# else
world - > edict_size = sizeof ( stdentvars_t ) ;
# endif
//force items2 instead of serverflags
sv . haveitems2 = true ;
//initalise basic lua context
2018-04-06 17:21:15 +00:00
lua . ctx = lua_newstate ( my_lua_alloc , NULL ) ; //create our lua state
// luaL_openlibs(lua.ctx);
2014-03-30 08:55:06 +00:00
my_lua_registerbuiltins ( lua . ctx ) ;
//spawn the world, woo.
2017-12-28 16:24:50 +00:00
world - > edicts = ( wedict_t * ) pf - > EntAlloc ( pf , false , 0 ) ;
2014-03-30 08:55:06 +00:00
//load the gamecode now. it should be safe for it to call various builtins.
2018-04-06 17:21:15 +00:00
if ( 0 ! = lua_load ( lua . ctx , my_lua_Reader , sourcefile , " progs.lua " , " bt " ) ) //load the file, embed it within a function and push it
2014-03-30 08:55:06 +00:00
{
2018-04-06 17:21:15 +00:00
Con_Printf ( " Error trying to parse %s: %s \n " , " progs.lua " , lua_tolstring ( lua . ctx , - 1 , NULL ) ) ;
lua_pop ( lua . ctx , 1 ) ;
2014-03-30 08:55:06 +00:00
}
else
{
2018-04-06 17:21:15 +00:00
if ( lua_pcall ( lua . ctx , 0 , 0 , 0 ) ! = 0 )
2014-03-30 08:55:06 +00:00
{
2018-04-06 17:21:15 +00:00
const char * s = lua_tolstring ( lua . ctx , - 1 , NULL ) ;
2014-03-30 08:55:06 +00:00
Con_Printf ( CON_WARNING " %s \n " , s ) ;
2018-04-06 17:21:15 +00:00
lua_pop ( lua . ctx , 1 ) ;
2014-03-30 08:55:06 +00:00
}
}
VFS_CLOSE ( sourcefile ) ;
return true ;
}
# endif //VM_LUA