function do_color(txt)
buf = txt
colors = {}
colors["{x"] = "\e = "\e[0m"
colors["{r"] = "\e[0;31m"
colors["{g"] = "\e[0;32m"
colors["{y"] = "\e[0;33m"
colors["{b"] = "\e[0;34m"
colors["{m"] = "\e[0;35m"
colors["{c"] = "\e[0;36m"
colors["{w"] = "\e[0;37m"
colors["{d"] = "\e[1;30m"
colors["{R"] = "\e[0;31m"
colors["{G"] = "\e[0;32m"
colors["{Y"] = "\e[0;33m"
colors["{B"] = "\e[0;34m"
colors["{M"] = "\e[0;35m"
colors["{C"] = "\e[0;36m"
colors["{W"] = "\e[0;37m"
colors["{D"] = "\e[1;30m"
– gsub takes care of everything using key(k) to value(v)
for k,v in pairs(colors) do buf = string.gsub(buf, k, v) end
return buf
end
[/code]
– new area
a = area.new()
a:set_name("The Shire")
a:set_desc("A super cool area.")
– add room
r = room.new()
r:set_vnum("shire.bagend-entrance")
r:set_name("Bagend")
r:set_desc("You are in bagend, it's really cool.")
– exits
r:add_exit("west", "shire.bagend-bedroom", 0)
r:add_exit("east", "shire.bagend-kitchen", 0)
– resets
r:add_reset("mob", "shire.darkelf", 5, 10)
r:add_reset("obj", "mordor.one-ring", 60, 1)
– done
a:add_room(r)
mob:name = "Orc"
mob:level = 25
Lua Error: ../lua/player.lua:5: attempt to index local 'ch' (a userdata value)
/* constructs new lua_State* for character */
void load_char_lua( CHAR_DATA *ch )
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
luaL_register(L, "mud", mudlib);
luaL_newmetatable(L, "lunacy.ch");
luaL_register(L, NULL, charlib);
if (luaL_loadfile(L, "../lua/player.lua") || lua_pcall(L, 0, 0, 0))
errorL ("LUA-ERROR [%s: %s]\r\n", __FUNCTION__, lua_tostring(L, -1));
if (L)
ch->L = L;
else
bug ("load_char_lua: bad lua state", 0);
}
// in call_lua…
lua_getglobal(L, func); /* stack: function … */
CHAR_DATA *a = (CHAR_DATA*)lua_newuserdata(L, sizeof(CHAR_DATA*));
luaL_getmetatable(L, "lunacy.ch");
lua_setmetatable(L, -3);
lua_pushstring(L, argument); /* stack: function(actor, argument) … */
err = lua_pcall(L, 2, 1, 0);
void LuaEngine::pushUD( Instance *ud, const char *meta )
{
if ( ud )
{
Instance **ptr = (Instance **)lua_newuserdata( L, sizeof(Instance**) );
*ptr = ud;
luaL_getmetatable( L, meta );
lua_setmetatable( L, -2 );
/* Lua provides a registry, a pre-defined table that can be used by any C code to store whatever Lua value it needs to store.
This table is always located at pseudo-index LUA_REGISTRYINDEX. Any C library can store data into this table,
but it should take care to choose keys different from those used by other libraries, to avoid collisions.
Typically, you should use as key a string containing your library name or a light userdata with the address of a C object in your code.
The integer keys in the registry are used by the reference mechanism, implemented by the auxiliary library, and therefore should not be used for other purposes.
*/
}
else
lua_pushnil( L );
}
void LCharacter::push( lua_State *L, Character *ch )
{
luaEngine.pushUD( ch, CHARACTER_META );
}
mob:name = "Orc"
mob:level = 25
lua_setmetatable(L, -3);
Lua Stack Dump:
(null)
(null)
(null)
(null)
Hey you guys!
Lua Error: ../lua/player.lua:5: attempt to index local 'ch' (a userdata value)
#include <stdio.h>
#include <stdarg.h>
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "merc.h"
/* global Lua state declaration, used for server calls to Lua */
lua_State *global_L;
/* errorL() a general error message handler */
void errorL (char *fmt, …)
{
CHAR_DATA *ch;
char buf[MAX_STRING_LENGTH];
va_list args;
va_start (args, fmt);
vsprintf (buf, fmt, args);
va_end (args);
for (ch = char_list; ch != NULL; ch = ch->next)
if (!IS_NPC(ch))
send_to_char(buf, ch);
}
/* stack_dump() another testing function to view contents of stack */
static void stack_dump( lua_State *L, CHAR_DATA *ch )
{
send_to_char("Lua Stack Dump:\r\n", ch);
int i;
int top = lua_gettop(L);
for ( i = 1; i <= top; i++ ) {
int t = lua_type(L, i);
switch(t) {
case LUA_TSTRING:
sendf(ch, "%s", lua_tostring(L, i));
break;
case LUA_TBOOLEAN:
sendf(ch, lua_toboolean(L, i) ? "true" : "false");
break;
case LUA_TNUMBER:
sendf(ch, "%g", lua_tostring(L, i));
break;
case LUA_TUSERDATA:
sendf(ch, "%s", lua_tostring(L, i));
break;
default:
sendf(ch, "%s", lua_tostring(L, i));
break;
}
send_to_char("\r\n", ch);
}
}
/*
* Mudlib functions: ML
* Used in the global lua_State as a call to the system: "mud.function()"
*/
/* sends a message to every player, used for testing */
static int ML_send(lua_State *L)
{
CHAR_DATA *ch;
for (ch = char_list; ch != NULL; ch = ch->next)
if (!IS_NPC(ch))
sendf(ch, "%s\r\n", luaL_checkstring(L, 1));
log_string(luaL_checkstring(L, 1));
return 0;
}
/* End of mudlib ——————————————————*/
/*
* charlib functions CHL
*/
static int CHL_send( lua_State *L )
{
CHAR_DATA *ch = (CHAR_DATA *)lua_touserdata(L, 1);
send_to_char(luaL_checkstring(L, 2), ch);
return 1;
}
/* registry for mudlib */
static const struct luaL_reg mudlib [] = {
{"send", ML_send},
{NULL, NULL}
};
/* registry for charlib */
static const struct luaL_reg charlib [] = {
{"send", CHL_send},
{NULL, NULL}
};
/* constructs global lua_State* */
void load_global_lua(void)
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
luaL_register(L, "mud", mudlib);
if (luaL_loadfile(L, "../lua/mud.lua") || lua_pcall(L, 0, 0, 0))
errorL ("LUA-ERROR [%s: %s]\r\n", __FUNCTION__, lua_tostring(L, -1));
/* global Lua state */
global_L = L;
}
int set_env( lua_State *L )
{
lua_newtable(L);
lua_replace (L, LUA_ENVIRONINDEX);
return 0;
}
/* constructs new lua_State* for character */
void load_char_lua( CHAR_DATA *ch )
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
luaL_register(L, "mud", mudlib);
luaL_newmetatable(L, "lunacy.ch");
luaL_register(L, NULL, charlib);
if (luaL_loadfile(L, "../lua/player.lua") || lua_pcall(L, 0, 0, 0))
errorL ("LUA-ERROR [%s: %s]\r\n", __FUNCTION__, lua_tostring(L, -1));
if (L)
ch->L = L;
else
bug ("load_char_lua: bad lua state", 0);
}
/* main lua interface. Hooks into lua and returns a char* string for output */
char* call_lua(lua_State *L, CHAR_DATA *actor, int call_type, char *func, char *argument)
{
int err = 0;
char *output = NULL;
switch (call_type) {
/* one text argument */
case LCALL_TEXT:
lua_getglobal(L, func); /* stack: function … */
CHAR_DATA **a = (CHAR_DATA**)lua_newuserdata(L, sizeof(CHAR_DATA**));
*a = actor;
luaL_getmetatable(L, "lunacy.ch");
lua_setmetatable(L, -2);
lua_pushstring(L, argument); /* stack: function(argument) … */
if (actor)
stack_dump(L, actor);
err = lua_pcall(L, 2, 1, 0);
if (lua_isstring(L, -1))
output = str_dup( lua_tostring(L, -1));
else
output = NULL;
break;
default:
bug("call_lua: bad call_type", 0);
}
if (err) {
errorL ("Lua Error: %s", lua_tostring(L, -1));
return NULL;
}
return (output);
}
CHAR_DATA **a = (CHAR_DATA**)lua_newuserdata(L, sizeof(CHAR_DATA**));
*a = actor;
// Now in CHL_getname()
static int CHL_getname( lua_State *L )
{
CHAR_DATA **ch = (CHAR_DATA **)lua_touserdata(L, 1);
lua_pushstring(L, ch->name);
return 1;
}
gcc -c -O -g -Wall lua_interface.c
lua_interface.c: In function `CHL_getname':
lua_interface.c:123: error: request for member `name' in something not a structure or union
static int CHL_send( lua_State *L )
{
CHAR_DATA **ch = (CHAR_DATA **)lua_touserdata(L, 1);
if (*ch)
sendf(*ch, "%s\r\n", luaL_checkstring(L, 2));
else
errorL("CHL_send: error");
return 0;
}
already is Lua code; 'ch' is a full user datum with a metatable such that it looks up sendText to know what it means. I don't have a quick example at the moment – I've been meaning to distill it from all the mess that is the full MUD system – but you can start by looking into userdata and metatables.
The idea is this:
ch:sendText("hello") <=> ch.sendText(ch, "hello")
this tries to find "sendText" in ch's metatable
sendText is a C function that takes a user datum and a string
sendText converts the user datum (which contains the globally unique ch id) to a Character* object.
It then called ch->sendText(<args>) – from the C++ side of things.