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
This commit is contained in:
helixhorned 2013-01-13 16:40:32 +00:00
parent 417dc33769
commit 39ce7aee62
8 changed files with 212 additions and 41 deletions

View file

@ -10435,6 +10435,9 @@ int32_t app_main(int32_t argc, const char **argv)
for (i=0; i<MAXPLAYERS; i++) for (i=0; i<MAXPLAYERS; i++)
{ {
if (!g_player[i].ps) g_player[i].ps = (DukePlayer_t *)Bcalloc(1, sizeof(DukePlayer_t)); if (!g_player[i].ps) g_player[i].ps = (DukePlayer_t *)Bcalloc(1, sizeof(DukePlayer_t));
#ifdef LUNATIC
g_player[i].ps->idx = i;
#endif
if (!g_player[i].sync) g_player[i].sync = (input_t *)Bcalloc(1, sizeof(input_t)); if (!g_player[i].sync) g_player[i].sync = (input_t *)Bcalloc(1, sizeof(input_t));
} }

View file

@ -276,6 +276,30 @@ labels =
GAMEFUNC, 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! -- NOTE: These MUST be in reverse lexicographical order!
-- Per CON syntax, valid identifiers names are disjunct from keywords, -- Per CON syntax, valid identifiers names are disjunct from keywords,

View file

@ -252,6 +252,26 @@ function rnd(x)
return (bit.rshift(ffiC.krand(), 8) >= (255-x)) return (bit.rshift(ffiC.krand(), 8) >= (255-x))
end 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 ===--- ---=== Weapon stuff ===---
@ -964,7 +984,7 @@ end
local function check_sound_idx(sndidx) local function check_sound_idx(sndidx)
if (sndidx >= con_lang.MAXSOUNDS+0ULL) then if (sndidx >= con_lang.MAXSOUNDS+0ULL) then
error("invalid sound number "..sndidx, 2) error("invalid sound number "..sndidx, 3)
end end
end end

View file

@ -232,7 +232,7 @@ local DUKEPLAYER_STRUCT = [[
const char name[32]; const char name[32];
const int8_t padding_[1]; const int8_t idx;
} }
]] ]]
@ -270,6 +270,9 @@ end
--print(mangle_arrays(ACTOR_STRUCT)) --print(mangle_arrays(ACTOR_STRUCT))
--- default defines etc.
local con_lang = require("con_lang")
ffi.cdef([[ ffi.cdef([[
#pragma pack(push, 1) #pragma pack(push, 1)
typedef struct typedef struct
@ -336,6 +339,11 @@ typedef struct {
} tiledata_t; } tiledata_t;
#pragma pack(pop) #pragma pack(pop)
// NOTE: not packed!
typedef struct {
]] .. table.concat(con_lang.wdata_members, ';')..';' .. [[
} weapondata_t;
enum enum
{ {
MAXMOUSEBUTTONS = 10, MAXMOUSEBUTTONS = 10,
@ -453,6 +461,7 @@ int32_t g_elCallDepth;
actor_t actor[MAXSPRITES]; actor_t actor[MAXSPRITES];
user_defs ud; user_defs ud;
playerdata_t g_player[MAXPLAYERS]; playerdata_t g_player[MAXPLAYERS];
weapondata_t g_playerWeapon[MAXPLAYERS][MAX_WEAPONS];
tiledata_t g_tile[MAXTILES]; tiledata_t g_tile[MAXTILES];
char *ScriptQuotes[]; char *ScriptQuotes[];
@ -717,9 +726,6 @@ local actor_mt = {
ffi.metatype("actor_t", actor_mt) ffi.metatype("actor_t", actor_mt)
--- default defines etc.
local con_lang = require("con_lang")
local function check_weapon_idx(weap) local function check_weapon_idx(weap)
if (weap >= ffiC.MAX_WEAPONS+0ULL) then if (weap >= ffiC.MAX_WEAPONS+0ULL) then
error("Invalid weapon ID "..weap, 3) error("Invalid weapon ID "..weap, 3)
@ -732,6 +738,55 @@ local function check_inventory_idx(inv)
end end
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 = { local player_mt = {
__index = { __index = {
--- Getters/setters --- Getters/setters
@ -777,6 +832,13 @@ local player_mt = {
ffi.cast(player_ptr_ct, p).customexitsound = soundnum ffi.cast(player_ptr_ct, p).customexitsound = soundnum
end, 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 -- CON-like addammo/addweapon, but without the non-local control flow
-- (returns true if weapon's ammo was at the max. instead). -- (returns true if weapon's ammo was at the max. instead).
addammo = con._addammo, addammo = con._addammo,
@ -971,6 +1033,7 @@ local module_mt = {
-- Our 'module' replacement doesn't get the module name from the function args -- Our 'module' replacement doesn't get the module name from the function args
-- since a malicious user could remove other loaded modules this way. -- since a malicious user could remove other loaded modules this way.
-- Also, our 'module' has no varargs ("option functions" in Lua).
-- TODO: make transactional? -- TODO: make transactional?
local function our_module() local function our_module()
local modname = modname_stack[#modname_stack] local modname = modname_stack[#modname_stack]

View file

@ -78,6 +78,7 @@ C_DefineLevelName;
actor; actor;
ud; ud;
g_player; g_player;
g_playerWeapon;
g_tile; g_tile;
ScriptQuotes; ScriptQuotes;

View file

@ -90,17 +90,24 @@ local g_numerrors = 0
local g_warn = { ["not-redefined"]=true, ["bad-identifier"]=true, local g_warn = { ["not-redefined"]=true, ["bad-identifier"]=true,
["number-conversion"]=true, } ["number-conversion"]=true, }
-- Code generation options.
local g_cgopt = { ["no"]=false, }
-- How many 'if' statements are following immediately each other, -- How many 'if' statements are following immediately each other,
-- needed to cope with CONs dangling-else resolution -- needed to cope with CONs dangling-else resolution
local g_iflevel = 0 local g_iflevel = 0
local g_ifelselevel = 0 local g_ifelselevel = 0
---=== Code generation ===--- ---=== 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: -- CON --> mangled Lua function name, also existence check:
local g_funcname = {} local g_funcname = {}
-- [identifier] = { name=<mangled name>, flags=<gamevar flags> } -- [identifier] = { name=<mangled name / code>, flags=<gamevar flags> }
local g_gamevar = {} local g_gamevar = {}
local g_have_file = {} -- [filename]=true 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 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 getlinecol(pos) end -- fwd-decl
local function new_initial_codetab() local function new_initial_codetab()
@ -120,9 +132,31 @@ local function new_initial_codetab()
} }
end 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() local function reset_codegen()
g_funcname = {} g_funcname = {}
g_gamevar = {} g_gamevar = new_initial_gvartab()
g_have_file = {} g_have_file = {}
g_curcode = new_initial_codetab() 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: Write gamevar system on the Lunatic side and hook it up.
-- TODO: per-player gamevars -- TODO: per-player gamevars
if (flags==GVFLAG.PERACTOR) then 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 else
return format("local %s=%d", gv.name, initval) addcodef("local %s=%d", gv.name, initval)
end end
end end
local function lookup_gamevar(identifier) local function lookup_gamevar(identifier, writable)
local gv = g_gamevar[identifier] local gv = g_gamevar[identifier]
if (gv == nil) then if (gv == nil) then
@ -710,6 +744,11 @@ local function lookup_gamevar(identifier)
return "_INVALIDGV" return "_INVALIDGV"
end 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 if (gv.flags==GVFLAG.PERACTOR) then
return format("%s[_aci]", gv.name) return format("%s[_aci]", gv.name)
else else
@ -890,6 +929,22 @@ local Couter = {
local varop = cmd(W,D) local varop = cmd(W,D)
local varvarop = cmd(W,R) 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 -- Allow nesting... stuff like
-- ifvarl actorvar[sprite[THISACTOR].owner].burning 0 -- ifvarl actorvar[sprite[THISACTOR].owner].burning 0
-- is kinda breaking the classic "no array nesting" rules -- is kinda breaking the classic "no array nesting" rules
@ -924,10 +979,6 @@ local setperxvarcmd = -- set<actor/player>var[<idx>].<member> <var>
arraypat * memberpat * sp1 * tok.rvar 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. -- Various inner command handling functions.
local handle = local handle =
{ {
@ -1003,29 +1054,29 @@ local Cinner = {
setsprite = cmd(R,R,R,R), setsprite = cmd(R,R,R,R),
setvarvar = varvarop, setvarvar = varvarop / "%1=%2",
addvarvar = varvarop, addvarvar = varvaropf "+",
subvarvar = varvarop, subvarvar = varvaropf "-",
mulvarvar = varvarop, mulvarvar = varvaropf "*",
divvarvar = varvarop, divvarvar = varvaropf "_con._div",
modvarvar = varvarop, modvarvar = varvaropf "_con._mod",
andvarvar = varvarop, andvarvar = varvaropf "_bit.band",
orvarvar = varvarop, orvarvar = varvaropf "_bit.bor",
xorvarvar = varvarop, xorvarvar = varvaropf "_bit.bxor",
randvarvar = varvarop, randvarvar = varvarop / "%1=_con._rand(%2)",
setvar = varop, setvar = varop / "%1=%2",
addvar = varop, addvar = varopf "+",
subvar = varop, subvar = varopf "-",
mulvar = varop, mulvar = varopf "*",
divvar = varop, divvar = varopf "_con._div",
modvar = varop, modvar = varopf "_con._mod",
andvar = varop, andvar = varopf "_bit.band",
orvar = varop, orvar = varopf "_bit.bor",
xorvar = varop, xorvar = varopf "_bit.bxor",
randvar = varop, randvar = varop / "%1=_con._rand(%2)",
shiftvarl = varop, shiftvarl = varopf "_bit.lshift",
shiftvarr = varop, shiftvarr = varopf "_bit.rshift",
--- 2. Math operations --- 2. Math operations
sqrt = cmd(R,W), sqrt = cmd(R,W),
@ -1771,7 +1822,7 @@ local Grammar = Pat{
-- XXX: now, when tok.rvar fails, the tok.define failure message is printed. -- 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, t_rvar = tok.arrayexp + lpeg.Cmt(tok.identifier, maybe_gamevar_Cmt) + tok.define,
-- not so with written-to vars: -- 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 = t_move =
POS()*tok.identifier / function(...) return lookup_composite(LABEL.MOVE, ...) end + POS()*tok.identifier / function(...) return lookup_composite(LABEL.MOVE, ...) end +
@ -1887,8 +1938,6 @@ end
---=== EXPORTED FUNCTIONS ===--- ---=== EXPORTED FUNCTIONS ===---
local g_printcode = true
function parse(contents) -- local function parse(contents) -- local
-- save outer state -- save outer state
local lastkw, lastkwpos, numerrors = g_lastkw, g_lastkwpos, g_numerrors local lastkw, lastkwpos, numerrors = g_lastkw, g_lastkwpos, g_numerrors
@ -1965,6 +2014,9 @@ local function handle_cmdline_arg(str)
g_warn[warnstr] = val g_warn[warnstr] = val
ok = true ok = true
end end
elseif (str:sub(2)=="fno") then
-- Disable printing code.
g_cgopt["no"] = true
end end
if (not ok) then if (not ok) then
@ -2019,7 +2071,7 @@ if (string.dump) then
print_on_failure(msg) print_on_failure(msg)
end end
if (g_printcode) then if (not g_cgopt["no"]) then
local file = require("io").stderr local file = require("io").stderr
file:write(format("-- GENERATED CODE for \"%s\":\n", filename)) file:write(format("-- GENERATED CODE for \"%s\":\n", filename))
file:write(get_code_string(g_curcode)) file:write(get_code_string(g_curcode))

View file

@ -205,6 +205,7 @@ gameevent("JUMP",
function(actori, playeri, dist) function(actori, playeri, dist)
print("I'm first!") print("I'm first!")
-- DBG_.oom() -- DBG_.oom()
player[playeri]:weapon(gv.PISTOL_WEAPON).shoots = 2605 -- RPG
end end
) )

View file

@ -219,7 +219,13 @@ typedef struct {
char name[32]; 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_; int8_t padding_;
#endif
} DukePlayer_t; } DukePlayer_t;
typedef struct { typedef struct {
@ -245,6 +251,7 @@ typedef struct {
} playerdata_t; } playerdata_t;
#pragma pack(pop) #pragma pack(pop)
// KEEPINSYNC lunatic/con_lang.lua
typedef struct typedef struct
{ {
// NOTE: the member names must be identical to aplWeapon* suffixes. // NOTE: the member names must be identical to aplWeapon* suffixes.