steed/src/sdl-instead/instead.c
2011-07-26 08:06:15 +00:00

1732 lines
34 KiB
C

#include "externals.h"
#include "internals.h"
#include "list.h"
#include "idf.h"
#ifndef STEAD_PATH
#define STEAD_PATH "./stead"
#endif
/* the Lua interpreter */
static gtimer_t instead_timer = NULL_TIMER;
static int instead_timer_nr = 0;
char *fromgame(const char *s);
char *togame(const char *s);
lua_State *L = NULL;
static int report (lua_State *L, int status)
{
if (status && !lua_isnil(L, -1)) {
char *p;
const char *msg = lua_tostring(L, -1);
if (msg == NULL)
msg = "(error object is not a string)";
fprintf(stderr,"Error: %s\n", msg);
p = fromgame(msg);
game_err_msg(p?p:msg);
if (p)
free(p);
lua_pop(L, 1);
status = -1;
gfx_del_timer(instead_timer); /* to avoid error loops */
instead_timer = NULL_TIMER;
}
return status;
}
static int traceback (lua_State *L)
{
lua_getfield(L, LUA_GLOBALSINDEX, "debug");
if (!lua_istable(L, -1)) {
lua_pop(L, 1);
return 1;
}
lua_getfield(L, -1, "traceback");
if (!lua_isfunction(L, -1)) {
lua_pop(L, 2);
return 1;
}
lua_pushvalue(L, 1); /* pass error message */
lua_pushinteger(L, 2); /* skip this function and traceback */
lua_call(L, 2, 1); /* call debug.traceback */
return 1;
}
static int docall (lua_State *L)
{
int status;
int base = 0;
if (debug_sw) {
base = lua_gettop(L); /* function index */
lua_pushcfunction(L, traceback); /* push traceback function */
lua_insert(L, base); /* put it under chunk and args */
}
status = lua_pcall(L, 0, LUA_MULTRET, base);
if (debug_sw)
lua_remove(L, base); /* remove traceback function */
/* force a complete garbage collection in case of errors */
if (status != 0)
lua_gc(L, LUA_GCCOLLECT, 0);
return status;
}
static int dofile (lua_State *L, const char *name) {
int status = luaL_loadfile(L, name) || docall(L);
return report(L, status);
}
static const char *idf_reader(lua_State *L, void *data, size_t *size)
{
static char buff[4096];
int rc;
rc = idf_read((idff_t)data, buff, 1, sizeof(buff));
*size = rc;
if (!rc)
return NULL;
return buff;
}
static int dofile_idf (lua_State *L, idff_t idf, const char *name) {
int status = lua_load(L, idf_reader, idf, name) || docall(L);
return report(L, status);
}
static int dostring (lua_State *L, const char *s) {
int status = luaL_loadstring(L, s) || docall(L);
return report(L, status);
}
char *getstring(char *cmd)
{
char *s;
int N;
if (!L)
return NULL;
if (dostring(L, cmd))
return NULL;
N = lua_gettop(L); /* number of arguments */
if (-N >=0)
return NULL;
s = (char*)lua_tostring(L, -N);
if (s)
s = fromgame(s);
return s;
}
int instead_eval(char *s)
{
if (!L)
return -1;
if (dostring(L, s))
return -1;
return 0;
}
int instead_clear(void)
{
int N;
if (!L)
return -1;
N = lua_gettop(L); /* number of arguments */
lua_pop(L, N);
return 0;
}
char *instead_retval(int n)
{
char *s;
int N;
if (!L)
return NULL;
N = lua_gettop(L); /* number of arguments */
/* fprintf(stderr,"%d\n", N); */
if (n - N >= 0)
return NULL;
s = (char*)lua_tostring(L, n - N);
if (s)
s = fromgame(s);
return s;
}
int instead_bretval(int n)
{
int N;
if (!L)
return 0;
N = lua_gettop(L); /* number of arguments */
if (n - N >= 0)
return 1;
return lua_toboolean(L, n - N);
}
int instead_iretval(int n)
{
int N;
if (!L)
return 0;
N = lua_gettop(L); /* number of arguments */
if (n - N >= 0)
return 0;
return lua_tonumber(L, n - N);
}
char *instead_cmd(char *s)
{
struct instead_args args[] = {
{ .val = NULL, .type = INSTEAD_STR },
{ .val = NULL, },
};
if (!s)
return NULL;
s = togame(s);
if (!s)
return NULL;
args[0].val = s;
instead_function("iface:cmd", args);
free(s);
return instead_retval(0);
}
int instead_function(char *s, struct instead_args *args)
{
int base = 0;
int status = 0;
int n = 0;
char *p;
char f[64];
int method = 0;
if (!L)
return -1;
strcpy(f, s);
p = strchr(f, '.');
if (!p)
p = strchr(f, ':');
if (p) {
if (*p == ':')
method = 1;
*p = 0;
p ++;
lua_getglobal(L, f);
lua_getfield(L, -1, p);
lua_remove(L, -2);
if (method)
lua_getglobal(L, f);
} else
lua_getglobal(L, s);
if (args) {
while (args->val) {
switch(args->type) {
case INSTEAD_NIL:
lua_pushnil(L);
break;
case INSTEAD_NUM:
lua_pushnumber(L, atoi(args->val));
break;
case INSTEAD_BOOL:
if (!strcmp(args->val, "true"))
lua_pushboolean(L, 1);
else
lua_pushboolean(L, 0);
break;
default:
case INSTEAD_STR:
lua_pushstring(L, args->val);
}
args ++;
n ++;
}
}
if (debug_sw) {
base = lua_gettop(L) - (method + n); /* function index */
lua_pushcfunction(L, traceback); /* push traceback function */
lua_insert(L, base); /* put it under chunk and args */
}
status = lua_pcall(L, method + n, LUA_MULTRET, base);
if (debug_sw)
lua_remove(L, base); /* remove traceback function */
if (status) {
fprintf(stderr, "Error calling:%s\n", s);
lua_gc(L, LUA_GCCOLLECT, 0);
}
return report(L, status);
}
int luacall(char *cmd)
{
int rc;
if (!L)
return -1;
if (dostring(L, cmd)) {
return -1;
}
rc = lua_tonumber(L, -1);
return rc;
}
#ifdef _HAVE_ICONV
static char *curcp = "UTF-8";
static char *fromcp = NULL;
#endif
#ifdef _HAVE_ICONV
char *fromgame(const char *s)
{
iconv_t han;
char *str;
if (!s)
return NULL;
if (!fromcp)
goto out0;
han = iconv_open(curcp, fromcp);
if (han == (iconv_t)-1)
goto out0;
if (!(str = decode(han, s)))
goto out1;
iconv_close(han);
return str;
out1:
iconv_close(han);
out0:
return strdup(s);
}
char *togame(const char *s)
{
iconv_t han;
char *str;
if (!s)
return NULL;
if (!fromcp)
goto out0;
han = iconv_open(fromcp, curcp);
if (han == (iconv_t)-1)
goto out0;
if (!(str = decode(han, s)))
goto out1;
iconv_close(han);
return str;
out1:
iconv_close(han);
out0:
return strdup(s);
}
#else
char *fromgame(const char *s)
{
if (!s)
return NULL;
return strdup(s);
}
char *togame(const char *s)
{
if (!s)
return NULL;
return strdup(s);
}
#endif
int instead_load(char *game)
{
idff_t idf = idf_open(game_idf, game);
if (idf) {
int rc = dofile_idf(L, idf, game);
idf_close(idf);
if (rc)
return -1;
} else if (dofile(L, dirpath(game))) {
return -1;
}
instead_clear();
#ifdef _HAVE_ICONV
if (fromcp)
free(fromcp);
fromcp = getstring("return game.codepage;");
instead_clear();
#endif
return 0;
}
typedef struct LoadF {
int extraline;
unsigned char byte;
FILE *f;
idff_t idff;
int enc;
unsigned char buff[4096];
} LoadF;
static const char *getF (lua_State *L, void *ud, size_t *size) {
int i = 0;
LoadF *lf = (LoadF *)ud;
(void)L;
if (lf->extraline) {
lf->extraline = 0;
*size = 1;
return "\n";
}
if (lf->f && feof(lf->f))
return NULL;
if (lf->idff && idf_eof(lf->idff))
return NULL;
if (lf->idff)
*size = idf_read(lf->idff, lf->buff, 1, sizeof(lf->buff));
else
*size = fread(lf->buff, 1, sizeof(lf->buff), lf->f);
if (lf->enc) {
for (i = 0; i < *size; i ++) {
unsigned char b = lf->buff[i];
lf->buff[i] ^= lf->byte;
lf->buff[i] = (lf->buff[i] >> 3) | (lf->buff[i] << 5);
lf->byte = b;
}
}
return (*size > 0) ? (char*)lf->buff : NULL;
}
static int errfile (lua_State *L, const char *what, int fnameindex) {
const char *serr = strerror(errno);
const char *filename = lua_tostring(L, fnameindex) + 1;
lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
lua_remove(L, fnameindex);
return LUA_ERRFILE;
}
static int loadfile (lua_State *L, const char *filename, int enc) {
LoadF lf;
int status, readstatus;
int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */
lf.extraline = 0;
lua_pushfstring(L, "@%s", filename);
lf.idff = idf_open(game_idf, filename);
if (!lf.idff)
lf.f = fopen(dirpath(filename), "rb");
else
lf.f = NULL;
lf.byte = 0xcc;
lf.enc = enc;
if (lf.f == NULL && lf.idff == NULL) return errfile(L, "open", fnameindex);
status = lua_load(L, getF, &lf, lua_tostring(L, -1));
if (lf.f)
readstatus = ferror(lf.f);
else
readstatus = idf_error(lf.idff);
if (filename) {
if (lf.f)
fclose(lf.f); /* close file (even in case of errors) */
idf_close(lf.idff);
}
if (readstatus) {
lua_settop(L, fnameindex); /* ignore results from `lua_load' */
return errfile(L, "read", fnameindex);
}
lua_remove(L, fnameindex);
return status;
}
static int luaB_doencfile (lua_State *L) {
const char *fname = luaL_optstring(L, 1, NULL);
int n = lua_gettop(L);
if (loadfile(L, fname, 1) != 0) lua_error(L);
lua_call(L, 0, LUA_MULTRET);
return lua_gettop(L) - n;
}
static int luaB_dofile (lua_State *L) {
const char *fname = luaL_optstring(L, 1, NULL);
int n = lua_gettop(L);
if (loadfile(L, fname, 0) != 0) lua_error(L);
lua_call(L, 0, LUA_MULTRET);
return lua_gettop(L) - n;
}
static int luaB_print (lua_State *L) {
int n = lua_gettop(L); /* number of arguments */
int i;
lua_getglobal(L, "tostring");
for (i=1; i<=n; i++) {
const char *s;
lua_pushvalue(L, -1); /* function to be called */
lua_pushvalue(L, i); /* value to print */
lua_call(L, 1, 1);
s = lua_tostring(L, -1); /* get result */
if (s == NULL)
return luaL_error(L, LUA_QL("tostring") " must return a string to "LUA_QL("print"));
if (i>1) fputs("\t", stdout);
fputs(s, stdout);
lua_pop(L, 1); /* pop result */
}
fputs("\n", stdout);
return 0;
}
static int luaB_is_sound(lua_State *L) {
const char *chan = luaL_optstring(L, 1, NULL);
int c, r;
if (!chan)
c = -1;
else
c = atoi(chan);
r = snd_playing(c);
lua_pushboolean(L, (r != 0)); /* else not a number */
return 1;
}
static int luaB_get_savepath(lua_State *L) {
lua_pushstring(L, dirname(game_save_path(1, 0)));
return 1;
}
static int luaB_get_gamepath(lua_State *L) {
char path[PATH_MAX];
char *p = getdir(path, sizeof(path));
if (p)
unix_path(p);
lua_pushstring(L, p);
return 1;
}
static int luaB_get_steadpath(lua_State *L) {
char stead_path[PATH_MAX];
strcpy(stead_path, game_cwd);
strcat(stead_path, "/");
strcat(stead_path, STEAD_PATH);
unix_path(stead_path);
lua_pushstring(L, stead_path);
return 1;
}
extern void mouse_reset(int hl); /* too bad */
extern void mouse_restore(void);
static void instead_timer_do(void *data)
{
char *p;
if (game_paused())
goto out;
if (instead_function("stead.timer", NULL)) {
instead_clear();
goto out;
}
p = instead_retval(0); instead_clear();
if (!p)
goto out;
mouse_reset(0);
// fprintf(stderr, "cmd =%s\n", p);
game_cmd(p); free(p);
mouse_restore();
game_cursor(CURSOR_ON);
out:
instead_timer_nr = 0;
}
static int instead_fn(int interval, void *p)
{
if (instead_timer_nr)
return interval; /* framedrop */
instead_timer_nr ++;
push_user_event(instead_timer_do, NULL);
return interval;
}
static int luaB_set_timer(lua_State *L) {
const char *delay = luaL_optstring(L, 1, NULL);
int d;
gfx_del_timer(instead_timer);
instead_timer = NULL_TIMER;
if (!delay)
d = 0;
else
d = atoi(delay);
if (!d)
return 0;
instead_timer_nr = 0;
instead_timer = gfx_add_timer(d, instead_fn, NULL);
return 0;
}
extern int theme_setvar(char *name, char *val);
extern char *theme_getvar(const char *name);
static int luaB_theme_var(lua_State *L) {
const char *var = luaL_optstring(L, 1, NULL);
const char *val = luaL_optstring(L, 2, NULL);
if (var && !val) { /* get */
char *p = theme_getvar(var);
if (p) {
lua_pushstring(L, p);
free(p);
return 1;
}
return 0;
}
if (!val || !var)
return 0;
game_own_theme = 1;
if (!opt_owntheme)
return 0;
if (!theme_setvar((char*)var, (char*)val))
game_theme_changed = 2;
return 0;
}
static int luaB_theme_name(lua_State *L) {
if (game_own_theme && opt_owntheme)
lua_pushstring(L, ".");
else
lua_pushstring(L, curtheme_dir);
return 1;
}
extern int dir_iter_factory (lua_State *L);
extern int luaopen_lfs (lua_State *L);
static LIST_HEAD(sprites);
static LIST_HEAD(fonts);
typedef struct {
struct list_head list;
char *name;
fnt_t fnt;
} _fnt_t;
typedef struct {
struct list_head list;
char *name;
img_t img;
} _spr_t;
static void sprites_free(void)
{
// fprintf(stderr, "sprites free \n");
while (!list_empty(&sprites)) {
_spr_t *sp = (_spr_t*)(sprites.next);
free(sp->name);
cache_forget(gfx_image_cache(), sp->img);
list_del(&sp->list);
free(sp);
}
while (!list_empty(&fonts)) {
_fnt_t *fn = (_fnt_t*)(fonts.next);
fnt_free(fn->fnt);
free(fn->name);
list_del(&fn->list);
free(fn);
}
game_pict_modify(NULL);
cache_shrink(gfx_image_cache());
}
static _spr_t *sprite_lookup(const char *name)
{
struct list_head *pos;
_spr_t *sp;
list_for_each(pos, &sprites) {
sp = (_spr_t*)pos;
if (!strcmp(name, sp->name)) {
list_move(&sp->list, &sprites); // move it on head
return sp;
}
}
return NULL;
}
static _fnt_t *font_lookup(const char *name)
{
struct list_head *pos;
_fnt_t *fn;
list_for_each(pos, &fonts) {
fn = (_fnt_t*)pos;
if (!strcmp(name, fn->name)) {
list_move(&fn->list, &fonts); // move it on head
return fn;
}
}
return NULL;
}
static _spr_t *sprite_new(const char *name, img_t img)
{
_spr_t *sp;
sp = malloc(sizeof(_spr_t));
if (!sp)
return NULL;
INIT_LIST_HEAD(&sp->list);
sp->name = strdup(name);
if (!sp->name) {
free(sp);
return NULL;
}
sp->img = img;
if (cache_add(gfx_image_cache(), name, img)) {
free(sp->name);
free(sp);
return NULL;
}
// fprintf(stderr, "added: %s\n", name);
list_add(&sp->list, &sprites);
return sp;
}
static _fnt_t *font_new(const char *name, fnt_t fnt)
{
_fnt_t *fn;
fn = malloc(sizeof(_fnt_t));
if (!fn)
return NULL;
INIT_LIST_HEAD(&fn->list);
fn->name = strdup(name);
if (!fn->name) {
free(fn);
return NULL;
}
fn->fnt = fnt;
list_add(&fn->list, &fonts);
return fn;
}
static void sprite_name(const char *name, char *sname, int size)
{
unsigned long h = 0;
if (!sname || !size)
return;
h = hash_string(name);
do { /* new uniq name */
snprintf(sname, size, "spr:%lx", h);
h ++;
} while (sprite_lookup(sname) || cache_lookup(gfx_image_cache(), sname));
sname[size - 1] = 0;
}
static void font_name(const char *name, char *sname, int size)
{
unsigned long h = 0;
if (!sname || !size)
return;
h = hash_string(name);
do { /* new uniq name */
snprintf(sname, size, "fnt:%lx", h);
h ++;
} while (font_lookup(sname));
sname[size - 1] = 0;
}
static int _free_sprite(const char *key);
static int luaB_free_sprites(lua_State *L) {
sprites_free();
return 0;
}
static int luaB_load_sprite(lua_State *L) {
img_t img = NULL;
_spr_t *sp;
const char *key;
char sname[sizeof(unsigned long) * 2 + 16];
const char *fname = luaL_optstring(L, 1, NULL);
const char *desc = luaL_optstring(L, 2, NULL);
if (!fname)
return 0;
img = gfx_load_image((char*)fname);
if (img)
img = gfx_display_alpha(img); /*speed up */
if (img)
theme_img_scale(&img);
if (!img)
goto err;
if (!desc || sprite_lookup(desc)) {
key = sname;
sprite_name(fname, sname, sizeof(sname));
} else
key = desc;
sp = sprite_new(key, img);
if (!sp)
goto err;
lua_pushstring(L, key);
return 1;
err:
gfx_free_image(img);
return 0;
}
static int luaB_load_font(lua_State *L) {
fnt_t fnt = NULL;
_fnt_t *fn;
const char *key;
char sname[sizeof(unsigned long) * 2 + 16];
struct game_theme *t = &game_theme;
const char *fname = luaL_optstring(L, 1, NULL);
int sz = luaL_optnumber(L, 2, t->font_size) * game_theme.scale;
const char *desc = luaL_optstring(L, 3, NULL);
if (!fname)
return 0;
fnt = fnt_load((char*)fname, sz);
if (!fnt)
return 0;
if (!desc || font_lookup(desc)) {
key = sname;
font_name(fname, sname, sizeof(sname));
} else
key = desc;
fn = font_new(key, fnt);
if (!fn)
goto err;
lua_pushstring(L, key);
return 1;
err:
fnt_free(fnt);
return 0;
}
static int luaB_text_size(lua_State *L) {
_fnt_t *fn;
int w = 0, h = 0;
const char *font = luaL_optstring(L, 1, NULL);
const char *text = luaL_optstring(L, 2, NULL);
if (!font)
return 0;
fn = font_lookup(font);
if (!fn)
return 0;
if (!text) {
w = 0;
h = ceil((float)fnt_height(fn->fnt) / game_theme.scale);
} else {
txt_size(fn->fnt, text, &w, &h);
w = ceil((float)w / game_theme.scale);
h = ceil((float)h / game_theme.scale);
}
lua_pushnumber(L, w);
lua_pushnumber(L, h);
return 2;
}
static int luaB_font_size_scaled(lua_State *L) {
int sz = luaL_optnumber(L, 1, game_theme.font_size);
lua_pushnumber(L, FONT_SZ(sz));
return 1;
}
static int luaB_text_sprite(lua_State *L) {
img_t img = NULL;
_spr_t *sp;
_fnt_t *fn;
const char *key;
char sname[sizeof(unsigned long) * 2 + 16];
const char *font = luaL_optstring(L, 1, NULL);
const char *text = luaL_optstring(L, 2, NULL);
char txtkey[32];
const char *color = luaL_optstring(L, 3, NULL);
int style = luaL_optnumber(L, 4, 0);
const char *desc = luaL_optstring(L, 5, NULL);
color_t col = { .r = game_theme.fgcol.r, .g = game_theme.fgcol.g, .b = game_theme.fgcol.b };
if (!font)
return 0;
if (color)
gfx_parse_color (color, &col);
if (!text)
text = "";
fn = font_lookup(font);
if (!fn)
return 0;
fnt_style(fn->fnt, style);
img = fnt_render(fn->fnt, text, col);
if (img)
img = gfx_display_alpha(img); /*speed up */
if (!img)
return 0;
if (!desc || sprite_lookup(desc)) {
key = sname;
strncpy(txtkey, text, sizeof(txtkey));
txtkey[sizeof(txtkey) - 1] = 0;
sprite_name(txtkey, sname, sizeof(sname));
} else
key = desc;
sp = sprite_new(key, img);
if (!sp)
goto err;
lua_pushstring(L, key);
return 1;
err:
gfx_free_image(img);
return 0;
}
static img_t grab_sprite(const char *dst, int *xoff, int *yoff)
{
img_t d;
if (DIRECT_MODE && !strcmp(dst, "screen")) {
d = gfx_screen(NULL);
*xoff = game_theme.xoff;
*yoff = game_theme.yoff;
} else {
*xoff = 0;
*yoff = 0;
d = cache_lookup(gfx_image_cache(), dst);
}
return d;
}
static int luaB_sprite_size(lua_State *L) {
img_t s = NULL;
float v;
int w, h;
int xoff, yoff;
const char *src = luaL_optstring(L, 1, NULL);
if (!src)
return 0;
s = grab_sprite(src, &xoff, &yoff);
if (!s)
return 0;
v = game_theme.scale;
w = ceil ((float)(gfx_img_w(s) - xoff * 2) / v);
h = ceil ((float)(gfx_img_h(s) - yoff * 2) / v);
lua_pushnumber(L, w);
lua_pushnumber(L, h);
return 2;
}
static int luaB_draw_sprite(lua_State *L) {
img_t s, d;
img_t img2 = NULL;
float v;
const char *src = luaL_optstring(L, 1, NULL);
int x = luaL_optnumber(L, 2, 0);
int y = luaL_optnumber(L, 3, 0);
int w = luaL_optnumber(L, 4, -1);
int h = luaL_optnumber(L, 5, -1);
const char *dst = luaL_optstring(L, 6, NULL);
int xx = luaL_optnumber(L, 7, 0);
int yy = luaL_optnumber(L, 8, 0);
int alpha = luaL_optnumber(L, 9, 255);
int xoff = 0, yoff = 0;
int xoff0 = 0, yoff0 = 0;
if (!src || !dst)
return 0;
s = grab_sprite(src, &xoff0, &yoff0);
d = grab_sprite(dst, &xoff, &yoff);
if (!s || !d)
return 0;
v = game_theme.scale;
if (v != 1.0f) {
x *= v;
y *= v;
if (w != -1)
w = ceil(w * v);
if (h != -1)
h = ceil(h * v);
xx *= v;
yy *= v;
}
if (w == -1)
w = gfx_img_w(s) - 2 * xoff0;
if (h == -1)
h = gfx_img_h(s) - 2 * yoff0;
game_pict_modify(d);
if (alpha != 255) {
img2 = gfx_alpha_img(s, alpha);
if (img2)
s = img2;
}
gfx_clip(game_theme.xoff, game_theme.yoff, game_theme.w - 2*game_theme.xoff, game_theme.h - 2*game_theme.yoff);
gfx_draw_from(s, x + xoff0, y + yoff0, w, h, d, xx + xoff, yy + yoff);
gfx_noclip();
gfx_free_image(img2);
lua_pushboolean(L, 1);
return 1;
}
static int luaB_copy_sprite(lua_State *L) {
img_t s, d;
img_t img2 = NULL;
float v;
const char *src = luaL_optstring(L, 1, NULL);
int x = luaL_optnumber(L, 2, 0);
int y = luaL_optnumber(L, 3, 0);
int w = luaL_optnumber(L, 4, -1);
int h = luaL_optnumber(L, 5, -1);
const char *dst = luaL_optstring(L, 6, NULL);
int xx = luaL_optnumber(L, 7, 0);
int yy = luaL_optnumber(L, 8, 0);
int xoff = 0, yoff = 0;
int xoff0 = 0, yoff0 = 0;
if (!src || !dst)
return 0;
s = grab_sprite(src, &xoff0, &yoff0);
d = grab_sprite(dst, &xoff, &yoff);
if (!s || !d)
return 0;
v = game_theme.scale;
if (v != 1.0f) {
x *= v;
y *= v;
if (w != -1)
w = ceil(w * v);
if (h != -1)
h = ceil(h * v);
xx *= v;
yy *= v;
}
if (w == -1)
w = gfx_img_w(s) - 2 * xoff0;
if (h == -1)
h = gfx_img_h(s) - 2 * yoff0;
game_pict_modify(d);
gfx_clip(game_theme.xoff, game_theme.yoff, game_theme.w - game_theme.xoff * 2, game_theme.h - game_theme.yoff * 2);
gfx_copy_from(s, x + xoff0, y + yoff0, w, h, d, xx + xoff, yy + yoff);
gfx_noclip();
gfx_free_image(img2);
lua_pushboolean(L, 1);
return 1;
}
static int luaB_alpha_sprite(lua_State *L) {
_spr_t *sp;
img_t s;
img_t img2 = NULL;
const char *key;
char sname[sizeof(unsigned long) * 2 + 16];
const char *src = luaL_optstring(L, 1, NULL);
int alpha = luaL_optnumber(L, 2, 255);
const char *desc = luaL_optstring(L, 3, NULL);
if (!src)
return 0;
s = cache_lookup(gfx_image_cache(), src);
if (!s)
return 0;
img2 = gfx_alpha_img(s, alpha);
if (!img2)
return 0;
if (!desc || sprite_lookup(desc)) {
key = sname;
sprite_name(src, sname, sizeof(sname));
} else
key = desc;
sp = sprite_new(key, img2);
if (!sp)
goto err;
lua_pushstring(L, sname);
return 1;
err:
gfx_free_image(img2);
return 0;
}
static int luaB_dup_sprite(lua_State *L) {
_spr_t *sp;
img_t s;
img_t img2 = NULL;
const char *key;
char sname[sizeof(unsigned long) * 2 + 16];
const char *src = luaL_optstring(L, 1, NULL);
const char *desc = luaL_optstring(L, 2, NULL);
if (!src)
return 0;
s = cache_lookup(gfx_image_cache(), src);
if (!s)
return 0;
img2 = gfx_alpha_img(s, 255);
if (!img2)
return 0;
if (!desc || sprite_lookup(desc)) {
key = sname;
sprite_name(src, sname, sizeof(sname));
} else
key = desc;
sp = sprite_new(key, img2);
if (!sp)
goto err;
lua_pushstring(L, sname);
return 1;
err:
gfx_free_image(img2);
return 0;
}
static int luaB_scale_sprite(lua_State *L) {
_spr_t *sp;
img_t s;
img_t img2 = NULL;
const char *key;
char sname[sizeof(unsigned long) * 2 + 16];
const char *src = luaL_optstring(L, 1, NULL);
float xs = luaL_optnumber(L, 2, 0);
float ys = luaL_optnumber(L, 3, 0);
const char *desc = luaL_optstring(L, 4, NULL);
if (!src)
return 0;
s = cache_lookup(gfx_image_cache(), src);
if (!s)
return 0;
if (xs == 0)
xs = 1.0f;
if (ys == 0)
ys = xs;
img2 = gfx_scale(s, xs, ys);
if (!img2)
return 0;
if (!desc || sprite_lookup(desc)) {
key = sname;
sprite_name(src, sname, sizeof(sname));
} else
key = desc;
sp = sprite_new(key, img2);
if (!sp)
goto err;
lua_pushstring(L, sname);
return 1;
err:
gfx_free_image(img2);
return 0;
}
static int luaB_rotate_sprite(lua_State *L) {
_spr_t *sp;
img_t s;
img_t img2 = NULL;
const char *key;
char sname[sizeof(unsigned long) * 2 + 16];
const char *src = luaL_optstring(L, 1, NULL);
float angle = luaL_optnumber(L, 2, 1.0f);
const char *desc = luaL_optstring(L, 3, NULL);
if (!src)
return 0;
s = cache_lookup(gfx_image_cache(), src);
if (!s)
return 0;
img2 = gfx_rotate(s, angle);
if (!img2)
return 0;
if (!desc || sprite_lookup(desc)) {
key = sname;
sprite_name(src, sname, sizeof(sname));
} else
key = desc;
sp = sprite_new(key, img2);
if (!sp)
goto err;
lua_pushstring(L, sname);
return 1;
err:
gfx_free_image(img2);
return 0;
}
static int luaB_fill_sprite(lua_State *L) {
img_t d;
float v;
const char *dst = luaL_optstring(L, 1, NULL);
int x = luaL_optnumber(L, 2, 0);
int y = luaL_optnumber(L, 3, 0);
int w = luaL_optnumber(L, 4, -1);
int h = luaL_optnumber(L, 5, -1);
const char *color = luaL_optstring(L, 6, NULL);
int xoff = 0, yoff = 0;
color_t col = { .r = game_theme.bgcol.r, .g = game_theme.bgcol.g, .b = game_theme.bgcol.b };
if (!dst)
return 0;
d = grab_sprite(dst, &xoff, &yoff);
if (color)
gfx_parse_color(color, &col);
if (!d)
return 0;
v = game_theme.scale;
if (v != 1.0f) {
x *= v;
y *= v;
if (w != -1)
w = ceil(w * v);
if (h != -1)
h = ceil(h * v);
}
if (w == -1)
w = gfx_img_w(d) - 2 * xoff;
if (h == -1)
h = gfx_img_h(d) - 2 * yoff;
game_pict_modify(d);
gfx_clip(game_theme.xoff, game_theme.yoff, game_theme.w - 2*game_theme.xoff, game_theme.h - 2*game_theme.yoff);
gfx_img_fill(d, x + xoff, y + yoff, w, h, col);
gfx_noclip();
lua_pushboolean(L, 1);
return 1;
}
static int luaB_pixel_sprite(lua_State *L) {
img_t d;
float v;
int rc, w, h;
color_t col = { .r = game_theme.bgcol.r, .g = game_theme.bgcol.g, .b = game_theme.bgcol.b, .a = 255 };
const char *dst = luaL_optstring(L, 1, NULL);
int x = luaL_optnumber(L, 2, 0);
int y = luaL_optnumber(L, 3, 0);
const char *color = luaL_optstring(L, 4, NULL);
int alpha = luaL_optnumber(L, 5, 255);
int xoff = 0, yoff = 0;
if (!dst)
return 0;
d = grab_sprite(dst, &xoff, &yoff);
if (color)
gfx_parse_color(color, &col);
if (!d)
return 0;
w = gfx_img_w(d) - 2 * xoff;
h = gfx_img_h(d) - 2 * yoff;
v = game_theme.scale;
if (v != 1.0f) {
x *= v;
y *= v;
}
if (color) {
if (x < 0 || y < 0 || x >= w || y >= h)
return 0;
game_pict_modify(d);
col.a = alpha;
rc = gfx_set_pixel(d, x + xoff, y + yoff, col);
} else {
rc = gfx_get_pixel(d, x + xoff, y + yoff, &col);
}
if (rc)
return 0;
lua_pushnumber(L, col.r);
lua_pushnumber(L, col.g);
lua_pushnumber(L, col.b);
lua_pushnumber(L, col.a);
return 4;
}
static int _free_sprite(const char *key)
{
_spr_t *sp;
if (!key)
return -1;
sp = sprite_lookup(key);
if (!sp)
return -1;
cache_forget(gfx_image_cache(), sp->img);
cache_shrink(gfx_image_cache());
list_del(&sp->list);
free(sp->name); free(sp);
return 0;
}
static int luaB_free_sprite(lua_State *L) {
const char *key = luaL_optstring(L, 1, NULL);
if (_free_sprite(key))
return 0;
lua_pushboolean(L, 1);
return 1;
}
static int luaB_show_menu(lua_State *L) {
menu_toggle();
return 0;
}
static int luaB_free_font(lua_State *L) {
const char *key = luaL_optstring(L, 1, NULL);
_fnt_t *fn;
if (!key)
return 0;
fn = font_lookup(key);
if (!fn)
return 0;
list_del(&fn->list);
free(fn->name); free(fn);
lua_pushboolean(L, 1);
return 1;
}
static int luaB_load_sound(lua_State *L) {
int rc;
const char *fname = luaL_optstring(L, 1, NULL);
if (!fname)
return 0;
rc = sound_load(fname);
if (rc)
return 0;
lua_pushstring(L, fname);
return 1;
}
static int luaB_free_sound(lua_State *L) {
const char *fname = luaL_optstring(L, 1, NULL);
if (!fname)
return 0;
sound_unload(fname);
return 0;
}
static int luaB_free_sounds(lua_State *L) {
sounds_free();
return 0;
}
static int luaB_panning_sound(lua_State *L) {
int chan = luaL_optnumber(L, 1, -1);
int left = luaL_optnumber(L, 2, 255);
int right = luaL_optnumber(L, 3, 255);
snd_panning(chan, left, right);
return 0;
}
static int luaB_volume_sound(lua_State *L) {
int vol = luaL_optnumber(L, 1, -1);
vol = snd_volume_mus(vol);
lua_pushnumber(L, vol);
return 1;
}
static int luaB_channel_sound(lua_State *L) {
const char *s;
int ch = luaL_optnumber(L, 1, 0);
ch = ch % SND_CHANNELS;
s = sound_channel(ch);
if (s) {
lua_pushstring(L, s);
return 1;
}
return 0;
}
static int luaB_mouse_pos(lua_State *L) {
int x = luaL_optnumber(L, 1, -1);
int y = luaL_optnumber(L, 2, -1);
float v = game_theme.scale;
if (x != -1 && y != -1) {
x *= v;
y *= v;
gfx_warp_cursor(x + game_theme.xoff, y + game_theme.yoff);
x = -1;
y = -1;
}
gfx_cursor(&x, &y);
x = (x - game_theme.xoff) / v;
y = (y - game_theme.yoff) / v;
lua_pushnumber(L, x);
lua_pushnumber(L, y);
return 2;
}
static int luaB_get_ticks(lua_State *L) {
lua_pushnumber(L, gfx_ticks());
return 1;
}
static int luaB_bit_and(lua_State *L) {
unsigned int a = luaL_optnumber(L, 1, 0);
unsigned int b = luaL_optnumber(L, 2, 0);
unsigned int r = a & b;
lua_pushnumber(L, r);
return 1;
}
static int luaB_bit_or(lua_State *L) {
unsigned int a = luaL_optnumber(L, 1, 0);
unsigned int b = luaL_optnumber(L, 2, 0);
unsigned int r = a | b;
lua_pushnumber(L, r);
return 1;
}
static int luaB_bit_xor(lua_State *L) {
unsigned int a = luaL_optnumber(L, 1, 0);
unsigned int b = luaL_optnumber(L, 2, 0);
unsigned int r = a ^ b;
lua_pushnumber(L, r);
return 1;
}
static int luaB_bit_shl(lua_State *L) {
unsigned int a = luaL_optnumber(L, 1, 0);
unsigned int b = luaL_optnumber(L, 2, 0);
unsigned int r = a << b;
lua_pushnumber(L, r);
return 1;
}
static int luaB_bit_shr(lua_State *L) {
unsigned int a = luaL_optnumber(L, 1, 0);
unsigned int b = luaL_optnumber(L, 2, 0);
unsigned int r = a >> b;
lua_pushnumber(L, r);
return 1;
}
static int luaB_bit_not(lua_State *L) {
unsigned int a = luaL_optnumber(L, 1, 0);
unsigned int r = ~a;
lua_pushnumber(L, r);
return 1;
}
static int luaB_bit_div(lua_State *L) {
unsigned int a = luaL_optnumber(L, 1, 0);
unsigned int b = luaL_optnumber(L, 2, 1);
unsigned int r;
if (b) {
r = a / b;
lua_pushnumber(L, r);
return 1;
}
return 0;
}
static int luaB_bit_idiv(lua_State *L) {
int a = luaL_optnumber(L, 1, 0);
int b = luaL_optnumber(L, 2, 1);
int r;
if (b) {
r = a / b;
lua_pushnumber(L, r);
return 1;
}
return 0;
}
static int luaB_bit_mod(lua_State *L) {
unsigned int a = luaL_optnumber(L, 1, 0);
unsigned int b = luaL_optnumber(L, 2, 1);
unsigned int r;
if (b) {
r = a % b;
lua_pushnumber(L, r);
return 1;
}
return 0;
}
static int luaB_bit_mul(lua_State *L) {
unsigned int a = luaL_optnumber(L, 1, 0);
unsigned int b = luaL_optnumber(L, 2, 0);
unsigned int r = a * b;
lua_pushnumber(L, r);
return 1;
}
static int luaB_bit_imul(lua_State *L) {
int a = luaL_optnumber(L, 1, 0);
int b = luaL_optnumber(L, 2, 0);
int r = a * b;
lua_pushnumber(L, r);
return 1;
}
static int luaB_bit_sub(lua_State *L) {
unsigned int a = luaL_optnumber(L, 1, 0);
unsigned int b = luaL_optnumber(L, 2, 0);
unsigned int r = a - b;
lua_pushnumber(L, r);
return 1;
}
static int luaB_bit_add(lua_State *L) {
unsigned int a = luaL_optnumber(L, 1, 0);
unsigned int b = luaL_optnumber(L, 2, 0);
unsigned int r = a + b;
lua_pushnumber(L, r);
return 1;
}
static int luaB_bit_unsigned(lua_State *L) {
unsigned int a = luaL_optnumber(L, 1, 0);
lua_pushnumber(L, a);
return 1;
}
static int luaB_bit_signed(lua_State *L) {
unsigned int a = luaL_optnumber(L, 1, 0);
lua_pushnumber(L, (int)a);
return 1;
}
static const luaL_Reg base_funcs[] = {
{"doencfile", luaB_doencfile},
{"dofile", luaB_dofile},
{"print", luaB_print}, /* for some mystic, it is needed in win version (with -debug) */
{"is_sound", luaB_is_sound},
{"get_savepath", luaB_get_savepath},
{"get_gamepath", luaB_get_gamepath},
{"get_steadpath", luaB_get_steadpath},
{"set_timer", luaB_set_timer},
{"theme_var", luaB_theme_var},
{"theme_name", luaB_theme_name},
{"readdir", dir_iter_factory},
{"menu_toggle", luaB_show_menu},
{"sound_load", luaB_load_sound},
{"sound_free", luaB_free_sound},
{"sound_channel", luaB_channel_sound},
{"sound_panning", luaB_panning_sound},
{"sound_volume", luaB_volume_sound},
{"sounds_free", luaB_free_sounds},
{"mouse_pos", luaB_mouse_pos},
{"font_load", luaB_load_font},
{"font_free", luaB_free_font},
{"font_scaled_size", luaB_font_size_scaled},
{"get_ticks", luaB_get_ticks},
{"sprite_load", luaB_load_sprite},
{"sprite_text", luaB_text_sprite},
{"sprite_free", luaB_free_sprite},
{"sprites_free", luaB_free_sprites},
{"sprite_draw", luaB_draw_sprite},
{"sprite_copy", luaB_copy_sprite},
{"sprite_fill", luaB_fill_sprite},
{"sprite_dup", luaB_dup_sprite},
{"sprite_alpha", luaB_alpha_sprite},
{"sprite_size", luaB_sprite_size},
{"sprite_scale", luaB_scale_sprite},
{"sprite_rotate", luaB_rotate_sprite},
{"sprite_text_size", luaB_text_size},
{"sprite_pixel", luaB_pixel_sprite},
{"bit_or", luaB_bit_or},
{"bit_and", luaB_bit_and},
{"bit_xor", luaB_bit_xor},
{"bit_shl", luaB_bit_shl},
{"bit_shr", luaB_bit_shr},
{"bit_not", luaB_bit_not},
{"bit_div", luaB_bit_div},
{"bit_idiv", luaB_bit_idiv},
{"bit_mod", luaB_bit_mod},
{"bit_mul", luaB_bit_mul},
{"bit_imul", luaB_bit_imul},
{"bit_sub", luaB_bit_sub},
{"bit_add", luaB_bit_add},
{"bit_signed", luaB_bit_signed},
{"bit_unsigned", luaB_bit_unsigned},
{NULL, NULL}
};
int instead_lang(void)
{
char lang[64];
if (!L)
return 0;
if (opt_lang && *opt_lang)
snprintf(lang, sizeof(lang) - 1, "LANG='%s'", opt_lang);
else
snprintf(lang, sizeof(lang) - 1, "LANG='en'");
instead_eval(lang); instead_clear();
return 0;
}
static int instead_package(void)
{
char *p;
char stead_path[PATH_MAX] = "package.path=\"./?.lua;";
p = game_local_stead_path();
if (p) {
strcat(stead_path, p);
strcat(stead_path, "/?.lua");
strcat(stead_path, ";");
}
if (STEAD_PATH[0] != '/') {
strcat(stead_path, game_cwd);
strcat(stead_path, "/");
strcat(stead_path, STEAD_PATH);
} else {
strcat(stead_path, STEAD_PATH);
}
strcat(stead_path, "/?.lua");
strcat(stead_path, "\"");
instead_eval(stead_path); instead_clear();
/* putenv(stead_path); */
return 0;
}
int instead_init(void)
{
setlocale(LC_ALL,"");
setlocale(LC_NUMERIC,"C"); /* to avoid . -> , in numbers */
// strcpy(curcp, "UTF-8");
/* initialize Lua */
L = lua_open();
if (!L)
return -1;
luaL_openlibs(L);
luaL_register(L, "_G", base_funcs);
luaopen_lfs (L);
instead_package();
instead_lang();
if (dofile(L, dirpath(STEAD_PATH"/stead.lua"))) {
return -1;
}
if (dofile(L, dirpath(STEAD_PATH"/gui.lua"))) {
instead_clear();
return -1;
}
/* cleanup Lua */
instead_clear();
srand(time(NULL));
return 0;
}
void instead_done(void)
{
gfx_del_timer(instead_timer);
instead_timer = NULL_TIMER;
#ifdef _HAVE_ICONV
if (fromcp)
free(fromcp);
#endif
if (L)
lua_close(L);
L = NULL;
#ifdef _HAVE_ICONV
fromcp = NULL;
#endif
sprites_free();
}
int instead_encode(const char *s, const char *d)
{
FILE *src;
FILE *dst;
size_t size;
int i = 0;
unsigned char byte = 0xcc;
unsigned char buff[4096];
src = fopen(s, "rb");
if (!src) {
fprintf(stderr,"Can't open on read: '%s'.\n", s);
return -1;
}
dst = fopen(d, "wb");
if (!dst) {
fprintf(stderr,"Can't open on write: '%s'.\n", s);
return -1;
}
while ((size = fread(buff, 1, sizeof(buff), src))) {
for (i = 0; i < size; i++) {
buff[i] = (buff[i] << 3) | (buff[i] >> 5);
buff[i] ^= byte;
byte = buff[i];
}
if (fwrite(buff, 1, size, dst) != size) {
fprintf(stderr, "Error while writing file: '%s'.\n", d);
return -1;
}
}
fclose(src);
fclose(dst);
return 0;
}