diff --git a/cgame/Makefile b/cgame/Makefile
index 30281b9..bc8a7e8 100644
--- a/cgame/Makefile
+++ b/cgame/Makefile
@@ -56,6 +56,7 @@ OBJ = \
cg_drawtools.o \
cg_draw.o \
cg_consolecmds.o \
+ cg_lua.o \
lua_vector.o \
lua_qmath.o \
@@ -136,6 +137,7 @@ cg_servercmds.o : cg_servercmds.c; $(DO_CC)
cg_snapshot.o : cg_snapshot.c; $(DO_CC)
cg_view.o : cg_view.c; $(DO_CC)
cg_weapons.o : cg_weapons.c; $(DO_CC)
+cg_lua.o : cg_lua.c; $(DO_CC)
fx_compression.o : fx_compression.c; $(DO_CC)
fx_grenade.o : fx_grenade.c; $(DO_CC)
fx_item.o : fx_item.c; $(DO_CC)
diff --git a/cgame/cg_local.h b/cgame/cg_local.h
index 01114ec..d2d0a52 100644
--- a/cgame/cg_local.h
+++ b/cgame/cg_local.h
@@ -1821,6 +1821,12 @@ extern vmCvar_t rpg_forceFieldSet;
// grp cvars
extern vmCvar_t grp_berp;
+// lua
+#ifdef CG_LUA
+extern vmCvar_t cg_debugLua;
+extern vmCvar_t cg_logLua;
+#endif
+
diff --git a/cgame/cg_lua.c b/cgame/cg_lua.c
new file mode 100644
index 0000000..d7f88df
--- /dev/null
+++ b/cgame/cg_lua.c
@@ -0,0 +1,368 @@
+// g_lua.c
+
+#include "cg_lua.h"
+
+#ifdef G_LUA
+
+lvm_t *lVM[NUM_VMS];
+fileHandle_t lualog;
+
+void QDECL LUA_DEBUG(const char *fmt, ...)
+{
+ va_list argptr;
+ char text[1024];
+
+ if(cg_debugLua.integer >= 1)
+ {
+ va_start(argptr, fmt);
+ Com_sprintf(text, sizeof(text), fmt, argptr);
+ va_end(argptr);
+ CG_Printf(S_COLOR_YELLOW "LUA DEBUG:" S_COLOR_WHITE " %s\n", text);
+ }
+}
+
+void QDECL LUA_LOG(const char *fmt, ...)
+{
+ va_list argptr;
+ char buff[1024], string[1024];
+ int min, tens, sec;
+
+ va_start(argptr, fmt);
+ Com_sprintf(buff, sizeof(buff), fmt, argptr);
+ va_end(argptr);
+
+ if(cg_logLua.integer) {
+ sec = cg.time / 1000;
+ min = sec / 60;
+ sec -= min * 60;
+ tens = sec / 10;
+ sec -= tens * 10;
+
+ Com_sprintf(string, sizeof(string), "%i:%i%i %s", min, tens, sec, buff);
+
+ trap_FS_Write(string, strlen(string), lualog);
+ }
+}
+
+qboolean LoadLuaFile(char *path, int num_vm)
+{
+ int flen = 0;
+ char *code;
+ fileHandle_t f;
+ lvm_t *vm;
+
+ flen = trap_FS_FOpenFile(path, &f, FS_READ);
+ if(flen < 0)
+ {
+ LUA_LOG("Lua: can not open file %s\n", path);
+ CG_Printf(S_COLOR_YELLOW "Lua: can not open file %s\n", path);
+ trap_FS_FCloseFile(f);
+ return qfalse;
+ }
+ else
+ {
+ code = (char *)malloc(flen + 1);
+ if(!code) return qfalse;
+ trap_FS_Read(code, flen, f);
+ *(code + flen) = '\0';
+ trap_FS_FCloseFile(f);
+
+ vm = (lvm_t *) malloc(sizeof(lvm_t));
+ if(vm == NULL)
+ {
+ LUA_LOG("Lua: failed to allocate memory for lua VM\n");
+ CG_Printf(S_COLOR_YELLOW "Lua: failed to allocate memory for lua VM\n");
+ return qfalse;
+ }
+ memset(vm, 0, sizeof(lvm_t));
+ vm->id = -1;
+ Q_strncpyz(vm->filename, path, sizeof(vm->filename));
+ vm->code = code;
+ vm->code_size = flen;
+ vm->error = 0;
+
+ if(CG_LuaStartVM(vm) == qfalse)
+ {
+ CG_LuaStopVM(vm);
+ vm = NULL;
+ return qfalse;
+ }
+ else
+ {
+ vm->id = num_vm;
+ lVM[num_vm] = vm;
+ return qtrue;
+ }
+ }
+ //return qfalse;
+}
+
+qboolean CG_LuaInit()
+{
+
+ CG_Printf("------- CG_LuaInit -------\n");
+
+ // not much to do for now
+ if(cg_logLua.integer) {
+ trap_FS_FOpenFile("./cg_lua.log", &lualog, FS_APPEND);
+ }
+
+ CG_Printf("------- CG_LuaInit Finish -------\n");
+
+ return qtrue;
+}
+
+qboolean CG_LuaResume(lvm_t *vm, lua_State *T, char *func, int nargs) {
+ int res = lua_resume(T, nargs);
+
+ if(res == LUA_ERRRUN) {
+ LUA_LOG("Lua: %s error running lua script: %s\n", func, lua_tostring(T, -1));
+ CG_Printf(S_COLOR_YELLOW "Lua: %s error running lua script: %s\n", func, lua_tostring(T, -1));
+ lua_pop(T, 1);
+ vm->error++;
+ return qfalse;
+ } else if(res == LUA_ERRMEM) {
+ LUA_LOG("Lua: memory allocation error #2 ( %s )\n", vm->filename);
+ vm->error++;
+ return qfalse;
+ } else if(res == LUA_ERRERR) {
+ LUA_LOG("Lua: traceback error ( %s )\n", vm->filename);
+ CG_Printf(S_COLOR_YELLOW "Lua: traceback error ( %s )\n", vm->filename);
+ vm->error++;
+ return qfalse;
+ }
+ return qtrue;
+}
+
+qboolean CG_LuaCall(lvm_t * vm, char *func, int nargs, int nresults)
+{
+ int res = lua_pcall(vm->L, nargs, nresults, 0);
+
+ if(res == LUA_ERRRUN)
+ {
+ LUA_LOG("Lua: %s error running lua script: %s\n", func, lua_tostring(vm->L, -1));
+ CG_Printf(S_COLOR_YELLOW "Lua: %s error running lua script: %s\n", func, lua_tostring(vm->L, -1));
+ lua_pop(vm->L, 1);
+ vm->error++;
+ return qfalse;
+ }
+ else if(res == LUA_ERRMEM)
+ {
+ LUA_LOG("Lua: memory allocation error #2 ( %s )\n", vm->filename);
+ vm->error++;
+ return qfalse;
+ }
+ else if(res == LUA_ERRERR)
+ {
+ LUA_LOG("Lua: traceback error ( %s )\n", vm->filename);
+ CG_Printf(S_COLOR_YELLOW "Lua: traceback error ( %s )\n", vm->filename);
+ vm->error++;
+ return qfalse;
+ }
+ return qtrue;
+}
+
+#define SAY_ALL 0
+#define SAY_TEAM 1
+
+qboolean CG_LuaGetFunctionT(lua_State *T, char *name)
+{
+ if(T)
+ {
+ lua_getglobal(T, name);
+ if(lua_isfunction(T, -1))
+ {
+ return qtrue;
+ }
+ else
+ {
+ lua_pop(T, 1);
+ return qfalse;
+ }
+ }
+ return qfalse;
+}
+
+qboolean CG_LuaGetFunction(lvm_t * vm, char *name)
+{
+ if(vm->L)
+ {
+ lua_getglobal(vm->L, name);
+ if(lua_isfunction(vm->L, -1))
+ {
+ return qtrue;
+ }
+ else
+ {
+ lua_pop(vm->L, 1);
+ return qfalse;
+ }
+ }
+ return qfalse;
+}
+
+qboolean CG_LuaStartVM(lvm_t * vm)
+{
+ int res = 0;
+ char homepath[MAX_QPATH], gamepath[MAX_QPATH];
+
+ vm->L = luaL_newstate();
+ if(!vm->L)
+ {
+ LUA_LOG("Lua: Lua failed to initialise.\n");
+ return qfalse;
+ }
+
+ luaL_openlibs(vm->L);
+
+ trap_Cvar_VariableStringBuffer("fs_homepath", homepath, sizeof(homepath));
+ trap_Cvar_VariableStringBuffer("fs_game", gamepath, sizeof(gamepath));
+
+ lua_getglobal(vm->L, LUA_LOADLIBNAME);
+ if(lua_istable(vm->L, -1))
+ {
+ lua_pushstring(vm->L, va("%s%s%s%s?.lua;%s%s%s%slualib%slua%s?.lua",
+ homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP,
+ homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP));
+ lua_setfield(vm->L, -2, "path");
+ lua_pushstring(vm->L, va("%s%s%s%s?.%s;%s%s%s%slualib%sclibs%s?.%s",
+ homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, EXTENSION,
+ homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP, EXTENSION));
+ lua_setfield(vm->L, -2, "cpath");
+ }
+ lua_pop(vm->L, 1);
+
+ Lua_RegisterGlobal(vm->L, "LUA_PATH", va("%s%s%s%s?.lua;%s%s%s%slualib%slua%s?.lua",
+ homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP,
+ homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP));
+ Lua_RegisterGlobal(vm->L, "LUA_CPATH", va("%s%s%s%s?.%s;%s%s%s%slualib%sclibs%s?.%s",
+ homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, EXTENSION,
+ homepath, LUA_DIRSEP, gamepath, LUA_DIRSEP, LUA_DIRSEP, LUA_DIRSEP, EXTENSION));
+ Lua_RegisterGlobal(vm->L, "LUA_DIRSEP", LUA_DIRSEP);
+
+ lua_newtable(vm->L);
+ Lua_RegConstInteger(vm->L, CS_PLAYERS);
+ Lua_RegConstInteger(vm->L, EXEC_NOW);
+ Lua_RegConstInteger(vm->L, EXEC_INSERT);
+ Lua_RegConstInteger(vm->L, EXEC_APPEND);
+ Lua_RegConstInteger(vm->L, FS_READ);
+ Lua_RegConstInteger(vm->L, FS_WRITE);
+ Lua_RegConstInteger(vm->L, FS_APPEND);
+ Lua_RegConstInteger(vm->L, FS_APPEND_SYNC);
+ Lua_RegConstInteger(vm->L, SAY_ALL);
+ Lua_RegConstInteger(vm->L, SAY_TEAM);
+ Lua_RegConstString(vm->L, HOSTARCH);
+
+ luaopen_base(vm->L);
+ luaopen_string(vm->L);
+ luaopen_coroutine(vm->L);
+ Luaopen_Qmath(vm->L);
+ Luaopen_Vector(vm->L);
+
+ res = luaL_loadbuffer(vm->L, vm->code, vm->code_size, vm->filename);
+ if(res == LUA_ERRSYNTAX)
+ {
+ LUA_LOG("Lua: syntax error during pre-compilation: %s\n", (char *)lua_tostring(vm->L, -1));
+ CG_Printf(S_COLOR_YELLOW "Lua: syntax error: %s\n", (char *)lua_tostring(vm->L, -1));
+ lua_pop(vm->L, 1);
+ vm->error++;
+ return qfalse;
+ }
+ else if(res == LUA_ERRMEM)
+ {
+ LUA_LOG("Lua: memory allocation error #1 ( %s )\n", vm->filename);
+ vm->error++;
+ return qfalse;
+ }
+
+ if(!CG_LuaCall(vm, "CG_LuaStartVM", 0, 0))
+ return qfalse;
+
+ LUA_LOG("Lua: Loading %s\n", vm->filename);
+ return qtrue;
+}
+
+void CG_LuaStopVM(lvm_t * vm)
+{
+ if(vm == NULL)
+ return;
+ if(vm->code != NULL)
+ {
+ free(vm->code);
+ vm->code = NULL;
+ }
+ if(vm->id >= 0)
+ {
+ if(lVM[vm->id] == vm)
+ lVM[vm->id] = NULL;
+ if(!vm->error)
+ {
+ LUA_LOG("Lua: Lua module [%s] unloaded.\n", vm->filename);
+ }
+ }
+ free(vm);
+}
+
+void CG_LuaShutdown()
+{
+ int i;
+ lvm_t *vm;
+
+ for(i = 0; i < NUM_VMS; i++)
+ {
+ vm = lVM[i];
+ if(vm)
+ {
+ CG_LuaStopVM(vm);
+ }
+ }
+
+ trap_FS_FCloseFile(lualog);
+}
+
+void CG_LuaStatus(void)
+{
+ int i, cnt = 0;
+
+ for(i = 0; i < NUM_VMS; i++)
+ if(lVM[i])
+ cnt++;
+
+ if(cnt == 0)
+ {
+ CG_Printf("Lua: no scripts loaded.\n");
+ return;
+ }
+ else if(cnt == 1)
+ {
+ CG_Printf("Lua: showing lua information ( 1 module loaded )\n");
+ }
+ else
+ {
+ CG_Printf("Lua: showing lua information ( %d modules loaded )\n", cnt);
+ }
+ CG_Printf("%-2s %-24s\n", "VM", "Filename");
+ CG_Printf("-- ------------------------\n");
+ for(i = 0; i < NUM_VMS; i++)
+ {
+ if(lVM[i])
+ {
+ CG_Printf("%2d %-24s\n", lVM[i]->id, lVM[i]->filename);
+ }
+ }
+ CG_Printf("-- ------------------------\n");
+
+}
+
+lvm_t *CG_LuaGetVM(lua_State * L)
+{
+ int i;
+
+ for(i = 0; i < NUM_VMS; i++)
+ if(lVM[i] && lVM[i]->L == L)
+ return lVM[i];
+ return NULL;
+}
+
+
+#endif
diff --git a/cgame/cg_lua.h b/cgame/cg_lua.h
new file mode 100644
index 0000000..a11ebaa
--- /dev/null
+++ b/cgame/cg_lua.h
@@ -0,0 +1,69 @@
+#ifndef _G_LUA_H
+#define _G_LUA_H
+
+#include "cg_local.h"
+
+#if (defined __linux__ || defined __WIN32__) // linux or mingw
+#include "../game/lua.h"
+#include "../game/lauxlib.h"
+#include "../game/lualib.h"
+#else
+#include "../game/lua.h"
+#include "../game/lauxlib.h"
+#include "../game/lualib.h"
+#endif
+
+#define NUM_VMS 1
+
+#if defined __linux__
+#define HOSTARCH "UNIX"
+#define EXTENSION "so"
+#elif defined WIN32
+#define HOSTARCH "WIN32"
+#define EXTENSION "dll"
+#elif defined __APPLE__
+#define HOSTARCH "UNIX"
+#define EXTENSION "dylib"
+#endif
+
+#define Lua_RegisterGlobal(L, n, v) (lua_pushstring(L, v), lua_setglobal(L, n))
+#define Lua_RegConstInteger(L, n) (lua_pushstring(L, #n), lua_pushinteger(L, n), lua_settable(L, -3))
+#define Lua_RegConstString(L, n) (lua_pushstring(L, #n), lua_pushstring(L, n), lua_settable(L, -3))
+
+typedef struct {
+ int id;
+ char filename[MAX_QPATH];
+ char *code;
+ int code_size;
+ int error;
+ lua_State *L;
+} lvm_t;
+
+extern lvm_t *lVM[NUM_VMS];
+
+void QDECL LUA_DEBUG(const char *fmt, ...);
+void QDECL LUA_LOG(const char *fmt, ...);
+qboolean CG_LuaInit(void);
+qboolean CG_LuaCall(lvm_t *vm, char *func, int nargs, int nresults);
+qboolean CG_LuaResume(lvm_t *vm, lua_State *T, char *func, int nargs);
+qboolean CG_LuaGetFunction(lvm_t *vm, char *name);
+qboolean CG_LuaGetFunctionT(lua_State *T, char *name);
+qboolean CG_LuaStartVM(lvm_t *vm);
+void CG_LuaStopVM(lvm_t *vm);
+void CG_LuaShutdown(void);
+void CG_LuaStatus(void);
+lvm_t *CG_LuaGetVM(lua_State *L);
+
+// lua_cgame.c
+int Luaopen_CGame(lua_State *L);
+
+// lua_qmath.c
+int Luaopen_Qmath(lua_State *L);
+
+// lua_vector.c
+int Luaopen_Vector(lua_State *L);
+void Lua_PushVector(lua_State *L, vec3_t v);
+vec_t *Lua_GetVector(lua_State *L, int argNum);
+int Lua_IsVector(lua_State *L, int index);
+vec3_t *Lua_GetVectorMisc(lua_State *L, int *index);
+#endif
diff --git a/cgame/cg_main.c b/cgame/cg_main.c
index 75d0278..0771a27 100644
--- a/cgame/cg_main.c
+++ b/cgame/cg_main.c
@@ -195,6 +195,12 @@ vmCvar_t rpg_forceFieldSet;
// grp cvars
vmCvar_t grp_berp;
+// lua
+#ifdef CG_LUA
+vmCvar_t cg_debugLua;
+vmCvar_t cg_logLua;
+#endif
+
//RPG-X | Phenix | 05/02/2006
//Ban System (and it's backup cvars)
@@ -342,7 +348,14 @@ static cvarTable_t cvarTable[] = {
//{ &cg_playerID, "cg_playerID", "0", CVAR_ARCHIVE | CVAR_ROM | CVAR_NORESTART }
// grp cvars
- { &grp_berp, "grp_berp", "0", CVAR_ARCHIVE | CVAR_LATCH }
+ { &grp_berp, "grp_berp", "0", CVAR_ARCHIVE | CVAR_LATCH },
+
+ // lua
+#ifdef CG_LUA
+ { &cg_debugLua, "cg_debuglua", "0", CVAR_ARCHIVE | CVAR_LATCH },
+ { &cg_logLua, "cg_loglua", "0", CVAR_ARCHIVE }
+#endif
+
};
static int cvarTableSize = sizeof( cvarTable ) / sizeof( cvarTable[0] );
diff --git a/cgame/cgame.vcxproj b/cgame/cgame.vcxproj
index ab1ec04..319b2de 100644
--- a/cgame/cgame.vcxproj
+++ b/cgame/cgame.vcxproj
@@ -269,6 +269,7 @@
WIN32;NDEBUG;_WINDOWS
true
+
Disabled
WIN32;_DEBUG;_WINDOWS
@@ -461,6 +462,7 @@
+
diff --git a/cgame/cgame.vcxproj.filters b/cgame/cgame.vcxproj.filters
index bd58327..ee12c12 100644
--- a/cgame/cgame.vcxproj.filters
+++ b/cgame/cgame.vcxproj.filters
@@ -128,6 +128,9 @@
Source Files
+
+ Source Files
+
@@ -163,6 +166,9 @@
Header Files
+
+ Header Files
+
diff --git a/stefgame.suo b/stefgame.suo
index 4471281..53f0796 100644
Binary files a/stefgame.suo and b/stefgame.suo differ