okay honestly this all can and should just be CSVs
This commit is contained in:
		
							
								
								
									
										61
									
								
								the_parser.p8
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								the_parser.p8
									
									
									
									
									
										Normal 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 | ||||
							
								
								
									
										126
									
								
								updatedshmup.p8
									
									
									
									
									
								
							
							
						
						
									
										126
									
								
								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), | ||||
|   | ||||
		Reference in New Issue
	
	Block a user