From 39ce7aee62fd44fa56a2d575dba491356b36bf40 Mon Sep 17 00:00:00 2001 From: helixhorned Date: Sun, 13 Jan 2013 16:40:32 +0000 Subject: [PATCH] Lunatic: codegen beyond milestone 1. - weapon data - changing ones... (locals for now) - operators git-svn-id: https://svn.eduke32.com/eduke32@3392 1a8010ca-5511-0410-912e-c29ae57300e0 --- polymer/eduke32/source/game.c | 3 + polymer/eduke32/source/lunatic/con_lang.lua | 24 ++++ polymer/eduke32/source/lunatic/control.lua | 22 +++- polymer/eduke32/source/lunatic/defs.ilua | 71 ++++++++++- polymer/eduke32/source/lunatic/dynsymlist | 1 + polymer/eduke32/source/lunatic/lunacon.lua | 124 ++++++++++++++------ polymer/eduke32/source/lunatic/test.elua | 1 + polymer/eduke32/source/player.h | 7 ++ 8 files changed, 212 insertions(+), 41 deletions(-) diff --git a/polymer/eduke32/source/game.c b/polymer/eduke32/source/game.c index 087c2722a..fe5c00b1d 100644 --- a/polymer/eduke32/source/game.c +++ b/polymer/eduke32/source/game.c @@ -10435,6 +10435,9 @@ int32_t app_main(int32_t argc, const char **argv) for (i=0; iidx = i; +#endif if (!g_player[i].sync) g_player[i].sync = (input_t *)Bcalloc(1, sizeof(input_t)); } diff --git a/polymer/eduke32/source/lunatic/con_lang.lua b/polymer/eduke32/source/lunatic/con_lang.lua index e49c9bf3e..dcc63ac18 100644 --- a/polymer/eduke32/source/lunatic/con_lang.lua +++ b/polymer/eduke32/source/lunatic/con_lang.lua @@ -276,6 +276,30 @@ labels = GAMEFUNC, } +-- KEEPINSYNC player.h +wdata_members = +{ + -- NOTE: they are lowercased for Lunatic + "int32_t workslike", + "int32_t clip", + "int32_t reload", + "int32_t firedelay", + "int32_t totaltime", + "int32_t holddelay", + "int32_t flags", + "int32_t shoots", + "int32_t spawntime", + "int32_t spawn", + "int32_t shotsperburst", + "int32_t initialsound", + "int32_t firesound", + "int32_t sound2time", + "int32_t sound2sound", + "int32_t reloadsound1", + "int32_t reloadsound2", + "int32_t selectsound", + "int32_t flashcolor", +} -- NOTE: These MUST be in reverse lexicographical order! -- Per CON syntax, valid identifiers names are disjunct from keywords, diff --git a/polymer/eduke32/source/lunatic/control.lua b/polymer/eduke32/source/lunatic/control.lua index 4485e1317..a77f2b150 100644 --- a/polymer/eduke32/source/lunatic/control.lua +++ b/polymer/eduke32/source/lunatic/control.lua @@ -252,6 +252,26 @@ function rnd(x) return (bit.rshift(ffiC.krand(), 8) >= (255-x)) end +-- Legacy operators + +function _rand(x) + return bit.rshift(ffiC.krand()*(x+1), 16) +end + +function _div(a,b) + if (b==0) then + error("divide by zero", 2) + end + return (a - math.fmod(a,b))/b +end + +function _mod(a,b) + if (b==0) then + error("mod by zero", 2) + end + return math.fmod(a,b) +end + ---=== Weapon stuff ===--- @@ -964,7 +984,7 @@ end local function check_sound_idx(sndidx) if (sndidx >= con_lang.MAXSOUNDS+0ULL) then - error("invalid sound number "..sndidx, 2) + error("invalid sound number "..sndidx, 3) end end diff --git a/polymer/eduke32/source/lunatic/defs.ilua b/polymer/eduke32/source/lunatic/defs.ilua index 81d403dd9..af965a60d 100644 --- a/polymer/eduke32/source/lunatic/defs.ilua +++ b/polymer/eduke32/source/lunatic/defs.ilua @@ -232,7 +232,7 @@ local DUKEPLAYER_STRUCT = [[ const char name[32]; - const int8_t padding_[1]; + const int8_t idx; } ]] @@ -270,6 +270,9 @@ end --print(mangle_arrays(ACTOR_STRUCT)) +--- default defines etc. +local con_lang = require("con_lang") + ffi.cdef([[ #pragma pack(push, 1) typedef struct @@ -336,6 +339,11 @@ typedef struct { } tiledata_t; #pragma pack(pop) +// NOTE: not packed! +typedef struct { +]] .. table.concat(con_lang.wdata_members, ';')..';' .. [[ +} weapondata_t; + enum { MAXMOUSEBUTTONS = 10, @@ -453,6 +461,7 @@ int32_t g_elCallDepth; actor_t actor[MAXSPRITES]; user_defs ud; playerdata_t g_player[MAXPLAYERS]; +weapondata_t g_playerWeapon[MAXPLAYERS][MAX_WEAPONS]; tiledata_t g_tile[MAXTILES]; char *ScriptQuotes[]; @@ -717,9 +726,6 @@ local actor_mt = { ffi.metatype("actor_t", actor_mt) ---- default defines etc. -local con_lang = require("con_lang") - local function check_weapon_idx(weap) if (weap >= ffiC.MAX_WEAPONS+0ULL) then error("Invalid weapon ID "..weap, 3) @@ -732,6 +738,55 @@ local function check_inventory_idx(inv) end end +-- XXX: CODEDUP control.lua +local function check_sound_idx(sndidx) + if (sndidx >= con_lang.MAXSOUNDS+0ULL) then + error("invalid sound number "..sndidx, 3) + end +end + +-- XXX: CODEDUP control.lua +local function check_tile_idx(tilenum) + if (tilenum >= ffiC.MAXTILES+0ULL) then + error("invalid argument: must be a valid tile number", 3) + end +end + +local weapondata_accessor = {} +local function get_weapondata_accessor(pli, weap) + assert(pli < ffiC.MAXPLAYERS+0ULL) + + local wdaidx = pli*1024 + weap + + if (weapondata_accessor[wdaidx] ~= nil) then + return weapondata_accessor[wdaidx] + end + + local weapondata_mt = { + __index = ffiC.g_playerWeapon[pli][weap], + + __newindex = function(_, member, val) + if (string.match(member, "sound")) then + check_sound_idx(val) + elseif (member=="workslike") then + check_weapon_idx(val) + elseif (member=="shoots" or member=="spawn") then + -- TODO: set to 0 if oob? (e.g. AMC TC) + check_tile_idx(val) + end + + ffiC.g_playerWeapon[pli][weap][member] = val + end, + + __metatable = true, + } + + local tab = setmetatable({}, weapondata_mt) + weapondata_accessor[wdaidx] = tab + + return tab +end + local player_mt = { __index = { --- Getters/setters @@ -777,6 +832,13 @@ local player_mt = { ffi.cast(player_ptr_ct, p).customexitsound = soundnum end, + -- Access to weapon data (g_playerWeapon) + -- TODO: Make syntax e.g. "player[0].weapon.KNEE.shoots" possible + weapon = function(p, weap) + check_weapon_idx(weap) + return get_weapondata_accessor(p.idx, weap) + end, + -- CON-like addammo/addweapon, but without the non-local control flow -- (returns true if weapon's ammo was at the max. instead). addammo = con._addammo, @@ -971,6 +1033,7 @@ local module_mt = { -- Our 'module' replacement doesn't get the module name from the function args -- since a malicious user could remove other loaded modules this way. +-- Also, our 'module' has no varargs ("option functions" in Lua). -- TODO: make transactional? local function our_module() local modname = modname_stack[#modname_stack] diff --git a/polymer/eduke32/source/lunatic/dynsymlist b/polymer/eduke32/source/lunatic/dynsymlist index 3c75a152b..959b88f49 100644 --- a/polymer/eduke32/source/lunatic/dynsymlist +++ b/polymer/eduke32/source/lunatic/dynsymlist @@ -78,6 +78,7 @@ C_DefineLevelName; actor; ud; g_player; +g_playerWeapon; g_tile; ScriptQuotes; diff --git a/polymer/eduke32/source/lunatic/lunacon.lua b/polymer/eduke32/source/lunatic/lunacon.lua index 134664dfb..9d7ddb321 100644 --- a/polymer/eduke32/source/lunatic/lunacon.lua +++ b/polymer/eduke32/source/lunatic/lunacon.lua @@ -90,17 +90,24 @@ local g_numerrors = 0 local g_warn = { ["not-redefined"]=true, ["bad-identifier"]=true, ["number-conversion"]=true, } +-- Code generation options. +local g_cgopt = { ["no"]=false, } + -- How many 'if' statements are following immediately each other, -- needed to cope with CONs dangling-else resolution local g_iflevel = 0 local g_ifelselevel = 0 ---=== Code generation ===--- -local GVFLAG = { PERPLAYER=1, PERACTOR=2, PERX_MASK=3, } +local GVFLAG = { + PERPLAYER=1, PERACTOR=2, PERX_MASK=3, + SYSTEM = 0x00000800, + READONLY = 0x00001000, +} -- CON --> mangled Lua function name, also existence check: local g_funcname = {} --- [identifier] = { name=, flags= } +-- [identifier] = { name=, flags= } local g_gamevar = {} local g_have_file = {} -- [filename]=true @@ -110,6 +117,11 @@ local g_curcode = nil -- a table of string pieces or other "gencode" tables local g_code = { actor={}, event={}, loadactor={} } +local function ACS(s) return "actor[_aci]"..s end +local function SPS(s) return "sprite[_aci]"..s end +local function PLS(s) return "player[_pli]"..s end + + local function getlinecol(pos) end -- fwd-decl local function new_initial_codetab() @@ -120,9 +132,31 @@ local function new_initial_codetab() } end +-- Creates the table of predefined game variables. +-- KEEPINSYNC gamevars.c: Gv_AddSystemVars() +local function new_initial_gvartab() + local wmembers = conl.wdata_members + local gamevar = {} + + local MAX_WEAPONS = ffiC and ffiC.MAX_WEAPONS or 12 + + for w=0,MAX_WEAPONS-1 do + for i=1,#wmembers do + local member = wmembers[i]:gsub(".* ","") -- strip e.g. "int32_t " + local name = format("WEAPON%d_%s", w, member:upper()) + + local code = format(PLS":weapon(%d).%s", w, member) + + gamevar[name] = { name=code, flags=GVFLAG.PERPLAYER+GVFLAG.SYSTEM } + end + end + + return gamevar +end + local function reset_codegen() g_funcname = {} - g_gamevar = {} + g_gamevar = new_initial_gvartab() g_have_file = {} g_curcode = new_initial_codetab() @@ -696,13 +730,13 @@ function Cmd.gamevar(identifier, initval, flags) -- TODO: Write gamevar system on the Lunatic side and hook it up. -- TODO: per-player gamevars if (flags==GVFLAG.PERACTOR) then - return format("local %s=_con.peractorvar(%d)", gv.name, initval) + addcodef("local %s=_con.peractorvar(%d)", gv.name, initval) else - return format("local %s=%d", gv.name, initval) + addcodef("local %s=%d", gv.name, initval) end end -local function lookup_gamevar(identifier) +local function lookup_gamevar(identifier, writable) local gv = g_gamevar[identifier] if (gv == nil) then @@ -710,6 +744,11 @@ local function lookup_gamevar(identifier) return "_INVALIDGV" end + if (writable and bit.band(gv.flags, GVFLAG.READONLY) ~= 0) then + errprintf("variable `%s' is read-only", identifier) + return "_READONLYGV" + end + if (gv.flags==GVFLAG.PERACTOR) then return format("%s[_aci]", gv.name) else @@ -890,6 +929,22 @@ local Couter = { local varop = cmd(W,D) local varvarop = cmd(W,R) +local function varopf(op) + if (#op == 1) then + return varop / ("%1=%1"..op.."%2") + else + return varop / ("%1="..op.."(%1,%2)") + end +end + +local function varvaropf(op) + if (#op == 1) then + return varvarop / ("%1=%1"..op.."%2") + else + return varvarop / ("%1="..op.."(%1,%2)") + end +end + -- Allow nesting... stuff like -- ifvarl actorvar[sprite[THISACTOR].owner].burning 0 -- is kinda breaking the classic "no array nesting" rules @@ -924,10 +979,6 @@ local setperxvarcmd = -- setvar[]. arraypat * memberpat * sp1 * tok.rvar -local function ACS(s) return "actor[_aci]"..s end -local function SPS(s) return "sprite[_aci]"..s end -local function PLS(s) return "player[_pli]"..s end - -- Various inner command handling functions. local handle = { @@ -1003,29 +1054,29 @@ local Cinner = { setsprite = cmd(R,R,R,R), - setvarvar = varvarop, - addvarvar = varvarop, - subvarvar = varvarop, - mulvarvar = varvarop, - divvarvar = varvarop, - modvarvar = varvarop, - andvarvar = varvarop, - orvarvar = varvarop, - xorvarvar = varvarop, - randvarvar = varvarop, + setvarvar = varvarop / "%1=%2", + addvarvar = varvaropf "+", + subvarvar = varvaropf "-", + mulvarvar = varvaropf "*", + divvarvar = varvaropf "_con._div", + modvarvar = varvaropf "_con._mod", + andvarvar = varvaropf "_bit.band", + orvarvar = varvaropf "_bit.bor", + xorvarvar = varvaropf "_bit.bxor", + randvarvar = varvarop / "%1=_con._rand(%2)", - setvar = varop, - addvar = varop, - subvar = varop, - mulvar = varop, - divvar = varop, - modvar = varop, - andvar = varop, - orvar = varop, - xorvar = varop, - randvar = varop, - shiftvarl = varop, - shiftvarr = varop, + setvar = varop / "%1=%2", + addvar = varopf "+", + subvar = varopf "-", + mulvar = varopf "*", + divvar = varopf "_con._div", + modvar = varopf "_con._mod", + andvar = varopf "_bit.band", + orvar = varopf "_bit.bor", + xorvar = varopf "_bit.bxor", + randvar = varop / "%1=_con._rand(%2)", + shiftvarl = varopf "_bit.lshift", + shiftvarr = varopf "_bit.rshift", --- 2. Math operations sqrt = cmd(R,W), @@ -1771,7 +1822,7 @@ local Grammar = Pat{ -- XXX: now, when tok.rvar fails, the tok.define failure message is printed. t_rvar = tok.arrayexp + lpeg.Cmt(tok.identifier, maybe_gamevar_Cmt) + tok.define, -- not so with written-to vars: - t_wvar = tok.arrayexp + (tok.identifier/lookup_gamevar), + t_wvar = tok.arrayexp + (tok.identifier / function(id) return lookup_gamevar(id, true) end), t_move = POS()*tok.identifier / function(...) return lookup_composite(LABEL.MOVE, ...) end + @@ -1887,8 +1938,6 @@ end ---=== EXPORTED FUNCTIONS ===--- -local g_printcode = true - function parse(contents) -- local -- save outer state local lastkw, lastkwpos, numerrors = g_lastkw, g_lastkwpos, g_numerrors @@ -1965,6 +2014,9 @@ local function handle_cmdline_arg(str) g_warn[warnstr] = val ok = true end + elseif (str:sub(2)=="fno") then + -- Disable printing code. + g_cgopt["no"] = true end if (not ok) then @@ -2019,7 +2071,7 @@ if (string.dump) then print_on_failure(msg) end - if (g_printcode) then + if (not g_cgopt["no"]) then local file = require("io").stderr file:write(format("-- GENERATED CODE for \"%s\":\n", filename)) file:write(get_code_string(g_curcode)) diff --git a/polymer/eduke32/source/lunatic/test.elua b/polymer/eduke32/source/lunatic/test.elua index 4df85fe4e..66892946d 100644 --- a/polymer/eduke32/source/lunatic/test.elua +++ b/polymer/eduke32/source/lunatic/test.elua @@ -205,6 +205,7 @@ gameevent("JUMP", function(actori, playeri, dist) print("I'm first!") -- DBG_.oom() + player[playeri]:weapon(gv.PISTOL_WEAPON).shoots = 2605 -- RPG end ) diff --git a/polymer/eduke32/source/player.h b/polymer/eduke32/source/player.h index 675df4c07..ae936d429 100644 --- a/polymer/eduke32/source/player.h +++ b/polymer/eduke32/source/player.h @@ -219,7 +219,13 @@ typedef struct { char name[32]; +#ifdef LUNATIC + // The player index. Always valid since we have no loose DukePlayer_t's + // anywhere (like with spritetype_t): g_player[i].ps->idx == i. + int8_t idx; +#else int8_t padding_; +#endif } DukePlayer_t; typedef struct { @@ -245,6 +251,7 @@ typedef struct { } playerdata_t; #pragma pack(pop) +// KEEPINSYNC lunatic/con_lang.lua typedef struct { // NOTE: the member names must be identical to aplWeapon* suffixes.