Lunatic: begin changing ones...

git-svn-id: https://svn.eduke32.com/eduke32@3390 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2013-01-13 16:40:21 +00:00
parent 7d2dd223bb
commit 8e5d5f9b89
3 changed files with 162 additions and 38 deletions

View file

@ -1020,3 +1020,35 @@ function killit()
-- TODO: guard against deletion of player sprite?
error(true)
end
-- Per-actor variable
-- TODO: serialization
local peractorvar_mt = {
__index = function(acv, idx)
check_sprite_idx(idx)
return acv._defval
end,
__newindex = function(acv, idx, val)
check_sprite_idx(idx)
acv[idx] = val
end,
-- Calling a per-actor variable causes its cleanup:
-- * All values for sprite not in the game world are cleared.
-- * All values equal to the default one are cleared.
__call = function(acv)
for i=0,ffiC.MAXSPRITES-1 do
if (ffiC.sprite[i].statnum == ffiC.MAXSTATUS or acv[i]==acv._defval) then
acv[i] = nil
end
end
end,
__metatable = true,
}
function peractorvar(initval)
return setmetatable({ _defval=initval }, peractorvar_mt)
end

View file

@ -784,11 +784,14 @@ local player_mt = {
addinventory = con._addinventory,
pstomp = con._pstomp,
stomp = con._pstomp,
wack = function(p)
-- XXX: is the correct spelling "whack"?
wack = function(p, no_return_to_center)
p.horiz = p.horiz + 64
p.return_to_center = 9
if (not no_return_to_center) then
p.return_to_center = 9
end
local n = bit.arshift(128-bit.band(ffiC.krand(),255), 1)
p.rotscrnang = n
p.look_ang = n
@ -890,7 +893,7 @@ local function readintostr(fn)
error("INTERNAL ERROR: kfilelength() returned negative length", ERRLEV)
end
local str = ffi.new("char [?]", sz) -- XXX: what does it do on out of mem?
local str = ffi.new("char [?]", sz)
local readlen = ffiC.kread(fd, str, sz)
ffiC.kclose(fd); fd=-1
@ -905,9 +908,10 @@ end
-- The "require" function accessible to Lunatic code.
-- Base modules in allowed_modules are wrapped so that they cannot be
-- modified, user modules are searched in the EDuke32 search
-- path. Also, our require never messes with the global environment,
-- it only returns the module.
local function our_require(modname)
-- path. Also, our require
-- * never messes with the global environment, it only returns the module.
-- * allows passing varargs beyond the name to the module.
local function our_require(modname, ...)
check_valid_modname(modname, 2)
-- see whether it's a base module name first
@ -937,7 +941,7 @@ local function our_require(modname)
table.insert(modname_stack, modname)
-- Run the module code!
modfunc(modname) -- TODO: call protected and report errors here later
modfunc(modname, ...) -- TODO: call protected and report errors here later
table.remove(modname_stack)
@ -959,9 +963,6 @@ local function our_require(modname)
end
-- _G tweaks -- pull in only 'safe' stuff
local G_ = {} -- our soon-to-be global environment
local module_mt = {
__index = function (_, n)
error("attempt to read undeclared variable '"..n.."'", 2)
@ -1000,6 +1001,10 @@ local function our_error(errmsg, level)
error(errmsg, 2)
end
-- _G tweaks -- pull in only 'safe' stuff
local G_ = {} -- our soon-to-be global environment
G_.assert = assert
G_.error = our_error
G_.ipairs = ipairs
@ -1154,6 +1159,9 @@ do
end
concode = lunacon.compile(confn)
if (concode == nil) then
error("Failure compiling CON code, exiting.", 0)
end
end
-- change the environment of this chunk to the table G_

View file

@ -96,15 +96,18 @@ local g_iflevel = 0
local g_ifelselevel = 0
---=== Code generation ===---
local GVFLAG = { PERPLAYER=1, PERACTOR=2, PERX_MASK=3, }
-- CON --> mangled Lua function name, also existence check:
local g_funcname = {}
-- [identifier] = { name=<mangled name>, flags=<gamevar flags> }
local g_gamevar = {}
local g_have_file = {} -- [filename]=true
local g_curcode = nil -- a table of string pieces or other "gencode" tables
local g_actor_code = {} -- [actornum]=gencode_table
local g_event_code = {} -- [eventnum]=gencode_table
local g_loadactor_code = {} -- [actornum]=gencode_table
-- [{actor, event, actor}num]=gencode_table
local g_code = { actor={}, event={}, loadactor={} }
local function getlinecol(pos) end -- fwd-decl
@ -119,10 +122,11 @@ end
local function reset_codegen()
g_funcname = {}
g_gamevar = {}
g_have_file = {}
g_curcode = new_initial_codetab()
g_actor_code, g_event_code, g_loadactor_code = {}, {}, {}
g_code.actor, g_code.event, g_code.loadactor = {}, {}, {}
g_recurslevel = -1
g_numerrors = 0
@ -163,7 +167,7 @@ local function on_actor_end(usertype, tsamm, codetab)
addcodef("gameactor(%d,%sfunction(_aci, _pli, _dist)", tilenum, str)
add_code_and_end(codetab, "end)")
g_actor_code[tilenum] = codetab
g_code.actor[tilenum] = codetab
end
local BAD_ID_CHARS0 = "_/\\*?" -- allowed 1st identifier chars
@ -193,7 +197,7 @@ local function on_event_end(eventidx, codetab)
addcodef("gameevent(%d, function (_aci, _pli, _dist)", eventidx)
add_code_and_end(codetab, "end)")
g_event_code[eventidx] = codetab
g_code.event[eventidx] = codetab
end
----------
@ -318,6 +322,10 @@ local function do_define_label(identifier, num)
end
end
else
if (g_gamevar[identifier]) then
warnprintf("symbol `%s' already used for game variable", identifier)
end
-- New definition of a label
g_labeldef[identifier] = num
g_labeltype[identifier] = LABEL.NUMBER
@ -646,6 +654,73 @@ local function cmd_music(volnum, ...)
end
--- GAMEVARS / GAMEARRAYS
local function cmd_gamevar(identifier, initval, flags)
local invalid_code = "local _INVALIDGV"
if (bit.band(flags, bit.bnot(GVFLAG.PERX_MASK)) ~= 0) then
-- TODO: a couple of the presumably safe ones
errprintf("gamevar flags other than PERPLAYER or PERACTOR: NYI or forbidden")
return invalid_code
end
if (flags==GVFLAG.PERPLAYER+GVFLAG.PERACTOR) then
errprintf("invalid gamevar flags: must be either PERPLAYER or PERACTOR, not both")
return invalid_code
end
local ogv = g_gamevar[identifier]
if (ogv ~= nil) then
if (ogv.flags ~= flags) then
errprintf("duplicate gamevar definition `%s' has different flags", identifier)
return invalid_code
else
warnprintf("duplicate gamevar definition `%s' ignored", identifier)
return ""
end
end
local ltype = g_labeltype[identifier]
if (ltype ~= nil) then
warnprintf("symbol `%s' already used for a defined %s", identifier, LABEL[ltype])
end
local gv = { name=mangle_name(identifier, "V"), flags=flags }
g_gamevar[identifier] = gv
-- 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)
else
return format("local %s=%d", gv.name, initval)
end
end
local function lookup_gamevar(identifier)
local gv = g_gamevar[identifier]
if (gv == nil) then
errprintf("symbol `%s' is not a game variable", identifier)
return "_INVALIDGV"
end
if (gv.flags==GVFLAG.PERACTOR) then
return format("%s[_aci]", gv.name)
else
return gv.name
end
end
local function maybe_gamevar_Cmt(subj, pos, identifier)
if (g_gamevar[identifier]) then
return true, lookup_gamevar(identifier)
end
end
----==== patterns ====----
---- basic ones
@ -665,12 +740,10 @@ local alpha = Range("AZ", "az") -- locale?
local alphanum = alpha + Range("09")
--local alnumtok = alphanum + Set("{}/\\*-_.") -- see isaltok() in gamedef.c
--- basic lexical elements ("tokens")
--- Basic lexical elements ("tokens"). See the final grammar ("Grammar") for
--- their definitions.
local t_maybe_minus = (Pat("-") * sp0)^-1;
local t_number = POS() * lpeg.C(
t_maybe_minus * ((Pat("0x") + "0X") * Range("09", "af", "AF")^1 * Pat("h")^-1
+ Range("09")^1)
) / parse_number
local t_number = Var("t_number")
-- Valid identifier names are disjunct from keywords!
-- XXX: CON is more permissive with identifier name characters:
local t_identifier = Var("t_identifier")
@ -687,12 +760,8 @@ local t_newline_term_str = match_until(anychar, newline)
-- new-style inline arrays and structures:
local t_arrayexp = Var("t_arrayexp")
-- defines and constants can take the place of vars that are only read:
-- NOTE: when one of t_identifier+t_define matches, we don't actually know
-- whether it's the right one yet, since their syntax overlaps.
local t_rvar = t_arrayexp + t_identifier + t_define
-- not so with written-to vars:
local t_wvar = t_arrayexp + t_identifier
local t_rvar = Var("t_rvar")
local t_wvar = Var("t_wvar")
---- helper patterns / pattern constructing functions
@ -784,7 +853,7 @@ local Co = {
spriteflags = cmd(D,D), -- also see inner
--- 4. Game Variables / Arrays
gamevar = cmd(I,D,D),
gamevar = cmd(I,D,D) / cmd_gamevar,
gamearray = cmd(I,D),
--- 5. Top level commands that are also run-time commands
@ -1096,7 +1165,7 @@ local Ci = {
pkick = cmd()
/ format("_con._pkick(%s,%s)", PLS"", ACS""),
pstomp = cmd()
/ PLS":pstomp(_aci)",
/ PLS":stomp(_aci)",
resetactioncount = cmd()
/ ACS":reset_acount()",
resetcount = cmd()
@ -1668,6 +1737,11 @@ local Grammar = Pat{
-- NOTE: NW demo (NWSNOW.CON) contains a Ctrl-Z char (decimal 26)
whitespace = Set(" \t\r\26") + newline + Set("(),;") + comment + linecomment,
t_number = POS() * lpeg.C(
t_maybe_minus * ((Pat("0x") + "0X") * Range("09", "af", "AF")^1 * Pat("h")^-1
+ Range("09")^1)
) / parse_number,
t_identifier_all = t_broken_identifier + t_good_identifier,
-- NOTE: -conl.keyword alone would be wrong, e.g. "state breakobject":
-- NOTE 2: The + "[" is so that stuff like
@ -1680,6 +1754,12 @@ local Grammar = Pat{
t_identifier = -NotKeyw(conl.keyword * (sp1 + "[")) * lpeg.C(t_identifier_all),
t_define = (POS() * lpeg.C(t_maybe_minus) * t_identifier / lookup_defined_label) + t_number,
-- Defines and constants can take the place of vars that are only read.
-- XXX: now, when t_rvar fails, the t_define failure message is printed.
t_rvar = t_arrayexp + lpeg.Cmt(t_identifier, maybe_gamevar_Cmt) + t_define,
-- not so with written-to vars:
t_wvar = t_arrayexp + (t_identifier/lookup_gamevar),
t_move =
POS()*t_identifier / function(...) return lookup_composite(LABEL.MOVE, ...) end +
POS()*t_number / function(...) return check_composite_literal(LABEL.MOVE, ...) end,
@ -1780,6 +1860,17 @@ local function get_code_string(codetab)
return table.concat(flatten_codetab(g_curcode), "\n")
end
local function on_parse_begin()
g_iflevel = 0
g_ifelselevel = 0
g_have_file[g_filename] = true
-- set up new state
-- TODO: pack into one "parser state" table?
g_lastkw, g_lastkwpos, g_numerrors = nil, nil, 0
g_recurslevel = g_recurslevel+1
end
---=== EXPORTED FUNCTIONS ===---
@ -1790,17 +1881,10 @@ function parse(contents) -- local
local lastkw, lastkwpos, numerrors = g_lastkw, g_lastkwpos, g_numerrors
local newlineidxs = g_newlineidxs
g_iflevel = 0
g_ifelselevel = 0
g_have_file[g_filename] = true
on_parse_begin()
-- set up new state
-- TODO: pack into one "parser state" table?
g_lastkw, g_lastkwpos, g_numerrors = nil, nil, 0
g_newlineidxs = setup_newlineidxs(contents)
g_recurslevel = g_recurslevel+1
addcodef("-- BEGIN %s", g_filename)
local idx = lpeg.match(Grammar, contents)