/***************************************************************************
* _/_/_/_/ _/ _/ _/_/_/_/ _/_/_/_/ AckFUSS is modified ACK!MUD 4.3.1 *
* _/ _/ _/ _/ _/ copyright Matt Goff (Kline) 2008 *
* _/_/ _/ _/ _/_/_/_/ _/_/_/_/ *
* _/ _/ _/ _/ _/ Support for this code is provided *
* _/ _/_/_/_/ _/_/_/_/ _/_/_/_/ at www.ackmud.net -- check it out!*
***************************************************************************/
/* Lua embedding inspired by Nick Gammon's work on Smaug */
#include "h/globals.h"
#ifndef DEC_ACT_WIZ_H
#include "h/act_wiz.h"
#endif
#ifndef DEC_COMM_H
#include "h/comm.h"
#endif
#ifndef DEC_DB_H
#include "h/db.h"
#endif
#ifndef DEC_HANDLER_H
#include "h/handler.h"
#endif
#ifndef DEC_LUASCRIPT_H
#include "h/luascript.h"
#endif
#define CH_STATE "ch.state"
#define OBJ_STATE "obj.state"
#define ROOM_STATE "room.state"
#define MUD_LIBRARY "mud"
#define CH_STARTUP SCRIPT_DIR "ch_startup.lua"
#define OBJ_STARTUP SCRIPT_DIR "obj_startup.lua"
#define ROOM_STARTUP SCRIPT_DIR "room_startup.lua"
#define PUSH_STR(from,x) \
lua_pushstring(L,from->x); \
lua_setfield(L,-2,#x)
#define PUSH_STRA(from,x,max) \
lua_newtable(L); \
for( int i = 0; i < max; ) \
{ \
lua_pushstring(L,from->x[i]); \
i++; \
lua_rawseti(L,-2,i); \
} \
lua_setfield(L,-2,#x)
#define PUSH_NUM(from,x) \
lua_pushnumber(L,from->x); \
lua_setfield(L,-2,#x)
#define PUSH_NUMA(from,x,max) \
lua_newtable(L); \
for( int i = 0; i < max; ) \
{ \
lua_pushnumber(L,from->x[i]); \
i++; \
lua_rawseti(L,-2,i); \
} \
lua_setfield(L,-2,#x)
static const struct luaL_reg mudlib [] =
{
{"char_info", L_character_info},
{"obj_info", L_obj_info },
{"room_info", L_room_info },
{"send_to_char", L_send_to_char },
{"recho", L_recho },
{NULL, NULL}
};
void init_lua( CHAR_DATA *ch )
{
ch->lua->owner = ch;
ch->lua->type = LUA_TYPE_CH;
luaL_openlibs(ch->lua->L); /* open all standard libraries */
/* call as Lua function because we need the environment */
lua_pushcfunction(ch->lua->L,RegisterLuaRoutines);
lua_pushstring(ch->lua->L,CH_STATE); /* push address */
lua_pushlightuserdata(ch->lua->L,(void *)ch); /* push value */
lua_call(ch->lua->L,2,0);
/* run initialiation script */
if( luaL_loadfile(ch->lua->L,CH_STARTUP) || CallLuaWithTraceBack(ch->lua->L,0,0) )
{
const char * sError = lua_tostring(ch->lua->L,-1);
snprintf(log_buf,(2 * MIL),"Error loading ch Lua startup file:\n %s\n",sError);
monitor_chan(log_buf,MONITOR_DEBUG);
}
lua_settop(ch->lua->L,0); /* get rid of stuff lying around */
return;
}
void init_lua( OBJ_DATA *obj )
{
obj->lua->owner = obj;
obj->lua->type = LUA_TYPE_OB;
luaL_openlibs(obj->lua->L);
lua_pushcfunction(obj->lua->L,RegisterLuaRoutines);
lua_pushstring(obj->lua->L,OBJ_STATE);
lua_pushlightuserdata(obj->lua->L,(void *)obj);
lua_call(obj->lua->L,2,0);
if( luaL_loadfile(obj->lua->L,OBJ_STARTUP) || CallLuaWithTraceBack(obj->lua->L,0,0) )
{
const char * sError = lua_tostring(obj->lua->L,-1);
snprintf(log_buf,(2 * MIL),"Error loading obj Lua startup file:\n %s\n",sError);
monitor_chan(log_buf,MONITOR_DEBUG);
}
lua_settop(obj->lua->L,0);
return;
}
void init_lua( ROOM_INDEX_DATA *room )
{
room->lua->owner = room;
room->lua->type = LUA_TYPE_RM;
luaL_openlibs(room->lua->L);
lua_pushcfunction(room->lua->L,RegisterLuaRoutines);
lua_pushstring(room->lua->L,ROOM_STATE);
lua_pushlightuserdata(room->lua->L,(void *)room);
lua_call(room->lua->L,2,0);
if( luaL_loadfile(room->lua->L,ROOM_STARTUP) || CallLuaWithTraceBack(room->lua->L,0,0) )
{
const char * sError = lua_tostring(room->lua->L,-1);
snprintf(log_buf,(2 * MIL),"Error loading room Lua startup file:\n %s\n",sError);
monitor_chan(log_buf,MONITOR_DEBUG);
}
lua_settop(room->lua->L,0);
return;
}
lua_State *find_lua_function( CHAR_DATA *ch, string arg )
{
lua_State *L = ch->lua->L;
if( !L || arg.empty() )
return NULL; /* can't do it */
/* find requested function */
lua_getglobal(L,arg.c_str());
if( !lua_isfunction(L,-1) )
{
lua_pop(L,1);
snprintf(log_buf,(2 * MIL),"Warning: Lua script function '%s' does not exist",arg.c_str());
monitor_chan(log_buf,MONITOR_DEBUG);
return NULL; /* not there */
}
return L;
}
lua_State *find_lua_function( OBJ_DATA *ob, string arg )
{
lua_State *L = ob->lua->L;
if( !L || arg.empty() )
return NULL; /* can't do it */
/* find requested function */
lua_getglobal(L,arg.c_str());
if( !lua_isfunction(L,-1) )
{
lua_pop(L,1);
snprintf(log_buf,(2 * MIL),"Warning: Lua script function '%s' does not exist",arg.c_str());
monitor_chan(log_buf,MONITOR_DEBUG);
return NULL; /* not there */
}
return L;
}
lua_State *find_lua_function( ROOM_INDEX_DATA *rm, string arg )
{
lua_State *L = rm->lua->L;
if( !L || arg.empty() )
return NULL; /* can't do it */
/* find requested function */
lua_getglobal(L,arg.c_str());
if( !lua_isfunction(L,-1) )
{
lua_pop(L,1);
snprintf(log_buf,(2 * MIL),"Warning: Lua script function '%s' does not exist",arg.c_str());
monitor_chan(log_buf,MONITOR_DEBUG);
return NULL; /* not there */
}
return L;
}
void call_lua_function( lua_State *L, string str, const int nArgs )
{
if( CallLuaWithTraceBack(L,nArgs,0) )
{
snprintf(log_buf,(2 * MIL),"Error executing Lua function %s:\n %s",str.c_str(),lua_tostring(L,-1));
monitor_chan(log_buf,MONITOR_DEBUG);
lua_pop(L,1); /* pop error */
} /* end of error */
return;
}
int RegisterLuaRoutines( lua_State *L )
{
lua_newtable(L); /* environment */
lua_replace(L,LUA_ENVIRONINDEX);
/* this makes environment variable "ch.state" by the pointer to our character */
lua_settable(L,LUA_ENVIRONINDEX);
/* register all mud.xxx routines */
luaL_register(L,MUD_LIBRARY,mudlib);
/* using interpret now
RegisterLuaCommands (L);
*/
return 0;
}
int CallLuaWithTraceBack( lua_State *L, const int iArguments, const int iReturn )
{
int error;
int base = lua_gettop(L) - iArguments; /* function index */
GetTracebackFunction(L);
if( lua_isnil(L,-1) )
{
lua_pop(L,1); /* pop non-existent function */
error = lua_pcall(L,iArguments,iReturn,0);
}
else
{
lua_insert(L,base); /* put it under chunk and args */
error = lua_pcall(L,iArguments,iReturn,base);
lua_remove(L,base); /* remove traceback function */
}
return error;
}
void GetTracebackFunction( lua_State *L )
{
lua_pushliteral(L,LUA_DBLIBNAME); /* "debug" */
lua_rawget(L,LUA_GLOBALSINDEX); /* get debug library */
if( !lua_istable(L,-1) )
{
lua_pop(L,2); /* pop result and debug table */
lua_pushnil(L);
return;
}
/* get debug.traceback */
lua_pushstring(L,"traceback");
lua_rawget(L,-2); /* get traceback function */
if( !lua_isfunction(L,-1) )
{
lua_pop(L,2); /* pop result and debug table */
lua_pushnil(L);
return;
}
lua_remove (L, -2); /* remove debug table, leave traceback function */
}
ROOM_INDEX_DATA *L_getroom( lua_State *L )
{
CHAR_DATA *ch;
OBJ_DATA *ob;
ROOM_INDEX_DATA *rm;
LUA_DATA *lua;
list<LUA_DATA *>::iterator li;
for( li = lua_list.begin(); li != lua_list.end(); li++ )
{
lua = *li;
switch( lua->type )
{
default:
{
snprintf(log_buf,(2 * MIL),"Invalid Lua owner type in lua_list: %d",lua->type);
monitor_chan(log_buf,MONITOR_DEBUG);
return NULL;
}
case LUA_TYPE_CH:
{
ch = static_cast<CHAR_DATA *>(lua->owner);
if( ch->lua->L == L )
{
lua_pushstring(L,CH_STATE);
lua_gettable(L,LUA_ENVIRONINDEX);
lua_pop(L,1);
return ch->in_room;
}
}
case LUA_TYPE_OB:
{
ob = static_cast<OBJ_DATA *>(lua->owner);
if( ob->lua->L == L )
{
lua_pushstring(L,OBJ_STATE);
lua_gettable(L,LUA_ENVIRONINDEX);
lua_pop(L,1);
return in_loc(ob);
}
}
case LUA_TYPE_RM:
{
rm = static_cast<ROOM_INDEX_DATA *>(lua->owner);
if( rm->lua->L == L )
{
lua_pushstring(L,ROOM_STATE);
lua_gettable(L,LUA_ENVIRONINDEX);
lua_pop(L,1);
return rm;
}
}
}
}
return NULL;
}
CHAR_DATA *L_getchar( lua_State *L )
{
/* retrieve our character */
CHAR_DATA * ch;
/* retrieve the character */
lua_pushstring(L,CH_STATE); /* push address */
lua_gettable(L,LUA_ENVIRONINDEX); /* retrieve value */
ch = (CHAR_DATA *)lua_touserdata(L,-1); /* convert to data */
lua_pop(L,1); /* pop result */
return ch;
}
int L_character_info( lua_State *L )
{
CHAR_DATA *ch = NULL;
bool found = false;
list<LUA_DATA *>::iterator li;
LUA_DATA *lua = NULL;
for( li = lua_list.begin(); li != lua_list.end(); li++ )
{
lua = *li;
if( lua->type == LUA_TYPE_CH )
{
ch = static_cast<CHAR_DATA *>(lua->owner);
if( ch->lua->L == L )
found = true;
}
}
if( !found )
return 0;
lua_newtable(L); /* table for the info */
/* strings */
PUSH_STR(ch,description.c_str());
PUSH_STR(ch,long_descr.c_str());
PUSH_STR(ch,long_descr_orig.c_str());
PUSH_STR(ch,name.c_str());
PUSH_STR(ch,old_prompt.c_str());
PUSH_STR(ch,prompt.c_str());
PUSH_STR(ch,searching.c_str());
/* numbers */
PUSH_NUM(ch,alignment);
PUSH_NUM(ch,armor);
PUSH_NUM(ch,carry_number);
PUSH_NUM(ch,carry_weight);
PUSH_NUM(ch,clan);
PUSH_NUMA(ch,cooldown,MAX_COOLDOWN);
PUSH_NUM(ch,damroll);
PUSH_NUM(ch,exp);
PUSH_NUM(ch,hit);
PUSH_NUM(ch,hitroll);
PUSH_NUM(ch,level);
PUSH_NUMA(ch,lvl,MAX_CLASS);
PUSH_NUMA(ch,lvl2,MAX_CLASS);
PUSH_NUM(ch,mana);
PUSH_NUM(ch,max_hit);
PUSH_NUM(ch,max_mana);
PUSH_NUM(ch,max_move);
PUSH_NUM(ch,move);
PUSH_NUM(ch,npc);
PUSH_NUM(ch,num_followers);
PUSH_NUM(ch,played);
PUSH_NUM(ch,poly_level);
PUSH_NUM(ch,position);
PUSH_NUM(ch,p_class);
PUSH_NUM(ch,race);
PUSH_NUM(ch,saving_throw);
PUSH_NUM(ch,sex);
PUSH_NUMA(ch,speed,MAX_SPEED);
PUSH_NUM(ch,stance);
PUSH_NUM(ch,stun_timer);
PUSH_NUM(ch,switched);
PUSH_NUM(ch,timer);
PUSH_NUM(ch,trust);
PUSH_NUM(ch,wait);
PUSH_NUM(ch,wimpy);
PUSH_NUM(ch,wizbit);
if( !IS_NPC(ch) )
{
lua_newtable(L);
/* strings */
PUSH_STR(ch->pcdata,assist_msg);
PUSH_STR(ch->pcdata,bamfin);
PUSH_STR(ch->pcdata,bamfout);
PUSH_STR(ch->pcdata,email_address);
PUSH_STR(ch->pcdata,load_msg);
PUSH_STR(ch->pcdata,room_enter);
PUSH_STR(ch->pcdata,room_exit);
PUSH_STR(ch->pcdata,title);
PUSH_STR(ch->pcdata,who_name);
/* numbers */
PUSH_NUM(ch->pcdata,adept_level);
PUSH_NUMA(ch->pcdata,condition,MAX_COND);
PUSH_NUM(ch->pcdata,death_cnt);
PUSH_NUM(ch->pcdata,invis);
PUSH_NUMA(ch->pcdata,learned,MAX_SKILL);
PUSH_NUM(ch->pcdata,max_con);
PUSH_NUM(ch->pcdata,max_dex);
PUSH_NUM(ch->pcdata,max_int);
PUSH_NUM(ch->pcdata,max_str);
PUSH_NUM(ch->pcdata,max_wis);
PUSH_NUM(ch->pcdata,mod_con);
PUSH_NUM(ch->pcdata,mod_dex);
PUSH_NUM(ch->pcdata,mod_int);
PUSH_NUM(ch->pcdata,mod_str);
PUSH_NUM(ch->pcdata,mod_wis);
PUSH_NUMA(ch->pcdata,order,MAX_CLASS);
PUSH_NUM(ch->pcdata,perm_con);
PUSH_NUM(ch->pcdata,perm_dex);
PUSH_NUM(ch->pcdata,perm_int);
PUSH_NUM(ch->pcdata,perm_str);
PUSH_NUM(ch->pcdata,perm_wis);
PUSH_NUM(ch->pcdata,practice);
PUSH_NUM(ch->pcdata,quest_points);
PUSH_NUM(ch->pcdata,recall_vnum);
PUSH_NUM(ch->pcdata,ruler_rank);
PUSH_NUM(ch->pcdata,sentence);
lua_setfield(L,-2,"pcdata");
}
else
{
lua_newtable(L);
/* strings */
PUSH_STR(ch->npcdata,short_descr);
/* numbers */
PUSH_NUM(ch->npcdata,cast);
PUSH_NUM(ch->npcdata,def);
PUSH_NUM(ch->npcdata,extract_timer);
PUSH_NUM(ch->npcdata,resist);
PUSH_NUM(ch->npcdata,skills);
PUSH_NUM(ch->npcdata,strong_magic);
PUSH_NUM(ch->npcdata,suscept);
PUSH_NUM(ch->npcdata,weak_magic);
lua_setfield(L,-2,"npcdata");
}
return 1;
}
int L_obj_info( lua_State *L )
{
OBJ_DATA *ob = NULL;
bool found = false;
list<LUA_DATA *>::iterator li;
LUA_DATA *lua = NULL;
for( li = lua_list.begin(); li != lua_list.end(); li++ )
{
lua = *li;
if( lua->type == LUA_TYPE_OB )
{
ob = static_cast<OBJ_DATA *>(lua->owner);
if( ob->lua->L == L )
found = true;
}
}
if( !found )
return 0;
lua_newtable(L);
PUSH_STR(ob,owner);
PUSH_STR(ob,name);
PUSH_STR(ob,script_name);
PUSH_STR(ob,short_descr);
PUSH_STR(ob,long_descr);
PUSH_NUM(ob,item_type);
PUSH_NUM(ob,item_apply);
PUSH_NUM(ob,wear_loc);
PUSH_NUM(ob,weight);
PUSH_NUM(ob,cost);
PUSH_NUM(ob,level);
PUSH_NUM(ob,timer);
PUSH_NUMA(ob,value,MAX_OBJ_VALUE);
PUSH_NUM(ob,durability);
PUSH_NUM(ob,max_durability);
PUSH_NUM(ob,speed);
return 1;
}
int L_room_info( lua_State *L )
{
ROOM_INDEX_DATA *rm = NULL;
bool found = false;
list<LUA_DATA *>::iterator li;
LUA_DATA *lua = NULL;
for( li = lua_list.begin(); li != lua_list.end(); li++ )
{
lua = *li;
if( lua->type == LUA_TYPE_RM )
{
rm = static_cast<ROOM_INDEX_DATA *>(lua->owner);
if( rm->lua->L == L )
found = true;
}
}
if( !found )
return 0;
lua_newtable(L);
PUSH_STR(rm,description);
PUSH_STR(rm,name);
PUSH_STR(rm,script_name);
PUSH_NUM(rm,affected_by);
PUSH_NUM(rm,light);
PUSH_NUM(rm,sector_type);
PUSH_NUM(rm,vnum);
return 1;
}
int L_send_to_char( lua_State *L )
{
send_to_char(luaL_checkstring(L,1),L_getchar(L));
return 0;
}
int L_recho( lua_State *L )
{
recho(L_getroom(L),luaL_checkstring(L,1));
return 0;
}
void call_lua( LUA_DATA *lua, string str, string arg )
{
if( lua )
{
if( lua->type == LUA_TYPE_CH )
call_lua(static_cast<CHAR_DATA *>(lua->owner),str,arg);
else if( lua->type == LUA_TYPE_OB )
call_lua(static_cast<OBJ_DATA *>(lua->owner),str,arg);
else if( lua->type == LUA_TYPE_RM )
call_lua(static_cast<ROOM_INDEX_DATA *>(lua->owner),str,arg);
else
monitor_chan("Invalid Lua type in call_lua().",MONITOR_DEBUG);
}
}
void call_lua( CHAR_DATA *ch, string str, string arg )
{
int cnt = 0;
if( !ch || str.empty() ) /* note, argument is OPTIONAL */
return;
lua_State *L = find_lua_function(ch,str.c_str());
if( !L )
return;
/* if they want to send an argument, push it now */
if( !arg.empty() )
{
cnt++;
lua_pushstring(L,arg.c_str()); /* push argument, if any */
}
call_lua_function(L,str,cnt);
return;
}
void call_lua( OBJ_DATA *ob, string str, string arg )
{
int cnt = 0;
if( !ob || str.empty() ) /* note, argument is OPTIONAL */
return;
lua_State *L = find_lua_function(ob,str.c_str());
if( !L )
return;
/* if they want to send an argument, push it now */
if( !arg.empty() )
{
cnt++;
lua_pushstring(L,arg.c_str()); /* push argument, if any */
}
call_lua_function(L,str,cnt);
return;
}
void call_lua( ROOM_INDEX_DATA *rm, string str, string arg )
{
int cnt = 0;
if( !rm || str.empty() ) /* note, argument is OPTIONAL */
return;
lua_State *L = find_lua_function(rm,str.c_str());
if( !L )
return;
/* if they want to send an argument, push it now */
if( !arg.empty() )
{
cnt++;
lua_pushstring(L,arg.c_str()); /* push argument, if any */
}
call_lua_function(L,str,cnt);
return;
}