From 8955316bba54ed637f226b924314f1e6eacd0f43 Mon Sep 17 00:00:00 2001 From: helixhorned Date: Thu, 28 Feb 2013 17:30:15 +0000 Subject: [PATCH] Lunatic t.: {read,save}gamevar, fix break in nested while, fix rotatesprite16. git-svn-id: https://svn.eduke32.com/eduke32@3533 1a8010ca-5511-0410-912e-c29ae57300e0 --- polymer/eduke32/source/lunatic/control.lua | 35 ++++++++++++ polymer/eduke32/source/lunatic/defs.ilua | 4 ++ polymer/eduke32/source/lunatic/dynsymlist | 3 + polymer/eduke32/source/lunatic/lunacon.lua | 56 ++++++++++++++----- .../eduke32/source/lunatic/test/switch.con | 17 ++++++ 5 files changed, 102 insertions(+), 13 deletions(-) diff --git a/polymer/eduke32/source/lunatic/control.lua b/polymer/eduke32/source/lunatic/control.lua index a5330c09a..851209cec 100644 --- a/polymer/eduke32/source/lunatic/control.lua +++ b/polymer/eduke32/source/lunatic/control.lua @@ -276,6 +276,13 @@ function rotatesprite(x, y, zoom, ang, tilenum, shade, pal, orientation, check_tile_idx(tilenum) orientation = bit.band(orientation, 2047) -- ROTATESPRITE_MAX-1 + -- XXX: This is the same as the check in gameexec.c, but ideally we'd want + -- rotatesprite to accept all coordinates and simply draw nothing if they + -- denote an area beyond the screen. + if (not (x >= -320 and x < 640) or not (y >= -200 and y < 400)) then + error(format("invalid coordinates (%.03f, %.03f)", x, y), 2) + end + -- TODO: check that it works correctly with all coordinates, also if one -- border is outside the screen etc... ffiC.rotatesprite(65536*x, 65536*y, zoom, ang, tilenum, shade, pal, bit.bor(2,orientation), @@ -1578,6 +1585,34 @@ function _setgamepalette(pli, basepal) ffiC.P_SetGamePalette(player[pli], basepal) end +-- Gamevar persistence in the configuration file + +function _savegamevar(name, val) + if (ffiC.ud.config.scripthandle < 0) then + return + end + + assert(type(name)=="string") + assert(type(val)=="number") + + ffiC.SCRIPT_PutNumber(ffiC.ud.config.scripthandle, "Gamevars", name, + val, 0, 0); +end + +function _readgamevar(name) + if (ffiC.ud.config.scripthandle < 0) then + return + end + + assert(type(name)=="string") + + local v = ffi.new("int32_t [1]") + ffiC.SCRIPT_GetNumber(ffiC.ud.config.scripthandle, "Gamevars", name, v); + -- NOTE: doesn't examine SCRIPT_GetNumber() return value and returns 0 if + -- there was no such gamevar saved, like C-CON. + return v[0] +end + --- Game arrays --- diff --git a/polymer/eduke32/source/lunatic/defs.ilua b/polymer/eduke32/source/lunatic/defs.ilua index 4cc243406..d54aaca34 100644 --- a/polymer/eduke32/source/lunatic/defs.ilua +++ b/polymer/eduke32/source/lunatic/defs.ilua @@ -595,6 +595,10 @@ void C_DefineLevelName(int32_t vol, int32_t lev, const char *fn, void C_DefineProjectile(int32_t j, int32_t what, int32_t val); void C_DefineGameFuncName(int32_t idx, const char *name); int32_t C_SetDefName(const char *name); + +int32_t SCRIPT_GetNumber(int32_t scripthandle, const char *sectionname, const char *entryname, int32_t *number); +void SCRIPT_PutNumber(int32_t scripthandle, const char *sectionname, const char *entryname, int32_t number, + int32_t hexadecimal, int32_t defaultvalue); ]] diff --git a/polymer/eduke32/source/lunatic/dynsymlist b/polymer/eduke32/source/lunatic/dynsymlist index 024a129c1..8aef7b513 100644 --- a/polymer/eduke32/source/lunatic/dynsymlist +++ b/polymer/eduke32/source/lunatic/dynsymlist @@ -94,6 +94,9 @@ C_DefineProjectile; C_DefineGameFuncName; C_SetDefName; +SCRIPT_GetNumber; +SCRIPT_PutNumber; + actor; g_camera; ud; diff --git a/polymer/eduke32/source/lunatic/lunacon.lua b/polymer/eduke32/source/lunatic/lunacon.lua index e5e08d67a..92f688dfa 100644 --- a/polymer/eduke32/source/lunatic/lunacon.lua +++ b/polymer/eduke32/source/lunatic/lunacon.lua @@ -28,8 +28,12 @@ local unpack = unpack local read_into_string = read_into_string local ffi, ffiC -if (string.dump) then - bit = require("bit") +if (string.dump) then -- running stand-alone + local ljp = pcall(function() require("ffi") end) + -- "lbit" is the same module as LuaJIT's "bit" (LuaBitOp: + -- http://bitop.luajit.org/), but under a different name for (IMO) less + -- confusion. Useful for running with Rio Lua for cross-checking. + bit = ljp and require("bit") or require("lbit") require("strict") else bit = require("bit") @@ -948,7 +952,7 @@ function Cmd.gamearray(identifier, initsize) return end - if (initsize >= 0x7fffffff+0ULL) then + if (not (initsize >= 0 and initsize < 0x7fffffff)) then errprintf("invalid initial size %d for gamearray `%s'", initsize, identifier) return end @@ -1587,7 +1591,35 @@ local handle = end, rotatesprite16 = function(...) - return format("_con.rotatesprite(%s,%s/65536,%s/65536,%s,%s,%s,%s,%s,%s,%s,%s,%s)", ...) + return format("_con.rotatesprite(%s/65536,%s/65536,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", ...) + end, + + -- readgamevar or savegamevar + RSgamevar = function(identifier, dosave) + -- check identifier for sanity + if (not identifier:match("^[A-Za-z][A-Za-z0-9_]*$")) then + errprintf("%s: invalid identifier name `%s' for config file persistence", + g_lastkw) + return "_BADRSGV()" + end + + local gv = g_gamevar[identifier] + if (gv and bit.band(gv.flags, GVFLAG.PERX_MASK)==GVFLAG.PERACTOR) then + -- Per-player are kind of global without multiplayer anyway. TODO_MP + errprintf("can only %s global or per-player gamevars", g_lastkw, + dosave and "save" or "read") + return "_BADRSGV()" + end + + -- NOTE: more strict than C-CON: we require the gamevar being writable + -- even if we're saving it. + local code = lookup.gamevar(identifier, nil, true) + + if (dosave) then + return format("_con._savegamevar(%q,%s)", identifier, code) + else + return format("%s=_con._readgamevar(%q)", code, identifier) + end end, state = function(statename) @@ -1618,7 +1650,7 @@ local Cinner = { ["break"] = cmd() / function() return g_isWhile[#g_isWhile] - and format("goto l%d", g_whilenum) + and format("goto l%d", #g_isWhile) or "do return end" end, ["return"] = cmd() -- NLCF @@ -1976,10 +2008,10 @@ local Cinner = { / handle.dynNYI, savemapstate = cmd() / handle.dynNYI, - savegamevar = cmd(R) - / handle.dynNYI, - readgamevar = cmd(W) - / handle.dynNYI, + savegamevar = cmd(I) + / function(id) return handle.RSgamevar(id, true) end, + readgamevar = cmd(I) + / function(id) return handle.RSgamevar(id, false) end, savenn = cmd(D) / handle.dynNYI, save = cmd(D) @@ -2621,10 +2653,9 @@ function on.while_begin(v1, v2) end function on.while_end() + local whilenum = #g_isWhile table.remove(g_isWhile) - local code=format("::l%d:: end", g_whilenum) - g_whilenum = g_whilenum+1 - return code + return format("::l%d:: end", whilenum) end function on.switch_begin() @@ -2838,7 +2869,6 @@ function on.parse_begin() g_iflevel = 0 g_ifelselevel = 0 g_isWhile = {} - g_whilenum = 0 g_have_file[g_filename] = true -- set up new state diff --git a/polymer/eduke32/source/lunatic/test/switch.con b/polymer/eduke32/source/lunatic/test/switch.con index fb3be3d63..b738c48a8 100644 --- a/polymer/eduke32/source/lunatic/test/switch.con +++ b/polymer/eduke32/source/lunatic/test/switch.con @@ -107,4 +107,21 @@ onevent EVENT_ENTERLEVEL userquote 30 endswitch */ + + // nested whilevar*n + setvar j -1 + setvar k -1 + whilevarn j 0 + { + whilevarn k 0 + { + setvar k 0 + break + setvar k 1 + } + + setvar j 0 + break + setvar j -1 + } endevent