Compare commits
9 Commits
do_rearm
...
9ef762268f
Author | SHA1 | Date | |
---|---|---|---|
9ef762268f
|
|||
e50f516b11
|
|||
f9e28fa0e2
|
|||
38a054dec1
|
|||
fd391ff3bc
|
|||
fbd9f97429
|
|||
2a61e8b5d6
|
|||
4ccbe1dc35
|
|||
b536d2c987
|
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
|
400
updatedshmup.p8
400
updatedshmup.p8
@ -26,22 +26,19 @@ end
|
|||||||
-- ret is definitely not nil
|
-- ret is definitely not nil
|
||||||
-- before calling setmetatable.
|
-- before calling setmetatable.
|
||||||
-- use to initialize mutables.
|
-- use to initialize mutables.
|
||||||
|
--
|
||||||
|
-- if there was a previous new,
|
||||||
|
-- it is invoked on the new
|
||||||
|
-- object *after* more, because
|
||||||
|
-- this works better with the
|
||||||
|
-- `more` impls i use.
|
||||||
function mknew(tt, more)
|
function mknew(tt, more)
|
||||||
local mt = {__index=tt}
|
local mt,oldnew = {__index=tt},tt.new
|
||||||
-- check "more" only once ever
|
tt.new=function(ret)
|
||||||
if more then
|
if(not ret) ret = {}
|
||||||
tt.new = function(ret)
|
if(more) more(ret)
|
||||||
if (not ret) ret = {}
|
if(oldnew) oldnew(ret)
|
||||||
more(ret)
|
setmetatable(ret, mt)
|
||||||
setmetatable(ret, mt)
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
else
|
|
||||||
tt.new=function(ret)
|
|
||||||
if (not ret) ret = {}
|
|
||||||
setmetatable(ret, mt)
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -121,7 +118,7 @@ function _init()
|
|||||||
init_blip_pals()
|
init_blip_pals()
|
||||||
wipe_level()
|
wipe_level()
|
||||||
primary_ship.main_gun = zap_gun.new()
|
primary_ship.main_gun = zap_gun.new()
|
||||||
load_level(example_level)
|
load_level(example_level_csv)
|
||||||
state = game
|
state = game
|
||||||
pal(2,129)
|
pal(2,129)
|
||||||
pal()
|
pal()
|
||||||
@ -416,59 +413,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
|
|
||||||
|
|
||||||
-->8
|
-->8
|
||||||
--ship behavior
|
--ship behavior
|
||||||
|
|
||||||
@ -725,34 +669,29 @@ blocky = frownie.new{
|
|||||||
}
|
}
|
||||||
mknew(blocky)
|
mknew(blocky)
|
||||||
|
|
||||||
function spawn_spewy_at(x, y)
|
spewy = frownie.new{
|
||||||
local spewy = frownie.new{
|
sprite=26,
|
||||||
x = x,
|
power=-20,
|
||||||
y = y,
|
hurt = {
|
||||||
sprite = 26,
|
x_off=0,
|
||||||
power = -20,
|
y_off=1,
|
||||||
hurt = {
|
width=8,
|
||||||
x_off = 0,
|
height=5
|
||||||
y_off = 1,
|
},
|
||||||
width = 8,
|
hp=1,
|
||||||
height = 5
|
maxpower=70,
|
||||||
},
|
generator=0.5,
|
||||||
|
fire_off_x=4,
|
||||||
hp = 1,
|
fire_off_y = 7,
|
||||||
maxpower = 70,
|
grab_butts=function()
|
||||||
generator = 0.5,
|
local butts=frownie.grab_butts()
|
||||||
main_gun = protron_gun.new{enemy=true},
|
butts[5]=1
|
||||||
fire_off_x = 4,
|
return butts
|
||||||
fire_off_y = 7,
|
end
|
||||||
grab_butts = function()
|
}
|
||||||
local butts = frownie.grab_butts()
|
mknew(spewy, function(ship)
|
||||||
butts[5] = 1
|
ship.main_gun=ship.main_gun or protron_gun.new{enemy=true}
|
||||||
return butts
|
end)
|
||||||
end,
|
|
||||||
}
|
|
||||||
eships:push_back(spewy)
|
|
||||||
return spewy
|
|
||||||
end
|
|
||||||
|
|
||||||
chasey = ship_m.new{
|
chasey = ship_m.new{
|
||||||
sprite = 5,
|
sprite = 5,
|
||||||
@ -777,59 +716,47 @@ chasey = ship_m.new{
|
|||||||
thrust = 0.2,
|
thrust = 0.2,
|
||||||
drag = 0.075,
|
drag = 0.075,
|
||||||
slip = true,
|
slip = true,
|
||||||
|
}
|
||||||
|
mknew(chasey, function(ship)
|
||||||
|
ship.main_gun=ship.main_gun or zap_gun.new{enemy=true}
|
||||||
|
end)
|
||||||
|
|
||||||
|
function chasey:grab_butts()
|
||||||
|
local butts = {[0]=0,0,0,0,0,0}
|
||||||
|
if (self.x < primary_ship.x) butts[1] = 1
|
||||||
|
if (self.x > primary_ship.x) butts[0] = 1
|
||||||
|
if (self.x - 16 < primary_ship.x and self.x + 16 > primary_ship.x) butts[5] = 1
|
||||||
|
return butts
|
||||||
|
end
|
||||||
|
|
||||||
|
xl_chasey=chasey.new{
|
||||||
|
size=2,
|
||||||
|
maxspd=1.25,
|
||||||
|
hurt = {
|
||||||
|
x_off = 2,
|
||||||
|
y_off = 4,
|
||||||
|
width = 12,
|
||||||
|
height = 10
|
||||||
|
},
|
||||||
|
hp = 20,
|
||||||
|
shield = 5,
|
||||||
|
boss = true,
|
||||||
|
slip = false,
|
||||||
|
main_gun = zap_gun.new{enemy=true},
|
||||||
grab_butts = function(self)
|
grab_butts = function(self)
|
||||||
local butts = {0,0,0,0,0}
|
local butts = chasey.grab_butts(self)
|
||||||
butts[0] = 0
|
if (self.y < 4) butts[3] = 1
|
||||||
if (self.x < primary_ship.x) butts[1] = 1
|
|
||||||
if (self.x > primary_ship.x) butts[0] = 1
|
|
||||||
if (self.x - 16 < primary_ship.x and self.x + 16 > primary_ship.x) butts[5] = 1
|
|
||||||
return butts
|
return butts
|
||||||
end,
|
end,
|
||||||
|
draw = function(self)
|
||||||
|
if(self.fx_pal) pal(self.fx_pal)
|
||||||
|
sspr(40, 0, 8, 8, self.x, self.y, 16, 16)
|
||||||
|
pal()
|
||||||
|
end,
|
||||||
}
|
}
|
||||||
mknew(chasey)
|
mknew(xl_chasey, function(ship)
|
||||||
|
ship.main_gun=ship.main_gun or zap_gun.new{enemy=true}
|
||||||
function spawn_chasey_at(x, y)
|
end)
|
||||||
local c = chasey.new{
|
|
||||||
x = x,
|
|
||||||
y = y,
|
|
||||||
main_gun = zap_gun.new{enemy=true},
|
|
||||||
}
|
|
||||||
eships:push_back(c)
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
|
|
||||||
function spawn_xl_chasey_at(x, y)
|
|
||||||
local c = chasey.new{
|
|
||||||
x = x,
|
|
||||||
y = y,
|
|
||||||
size = 2,
|
|
||||||
maxspd = 1.25,
|
|
||||||
hurt = {
|
|
||||||
x_off = 2,
|
|
||||||
y_off = 4,
|
|
||||||
width = 12,
|
|
||||||
height = 10
|
|
||||||
},
|
|
||||||
hp = 20,
|
|
||||||
shield = 5,
|
|
||||||
boss = true,
|
|
||||||
slip = false,
|
|
||||||
main_gun = zap_gun.new{enemy=true},
|
|
||||||
grab_butts = function(self)
|
|
||||||
local butts = chasey.grab_butts(self)
|
|
||||||
if (self.y < 4) butts[3] = 1
|
|
||||||
return butts
|
|
||||||
end,
|
|
||||||
draw = function(self)
|
|
||||||
if(self.fx_pal) pal(self.fx_pal)
|
|
||||||
sspr(40, 0, 8, 8, self.x, self.y, 16, 16)
|
|
||||||
pal()
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
eships:push_back(c)
|
|
||||||
return c
|
|
||||||
end
|
|
||||||
-->8
|
-->8
|
||||||
-- collisions
|
-- collisions
|
||||||
|
|
||||||
@ -900,7 +827,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
|
||||||
@ -924,18 +853,26 @@ 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 = {}
|
|
||||||
-- copy the level so we can
|
|
||||||
-- modify it dynamically
|
|
||||||
-- without losing the original
|
|
||||||
for frame, cb in pairs(lvltbl) do
|
|
||||||
current_level[frame] = cb
|
|
||||||
end
|
|
||||||
leveldone = false
|
leveldone = false
|
||||||
|
current_level = {}
|
||||||
|
local found_eol = false
|
||||||
|
if (type(levelfile)=="string") levelfile = csv(levelfile)
|
||||||
|
for row in all(levelfile) do
|
||||||
|
local x = current_level[row[1]]
|
||||||
|
if row[2] == "eol" then
|
||||||
|
found_eol = true
|
||||||
|
assert(x==nil, "events on eol frame")
|
||||||
|
current_level[row[1]] = eol
|
||||||
|
else
|
||||||
|
row.next = x
|
||||||
|
currentlevel[row[1]]=row
|
||||||
|
end
|
||||||
|
end
|
||||||
|
assert(found_eol)
|
||||||
end
|
end
|
||||||
|
|
||||||
function level_frame()
|
function level_frame()
|
||||||
@ -943,13 +880,19 @@ 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()
|
while cbs do
|
||||||
|
assert(cbs[1] == distance)
|
||||||
|
local f = _ENV[cbs[2]]
|
||||||
|
assert(type(f) == "function", cbs[2].." at "..distance.." is not a function")
|
||||||
|
f(unpack(cbs, 3))
|
||||||
|
cbs=cbs.next
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -958,14 +901,7 @@ end
|
|||||||
-->8
|
-->8
|
||||||
-- example level
|
-- example level
|
||||||
|
|
||||||
function spawn_rnd_x(typ)
|
|
||||||
s = typ.new{
|
|
||||||
x = rnd(104),
|
|
||||||
y = -(typ.size * 8 - 1)
|
|
||||||
}
|
|
||||||
eships:push_back(s)
|
|
||||||
return s
|
|
||||||
end
|
|
||||||
|
|
||||||
function spawn_blocking_rnd_x(typ)
|
function spawn_blocking_rnd_x(typ)
|
||||||
freeze += 1
|
freeze += 1
|
||||||
@ -978,7 +914,7 @@ function spawn_blocking_rnd_x(typ)
|
|||||||
freeze -= self.ice
|
freeze -= self.ice
|
||||||
self.ice = 0
|
self.ice = 0
|
||||||
self:orig_die()
|
self:orig_die()
|
||||||
end
|
end,
|
||||||
}
|
}
|
||||||
eships:push_back(s)
|
eships:push_back(s)
|
||||||
return s
|
return s
|
||||||
@ -1071,51 +1007,89 @@ function spawn_blocking_boss_chasey()
|
|||||||
return c
|
return c
|
||||||
end
|
end
|
||||||
|
|
||||||
example_level = {
|
function std_spawn(tnm, n, blocking, goodie,altspr)
|
||||||
[1]=spawn_frownie,
|
local typ = _ENV[tnm]
|
||||||
[60]=spawn_bonus_vulcan_chasey,
|
assert(typ and typ.new, tostr(tnm).." not a class")
|
||||||
[61]=spawn_blocky,
|
for i=1,(n or 1) do
|
||||||
[85]=spawn_spewy,
|
spawn_rnd(typ, blocking, goodie,altspr)
|
||||||
[100]=spawn_spewy,
|
end
|
||||||
[115]=spawn_spewy,
|
end
|
||||||
[130]=spawn_bonus_frownie,
|
|
||||||
[145]=spawn_spewy,
|
-- blocking: 1 or 0
|
||||||
[200]=spawn_chasey,
|
function spawn_rnd(typ, blocking, goodie,altspr)
|
||||||
[250]=spawn_blocking_blocky,
|
freeze += blocking
|
||||||
[285]=function()
|
s = typ.new{
|
||||||
spawn_spec_gun_at(35, -11, blast_gun)
|
x = rnd(104),
|
||||||
end,
|
y = -(typ.size * 8 - 1),
|
||||||
[310]=function()
|
ice=blocking,
|
||||||
spawn_blocking_blocky()
|
die=function(self)
|
||||||
spawn_blocking_blocky()
|
freeze -= self.ice
|
||||||
spawn_blocking_blocky()
|
self.ice=0
|
||||||
end,
|
typ.die(self)
|
||||||
[311]=spawn_frownie,
|
spawn_goodie(goodie, self.x, self.y, self.size)
|
||||||
[350]=function()
|
end,
|
||||||
spawn_main_gun_at(70, -11, protron_gun)
|
}
|
||||||
end,
|
if (altspr) s.spr = altspr
|
||||||
[401]=spawn_frownie,
|
eships:push_back(s)
|
||||||
[420]=spawn_blocking_frownie,
|
return s
|
||||||
[430]=spawn_bonus_vulcan_chasey,
|
end
|
||||||
[450]=spawn_frownie,
|
|
||||||
[465]=spawn_bonus_frownie,
|
-- TODO: spawn_goodie compatible versions of gun drops
|
||||||
[480]=spawn_chasey,
|
-- TODO: goodie table
|
||||||
[500]=function()
|
function spawn_goodie(goodie_name, x, y, sz)
|
||||||
local tnext = lframe
|
if (not goodie_name or #goodie_name == 0) return
|
||||||
local remain = 20
|
local sh = sz and sz/2 or 0
|
||||||
events:push_back{move=function()
|
goodies[goodie_name].new{}:spawn_at(x+sh,y+sh)
|
||||||
if (lframe < tnext) return false
|
end
|
||||||
spawn_blocking_blocky()
|
|
||||||
tnext = lframe + 0x0.000c
|
function multi(times, interval, fnm, ...)
|
||||||
remain -= 1
|
local f,irm,vargs = _ENV[fnm],interval,pack(...)
|
||||||
return (remain <= 0)
|
assert(type(f) == "function", fnm.." not a function")
|
||||||
end}
|
fnm(...)
|
||||||
end,
|
events:push_back{move=function()
|
||||||
[501]=spawn_bonus_frownie,
|
irm-=1
|
||||||
[620]=spawn_blocking_blocky,
|
if irm <= 0 then
|
||||||
[700]=spawn_blocking_boss_chasey,
|
irm=interval
|
||||||
[701]=eol
|
times-=1
|
||||||
}
|
fnm(unpack(vargs))
|
||||||
|
return times <= 1
|
||||||
|
end
|
||||||
|
end}
|
||||||
|
end
|
||||||
|
|
||||||
|
-- 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.
|
||||||
|
|
||||||
|
example_level_csv=[[1,spawn_frownie
|
||||||
|
60,spawn_bonus_vulcan_chasey
|
||||||
|
61,spawn_blocky
|
||||||
|
85,spawn_spewy
|
||||||
|
100,spawn_spewy
|
||||||
|
115,spawn_spewy
|
||||||
|
130,spawn_bonus_frownie
|
||||||
|
145,spawn_spewy
|
||||||
|
200,spawn_chasey
|
||||||
|
250,spawn_blocking_blocky
|
||||||
|
285,spawn_spec_gun_at,35,-11,blast_gun
|
||||||
|
310,spawn_blocking_blocky
|
||||||
|
310,spawn_blocking_blocky
|
||||||
|
310,spawn_blocking_blocky
|
||||||
|
311,spawn_frownie
|
||||||
|
350,spawn_main_gun_at,70,-11,protron_gun
|
||||||
|
401,spawn_frownie
|
||||||
|
420,spawn_blocking_frownie
|
||||||
|
430,spawn_bonus_vulcan_chasey
|
||||||
|
450,spawn_frownie
|
||||||
|
465,spawn_bonus_frownie
|
||||||
|
480,spawn_chasey
|
||||||
|
500,multi,20,12,spawn_blocking_blocky
|
||||||
|
501,spawn_bonus_frownie
|
||||||
|
620,spawn_blocking_blocky
|
||||||
|
700,spawn_blocking_boss_chasey
|
||||||
|
701,eol]]
|
||||||
|
|
||||||
-->8
|
-->8
|
||||||
-- bullet and gun behaviors
|
-- bullet and gun behaviors
|
||||||
@ -1969,6 +1943,7 @@ gun_swap = powerup.new{
|
|||||||
mknew(gun_swap)
|
mknew(gun_swap)
|
||||||
|
|
||||||
function spawn_main_gun_at(x, y, gunt)
|
function spawn_main_gun_at(x, y, gunt)
|
||||||
|
if (type(gunt)=="string") gunt=_ENV[gunt]
|
||||||
local gun_p = gun_swap.new{
|
local gun_p = gun_swap.new{
|
||||||
gun = gunt.new()
|
gun = gunt.new()
|
||||||
}
|
}
|
||||||
@ -1982,6 +1957,7 @@ spec_gun_pl = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function spawn_spec_gun_at(x, y, gunt)
|
function spawn_spec_gun_at(x, y, gunt)
|
||||||
|
if (type(gunt)=="string") gunt=_ENV[gunt]
|
||||||
local gun_p = gun_swap.new{
|
local gun_p = gun_swap.new{
|
||||||
gun = gunt.new(),
|
gun = gunt.new(),
|
||||||
hitship = function(self, ship)
|
hitship = function(self, ship)
|
||||||
|
Reference in New Issue
Block a user