@@ -3,6 +3,7 @@
#include <engine/editor.h>
#include <engine/engine.h>
#include <engine/friends.h>
#include <engine/lua.h>
#include <engine/graphics.h>
#include <engine/textrender.h>
#include <engine/demo.h>
@@ -61,6 +62,8 @@
#include "components/spectator.h"
#include "components/statboard.h"
#include "components/voting.h"
#include "components/luarender.h"
#include "components/luainput.h"

#include <base/system.h>
#include "components/race_demo.h"
@@ -150,6 +153,7 @@ void CGameClient::OnConsoleInit()
m_pUpdater = Kernel()->RequestInterface<IUpdater>();
#endif
m_pIRC = Kernel()->RequestInterface<IIRC>();
m_pLuaCore = Kernel()->RequestInterface<ILua>();

// setup pointers
m_pBinds = &::gs_Binds;
@@ -5,12 +5,17 @@

#include <base/vmath.h>
#include <engine/client.h>
#include <engine/lua.h>
#include <engine/console.h>
#include <game/layers.h>
#include <game/gamecore.h>
#include <game/luamap.h>
#include <game/teamscore.h>

#include "render.h"
#include "lua.h"


#include <game/teamscore.h>

#define MIN3(x,y,z) ((y) <= (z) ? \
((x) <= (y) ? (x) : (y)) \
@@ -363,6 +368,14 @@ class CGameClient : public IGameClient
class CIRCBind *m_pIRCBind;
class CIdentity *m_pIdentity;

// Lua
class ILua *m_pLuaCore;
class CLuaClient *m_pLua;
class CLuaBinding *m_pLuaBinding;
int m_UpdateScoreboard;
static void ConAddLuaFile(IConsole::IResult *pResult, void *pUserData);
void AddLuaFile(char *pFileName) { if(m_pLuaCore) m_pLuaCore->AddLuaFile(pFileName, true); }

// DDRace

class CRaceDemo *m_pRaceDemo;

Large diffs are not rendered by default.

@@ -0,0 +1,309 @@
#include "luaevent.h"
#include <base/system.h>
//storage class for the event variables

CEventVariable::CEventVariable()
{
m_Type = EVENT_TYPE_INVALID;
m_pData = 0;
m_Size = 0;
}

CEventVariable::~CEventVariable()
{
if (m_pData)
delete [](char *)m_pData;
}

void CEventVariable::Allocate(int Size)
{
if (m_pData)
delete [](char *)m_pData;
m_Size = Size;
m_pData = 0;
if (Size > 0)
m_pData = new char[Size];
}

//allocate 16 bytes even if we need 4 or just 1
//why?
//because when we transform this var to something bigger
//bool -> int


void CEventVariable::Set(int Value)
{
m_Type = EVENT_TYPE_INTEGER;
Allocate(16);
mem_copy(m_pData, &Value, sizeof(Value));
}

void CEventVariable::Set(long int Value)
{
m_Type = EVENT_TYPE_INTEGER;
Allocate(16);
mem_copy(m_pData, &Value, sizeof(Value));
}

void CEventVariable::Set(lua_Number Value)
{
if (Value == (int)Value)
Set((int)Value);
Set((float)Value);
}

void CEventVariable::Set(float Value)
{
m_Type = EVENT_TYPE_FLOAT;
Allocate(16);
mem_copy(m_pData, &Value, sizeof(Value));
}

void CEventVariable::Set(bool Value)
{
m_Type = EVENT_TYPE_BOOL;
Allocate(16);
mem_copy(m_pData, &Value, sizeof(Value));
}

void CEventVariable::Set(char Value)
{
m_Type = EVENT_TYPE_CHAR;
Allocate(16);
mem_copy(m_pData, &Value, sizeof(Value));
}

void CEventVariable::Set(const char *pStr)
{
m_Type = EVENT_TYPE_STRING;
Allocate(str_length(pStr) + 1);
mem_copy(m_pData, pStr, str_length(pStr) + 1);
}

void CEventVariable::Set(const char *pData, int Size)
{
m_Type = EVENT_TYPE_DATA;
Allocate(Size);
mem_copy(m_pData, pData, Size);
}

void *CEventVariable::Get()
{
return m_pData;
}

int CEventVariable::GetSize()
{
return m_Size;
}

char *CEventVariable::GetString()
{
return (char *)m_pData;
}

int CEventVariable::GetInteger()
{
if (m_Type == EVENT_TYPE_STRING)
return str_toint((char *)m_pData);
if (IsNumeric() == false)
return 0;
if (m_Type == EVENT_TYPE_FLOAT)
return GetFloat();
if (!m_pData)
return 0;
return *((int *)m_pData);
}

float CEventVariable::GetFloat()
{
if (m_Type == EVENT_TYPE_STRING)
return str_tofloat((char *)m_pData);
if (IsNumeric() == false)
return 0;
if (m_Type != EVENT_TYPE_FLOAT)
return (float)GetInteger();
if (!m_pData)
return 0;
return *((float *)m_pData);
}

bool CEventVariable::GetBool()
{
if (IsNumeric() == false)
return 0;
if (!m_pData)
return 0;
return *((bool *)m_pData);
}

char CEventVariable::GetChar()
{
if (IsNumeric() == false)
return 0;
if (!m_pData)
return 0;
return *((char *)m_pData);
}

int CEventVariable::GetType()
{
return m_Type;
}

bool CEventVariable::IsNumeric()
{
return !(!(m_Type & (EVENT_TYPE_INTEGER | EVENT_TYPE_FLOAT | EVENT_TYPE_BOOL | EVENT_TYPE_CHAR)));
}

void CEventVariable::Reset()
{
Allocate(0); //free
m_Type = EVENT_TYPE_INVALID;
}

void CEvent::Reset()
{
for (int i = 0; i < MAX_EVENT_VARIABLES; i++)
{
m_aVars[i].Reset();
}
}

CEventVariable *CEvent::FindFree()
{
static CEventVariable Workaround; //remove me!!
Workaround.Reset();
for (int i = 0; i < MAX_EVENT_VARIABLES; i++)
{
if (m_aVars[i].GetType() == CEventVariable::EVENT_TYPE_INVALID)
{
return &m_aVars[i];
}
}
return &Workaround;
}
/*
//Eventlistener
template <class T>
void CLuaEventListener<T>::AddEventListener(T *pLuaFile, char *pEvent, char *pLuaFunction)
{
CLuaListenerData Listener;
Listener.m_pLuaFile = pLuaFile;
str_copy(Listener.m_aLuaFunction, pLuaFunction, sizeof(Listener.m_aLuaFunction));
str_copy(Listener.m_aEvent, pEvent, sizeof(Listener.m_aEvent));
m_aListeners.add(Listener);
}
template <class T>
void CLuaEventListener<T>::OnEvent(const char *pEvent)
{
/*if (GetState())
{
return; //fixes a event called in an event listener
//should check for function names! to support event by event
//to do this we have to copy the result and the parameters -.-
//have to be done before L1.4
}*/
/* m_aStackReturns[m_StackSize].Reset();
for(plain_range<CLuaListenerData> r = m_aListeners.all(); !r.empty(); r.pop_front())
{
if (r.front().m_aEvent && str_comp_nocase(r.front().m_aEvent, pEvent) == 0)
{
if (r.front().m_pLuaFile->FunctionExist(r.front().m_aLuaFunction))
{
int Num = lua_gettop(r.front().m_pLuaFile->m_pLua); //get stack size before calling fx
int Start = lua_gettop(r.front().m_pLuaFile->m_pLua); //get stack size before calling fx
r.front().m_pLuaFile->FunctionPrepare(r.front().m_aLuaFunction);
for (int i = 0; i < MAX_EVENT_VARIABLES; i++)
{
if (m_aStackParameters[m_StackSize].m_aVars[i].GetType() == CEventVariable::EVENT_TYPE_INTEGER)
{
r.front().m_pLuaFile->PushInteger(m_aStackParameters[m_StackSize].m_aVars[i].GetInteger());
}
else if (m_aStackParameters[m_StackSize].m_aVars[i].GetType() == CEventVariable::EVENT_TYPE_CHAR)
{
r.front().m_pLuaFile->PushInteger(m_aStackParameters[m_StackSize].m_aVars[i].GetInteger());
}
else if (m_aStackParameters[m_StackSize].m_aVars[i].GetType() == CEventVariable::EVENT_TYPE_FLOAT)
{
r.front().m_pLuaFile->PushFloat(m_aStackParameters[m_StackSize].m_aVars[i].GetFloat());
}
else if (m_aStackParameters[m_StackSize].m_aVars[i].GetType() == CEventVariable::EVENT_TYPE_BOOL)
{
r.front().m_pLuaFile->PushBoolean(m_aStackParameters[m_StackSize].m_aVars[i].GetInteger());
}
else if (m_aStackParameters[m_StackSize].m_aVars[i].GetType() == CEventVariable::EVENT_TYPE_STRING)
{
r.front().m_pLuaFile->PushString(m_aStackParameters[m_StackSize].m_aVars[i].GetString());
}
else if (m_aStackParameters[m_StackSize].m_aVars[i].GetType() == CEventVariable::EVENT_TYPE_DATA)
{
r.front().m_pLuaFile->PushData((char *)m_aStackParameters[m_StackSize].m_aVars[i].Get(), m_aStackParameters[m_StackSize].m_aVars[i].GetSize());
}
else
{
break;
}
}
r.front().m_pLuaFile->FunctionExec();
Num = lua_gettop(r.front().m_pLuaFile->m_pLua) - Num; //get number of returns
for (int i = 0; i < Num; i++) //lua stack begins with 1 - so manipulate every i
{
if (lua_isnumber(r.front().m_pLuaFile->m_pLua, Start + i + 1))
{
if (lua_tointeger(r.front().m_pLuaFile->m_pLua, Start + i + 1) == lua_tonumber(r.front().m_pLuaFile->m_pLua, Start + i + 1))
m_aStackReturns[m_StackSize].m_aVars[i].Set((int)lua_tointeger(r.front().m_pLuaFile->m_pLua, Start + i + 1));
else
m_aStackReturns[m_StackSize].m_aVars[i].Set((float)lua_tonumber(r.front().m_pLuaFile->m_pLua, Start + i + 1));
}
else if (lua_isboolean(r.front().m_pLuaFile->m_pLua, Start + i + 1))
{
m_aStackReturns[m_StackSize].m_aVars[i].Set(lua_toboolean(r.front().m_pLuaFile->m_pLua, Start + i + 1));
}
else if (lua_isstring(r.front().m_pLuaFile->m_pLua, Start + i + 1))
{
int Size = 0;
const char *pData = lua_tolstring(r.front().m_pLuaFile->m_pLua, Start + i + 1, (size_t *)&Size);
if (str_length(pData) == Size)
m_aStackReturns[m_StackSize].m_aVars[i].Set(pData);
else
m_aStackReturns[m_StackSize].m_aVars[i].Set(pData, Size);
}
}
for (int i = 0; i < Num; i++) //pop values
{
lua_remove(r.front().m_pLuaFile->m_pLua, -1); //remove value last first
//this solves the recusive-function-call-stack problem
//lua_pop(r.front().m_pLuaFile->m_pLua, 1);
}
}
}
}
m_aStackParameters[m_StackSize].Reset(); //
m_StackSize--;
}
/*
template <class T>
void CLuaEventListener<T>::RemoveEventListener(T *pLuaFile, char *pEvent)
{
for(plain_range<CLuaListenerData> r = m_aListeners.all(); !r.empty(); r.pop_front())
{
if (r.front().m_pLuaFile == pLuaFile && str_comp_nocase(r.front().m_aEvent, pEvent) == 0)
{
m_aListeners.remove(r.front());
}
}
}
template <class T>
void CLuaEventListener<T>::RemoveAllEventListeners(T *pLuaFile)
{
for(plain_range<CLuaListenerData> r = m_aListeners.all(); !r.empty(); r.pop_front())
{
if (r.front().m_pLuaFile == pLuaFile)
{
m_aListeners.remove(r.front());
}
}
}*/
@@ -0,0 +1,109 @@
#ifndef GAME_LUAEVENT_H
#define GAME_LUAEVENT_H

#include <base/tl/array.h>
#include <lua.hpp>
#include "client/lua.h"

//storage class for the event variables

class CEventVariable
{
int m_Type;
void *m_pData;
int m_Size;
void Allocate(int Size);
public:
CEventVariable();
~CEventVariable();
void Set(int Value);
void Set(long int Value);
void Set(lua_Number Value);
void Set(float Value);
void Set(bool Value);
void Set(char Value);
void Set(const char *pStr);
void Set(const char *pData, int Size);
void *Get();
int GetSize();
int GetInteger();
float GetFloat();
bool GetBool();
char GetChar();
char *GetString();
int GetType();
bool IsNumeric();
void Reset();

enum
{
EVENT_TYPE_INVALID = 0,
EVENT_TYPE_INTEGER = 1,
EVENT_TYPE_FLOAT = 2,
EVENT_TYPE_BOOL = 4,
EVENT_TYPE_CHAR = 8,
EVENT_TYPE_STRING = 16,
EVENT_TYPE_DATA = 32
};
};


#define MAX_EVENT_VARIABLES 64
class CEvent
{
public:
CEvent()
{
Reset();
}
CEventVariable m_aVars[MAX_EVENT_VARIABLES];
void Reset();
CEventVariable *FindFree();
};
/*
template <class T>
class CLuaEventListener
{
struct CLuaListenerData
{
T *m_pLuaFile;
char m_aLuaFunction[256];
char m_aEvent[256];
bool operator==(const CLuaListenerData &Other) { return this == &Other; }
};
typedef array<CLuaListenerData> TEventList;
TEventList m_aListeners;
public:
void AddEventListener(T *pLuaFile, char *pEvent, char *pLuaFunction);
void RemoveEventListener(T *pLuaFile, char *pEvent);
void RemoveAllEventListeners(T *pLuaFile);
void OnEvent(const char *pEvent);
#define EVENTSTACKSIZE 32
int m_StackSize;
CEvent m_aStackParameters[EVENTSTACKSIZE];
CEvent m_aStackReturns[EVENTSTACKSIZE];
int CreateEventStack() { return ++m_StackSize; }
CEvent *GetParameters(int StackIndex)
{
if (StackIndex < 0 || StackIndex >= EVENTSTACKSIZE)
return 0;
return &m_aStackParameters[StackIndex];
}
CEvent *GetReturns(int StackIndex)
{
if (StackIndex < 0 || StackIndex >= EVENTSTACKSIZE)
return 0;
return &m_aStackReturns[StackIndex];;
}
CLuaEventListener() { m_aListeners.clear(); m_StackSize = -1; }
~CLuaEventListener() { m_aListeners.clear(); }
};*/

#endif
@@ -0,0 +1,106 @@
//some macros and helperfunctions
#include <stdlib.h>
#include <string.h>
#include <time.h>

#ifndef GAME_LUAGLOBAL_H
#define GAME_LUAGLOBAL_H


#if defined(LUA_USE_GMTIME_R)

#define l_gmtime(t,r) gmtime_r(t,r)
#define l_localtime(t,r) localtime_r(t,r)

#elif !defined(l_gmtime)

#define l_gmtime(t,r) ((void)r, gmtime(t))
#define l_localtime(t,r) ((void)r, localtime(t))

#endif

#define LUA_FUNCTION_HEADER lua_getglobal(L, "pLUA"); \
CLuaFile *pSelf = (CLuaFile *)lua_touserdata(L, -1); \
lua_Debug Frame; \
lua_getstack(L, 1, &Frame); \
lua_getinfo(L, "nlSf", &Frame); \
((void)(pSelf));

#if !defined(LUA_USE_POSIX)
#define LUA_STRFTIMEOPTIONS { "aAbBcdHIjmMpSUwWxXyYz%", "" }
#else
#define LUA_STRFTIMEOPTIONS \
{ "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%", "" \
"", "E", "cCxXyY", \
"O", "deHImMSuUVwWy" }
#endif

static void setfield (lua_State *L, const char *key, int value)
{
lua_pushinteger(L, value);
lua_setfield(L, -2, key);
}

static void setboolfield (lua_State *L, const char *key, int value)
{
if (value < 0) /* undefined? */
return; /* does not set field */
lua_pushboolean(L, value);
lua_setfield(L, -2, key);
}

static int getboolfield (lua_State *L, const char *key)
{
int res;
lua_getfield(L, -1, key);
res = lua_isnil(L, -1) ? -1 : lua_toboolean(L, -1);
lua_pop(L, 1);
return res;
}


static int getfield (lua_State *L, const char *key, int d)
{
int res, isnum;
lua_getfield(L, -1, key);
res = (int)lua_tointegerx(L, -1, &isnum);
if (!isnum)
{
if (d < 0)
return luaL_error(L, "field " LUA_QS " missing in date table", key);
res = d;
}
lua_pop(L, 1);
return res;
}


static const char *checkoption (lua_State *L, const char *conv, char *buff)
{
static const char *const options[] = LUA_STRFTIMEOPTIONS;
unsigned int i;
for (i = 0; i < sizeof(options)/sizeof(options[0]); i += 2)
{
if (*conv != '\0' && strchr(options[i], *conv) != NULL)
{
buff[1] = *conv;
if (*options[i + 1] == '\0') /* one-char conversion specifier? */
{
buff[2] = '\0'; /* end buffer */
return conv + 1;
}
else if (*(conv + 1) != '\0' &&
strchr(options[i + 1], *(conv + 1)) != NULL)
{
buff[2] = *(conv + 1); /* valid two-char conversion specifier */
buff[3] = '\0'; /* end buffer */
return conv + 2;
}
}
}
luaL_argerror(L, 1,
lua_pushfstring(L, "invalid conversion specifier '%%%s'", conv));
return conv; /* to avoid warnings */
}

#endif
@@ -0,0 +1,313 @@
#include "luamap.h"
#include <base/math.h>
/*DGI:Doc-Gen-Info*/
/*DGI:Type:Map*/
/*DGI:Exception:errorfunc*/
#include <lua.hpp>

#define LUA_FUNCTION_HEADER lua_getglobal(L, "pLUA"); \
CLuaMapFile *pSelf = (CLuaMapFile *)lua_touserdata(L, -1); \
lua_Debug Frame; \
lua_getstack(L, 1, &Frame); \
lua_getinfo(L, "nlSf", &Frame); \
((void)(pSelf));

int CLuaMapFile::StrIsInteger(const char *pStr)
{
while(*pStr)
{
if(!(*pStr >= '0' && *pStr <= '9'))
return 0;
pStr++;
}
return 1;
}

int CLuaMapFile::StrIsFloat(const char *pStr)
{
bool Dot = false;
while(*pStr)
{
if(*pStr < '0' || *pStr > '9')
{
if(!Dot && *pStr == '.')
Dot = true;
else
return 0;
}
pStr++;
}
return 1;
}

void CLuaMapFile::PushString(const char *pString)
{
if (m_pLua == 0)
return;
lua_pushstring(m_pLua, pString);
m_FunctionVarNum++;
}

void CLuaMapFile::PushData(const char *pData, int Size)
{
if (m_pLua == 0)
return;
lua_pushlstring(m_pLua, pData, Size);
m_FunctionVarNum++;
}

void CLuaMapFile::PushInteger(int value)
{
if (m_pLua == 0)
return;
lua_pushinteger(m_pLua, value);
m_FunctionVarNum++;
}

void CLuaMapFile::PushFloat(float value)
{
if (m_pLua == 0)
return;
lua_pushnumber(m_pLua, value);
m_FunctionVarNum++;
}

void CLuaMapFile::PushBoolean(bool value)
{
if (m_pLua == 0)
return;
lua_pushboolean(m_pLua, value);
m_FunctionVarNum++;
}

void CLuaMapFile::PushParameter(const char *pString)
{
if (m_pLua == 0)
return;
if (StrIsInteger(pString))
{
PushInteger(str_toint(pString));
}
else if (StrIsFloat(pString))
{
PushInteger(str_tofloat(pString));
}
else
{
PushString(pString);
}

}

bool CLuaMapFile::FunctionExist(const char *pFunctionName)
{
bool Ret = false;
if (m_pLua == 0)
return false;
lua_getglobal(m_pLua, ToLower(pFunctionName));
Ret = lua_isfunction(m_pLua, -1);
lua_pop(m_pLua, 1);
return Ret;
}

void CLuaMapFile::FunctionPrepare(const char *pFunctionName)
{
if (m_pLua == 0)
return;

//lua_pushstring (m_pLua, pFunctionName);
//lua_gettable (m_pLua, LUA_GLOBALSINDEX);
lua_getglobal(m_pLua, ToLower(pFunctionName));
m_FunctionVarNum = 0;
}

int CLuaMapFile::FunctionExec(const char *pFunctionName)
{
if (m_pLua == 0)
return 0;

if (pFunctionName)
{
if (FunctionExist(pFunctionName) == false)
return 0;
FunctionPrepare(pFunctionName);
}
int Ret = lua_pcall(m_pLua, m_FunctionVarNum, LUA_MULTRET, 0);
if (Ret)
ErrorFunc(m_pLua);
m_FunctionVarNum = 0;
return Ret;
}

CLuaMapFile::CLuaMapFile(CTile *pTiles, const char *pCode, int Width, int Height)
{
m_pTiles = pTiles;
m_pLua = luaL_newstate();
luaL_openlibs(m_pLua);

m_Width = Width;
m_Height = Height;

//lua_atpanic(m_pLua, &Panic); //Todo

lua_pushlightuserdata(m_pLua, this);
lua_setglobal(m_pLua, "pLUA");

lua_register(m_pLua, ToLower("errorfunc"), this->ErrorFunc);
lua_register(m_pLua, ToLower("GetTile"), this->GetTile);
lua_register(m_pLua, ToLower("SetTile"), this->SetTile);
lua_register(m_pLua, ToLower("GetFlag"), this->GetFlag);
lua_register(m_pLua, ToLower("SetFlag"), this->SetFlag);
lua_register(m_pLua, ToLower("GetWidth"), this->GetWidth);
lua_register(m_pLua, ToLower("GetHeight"), this->GetHeight);


luaL_dostring(m_pLua, pCode);
ErrorFunc(m_pLua);
}

CLuaMapFile::~CLuaMapFile()
{
if (m_pLua)
lua_close(m_pLua);
m_pLua = 0;
}

void CLuaMapFile::Tick(int ServerTick)
{
FunctionPrepare("Tick");
PushInteger((int)(time_get() * 1000 / time_freq())); //time in ms
PushInteger(ServerTick);
FunctionExec();
}

int CLuaMapFile::GetTile(lua_State *L)
{
LUA_FUNCTION_HEADER
if (lua_isnumber(L, 1) && lua_isnumber(L, 2))
{
if (lua_tointeger(L, 1) < 0)
return 0;
if (lua_tointeger(L, 1) >= pSelf->m_Width)
return 0;
if (lua_tointeger(L, 2) < 0)
return 0;
if (lua_tointeger(L, 2) >= pSelf->m_Height)
return 0;
lua_pushinteger(L, pSelf->m_pTiles[lua_tointeger(L, 2) * pSelf->m_Width + lua_tointeger(L, 1)].m_Index);
return 1;
}
return 0;
}

int CLuaMapFile::SetTile(lua_State *L)
{
LUA_FUNCTION_HEADER
if (lua_isnumber(L, 1) && lua_isnumber(L, 2) && lua_isnumber(L, 3))
{
if (lua_tointeger(L, 1) < 0)
return 0;
if (lua_tointeger(L, 1) >= pSelf->m_Width)
return 0;
if (lua_tointeger(L, 2) < 0)
return 0;
if (lua_tointeger(L, 2) >= pSelf->m_Height)
return 0;
pSelf->m_pTiles[lua_tointeger(L, 2) * pSelf->m_Width + lua_tointeger(L, 1)].m_Index = clamp((int)lua_tointeger(L, 3), 0, 255);
return 0;
}
return 0;
}

int CLuaMapFile::GetFlag(lua_State *L)
{
LUA_FUNCTION_HEADER
return 0;
}

int CLuaMapFile::SetFlag(lua_State *L)
{
LUA_FUNCTION_HEADER
return 0;
}

int CLuaMapFile::GetWidth(lua_State *L)
{
LUA_FUNCTION_HEADER
lua_pushinteger(L, pSelf->m_Width);
return 1;
}

int CLuaMapFile::GetHeight(lua_State *L)
{
LUA_FUNCTION_HEADER
lua_pushinteger(L, pSelf->m_Height);
return 1;
}

int CLuaMapFile::ErrorFunc(lua_State *L)
{
lua_getglobal(L, "pLUA");
CLuaMapFile *pSelf = (CLuaMapFile *)lua_touserdata(L, -1);
((void)(pSelf));

lua_pop(L,1);

int depth = 0;
int frameskip = 1;
lua_Debug frame;

if (lua_tostring(L, -1) == 0)
return 0;

dbg_msg("LuaMap", lua_tostring(L, -1));

dbg_msg("LuaMap", "Backtrace:");
while(lua_getstack(L, depth, &frame) == 1)
{
depth++;

lua_getinfo(L, "nlSf", &frame);

/* check for functions that just report errors. these frames just confuses more then they help */
if(frameskip && str_comp(frame.short_src, "[C]") == 0 && frame.currentline == -1)
continue;
frameskip = 0;

/* print stack frame */
dbg_msg("LuaMap", "%s(%d): %s %s", frame.short_src, frame.currentline, frame.name, frame.namewhat);
}
lua_pop(L, 1); // remove error message
lua_gc(L, LUA_GCCOLLECT, 0);
return 0;
}



CLuaMap::CLuaMap()
{
//m_pEventListener = new CLuaEventListener<CLuaMapFile>();
}

CLuaMap::~CLuaMap()
{
Clear();
}

void CLuaMap::Tick(int ServerTick, CTile *pTiles)
{
for (int i = 0; i < m_lLuaMapFiles.size(); i++)
{
if (m_lLuaMapFiles[i]->m_pTiles == pTiles || pTiles == 0)
m_lLuaMapFiles[i]->Tick(ServerTick);
}
}

void CLuaMap::Clear()
{
for (int i = 0; i < m_lLuaMapFiles.size(); i++)
{
delete m_lLuaMapFiles[i];
}
m_lLuaMapFiles.clear();
}
@@ -0,0 +1,58 @@
#ifndef GAME_LUAMAP_H
#define GAME_LUAMAP_H

#include <game/luaevent.h>
#include <game/mapitems.h>
#include <base/tl/array.h>

#include <lua.hpp>

class CLuaMapFile
{
int StrIsInteger(const char *pStr);
int StrIsFloat(const char *pStr);

bool FunctionExist(const char *pFunctionName);
int FunctionExec(const char *pFunctionName = 0);
void FunctionPrepare(const char *pFunctionName);
void PushString(const char *pString);
void PushData(const char *pData, int Size);
void PushInteger(int value);
void PushFloat(float value);
void PushBoolean(bool value);
void PushParameter(const char *pString);
int m_FunctionVarNum;

public:
CLuaMapFile(CTile *pTiles, const char *pCode, int Width, int Height);
~CLuaMapFile();
CTile *m_pTiles;
int m_Width;
int m_Height;
lua_State *m_pLua;
void Tick(int ServerTick);


static int ErrorFunc(lua_State *L);
static int GetTile(lua_State *L);
static int SetTile(lua_State *L);
static int GetFlag(lua_State *L);
static int SetFlag(lua_State *L);
static int GetWidth(lua_State *L);
static int GetHeight(lua_State *L);
};

class CLuaMap
{
public:
CLuaMap();
~CLuaMap();
void Tick(int ServerTick, CTile *pTiles = 0);
void Clear();

array<CLuaMapFile *> m_lLuaMapFiles;

//class CLuaEventListener<CLuaMapFile> *m_pEventListener;
};

#endif
@@ -165,6 +165,8 @@ MACRO_CONFIG_INT(ClIRCSound, cl_irc_sound, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE,
MACRO_CONFIG_INT(ClAllowJoin, cl_irc_allow_join, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Allow others to request the server you're playing on")
//
MACRO_CONFIG_INT(ClUiShowExtraBar, cl_ui_extra_bar, 0, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Show the extra bar")
//
MACRO_CONFIG_INT(ClLua, cl_lua, 1, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SAVE, "Enable Lua")


// translator stuff