okay honestly this all can and should just be CSVs

This commit is contained in:
Kistaro Windrider 2023-10-13 01:02:43 -07:00
parent b536d2c987
commit 4ccbe1dc35
Signed by: kistaro
SSH Key Fingerprint: SHA256:TBE2ynfmJqsAf0CP6gsflA0q5X5wD5fVKWPsZ7eVUg8
2 changed files with 100 additions and 87 deletions

61
the_parser.p8 Normal file
View File

@ -0,0 +1,61 @@
pico-8 cartridge // http://www.pico-8.com
version 41
__lua__
-- the parser
parser = {}
mknew(parser)
-- calls parse_into with a nop
-- emit function.
function parser:parse(str)
self:parse_into(str, function() end)
end
-- read a file of commands and
-- execute them, emitting the
-- results from each call into
-- `emit` as a table per row.
--
-- a "command" is a method on
-- self. a row alternates
-- commands with args. when
-- calling a command, it also
-- gets a table of previous
-- results as the first arg.
-- args are split on ','.
function parser:parse_into(str, emit)
for row in all(split(str, "\n")) do
local prev = {}
local sectors = split(row, ":")
for i=1,#sectors,2 do
local x = self[sectors[i]](self, prev, usplit(sectors[i+1]))
if (x) add(prev, x)
end
emit(prev)
end
end
-- saves prev[sel] as self.name.
-- if sel is unspecified, saves
-- all of prev (as a table).
function parser:saveas(prev, name, sel)
self[name] = sel and prev[sel] or prev
end
-- returns its args, ignoring
-- prev. Used to stuff things
-- into prev. args are packed
-- if there's multiple.
function parser:val(_, ...)
local ret := pack(...)
if (#ret == 1) return ret[1]
return ret
end
function parser:bind(_, fn, ...)
local f = self[fn]
return function()
f(...)
end
end

View File

@ -416,66 +416,6 @@ function grab_p1_butts()
} }
end end
-->8
-- the parser
parser = {}
mknew(parser)
-- calls parse_into with a nop
-- emit function.
function parser:parse(str)
self:parse_into(str, function() end)
end
-- read a file of commands and
-- execute them, emitting the
-- results from each call into
-- `emit` as a table per row.
--
-- a "command" is a method on
-- self. a row alternates
-- commands with args. when
-- calling a command, it also
-- gets a table of previous
-- results as the first arg.
-- args are split on ','.
function parser:parse_into(str, emit)
for row in all(split(str, "\n")) do
local prev = {}
local sectors = split(row, ":")
for i=1,#sectors,2 do
local x = self[sectors[i]](self, prev, usplit(sectors[i+1]))
if (x) add(prev, x)
end
emit(prev)
end
end
-- saves prev[sel] as self.name.
-- if sel is unspecified, saves
-- all of prev (as a table).
function parser:saveas(prev, name, sel)
self[name] = sel and prev[sel] or prev
end
-- returns its args, ignoring
-- prev. Used to stuff things
-- into prev. args are packed
-- if there's multiple.
function parser:val(_, ...)
local ret := pack(...)
if (#ret == 1) return ret[1]
return ret
end
function parser:bind(_, fn, ...)
local f = self[fn]
return function()
f(...)
end
end
-->8 -->8
--ship behavior --ship behavior
@ -907,7 +847,9 @@ end
-- a level is a map from -- a level is a map from
-- effective frame number to -- effective frame number to
-- callback for that frame. -- a list of actions for that
-- frame. an action is a
-- method name and its args.
-- effective frame number stops -- effective frame number stops
-- when freeze count is nonzero -- when freeze count is nonzero
@ -931,16 +873,20 @@ freeze = 0
eol = {} eol = {}
function load_level(lvltbl) function load_level(levelfile)
distance = 0 distance = 0
lframe = 0 lframe = 0
freeze = 0 freeze = 0
current_level = {} current_level = {}
-- copy the level so we can for row in all(csv(levelfile)) do
-- modify it dynamically local x = current_level[row[1]]
-- without losing the original if row[2] == "eol" then
for frame, cb in pairs(lvltbl) do assert(x==nil, "events on eol frame")
current_level[frame] = cb row[1] = eol
else
add(x, row)
end
row[1]=x
end end
leveldone = false leveldone = false
end end
@ -950,13 +896,16 @@ function level_frame()
if (current_level == nil) return true if (current_level == nil) return true
if freeze == 0 then if freeze == 0 then
distance += 1 distance += 1
local cb = current_level[distance] local cbs = current_level[distance]
if cb ~= nil then if cbs ~= nil then
if cb == eol then if cbs == eol then
current_level = nil current_level = nil
return true return true
else else
cb() for c in all(cbs) do
assert(c[1] == distance)
level_events[c[2]](unpack(c.params, 3))
end
end end
end end
end end
@ -965,24 +914,27 @@ end
-->8 -->8
-- example level -- example level
level_parser = parser.new{} function std_spawn(tnm, n, blocking, goodie)
mknew(level_parser) -- TODO: implement
-- look up enemy type from tnm
function level_parser:parse_level(lvl) -- spawn n of them at random positions,
local ret = {} -- see spawn_rnd_x.
self:parse_into(lvl, -- if blocking, patch the blocking logic in.
function(row) -- if they drop a goodie, find the goodie,
if (#row < 2 or type(row[1] ~= "number")) return -- then patch the bonus logic in.
local idx = row[1]
local x = ret[idx] or {}
for j=2,#row do
add(x, row[j])
end
ret[idx]=x
end)
return ret
end end
-- to implement: repeat(times, interval, f, ...)
-- once on this frame, then times-1 times after that spaced interval
-- frames apart, f(...). schedule this like the one-off written in
-- example_level.
-- then convert sample_level to csv.
-- spawn_spec_gun_at and spawn_main_gun_at will need parsed forms.
-- the boss also needs to be reachable, but one-off is fine.
-- each row of level csv is offset,event,event-args...
-- where offset,eol is a special case.
function spawn_rnd_x(typ) function spawn_rnd_x(typ)
s = typ.new{ s = typ.new{
x = rnd(104), x = rnd(104),