Refactor LuaScript code, split out API into separate files

This commit is contained in:
ROllerozxa 2026-03-15 22:09:12 +01:00
commit e83b594ef0
15 changed files with 3101 additions and 3034 deletions

View file

@ -110,6 +110,7 @@ file(GLOB SRCS
src/tms/modules/3ds.c
src/*.cc
src/luascript/*.cc
src/*.c
lib/GLAD/src/gl.c

File diff suppressed because it is too large Load diff

View file

@ -19,6 +19,8 @@
#define ESCRIPT_EXTERNAL_PATH_LEN 1024
extern escript *current_escript;
struct lua_State;
class receiver_base;

75
src/luascript/lua.cc Normal file
View file

@ -0,0 +1,75 @@
#include "lua.hh"
bool lua_push_stuff(lua_State *Lsrc, lua_State *Ldst, int pos)
{
if (lua_isnumber(Lsrc, pos)) {
lua_pushnumber(Ldst, lua_tonumber(Lsrc, pos));
} else if (lua_isboolean(Lsrc, pos)) {
lua_pushboolean(Ldst, lua_tonumber(Lsrc, pos));
} else if (lua_isstring(Lsrc, pos)) {
lua_pushstring(Ldst, lua_tostring(Lsrc, pos));
} else if (lua_islightuserdata(Lsrc, pos)) {
lua_pushlightuserdata(Ldst, lua_touserdata(Lsrc, pos)); // XXX: ? When will this be called? What is light userdata? :D
} else if (lua_isuserdata(Lsrc, pos)) {
lua_pushlightuserdata(Ldst, lua_touserdata(Lsrc, pos));
void *p = luaL_testudata(Lsrc, pos, "EntityMT");
if (luaL_testudata(Lsrc, pos, "EntityMT")) {
luaL_setmetatable(Ldst, "EntityMT");
} else if (luaL_testudata(Lsrc, pos, "This")) {
luaL_setmetatable(Ldst, "This");
} else {
// unknown userdata
}
} else if (lua_isnil(Lsrc, pos)) {
lua_pushnil(Ldst);
} else if (lua_istable(Lsrc, pos)) {
lua_newtable(Ldst);
lua_pushnil(Lsrc); // create place on stack to store key
if (pos < 0) {
pos = pos-1;
}
tms_assertf(lua_type(Lsrc, pos) == LUA_TTABLE, "item at stack pos is not a table");
while (lua_next(Lsrc, pos)) {
lua_push_stuff(Lsrc, Ldst, -2); // push key
lua_push_stuff(Lsrc, Ldst, -1); // push value
lua_settable(Ldst, -3); // bind the values into the table we created
lua_pop(Lsrc, 1); // pop value. we will reuse key
}
if (lua_type(Lsrc, -1) != LUA_TTABLE) {
lua_pop(Lsrc, 1); // pop key
}
} else {
// some unidentifiable argument
return false;
}
return true;
}
static char error_message[1024];
const char* lua_pop_error(lua_State *L, const char *prefix)
{
tms_assertf(lua_gettop(L) >= 1, "No error found on the stack");
const char* err_string = luaL_tolstring(L, -1, NULL);
if (err_string == 0) {
//XXX: luaL_tolstring shouldn't push anything in case of failure
lua_pop(L, 1);
return "";
}
snprintf(error_message, 1023, "%s%s", prefix, err_string);
// S: error string, error value
lua_pop(L, 2);
return error_message;
}

54
src/luascript/lua.hh Normal file
View file

@ -0,0 +1,54 @@
#pragma once
extern "C" {
#include "lua.h"
#include "lstate.h"
#include "lualib.h"
#include "lauxlib.h"
#include "eris.h"
#ifdef BUILD_LUASOCKET
#include "luasocket/luasocket.h"
#endif
}
// used for version checks
#include "world.hh"
#define lua_pushint32(L, n) (lua_pushinteger(L, static_cast<int32_t>(n)))
#define lua_pushuint32(L, n) (lua_pushinteger(L, static_cast<uint32_t>(n)))
#define ESCRIPT_VERSION_ERROR(L, function_name, version_str, version_num) \
if (W->level.version < version_num) { \
lua_pushstring(L, function_name " requires a level created with version " version_str " or above."); \
lua_error(L); \
return 0; \
}
#define ESCRIPT_FUNCTION_DEPRECATED(L, function_name, version_str, version_num) \
if (W->level.version > version_num) { \
lua_pushstring(L, function_name " has been deprecated in " version_str " and should no longer be used."); \
lua_error(L); \
return 0; \
}
#define MAX_SPRITES 512
#define TIMELIMIT 50
#define FIRST_RUN_TIMELIMIT 3000
#define FULL_SCRIPT_TIMELIMIT 5000
struct lua_vert {
tvec3 pos;
tvec2 uv;
tvec4 color;
};
/*
* Recursive function to push stuff!
* Can currently handle:
* Numbers, booleans, strings, nil, tables
*/
bool lua_push_stuff(lua_State *Lsrc, lua_State *Ldst, int pos);
const char* lua_pop_error(lua_State *L, const char *prefix);

146
src/luascript/lua_cam.cc Normal file
View file

@ -0,0 +1,146 @@
#include "lua_cam.hh"
#include "lua_game.hh"
#include "adventure.hh"
#include "game.hh"
/* cam:get_position() */
static int l_cam_get_position(lua_State *L)
{
lua_pushnumber(L, G->cam->_position.x);
lua_pushnumber(L, G->cam->_position.y);
lua_pushnumber(L, G->cam->_position.z);
return 3;
}
/* cam:get_velocity() */
static int l_cam_get_velocity(lua_State *L)
{
lua_pushnumber(L, G->cam_vel.x);
lua_pushnumber(L, G->cam_vel.y);
lua_pushnumber(L, G->cam_vel.z);
return 3;
}
/* cam:set_position(x, y, z) */
static int l_cam_set_position(lua_State *L)
{
double x = luaL_checknumber(L, 2);
double y = luaL_checknumber(L, 3);
double z = luaL_checknumber(L, 4);
G->cam->_position.z = z;
if (false && G->follow_object) {
/* camera is following something, set its relative position */
b2Vec2 fp = G->follow_object->get_position();
x -= fp.x;
y -= fp.y;
G->cam_rel_pos.x = x;
G->cam_rel_pos.y = y;
} else {
G->cam->_position.x = x;
G->cam->_position.y = y;
}
return 0;
}
/* cam:set_velocity(x, y, z) */
static int l_cam_set_velocity(lua_State *L)
{
// TODO: This probably needs to fiddle with the numbers whether the player has smooth cam enabled or not
double x = luaL_checknumber(L, 2);
double y = luaL_checknumber(L, 3);
double z = luaL_checknumber(L, 4);
G->cam_vel.x = x;
G->cam_vel.y = y;
G->cam_vel.z = z;
return 0;
}
/* cam:follow_entity(entity, snap, preserve_position) */
static int l_cam_follow_entity(lua_State *L)
{
entity *e = *(static_cast<entity**>(luaL_checkudata(L, 2, "EntityMT")));
bool snap = lua_toboolean(L, 3);
bool preserve_position = lua_toboolean(L, 4);
G->set_follow_object(e, snap, preserve_position);
return 0;
}
/* cam:follow_entity_by_id(entity_id, snap, preserve_position) */
static int l_cam_follow_entity_by_id(lua_State *L)
{
long entity_id = luaL_checklong(L, 2);
bool snap = lua_toboolean(L, 3);
bool preserve_position = lua_toboolean(L, 4);
entity *e = W->get_entity_by_id(entity_id);
if (e) {
G->set_follow_object(e, snap, preserve_position);
}
return 0;
}
/* cam:get_zoom_ratio() */
static int l_cam_get_zoom_ratio(lua_State *L)
{
float cur_z = G->cam->_position.z;
float max_z = 60.f;
float min_z = 4.f;
if (!W->level.flag_active(LVL_DISABLE_ADVENTURE_MAX_ZOOM) && !W->is_paused() && W->is_adventure() && G->follow_object == adventure::player) {
max_z = 20.f;
}
lua_pushnumber(L, tclampf((cur_z-min_z)/(max_z-min_z), 0.f, 1.f));
return 1;
}
// ---
static const luaL_Reg cam_meta[] = {
{ NULL, NULL }
};
static const luaL_Reg cam_methods[] = {
#define LUA_REG(name) { #name, l_cam_##name }
LUA_REG(get_position),
LUA_REG(get_velocity),
LUA_REG(set_position),
LUA_REG(set_velocity),
LUA_REG(follow_entity),
LUA_REG(follow_entity_by_id),
LUA_REG(get_zoom_ratio),
{ NULL, NULL }
#undef LUA_REG
};
void register_cam(lua_State *L)
{
int lib_id, meta_id;
lua_createtable(L, 0, 0);
lib_id = lua_gettop(L);
luaL_newmetatable(L, "Cam");
meta_id = lua_gettop(L);
luaL_setfuncs(L, game_meta, 0); // XXX
luaL_newlib(L, cam_methods);
lua_setfield(L, meta_id, "__index");
luaL_newlib(L, cam_meta);
lua_setfield(L, meta_id, "__metatable");
lua_setmetatable(L, lib_id);
lua_setglobal(L, "cam");
}

5
src/luascript/lua_cam.hh Normal file
View file

@ -0,0 +1,5 @@
#pragma once
#include "lua.hh"
void register_cam(lua_State *L);

1014
src/luascript/lua_entity.cc Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,5 @@
#pragma once
#include "lua.hh"
void register_entity(lua_State *L);

354
src/luascript/lua_game.cc Normal file
View file

@ -0,0 +1,354 @@
#include "lua_game.hh"
#include "escript.hh"
#include "game.hh"
#include "pkgman.hh"
#include "ui.hh"
/* GAME */
/* game:show_numfeed(number, num_decimals) */
static int l_game_show_numfeed(lua_State *L)
{
int num_decimals = 2;
if (lua_gettop(L) == 3) {
num_decimals = luaL_checkint(L, 3);
}
double d = luaL_checknumber(L, 2);
if (num_decimals < 0) num_decimals = 0;
if (num_decimals > 6) num_decimals = 6;
G->show_numfeed(d, num_decimals);
return 0;
}
/* game:finish(win) */
static int l_game_finish(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "game:finish", "1.3.0.2", LEVEL_VERSION_1_3_0_2);
bool win = (luaL_checkint(L, 2) == 1);
G->finish(win);
return 0;
}
/* game:add_score(score) */
static int l_game_add_score(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "game:add_score", "1.3.0.2", LEVEL_VERSION_1_3_0_2);
int score = luaL_checkint(L, 2);
G->add_score(score);
return 0;
}
/* game:set_score(new_score) */
static int l_game_set_score(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "game:set_score", "1.3.0.2", LEVEL_VERSION_1_3_0_2);
int new_score = luaL_checkint(L, 2);
G->set_score(new_score);
return 0;
}
/* game:get_score() */
static int l_game_get_score(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "game:get_score", "1.3.0.2", LEVEL_VERSION_1_3_0_2);
lua_pushnumber(L, G->get_real_score());
return 1;
}
/* game:activate_rc(entity) */
static int l_game_activate_rc(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "game:activate_rc", "1.3.0.2", LEVEL_VERSION_1_3_0_2);
entity *e = *(static_cast<entity**>(luaL_checkudata(L, 2, "EntityMT")));
G->set_control_panel(e);
return 0;
}
/* game:activate_rc_by_id(entity_id) */
static int l_game_activate_rc_by_id(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "game:activate_rc_by_id", "1.3.0.2", LEVEL_VERSION_1_3_0_2);
long entity_id = luaL_checklong(L, 2);
entity *e = W->get_entity_by_id(entity_id);
if (e) {
G->set_control_panel(e);
}
return 0;
}
/* game:message(msg, duration) */
static int l_game_message(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "game:message", "1.4", LEVEL_VERSION_1_4);
bool long_duration = false;
if (lua_gettop(L) == 3) {
long_duration = luaL_checkint(L, 3) ? true : false;
}
const char *s = luaL_checkstring(L, 2);
ui::message(s, long_duration);
return 0;
}
/* local x, y = game:get_cursor(layer) */
static int l_game_get_cursor(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "game:get_cursor", "1.4", LEVEL_VERSION_1_4);
int layer = 1;
if (lua_gettop(L) == 2)
layer = luaL_checkinteger(L, 2);
if (layer > 3) layer = 3;
else if (layer < 1) layer = 1;
layer --;
b2Vec2 cp = G->get_last_cursor_pos(layer);
lua_pushnumber(L, cp.x);
lua_pushnumber(L, cp.y);
return 2;
}
/* game:poll_event(event_id) */
static int l_game_poll_event(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "game:poll_event", "1.4", LEVEL_VERSION_1_4);
int ev = luaL_checkinteger(L, 2);
if (ev < 0) {
ev = 0;
} else if (ev >= WORLD_EVENT__NUM) {
ev = WORLD_EVENT__NUM-1;
}
lua_pushboolean(L, current_escript->events[ev] > 0);
return 1;
}
/* local x, y = game:get_screen_cursor() */
static int l_game_get_screen_cursor(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "game:get_screen_cursor", "1.5", LEVEL_VERSION_1_5);
G->refresh_last_cursor_pos();
lua_pushnumber(L, G->last_cursor_pos_x);
lua_pushnumber(L, G->last_cursor_pos_y);
return 2;
}
/* game:restart() */
static int l_game_restart(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "game:restart", "1.5", LEVEL_VERSION_1_5);
G->restart_level();
return 0;
}
/* game:submit_score() */
static int l_game_submit_score(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "game:submit_score", "1.5", LEVEL_VERSION_1_5);
if (W->level_id_type == LEVEL_DB)
G->submit_score();
else
ui::message("Can't submit score when playing a local level.");
return 0;
}
/* game:set_variable(varname, value) */
static int l_game_set_variable(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "game:set_variable", "1.5", LEVEL_VERSION_1_5);
const char *name = luaL_checkstring(L, 2);
double value = luaL_checknumber(L, 3);
std::pair<std::map<std::string, double>::iterator, bool> ret;
ret = W->level_variables.insert(std::pair<std::string, double>(name, value));
if (!ret.second) {
(ret.first)->second = value;
}
return 0;
}
/* value = game:get_variable(varname) */
static int l_game_get_variable(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "game:get_variable", "1.5", LEVEL_VERSION_1_5);
const char *name = luaL_checkstring(L, 2);
double value = 0.0;
std::map<std::string, double>::iterator i = W->level_variables.find(name);
if (i != W->level_variables.end()) {
value = i->second;
}
lua_pushnumber(L, value);
return 1;
}
/* fps = game:get_fps() */
static int l_game_get_fps(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "game:get_fps", "1.5", LEVEL_VERSION_1_5);
lua_pushnumber(L, _tms.fps_mean);
return 1;
}
/* prompt_id = game:prompt(message, btn1, btn2, btn3) */
static int l_game_prompt(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "game:prompt", "1.5.1", LEVEL_VERSION_1_5_1);
escript *self = static_cast<escript*>(L->userdata);
if (self->prompt_id == 0 && self->get_response() == PROMPT_RESPONSE_NONE && lua_gettop(L) >= 3) {
if (self->p_message) {
free(self->p_message);
self->p_message = 0;
}
if (self->p_btn1) {
free(self->p_btn1);
self->p_btn1 = 0;
self->p_btn1_len = 0;
}
if (self->p_btn2) {
free(self->p_btn2);
self->p_btn2 = 0;
self->p_btn2_len = 0;
}
if (self->p_btn3) {
free(self->p_btn3);
self->p_btn3 = 0;
self->p_btn3_len = 0;
}
const char *message = luaL_checkstring(L, 2);
const char *btn1 = luaL_checkstring(L, 3);
if (lua_gettop(L) >= 4) {
const char *btn2 = luaL_checkstring(L, 4);
if (lua_gettop(L) >= 5) {
const char *btn3 = luaL_checkstring(L, 5);
self->p_btn3 = strdup(btn3);
self->p_btn3_len = strlen(btn3);
}
self->p_btn2 = strdup(btn2);
self->p_btn2_len = strlen(btn2);
}
if (!G->occupy_prompt_slot()) {
lua_pushnil(L);
return 1;
}
self->p_message = strdup(message);
self->p_btn1 = strdup(btn1);
self->p_btn1_len = strlen(btn1);
self->prompt_id = rand() % 65535;
lua_pushnumber(L, self->prompt_id);
G->current_prompt = self;
ui::open_dialog(DIALOG_PROMPT, 0);
return 1;
}
/*
tms_infof("prompt id: %u", self->prompt_id);
tms_infof("response: %u", self->get_response());
*/
lua_pushnil(L);
return 1;
}
// ---
const luaL_Reg game_meta[] = {
{ NULL, NULL }
};
static const luaL_Reg game_methods[] = {
#define LUA_REG(name) { #name, l_game_##name }
LUA_REG(show_numfeed),
LUA_REG(finish),
LUA_REG(add_score),
LUA_REG(set_score),
LUA_REG(get_score),
LUA_REG(activate_rc),
LUA_REG(activate_rc_by_id),
LUA_REG(message),
LUA_REG(get_cursor),
LUA_REG(poll_event),
LUA_REG(get_screen_cursor),
LUA_REG(restart),
LUA_REG(submit_score),
LUA_REG(set_variable),
LUA_REG(get_variable),
LUA_REG(get_fps),
LUA_REG(prompt),
{ NULL, NULL }
#undef LUA_REG
};
void register_game(lua_State *L)
{
int lib_id, meta_id;
lua_createtable(L, 0, 0);
lib_id = lua_gettop(L);
luaL_newmetatable(L, "Game");
meta_id = lua_gettop(L);
luaL_setfuncs(L, game_meta, 0);
luaL_newlib(L, game_methods);
lua_setfield(L, meta_id, "__index");
luaL_newlib(L, game_meta);
lua_setfield(L, meta_id, "__metatable");
lua_setmetatable(L, lib_id);
lua_setglobal(L, "game");
}

View file

@ -0,0 +1,7 @@
#pragma once
#include "lua.hh"
void register_game(lua_State *L);
extern const luaL_Reg game_meta[]; // needed for lua_cam

866
src/luascript/lua_this.cc Normal file
View file

@ -0,0 +1,866 @@
#include "lua_this.hh"
#include "escript.hh"
#include "receiver.hh"
struct lua_vert base[4] = {
{
(tvec3){.5f,.5f,0.f},
(tvec2){.5f, 1.f},
(tvec4){0.f, 0.f, 0.f, 0.f},
}, {
(tvec3){-.5f,.5f,0.f},
(tvec2){0.f, 1.f},
(tvec4){0.f, 0.f, 0.f, 0.f},
}, {
(tvec3){-.5f,-.5f,0.f},
(tvec2){0.f, .5f},
(tvec4){0.f, 0.f, 0.f, 0.f},
}, {
(tvec3){.5f,-.5f,0.f},
(tvec2){.5f, .5f},
(tvec4){0.f, 0.f, 0.f, 0.f},
}
};
static uint32_t
upper_power_of_two(uint32_t v)
{
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
/* this:write(socket, value) */
static int l_this_write(lua_State *L)
{
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
int socket = luaL_checkint(L, 2);
double value = tclampf(luaL_checknumber(L, 3), 0.0, 1.0);
if (socket < 0) socket = 0;
if (socket > 3) socket = 3;
if (!e->s_out[socket].written()) {
e->s_out[socket].write(value);
}
return 0;
}
/* this:read(socket) */
static int l_this_read(lua_State *L)
{
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
int socket = luaL_checkint(L, 2);
if (socket < 0) socket = 0;
if (socket > 3) socket = 3;
lua_pushnumber(L, e->val[socket]);
return 1;
}
/* this:has_plug(socket) */
static int l_this_has_plug(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:has_plug", "1.5", LEVEL_VERSION_1_5);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
int socket = luaL_checkint(L, 2);
if (socket < 0) socket = 0;
if (socket > 3) socket = 3;
lua_pushboolean(L, e->socket_active[socket]);
return 1;
}
/* this:write_frequency(frequency, value) */
static int l_this_write_frequency(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:write_frequency", "1.3.0.2", LEVEL_VERSION_1_3_0_2);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
uint32_t freq = (uint32_t)luaL_checklong(L, 2);
double value = tclampf(luaL_checknumber(L, 3), 0.0, 1.0);
std::pair<std::multimap<uint32_t, receiver_base*>::iterator, std::multimap<uint32_t, receiver_base*>::iterator> range = W->receivers.equal_range(freq);
for (std::multimap<uint32_t, receiver_base*>::iterator
i = range.first;
i != range.second && i != W->receivers.end();
i++) {
i->second->pending_value = value;
i->second->no_broadcast = true;
}
return 0;
}
/* this:listen_on_frequency(frequency) */
static int l_this_listen_on_frequency(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:listen_on_frequency", "1.4", LEVEL_VERSION_1_4);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
uint32_t freq = (uint32_t)luaL_checklong(L, 2);
if (e->first_run) {
receiver_base *rb = new receiver_base();
std::pair<std::map<uint32_t, receiver_base*>::iterator, bool> ret;
ret = e->receivers.insert(std::pair<uint32_t, receiver_base*>(freq, rb));
if (!ret.second) {
delete rb;
} else {
W->add_receiver(freq, rb);
}
} else {
lua_pushstring(L, "You can only start listening to frequency in init().");
lua_error(L);
}
return 0;
}
/* this:read_frequency(frequency) */
static int l_this_read_frequency(lua_State *L)
{
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
uint32_t freq = luaL_checklong(L, 2);
std::map<uint32_t, receiver_base*>::iterator ret;
ret = e->receivers.find(freq);
float v = 0.f;
if (ret != e->receivers.end()) {
v = ret->second->pending_value;
} else {
char err[512];
snprintf(err, 511, "You are not listening to frequency %u.\nUse this:listen_on_frequency() to begin.", freq);
lua_pushstring(L, err);
lua_error(L);
}
lua_pushnumber(L, v);
return 1;
}
/* this:first_run() */
static int l_this_first_run(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:first_run", "1.3.0.2", LEVEL_VERSION_1_3_0_2);
ESCRIPT_FUNCTION_DEPRECATED(L, "this:first_run", "1.5", LEVEL_VERSION_1_5);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
lua_pushboolean(L, e->first_run);
return 1;
}
/* x, y = this:get_position() */
static int l_this_get_position(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:get_position", "1.3.0.2", LEVEL_VERSION_1_3_0_2);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
b2Vec2 pos = e->get_position();
lua_pushnumber(L, pos.x);
lua_pushnumber(L, pos.y);
return 2;
}
/* id = this:get_id() */
static int l_this_get_id(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:get_id", "1.5", LEVEL_VERSION_1_5);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
lua_pushnumber(L, e->id);
return 1;
}
/* width, height = this:get_resolution()*/
static int l_this_get_resolution(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:get_resolution", "1.5", LEVEL_VERSION_1_5);
lua_pushnumber(L, _tms.window_width);
lua_pushnumber(L, _tms.window_height);
return 2;
}
/* ratio = this:get_ratio()*/
static int l_this_get_ratio(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:get_ratio", "1.5", LEVEL_VERSION_1_5);
lua_pushnumber(L, (float)_tms.window_width/_tms.window_height);
return 1;
}
/* this:set_sprite_blending(int) */
static int l_this_set_sprite_blending(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:set_sprite_blending", "1.3.0.2", LEVEL_VERSION_1_3_0_2);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
e->blending_mode = luaL_checkint(L, 2);
if (e->blending_mode < 0 || e->blending_mode > 2) {
lua_pushstring(L, "Invalid blending mode");
lua_error(L);
}
return 0;
}
/* this:set_sprite_filtering(int) */
static int l_this_set_sprite_filtering(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:set_sprite_filtering", "1.3.0.2", LEVEL_VERSION_1_3_0_2);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
e->filtering = luaL_checkint(L, 2);
if (e->filtering < 0 || e->filtering > 1) {
lua_pushstring(L, "Invalid sprite filtering");
lua_error(L);
}
return 0;
}
/* this:set_sprite_texel(x, y, r, g, b, a) */
static int l_this_set_sprite_texel(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:set_sprite_texel", "1.3.0.2", LEVEL_VERSION_1_3_0_2);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
int u = luaL_checkint(L, 2);
int v = luaL_checkint(L, 3);
float r = luaL_checknumber(L, 4);
float g = luaL_checknumber(L, 5);
float b = luaL_checknumber(L, 6);
float a = luaL_checknumber(L, 7);
if (!e->normal_draw) {
e->normal_draw = new draw_data(e);
}
draw_data *draw = e->normal_draw;
if (u < 0 || u >= draw->texture_width || v < 0 || v >= draw->texture_height) {
lua_pushfstring(L, "texel coordinate out of range (%d/%d)", u, v);
lua_error(L);
}
draw->texture->data[draw->texture_width*4*v + 4*u] = (unsigned char)tclampf(roundf(r*255.f), 0, 255.f);
draw->texture->data[draw->texture_width*4*v + 4*u+1] = (unsigned char)tclampf(roundf(g*255.f), 0, 255.f);
draw->texture->data[draw->texture_width*4*v + 4*u+2] = (unsigned char)tclampf(roundf(b*255.f), 0.f, 255.f);
draw->texture->data[draw->texture_width*4*v + 4*u+3] = (unsigned char)tclampf(roundf(a*255.f), 0.f, 255.f);
draw->texture_modified = true;
return 0;
}
/* this:clear_texels() */
static int l_this_clear_texels(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:clear_texels", "1.4", LEVEL_VERSION_1_4);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
unsigned char clear_value = 0;
if (lua_gettop(L) > 1) {
float clr = luaL_checknumber(L, 2);
clear_value = (unsigned char)tclampf(roundf(clr*255.f), 0, 255.f);
}
if (!e->normal_draw) {
e->normal_draw = new draw_data(e);
}
draw_data *draw = e->normal_draw;
tms_texture_clear_buffer(draw->texture, clear_value);
draw->texture_modified = true;
return 0;
}
/* this:set_draw_tint(r,g,b,a) */
static int l_this_set_draw_tint(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:set_draw_tint", "1.3.0.2", LEVEL_VERSION_1_3_0_2);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
e->draw_tint.r = luaL_checknumber(L, 2);
e->draw_tint.g = luaL_checknumber(L, 3);
e->draw_tint.b = luaL_checknumber(L, 4);
e->draw_tint.a = luaL_checknumber(L, 5);
return 0;
}
/* this:set_draw_z(z) */
static int l_this_set_draw_z(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:set_draw_z", "1.3.0.2", LEVEL_VERSION_1_3_0_2);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
e->draw_z = luaL_checknumber(L, 2);
return 0;
}
/* this:set_draw_coordinates(int) */
static int l_this_set_draw_coordinates(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:set_draw_coordinates", "1.5", LEVEL_VERSION_1_5);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
int mode = luaL_checkint(L, 2);
if (mode < 0 || mode > 2) {
lua_pushstring(L, "Invalid camera mode.");
lua_error(L);
} else {
e->coordinate_mode = mode;
if (e->coordinate_mode == ESCRIPT_LOCAL && lua_gettop(L) == 3) {
e->local_id = luaL_checknumber(L, 3);
} else {
e->local_id = 0;
}
}
return 0;
}
/* this:draw_sprite(x, y, r, w, h, bx, by, tx, ty) */
static int l_this_draw_sprite(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:draw_sprite", "1.3.0.2", LEVEL_VERSION_1_3_0_2);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
if (!e->normal_draw) {
e->normal_draw = new draw_data(e);
}
draw_data *draw = e->normal_draw;
float x = luaL_checknumber(L, 2);
float y = luaL_checknumber(L, 3);
float r = luaL_checknumber(L, 4);
float w = luaL_checknumber(L, 5);
float h = luaL_checknumber(L, 6);
float bx = (float)luaL_checkint(L, 7);
float by = (float)luaL_checkint(L, 8);
float tx = (float)luaL_checkint(L, 9);
float ty = (float)luaL_checkint(L, 10);
if (tx == bx) tx = bx+.5f;
if (ty == by) ty = by+.5f;
tvec2 uvb = {(float)bx / draw->texture_width, (float)by / draw->texture_height};
tvec2 uvt = {(float)tx / draw->texture_width, (float)ty / draw->texture_height};
if (draw->sprite_count < MAX_SPRITES) {
struct lua_vert *_b = (struct lua_vert*)draw->verts->get_buffer();
int n = draw->sprite_count;
entity *local_entity = 0;
b2Vec2 local_position;
if (e->coordinate_mode == ESCRIPT_LOCAL) {
local_entity = (e->local_id != 0 ? W->get_entity_by_id(e->local_id) : 0);
if (local_entity) {
local_position = local_entity->get_position();
r += local_entity->get_angle();
} else {
local_position = e->get_position();
r += e->get_angle();
}
}
if (r != 0.f) {
float cs, sn;
tmath_sincos(r, &sn, &cs);
for (int ix=0; ix<4; ix++) {
_b[n*4+ix] = base[ix];
_b[n*4+ix].pos.x *= w;
_b[n*4+ix].pos.y *= h;
float _x = _b[n*4+ix].pos.x * cs - _b[n*4+ix].pos.y * sn;
float _y = _b[n*4+ix].pos.x * sn + _b[n*4+ix].pos.y * cs;
_b[n*4+ix].pos.x = _x;
_b[n*4+ix].pos.y = _y;
if (e->coordinate_mode == ESCRIPT_LOCAL) {
_b[n*4+ix].pos.x += local_position.x;
_b[n*4+ix].pos.y += local_position.y;
}
_b[n*4+ix].pos.x += x;
_b[n*4+ix].pos.y += y;
_b[n*4+ix].pos.z += e->draw_z;
_b[n*4+ix].color.r = e->draw_tint.r;
_b[n*4+ix].color.g = e->draw_tint.g;
_b[n*4+ix].color.b = e->draw_tint.b;
_b[n*4+ix].color.a = e->draw_tint.a;
_b[n*4+ix].uv.x = ((ix == 0 || ix == 3) ? uvt.x : uvb.x);
_b[n*4+ix].uv.y = (ix < 2 ? uvt.y : uvb.y);
}
} else {
for (int ix=0; ix<4; ix++) {
_b[n*4+ix] = base[ix];
_b[n*4+ix].pos.x *= w;
_b[n*4+ix].pos.y *= h;
if (e->coordinate_mode == ESCRIPT_LOCAL) {
_b[n*4+ix].pos.x += local_position.x;
_b[n*4+ix].pos.y += local_position.y;
}
_b[n*4+ix].pos.x += x;
_b[n*4+ix].pos.y += y;
_b[n*4+ix].pos.z += e->draw_z;
_b[n*4+ix].color.r = e->draw_tint.r;
_b[n*4+ix].color.g = e->draw_tint.g;
_b[n*4+ix].color.b = e->draw_tint.b;
_b[n*4+ix].color.a = e->draw_tint.a;
_b[n*4+ix].uv.x = ((ix == 0 || ix == 3) ? uvt.x : uvb.x);
_b[n*4+ix].uv.y = (ix < 2 ? uvt.y : uvb.y);
}
}
if (e->solving) {
draw->sprite_count ++;
} else {
draw->pending_sprite_count ++;
}
}
return 0;
}
/* this:draw_line(x1, y1, x2, y2, w) */
static int l_this_draw_line(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:draw_line", "1.4", LEVEL_VERSION_1_4);
escript_line line;
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
line.x1 = luaL_checknumber(L, 2);
line.y1 = luaL_checknumber(L, 3);
line.x2 = luaL_checknumber(L, 4);
line.y2 = luaL_checknumber(L, 5);
line.w1 = luaL_checknumber(L, 6);
line.w2 = line.w1;
line.z1 = e->draw_z;
line.z2 = e->draw_z;
line.r1 = e->draw_tint.r;
line.g1 = e->draw_tint.g;
line.b1 = e->draw_tint.b;
line.a1 = e->draw_tint.a;
line.r2 = e->draw_tint.r;
line.g2 = e->draw_tint.g;
line.b2 = e->draw_tint.b;
line.a2 = e->draw_tint.a;
e->add_line(line);
return 0;
}
/* this:draw_gradient_line(x1, y1, x2, y2, w, r, g, b, a) */
static int l_this_draw_gradient_line(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:draw_gradient_line", "1.5", LEVEL_VERSION_1_5);
escript_line line;
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
line.x1 = luaL_checknumber(L, 2);
line.y1 = luaL_checknumber(L, 3);
line.x2 = luaL_checknumber(L, 4);
line.y2 = luaL_checknumber(L, 5);
line.w1 = luaL_checknumber(L, 6);
line.w2 = line.w1;
line.z1 = e->draw_z;
line.z2 = e->draw_z;
line.r1 = e->draw_tint.r;
line.g1 = e->draw_tint.g;
line.b1 = e->draw_tint.b;
line.a1 = e->draw_tint.a;
line.r2 = luaL_checknumber(L, 7);
line.g2 = luaL_checknumber(L, 8);
line.b2 = luaL_checknumber(L, 9);
line.a2 = luaL_checknumber(L, 10);
e->add_line(line);
return 0;
}
/* this:draw_line_3d(x1, y1, z1, x2, y2, z2, w) */
static int l_this_draw_line_3d(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:draw_line_3d", "1.5", LEVEL_VERSION_1_5);
escript_line line;
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
line.x1 = luaL_checknumber(L, 2);
line.y1 = luaL_checknumber(L, 3);
line.z1 = luaL_checknumber(L, 4);
line.x2 = luaL_checknumber(L, 5);
line.y2 = luaL_checknumber(L, 6);
line.z2 = luaL_checknumber(L, 7);
line.w1 = luaL_checknumber(L, 8);
line.w2 = line.w1;
line.r1 = e->draw_tint.r;
line.g1 = e->draw_tint.g;
line.b1 = e->draw_tint.b;
line.a1 = e->draw_tint.a;
line.r2 = e->draw_tint.r;
line.g2 = e->draw_tint.g;
line.b2 = e->draw_tint.b;
line.a2 = e->draw_tint.a;
e->add_line(line);
return 0;
}
/* this:draw_gradient_line_3d(x1, y1, z1, x2, y2, z2, w, r, g, b, a) */
static int l_this_draw_gradient_line_3d(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:draw_gradient_line_3d", "1.5", LEVEL_VERSION_1_5);
escript_line line;
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
line.x1 = luaL_checknumber(L, 2);
line.y1 = luaL_checknumber(L, 3);
line.z1 = luaL_checknumber(L, 4);
line.x2 = luaL_checknumber(L, 5);
line.y2 = luaL_checknumber(L, 6);
line.z2 = luaL_checknumber(L, 7);
line.w1 = luaL_checknumber(L, 8);
line.w2 = line.w1;
line.r1 = e->draw_tint.r;
line.g1 = e->draw_tint.g;
line.b1 = e->draw_tint.b;
line.a1 = e->draw_tint.a;
line.r2 = luaL_checknumber(L, 9);
line.g2 = luaL_checknumber(L, 10);
line.b2 = luaL_checknumber(L, 11);
line.a2 = luaL_checknumber(L, 12);
e->add_line(line);
return 0;
}
/* r, g, b, a = this:get_sprite_texel(x, y) */
static int l_this_get_sprite_texel(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:get_sprite_texel", "1.5", LEVEL_VERSION_1_5);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
int u = luaL_checkint(L, 2);
int v = luaL_checkint(L, 3);
if (!e->normal_draw) {
lua_pushnumber(L, 0.f);
lua_pushnumber(L, 0.f);
lua_pushnumber(L, 0.f);
lua_pushnumber(L, 0.f);
return 4;
}
if (u < 0 || u >= e->normal_draw->texture_width || v < 0 || v >= e->normal_draw->texture_height) {
lua_pushstring(L, "texel coordinate out of range");
lua_error(L);
}
struct tms_texture *tex = e->normal_draw->texture;
int width = e->normal_draw->texture_width;
lua_pushnumber(L, tex->data[width*4*v + 4*u+0]/255.f); // r
lua_pushnumber(L, tex->data[width*4*v + 4*u+1]/255.f); // g
lua_pushnumber(L, tex->data[width*4*v + 4*u+2]/255.f); // b
lua_pushnumber(L, tex->data[width*4*v + 4*u+3]/255.f); // a
return 4;
}
/* this:init_draw(width, height) */
static int l_this_init_draw(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:init_draw", "1.5", LEVEL_VERSION_1_5);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
if (!e->first_run) {
lua_pushstring(L, "Draw can only be initialized in the init()-function.");
lua_error(L);
}
int width = luaL_checkint(L, 2);
int height = luaL_checkint(L, 3);
width = upper_power_of_two(width);
height = upper_power_of_two(height);
if (width < 1 || width > 1024 || height < 1 || height > 1024) {
lua_pushstring(L, "Draw width/height out of range. Must be between 1 and 1024.");
lua_error(L);
}
if (!e->normal_draw) {
e->normal_draw = new draw_data(e, width, height);
}
return 0;
}
/* this:set_static_sprite_texel(x, y, r, g, b, a)*/
static int l_this_set_static_sprite_texel(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:set_static_sprite_texel", "1.5", LEVEL_VERSION_1_5);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
int u = luaL_checkint(L, 2);
int v = luaL_checkint(L, 3);
float r = luaL_checknumber(L, 4);
float g = luaL_checknumber(L, 5);
float b = luaL_checknumber(L, 6);
float a = luaL_checknumber(L, 7);
if (!e->static_draw) {
e->static_draw = new draw_data(e);
}
draw_data *draw = e->static_draw;
if (u < 0 || u >= draw->texture_width || v < 0 || v >= draw->texture_height) {
lua_pushfstring(L, "texel coordinate out of range (%d/%d)", u, v);
lua_error(L);
}
draw->texture->data[draw->texture_width*4*v + 4*u] = (unsigned char)tclampf(roundf(r*255.f), 0, 255.f);
draw->texture->data[draw->texture_width*4*v + 4*u+1] = (unsigned char)tclampf(roundf(g*255.f), 0, 255.f);
draw->texture->data[draw->texture_width*4*v + 4*u+2] = (unsigned char)tclampf(roundf(b*255.f), 0.f, 255.f);
draw->texture->data[draw->texture_width*4*v + 4*u+3] = (unsigned char)tclampf(roundf(a*255.f), 0.f, 255.f);
draw->texture_modified = true;
return 0;
}
/* this:clear_static_texels() */
static int l_this_clear_static_texels(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:clear_static_texels", "1.5", LEVEL_VERSION_1_5);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
if (!e->static_draw) {
e->static_draw = new draw_data(e);
}
draw_data *draw = e->static_draw;
int numargs = lua_gettop(L);
if (numargs > 2) {
unsigned char colors[4] = {
127, 127, 127, 127
};
float v = luaL_checknumber(L, 2);
colors[0] = (unsigned char)tclampf(roundf(v*255.f), 0, 255.f);
if (numargs >= 3) {
float v = luaL_checknumber(L, 3);
colors[1] = (unsigned char)tclampf(roundf(v*255.f), 0, 255.f);
}
if (numargs >= 4) {
float v = luaL_checknumber(L, 4);
colors[2] = (unsigned char)tclampf(roundf(v*255.f), 0, 255.f);
}
if (numargs >= 5) {
float v = luaL_checknumber(L, 5);
colors[3] = (unsigned char)tclampf(roundf(v*255.f), 0, 255.f);
}
uint32_t buf_sz = draw->texture_width * draw->texture_height * draw->texture_num_channels;
for (uint32_t i=0; i<buf_sz; i += draw->texture_num_channels) {
for (uint8_t c=0; c<draw->texture_num_channels; ++c) {
draw->texture->data[i+c] = colors[c];
}
}
} else {
unsigned char clear_value = 0;
if (numargs == 2) {
float clr = luaL_checknumber(L, 2);
clear_value = (unsigned char)tclampf(roundf(clr*255.f), 0, 255.f);
}
tms_texture_clear_buffer(draw->texture, clear_value);
}
draw->texture_modified = true;
return 0;
}
/* this:add_static_sprite(x, y, r, w, h, bx, by, tx, ty) */
static int l_this_add_static_sprite(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:add_static_sprite", "1.5", LEVEL_VERSION_1_5);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
if (!e->static_draw) {
e->static_draw = new draw_data(e);
}
float x = luaL_checknumber(L, 2);
float y = luaL_checknumber(L, 3);
float r = luaL_checknumber(L, 4);
float w = luaL_checknumber(L, 5);
float h = luaL_checknumber(L, 6);
float bx = (float)luaL_checkint(L, 7);
float by = (float)luaL_checkint(L, 8);
float tx = (float)luaL_checkint(L, 9);
float ty = (float)luaL_checkint(L, 10);
if (tx == bx) tx = bx+.5f;
if (ty == by) ty = by+.5f;
e->add_static_sprite(x, y, r, w, h, bx, by, tx, ty);
return 0;
}
/* this:clear_static_sprites() */
static int l_this_clear_static_sprites(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "this:clear_static_sprites", "1.5", LEVEL_VERSION_1_5);
escript *e = *(static_cast<escript**>(luaL_checkudata(L, 1, "This")));
if (!e->static_draw) {
e->static_draw = new draw_data(e);
}
e->static_draw->sprite_count = 0;
e->static_sprites.clear();
return 0;
}
// ---
static const luaL_Reg this_meta[] = {
{ NULL, NULL }
};
static const luaL_Reg this_methods[] = {
#define LUA_REG(name) { #name, l_this_##name }
LUA_REG(write),
LUA_REG(read),
LUA_REG(has_plug),
LUA_REG(write_frequency),
LUA_REG(listen_on_frequency),
LUA_REG(read_frequency),
LUA_REG(first_run),
LUA_REG(get_position),
LUA_REG(get_id),
LUA_REG(get_resolution),
LUA_REG(get_ratio),
/* draw stuff */
LUA_REG(set_sprite_blending),
LUA_REG(set_sprite_filtering),
LUA_REG(set_sprite_texel),
LUA_REG(clear_texels),
LUA_REG(set_draw_tint),
{"set_sprite_tint", l_this_set_draw_tint}, // backwards compat
LUA_REG(set_draw_z),
{"set_sprite_z", l_this_set_draw_z}, // backwards compat
LUA_REG(set_draw_coordinates),
LUA_REG(draw_sprite),
LUA_REG(draw_line),
LUA_REG(draw_gradient_line),
LUA_REG(draw_line_3d),
LUA_REG(draw_gradient_line_3d),
LUA_REG(get_sprite_texel),
LUA_REG(init_draw),
LUA_REG(set_static_sprite_texel),
LUA_REG(clear_static_texels),
LUA_REG(add_static_sprite),
LUA_REG(clear_static_sprites),
{ NULL, NULL }
#undef LUA_REG
};
void register_this(lua_State *L, escript *e)
{
int lib_id, meta_id;
lua_createtable(L, 0, 0);
lib_id = lua_gettop(L);
luaL_newmetatable(L, "This");
meta_id = lua_gettop(L);
luaL_setfuncs(L, this_meta, 0);
luaL_newlib(L, this_methods);
lua_setfield(L, meta_id, "__index");
luaL_newlib(L, this_meta);
lua_setfield(L, meta_id, "__metatable");
lua_setmetatable(L, lib_id);
escript **ee = static_cast<escript**>(lua_newuserdata(L, sizeof(entity*)));
*(ee) = e;
luaL_setmetatable(L, "This");
lua_setglobal(L, "this");
lua_pop(L, 1);
}

View file

@ -0,0 +1,5 @@
#pragma once
#include "lua.hh"
void register_this(lua_State *L, escript *e);

367
src/luascript/lua_world.cc Normal file
View file

@ -0,0 +1,367 @@
#include "lua_world.hh"
#include "entity.hh"
#include "game.hh"
/* world:get_entity(entity_id) */
static int l_world_get_entity(lua_State *L)
{
uint32_t id = luaL_checkunsigned(L, 2);
entity *e = W->get_entity_by_id(id);
if (e) {
entity **ee = static_cast<entity**>(lua_newuserdata(L, sizeof(entity*)));
*(ee) = e;
luaL_setmetatable(L, "EntityMT");
// we _ALWAYS_ assume userdata is a pointer to this.
//escript *es = static_cast<escript*>(L->userdata);
//es->subscribe(e, ENTITY_EVENT_REMOVE, on_entity_absorb);
} else {
lua_pushnil(L);
}
return 1; /* We push one value to the lua stack */
}
/* entity, ptx, pty, norx, nory = world:raycast(startx, starty, endx, endy, layer) */
static int l_world_raycast(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "world:raycast", "1.4", LEVEL_VERSION_1_4);
float x1 = luaL_checknumber(L, 2);
float y1 = luaL_checknumber(L, 3);
float x2 = luaL_checknumber(L, 4);
float y2 = luaL_checknumber(L, 5);
int layer = 1;
int sublayer_mask = 15;
if (lua_gettop(L) > 5) {
layer = luaL_checkinteger(L, 6);
if (lua_gettop(L) == 7) {
sublayer_mask = luaL_checkinteger(L, 7);
}
}
sublayer_mask &= 15;
if (layer < 1) layer = 1;
else if (layer > 3) layer = 3;
layer --;
class callback : public b2RayCastCallback {
public:
int mask;
entity *result;
b2Vec2 result_pt;
b2Vec2 result_nor;
callback(int layer, int sublayer_mask)
{
this->mask = (sublayer_mask << (layer*4));
this->result = 0;
}
float32 ReportFixture(b2Fixture *f, const b2Vec2 &pt, const b2Vec2 &nor, float32 fraction)
{
entity *r = static_cast<entity*>(f->GetUserData());
if (f->IsSensor()) return -1;
if (r) {
if (f->GetFilterData().categoryBits & this->mask) {
result = r;
result_pt = pt;
result_nor = nor;
return fraction;
}
}
return -1;
}
} cb(layer, sublayer_mask);
W->b2->RayCast(&cb, b2Vec2(x1, y1), b2Vec2(x2, y2));
if (cb.result) {
entity **ee = static_cast<entity**>(lua_newuserdata(L, sizeof(entity*)));
*(ee) = cb.result;
luaL_setmetatable(L, "EntityMT");
lua_pushnumber(L, cb.result_pt.x);
lua_pushnumber(L, cb.result_pt.y);
lua_pushnumber(L, cb.result_nor.x);
lua_pushnumber(L, cb.result_nor.y);
return 5;
} else {
lua_pushnil(L);
return 1;
}
}
/* world:query(min_x, min_y, max_x, max_y, layer, sublayers) */
static int l_world_query(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "world:query", "1.4", LEVEL_VERSION_1_4);
float x1 = luaL_checknumber(L, 2);
float y1 = luaL_checknumber(L, 3);
float x2 = luaL_checknumber(L, 4);
float y2 = luaL_checknumber(L, 5);
int layer = 1;
int sublayer_mask = 15;
if (lua_gettop(L) > 5) {
layer = luaL_checkinteger(L, 6);
if (lua_gettop(L) == 7) {
sublayer_mask = luaL_checkinteger(L, 7);
}
}
sublayer_mask &= 15;
if (layer < 1) layer = 1;
else if (layer > 3) layer = 3;
layer --;
class callback : public b2QueryCallback {
public:
int mask;
std::set<entity*> results;
callback(int layer, int sublayer_mask)
{
this->mask = (sublayer_mask << (layer*4));
}
bool ReportFixture(b2Fixture *f)
{
entity *r = static_cast<entity*>(f->GetUserData());
if (f->IsSensor()) return true;
if (r) {
if (f->GetFilterData().categoryBits & this->mask) {
this->results.insert(r);
}
}
return true;
}
} cb(layer, sublayer_mask);
b2AABB aabb;
aabb.lowerBound.Set(x1, y1);
aabb.upperBound.Set(x2, y2);
W->b2->QueryAABB(&cb, aabb);
lua_newtable(L);
int x = 1;
for (std::set<entity*>::iterator i = cb.results.begin(); i != cb.results.end(); i ++, x++) {
lua_pushnumber(L, x);
entity **ee = static_cast<entity**>(lua_newuserdata(L, sizeof(entity*)));
*(ee) = (*i);
luaL_setmetatable(L, "EntityMT");
lua_settable(L, -3);
}
return 1;
}
/* x, y = world:get_gravity() */
static int l_world_get_gravity(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "world:get_gravity", "1.4", LEVEL_VERSION_1_4);
b2Vec2 g = W->get_gravity();
lua_pushnumber(L, g.x);
lua_pushnumber(L, g.y);
return 2;
}
/* world:set_gravity(x, y) */
static int l_world_set_gravity(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "world:set_gravity", "1.5.1", LEVEL_VERSION_1_5_1);
float x = luaL_checknumber(L, 2);
float y = luaL_checknumber(L, 3);
W->set_gravity(x, y);
return 0;
}
/* id = world:get_adventure_id() */
static int l_world_get_adventure_id(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "world:get_adventure_id", "1.5", LEVEL_VERSION_1_5);
lua_pushnumber(L, W->level.get_adventure_id());
return 1;
}
/* bup, bdown, bleft, bright = world:get_borders() */
static int l_world_get_borders(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "world:get_borders", "1.5", LEVEL_VERSION_1_5);
lua_pushnumber(L, W->level.size_y[1]);
lua_pushnumber(L, W->level.size_y[0]);
lua_pushnumber(L, W->level.size_x[0]);
lua_pushnumber(L, W->level.size_x[1]);
return 4;
}
/* x, y = world:get_world_point(x, y) */
static int l_world_get_world_point(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "world:get_world_point", "1.5", LEVEL_VERSION_1_5);
float x = luaL_checknumber(L, 2);
float y = luaL_checknumber(L, 3);
int layer = 1;
if (lua_gettop(L) > 3) {
layer = luaL_checkinteger(L, 4);
}
if (layer < 1) layer = 1;
else if (layer > 3) layer = 3;
-- layer;
tvec3 out;
W->get_layer_point(G->cam, x, y, layer, &out);
lua_pushnumber(L, out.x);
lua_pushnumber(L, out.y);
return 2;
}
/* x, y = world:get_screen_point(x, y) */
static int l_world_get_screen_point(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "world:get_screen_point", "1.5", LEVEL_VERSION_1_5);
float x = luaL_checknumber(L, 2);
float y = luaL_checknumber(L, 3);
lua_pushnumber(L, (x / _tms.window_width) * 100.);
lua_pushnumber(L, (y / _tms.window_height) * 100.);
return 2;
}
/* world:set_bg_color(r, g, b) */
static int l_world_set_bg_color(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "world:set_bg_color", "1.5", LEVEL_VERSION_1_5);
float r = luaL_checknumber(L, 2);
float g = luaL_checknumber(L, 3);
float b = luaL_checknumber(L, 4);
G->state.bg_color.r = r;
G->state.bg_color.g = g;
G->state.bg_color.b = b;
if (G->bgent) {
G->bgent->set_color4(r, g, b);
}
return 0;
}
/* world:set_ambient_light(intensity) */
static int l_world_set_ambient_light(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "world:set_ambient_light", "1.5", LEVEL_VERSION_1_5);
float i = luaL_checknumber(L, 2);
G->tmp_ambientdiffuse.x = i;
return 0;
}
/* world:set_diffuse_light(intensity) */
static int l_world_set_diffuse_light(lua_State *L)
{
ESCRIPT_VERSION_ERROR(L, "world:set_diffuse_light", "1.5", LEVEL_VERSION_1_5);
float i = luaL_checknumber(L, 2);
G->tmp_ambientdiffuse.y = i;
return 0;
}
// This is a secret function!
int l_world_unpersist_entity(lua_State *L)
{
uint32_t id = lua_tounsigned(L, lua_upvalueindex(1));
tms_debugf("Attempting to entity userdata with id %u", id);
entity *e = W->get_entity_by_id(id);
entity **ee = static_cast<entity**>(lua_newuserdata(L, sizeof(entity*)));
*(ee) = e;
luaL_setmetatable(L, "EntityMT");
/* If get_entity_by_id returns 0, the entity userdata will be "invalid".
* This might be something we should check for in all
* functions that use a raw pointer. */
return 1;
}
// ---
static const luaL_Reg world_meta[] = {
{ NULL, NULL }
};
static const luaL_Reg world_methods[] = {
#define LUA_REG(name) { #name, l_world_##name }
{"get_entity_by_id", l_world_get_entity}, // backward compat
LUA_REG(get_entity),
LUA_REG(raycast),
LUA_REG(query),
LUA_REG(get_gravity),
LUA_REG(set_gravity),
LUA_REG(get_adventure_id),
LUA_REG(get_borders),
LUA_REG(get_world_point),
LUA_REG(get_screen_point),
LUA_REG(set_bg_color),
LUA_REG(set_ambient_light),
LUA_REG(set_diffuse_light),
// private! ;-)
{"___persist_entity", l_world_unpersist_entity},
{ NULL, NULL }
#undef LUA_REG
};
void register_world(lua_State *L)
{
int lib_id, meta_id;
lua_createtable(L, 0, 0);
lib_id = lua_gettop(L);
luaL_newmetatable(L, "World");
meta_id = lua_gettop(L);
luaL_setfuncs(L, world_meta, 0);
luaL_newlib(L, world_methods);
lua_setfield(L, meta_id, "__index");
luaL_newlib(L, world_meta);
lua_setfield(L, meta_id, "__metatable");
lua_setmetatable(L, lib_id);
lua_setglobal(L, "world");
}

View file

@ -0,0 +1,8 @@
#pragma once
#include "lua.hh"
void register_world(lua_State *L);
// needed by lua_entity
int l_world_unpersist_entity(lua_State *L);