From 4ccbe1dc3541d7317b9871c420c2dfadd36da73c Mon Sep 17 00:00:00 2001 From: Kistaro Windrider Date: Fri, 13 Oct 2023 01:02:43 -0700 Subject: [PATCH] okay honestly this all can and should just be CSVs --- the_parser.p8 | 61 +++++++++++++++++++++++ updatedshmup.p8 | 126 +++++++++++++++--------------------------------- 2 files changed, 100 insertions(+), 87 deletions(-) create mode 100644 the_parser.p8 diff --git a/the_parser.p8 b/the_parser.p8 new file mode 100644 index 0000000..8c0a0e2 --- /dev/null +++ b/the_parser.p8 @@ -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 diff --git a/updatedshmup.p8 b/updatedshmup.p8 index 6310360..27ad9d0 100644 --- a/updatedshmup.p8 +++ b/updatedshmup.p8 @@ -416,66 +416,6 @@ function grab_p1_butts() } 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 --ship behavior @@ -907,7 +847,9 @@ end -- a level is a map from -- 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 -- when freeze count is nonzero @@ -931,16 +873,20 @@ freeze = 0 eol = {} -function load_level(lvltbl) +function load_level(levelfile) distance = 0 lframe = 0 freeze = 0 current_level = {} - -- copy the level so we can - -- modify it dynamically - -- without losing the original - for frame, cb in pairs(lvltbl) do - current_level[frame] = cb + for row in all(csv(levelfile)) do + local x = current_level[row[1]] + if row[2] == "eol" then + assert(x==nil, "events on eol frame") + row[1] = eol + else + add(x, row) + end + row[1]=x end leveldone = false end @@ -950,13 +896,16 @@ function level_frame() if (current_level == nil) return true if freeze == 0 then distance += 1 - local cb = current_level[distance] - if cb ~= nil then - if cb == eol then + local cbs = current_level[distance] + if cbs ~= nil then + if cbs == eol then current_level = nil return true else - cb() + for c in all(cbs) do + assert(c[1] == distance) + level_events[c[2]](unpack(c.params, 3)) + end end end end @@ -965,24 +914,27 @@ end -->8 -- example level -level_parser = parser.new{} -mknew(level_parser) - -function level_parser:parse_level(lvl) - local ret = {} - self:parse_into(lvl, - function(row) - if (#row < 2 or type(row[1] ~= "number")) return - 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 +function std_spawn(tnm, n, blocking, goodie) + -- TODO: implement + -- look up enemy type from tnm + -- spawn n of them at random positions, + -- see spawn_rnd_x. + -- if blocking, patch the blocking logic in. + -- if they drop a goodie, find the goodie, + -- then patch the bonus logic in. 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) s = typ.new{ x = rnd(104),