Compare commits

..

7 Commits

4 changed files with 743 additions and 813 deletions

View File

@ -1,5 +1,5 @@
pico-8 cartridge // http://www.pico-8.com
version 42
version 41
__lua__
-- vacuum gambit
-- by kistaro windrider
@ -18,17 +18,12 @@ function csv(s)
end
return ret
end
function const_fxn(x)
return function()
return x
end
end
-- generate standard "overlay"
-- constructor for type tt.
-- if tt.init is defined, generated
-- new calls tt.init(ret) after
-- ret is definitely not nil,
-- if more is defined, generated
-- new calls more(ret) after
-- ret is definitely not nil
-- before calling setmetatable.
-- use to initialize mutables.
--
@ -37,8 +32,8 @@ end
-- object *after* more, because
-- this works better with the
-- `more` impls i use.
function mknew(tt)
local mt,oldnew,more = {__index=tt},tt.new,rawget(tt, "init")
function mknew(tt, more)
local mt,oldnew = {__index=tt},tt.new
tt.new=function(ret)
if(not ret) ret = {}
if(more) more(ret)
@ -46,18 +41,15 @@ function mknew(tt)
setmetatable(ret, mt)
return ret
end
return tt
end
-- intrusive singly-linked list.
-- cannot be nested!
linked_list = mknew{
is_linked_list=true,
init = function(x)
linked_list = {is_linked_list=true}
mknew(linked_list, function(x)
x.next=nil
x.tail=x
end,
}
end)
function linked_list:push_back(x)
self.tail.next = x
@ -126,7 +118,7 @@ end
function _init()
init_blip_pals()
wipe_level()
primary_ship.main_gun = zap_gun_p.new() -- redundant?
primary_ship.main_gun = zap_gun.new()
load_level(example_level_csv)
state = game
pal(2,129)
@ -420,7 +412,7 @@ end
scrollrate = 0.25 --in px/frame
ship_m = mknew{
ship_m = {
-- ships have no shield by default
shield = 0,
@ -445,6 +437,7 @@ ship_m = mknew{
-- ymin, ymax default to nil
-- pship needs more constraint
}
mknew(ship_m)
function ship_m:die()
self.dead = true
@ -587,20 +580,16 @@ end
-->8
-- bullet and gun behaviors
function player_blt_cat()
return pbullets
end
bullet_base = {
enemyspd = 0.5
}
mknew(bullet_base)
function enemy_blt_cat()
return ebullets
end
bullet_base = mknew{ }
gun_base = mknew{
gun_base = {
shoot_ready = -32768,
icon = 20
}
mknew(gun_base)
function bullet_base:hitship(_)
self:die()
@ -612,10 +601,18 @@ end
function bullet_base:move()
self.x += self.dx
self.y += self.dy
if (self.y > 128) or (self.y < -8 * self.height) then
self:die()
return true
if self.enemy then
self.y += self.dy
if self.y > 128 then
self:die()
return true
end
else
self.y -= self.dy
if self.y < -8*self.height then
self:die()
return true
end
end
return false
end
@ -624,18 +621,17 @@ function bullet_base:draw()
spr(self.sprite, self.x, self.y, self.width, self.height)
end
-- An `actually_shoot` factory
-- for trivial guns
function spawn_one(t)
return function(gun, x, y)
t.new{}:spawn_at(x, y)
end
end
function bullet_base:spawn_at(x, y)
self.x = x - self.x_off
self.y = y - self.y_off
self.category():push_back(self)
self.x = x - self.center_x_off
if self.enemy then
self.dx *= self.enemyspd
self.dy *= self.enemyspd
self.y = y + self.top_y_off
ebullets:push_back(self)
else
self.y = y - (8 * self.height) + self.bottom_y_off
pbullets:push_back(self)
end
end
function gun_base:shoot(x, y)
@ -649,12 +645,23 @@ function gun_base:shoot(x, y)
return true
end
function gun_base:actually_shoot(x, y)
local typ = self.t
local b = typ.new{
enemy = self.enemy,
sprite = self.enemy and typ.esprite or typ.psprite,
}
b:spawn_at(x, y)
return true
end
-->8
-- bullets and guns
zap_e = mknew(bullet_base.new{
zap = bullet_base.new{
--shape
sprite = 9, --index of enemy ammo sprite
psprite = 8, --index of player ammo sprite
esprite = 9, -- index of enemy ammo sprite
width = 1, --in 8x8 blocks
height = 1,
hurt = { -- hurtbox - where this ship can be hit
@ -663,39 +670,33 @@ zap_e = mknew(bullet_base.new{
width = 2,
height = 8
},
x_off = 1, -- how to position by ship
y_off = 8,
center_x_off = 1, -- how to position by ship
bottom_y_off = 0,
top_y_off = 0,
damage = 1,
dx = 0, -- px/frame
dy = 4,
dy = 8,
hitship = const_fxn(true),
hitship = function(_, _)
return true
end
}
mknew(zap)
category = enemy_blt_cat,
})
zap_p = mknew(zap_e.new{
sprite = 8,
dy = -8,
y_off = 0,
category = player_blt_cat,
})
zap_gun_e = mknew(gun_base.new{
zap_gun = gun_base.new{
enemy = false,
power = 20, -- power consumed per shot
cooldown = 0x0.000a, -- frames between shots
ammo = nil, -- unlimited ammo - main gun
actually_shoot = spawn_one(zap_e),
})
t = zap -- metatable of bullet to fire
}
mknew(zap_gun)
zap_gun_p = mknew(zap_gun_e.new{
actually_shoot = spawn_one(zap_p),
})
blast = mknew(bullet_base.new{
blast = bullet_base.new{
--shape
sprite = 12, --index of player ammo sprite
psprite = 12, --index of player ammo sprite
esprite = 3, -- index of enemy ammo sprite
width = 1, --in 8x8 blocks
height = 1,
hurt = { -- hurtbox - where this ship can be hit
@ -704,12 +705,13 @@ blast = mknew(bullet_base.new{
width = 6,
height = 6
},
x_off = 4, -- how to position by ship
y_off = 0,
center_x_off = 4, -- how to position by ship
bottom_y_off = 0,
top_y_off = 0,
damage = 4,
dx = 0, -- px/frame
dy = -2,
dy = 2,
awaitcancel = false,
-- disable damage for 2 frames
@ -734,22 +736,25 @@ blast = mknew(bullet_base.new{
self.awaitcancel = false
end)
end
end,
category=player_blt_cat
})
end
}
mknew(blast)
blast_gun = mknew(gun_base.new{
blast_gun = gun_base.new{
icon = 13,
power = 0, -- only cost is ammo
enemy = false,
power = 0, -- ammo, not power
cooldown = 0x0.0020, -- frames between shots
ammo = 5,
maxammo = 5,
actually_shoot = spawn_one(blast),
})
t = blast -- type of bullet to fire
}
mknew(blast_gun)
protron_e = mknew(bullet_base.new{
protron = bullet_base.new{
--shape
sprite = 24,
psprite = 23, --index of player ammo sprite
esprite = 24, -- index of enemy ammo sprite
width = 1, --in 8x8 blocks
height = 1,
hurt = { -- hurtbox - where this ship can be hit
@ -758,59 +763,56 @@ protron_e = mknew(bullet_base.new{
width = 2,
height = 2
},
x_off = 1, -- how to position by ship
y_off = 4,
center_x_off = 1, -- how to position by ship
bottom_y_off = 4,
top_y_off = 0,
damage = 1,
dym = 0.5, -- gun sets dy;
-- this is mult
category = enemy_blt_cat,
})
dx = 0, -- px/frame
dy = 3,
}
mknew(protron)
protron_p = mknew(protron_e.new{
sprite=23,
dym = -1,
y_off = 0,
category=player_blt_cat,
})
protron_gun_e = mknew(gun_base.new{
protron_gun = gun_base.new{
icon = 25,
enemy = false,
power = 60,
cooldown = 0x0.000f, -- frames between shots
ammo = nil,
maxammo = nil,
munition = protron_e
})
function protron_gun_e:actually_shoot(x, y)
local m = self.munition.dym
for i=1,3 do
local b = self.munition.new{
dx = i*m,
dy = (4-i)*m,
actually_shoot = function(self, x, y)
local sprite = protron.psprite
if (self.enemy) sprite=protron.esprite
for i=1,3 do
local b = protron.new{
enemy=self.enemy,
sprite=sprite,
dx = i,
dy = 4-i
}
b:spawn_at(x,y)
local b2 = protron.new{
enemy=self.enemy,
sprite=sprite,
dx = -i,
dy = 4-i
}
b2:spawn_at(x,y)
end
local bup = protron.new{
enemy=self.enemy,
sprite=sprite,
dy=4
}
b:spawn_at(x,y)
local b2 = self.munition.new{
dx = -i*m,
dy = (4-i)*m,
}
b2:spawn_at(x,y)
bup:spawn_at(x,y)
end
local bup = self.munition.new{
dx=0,
dy=4*m,
}
bup:spawn_at(x,y)
end
}
mknew(protron_gun)
protron_gun_p = mknew(protron_gun_e.new{
munition = protron_p,
})
vulcan_e = mknew(bullet_base.new{
vulcan = bullet_base.new{
--shape
sprite = 21,
psprite = 22, --index of player ammo sprite
esprite = 21, -- index of enemy ammo sprite
width = 1, --in 8x8 blocks
height = 1,
hurt = { -- hurtbox - where this ship can be hit
@ -819,46 +821,39 @@ vulcan_e = mknew(bullet_base.new{
width = 1,
height = 4
},
x_off = 0.5, -- how to position by ship
y_off = 0,
center_x_off = 0.5, -- how to position by ship
bottom_y_off = 4,
top_y_off = 0,
damage = 0.5,
-- dx from gun
dy = 2,
category=enemy_blt_cat
})
dx = 0, -- px/frame
dy = 4,
}
mknew(vulcan)
vulcan_p = mknew(vulcan_e.new{
sprite=22,
y_off = 4,
dy = -4,
category=player_blt_cat
})
vulcan_gun_e = mknew(gun_base.new{
vulcan_gun = gun_base.new{
icon = 37,
enemy = false,
power = 8,
cooldown = 0x0.0002, -- frames between shots
ammo = nil,
maxammo = nil,
munition=vulcan_e,
dxs = {0.35, -0.35, -0.7, 0.7, 0.35, -0.35},
xoffs = {1, 0, -1, 1, 0, -1},
dxidx = 1,
actually_shoot = function(self, x, y)
local b = self.munition.new{
local sprite = self.enemy and vulcan.esprite or vulcan.psprite
local b = vulcan.new{
enemy=self.enemy,
sprite=sprite,
dx = self.dxs[self.dxidx],
}
b:spawn_at(self.xoffs[self.dxidx]+x,y)
self.dxidx += 1
if (self.dxidx > #self.dxs) self.dxidx = 1
end
})
vulcan_gun_p = mknew(vulcan_gun_e.new{
munition=vulcan_p,
})
}
mknew(vulcan_gun)
-->8
--ships, including player
@ -866,7 +861,7 @@ vulcan_gun_p = mknew(vulcan_gun_e.new{
firespark = split"9, 8, 2, 5, 1"
smokespark = split"13, 13, 5, 5"
player = mknew(ship_m.new{
player = ship_m.new{
--shape
sprite = 1, --index of ship sprite
size = 1, --all ships are square; how many 8x8 sprites?
@ -916,20 +911,21 @@ player = mknew(ship_m.new{
end
--dx, dy, shoot_spec, shoot_main
return (((b&0x2)>>1) - (b&0x1)) * th, (((b&0x8)>>3) - ((b&0x4)>>2)) * th, (b&0x10) > 0, (b&0x20) > 0
end,
init = function(p)
p.main_gun = zap_gun_p.new()
end
}
mknew(player,
function(p)
p.main_gun = zap_gun.new()
-- ONE HIT MODE
--
-- p.hp = 0
-- p.maxhp = 0
-- p.shield = 0
-- p.maxshield = 0
end,
})
end
)
frownie = mknew(ship_m.new{
frownie = ship_m.new{
--shape
sprite = 3, --index of ship sprite
size = 1, --all ships are square; how many 8x8 sprites?
@ -960,9 +956,10 @@ frownie = mknew(ship_m.new{
if (tstate>=4) dx=self.thrust
return dx,0,false,false
end,
})
}
mknew(frownie)
blocky = mknew(frownie.new{
blocky = frownie.new{
sprite = 10,
hp = 1.5,
hurt = {
@ -980,9 +977,10 @@ blocky = mknew(frownie.new{
end
ship_m.ow(self)
end
})
}
mknew(blocky)
spewy = mknew(frownie.new{
spewy = frownie.new{
sprite=26,
power=-20,
hurt = {
@ -999,13 +997,13 @@ spewy = mknew(frownie.new{
act=function(self)
local dx,dy,shoot_spec=frownie.act(self)
return dx, dy, shoot_spec, true
end,
init = function(ship)
ship.main_gun=ship.main_gun or protron_gun_e.new{}
end
})
}
mknew(spewy, function(ship)
ship.main_gun=ship.main_gun or protron_gun.new{enemy=true}
end)
chasey = mknew(ship_m.new{
chasey = ship_m.new{
sprite = 5,
size = 1,
hurt = {
@ -1028,11 +1026,10 @@ chasey = mknew(ship_m.new{
thrust = 0.2,
drag = 0.075,
slip = true,
init = function(ship)
ship.main_gun=ship.main_gun or zap_gun_e.new{}
end
})
}
mknew(chasey, function(ship)
ship.main_gun=ship.main_gun or zap_gun.new{enemy=true}
end)
function chasey:act()
self.xmin = max(primary_ship.x-8, 0)
@ -1040,7 +1037,7 @@ function chasey:act()
return 0, 0, false, self.x - 16 < primary_ship.x and self.x + 16 > primary_ship.x
end
xl_chasey=mknew(chasey.new{
xl_chasey=chasey.new{
size=2,
maxspd=1.25,
hurt = {
@ -1049,8 +1046,6 @@ xl_chasey=mknew(chasey.new{
width = 12,
height = 10
},
fire_off_x = 8,
fire_off_y = 15,
hp = 19.5,
shield = 5,
boss = true,
@ -1065,11 +1060,10 @@ xl_chasey=mknew(chasey.new{
sspr(40, 0, 8, 8, self.x, self.y, 16, 16)
pal()
end,
init = function(ship)
ship.main_gun=ship.main_gun or zap_gun_e.new{}
end,
})
}
mknew(xl_chasey, function(ship)
ship.main_gun=ship.main_gun or zap_gun.new{enemy=true}
end)
-->8
-- collisions
@ -1083,11 +1077,12 @@ function collides(box1, box2)
or box1.y+box1.height<box2.y)
end
collider = mknew{
init = function(x)
collider = { }
mknew(collider,
function(x)
x.suppress = {}
end,
}
end
)
function collider_indexes(box)
local ret = {}
@ -1276,9 +1271,9 @@ end
function spawn_bonus_vulcan_chasey()
local c = spawn_chasey()
c.main_gun=vulcan_gun_e.new{enemy=true}
c.main_gun=vulcan_gun.new{enemy=true}
c.die = function(self)
spawn_main_gun_at(self.x-1, self.y-1, vulcan_gun_p)
spawn_main_gun_at(self.x-1, self.y-1, vulcan_gun)
chasey.die(self)
end
c.sprite=4
@ -1381,7 +1376,7 @@ example_level_csv=[[1,spawn_frownie
310,spawn_blocking_blocky
310,spawn_blocking_blocky
311,spawn_frownie
350,spawn_main_gun_at,70,-11,protron_gun_p
350,spawn_main_gun_at,70,-11,protron_gun
401,spawn_frownie
420,spawn_blocking_frownie
430,spawn_bonus_vulcan_chasey
@ -1491,9 +1486,8 @@ bullets
shots much easier to dodge
* damage - damage per hit;
used by ships
* sprite - sprite index.
* x_off, y_off - renamed for
the next two vars. may revert
* psprite, esprite - index of
player or enemy sprite.
* center_off_x - the horizontal
centerpoint of the bullet,
for positioning when firing.
@ -1782,7 +1776,7 @@ true, they are dropped.
-->8
-- standard events
blip_fx = mknew{
blip_fx = {
cancel=false
}
@ -1800,6 +1794,8 @@ function blip_fx:abort()
self.cancel=true
end
mknew(blip_fx)
blip_pals = {}
function init_blip_pals()
for i=0,15 do
@ -1834,7 +1830,8 @@ function boom(x,y,boominess,is_boss)
return
end
spark_particle=mknew{}
spark_particle={}
mknew(spark_particle)
function spark_particle:move()
if (rnd(4) < 1) self.sidx += 1
@ -1863,7 +1860,7 @@ end
-->8
-- powerups
powerup = mknew(bullet_base.new{
powerup = bullet_base.new{
-- animated sprite array: "sprites"
-- to draw under or over anim,
-- override draw, draw the
@ -1879,12 +1876,13 @@ powerup = mknew(bullet_base.new{
-- easy to pick up
dx = 0,
dy = 1.5, -- 0.75 after enemyspd
category = enemy_blt_cat, -- collides with player ship
enemy = true, -- collides with player ship
damage = 0,
anim_speed = 2,
loop_pause = 30 -- affected by animspeed
})
}
mknew(powerup)
-- sprite indexes for "sheen" animation
sheen8x8 = split"2,54,55,56,57,58,59,60,61"
@ -1904,15 +1902,16 @@ function powerup:draw()
self.width, self.height)
end
repair = mknew(powerup.new{
repair = powerup.new{
hurt = {
x_off = -2,
y_off = -2,
width = 12,
height = 12
},
x_off = 4,
y_off = 0,
center_x_off = 4,
top_y_off = 0,
bottom_y_off = 0,
sprites = sheen8x8,
hitship = function(self, ship)
if (ship ~= primary_ship) return false
@ -1923,13 +1922,14 @@ repair = mknew(powerup.new{
spr(53, self.x, self.y, self.width, self.height)
powerup.draw(self)
end
})
}
mknew(repair)
function spawn_repair_at(x, y)
repair.new():spawn_at(x, y)
end
gun_swap = mknew(powerup.new{
gun_swap = powerup.new{
hurt = {
x_off = -2,
y_off = -2,
@ -1937,8 +1937,9 @@ gun_swap = mknew(powerup.new{
height = 16
},
-- gun = gun_type.new{}
x_off = 6,
y_off = 0,
center_x_off = 6,
top_y_off = 0,
bottom_y_off = 4,
width = 2,
height = 2,
sprites = {64, 66, 68, 70, 72, 74, 76, 78},
@ -1951,7 +1952,8 @@ gun_swap = mknew(powerup.new{
powerup.draw(self)
spr(self.gun.icon, self.x+2, self.y+2, 1, 1)
end
})
}
mknew(gun_swap)
function spawn_main_gun_at(x, y, gunt)
if (type(gunt)=="string") gunt=_ENV[gunt]

View File

@ -1,356 +0,0 @@
This file contains text that used to be in the cartridge itself, but
I'm getting increasingly anxious about cartridge space so I'm moving
it out ot a separate file.
---
main loop sequence
==================
1. level_frame
2. events
3. merge new_events into events
4. update bg intangibles
5. move ships (player first)
6. move bullets (player first)
7. calculate collisions
1. pship on eship
2. ebullet on pship
3. pbullet on eship
8. update fg intangibles
9. check for end of level
draw order
----------
bottom to top:
1. intangibles_bg
2. player bullets
3. player ships
4. enemy ships
5. enemy bullets
6. intangibles_fg
notes
-----
intangibles_fg move()s after
all collisions and other moves
are processed. if an intangible
is added to the list as a result
of a collision or move, it will
itself be move()d before it is
drawn.
data-driven items
=================
guns and bullets both allow the
most common behaviors to be
expressed with data alone.
ships only need a movement
algorithm expressed.
guns
----
* t - metatable for bullet type.
fired once in the bullet's
default direction per shot.
* enemy - if true, fired bullets
are flagged as enemy bullets.
* icon - sprite index of an
8x8 sprite to display in the
hud when the player has this
gun. default is 20, a generic
crosshair bullseye thing.
* cooldown - min frames between
shots.
* ammo, maxammo - permitted
number of shots. 0 is empty
and unfireable. maxammo = 0
will cause a divide by zero
so don't do that. if nil,
ammo is infinite.
default guns manage ammo and
cooldown in shoot, then call
actually_shoot to create the
projectile. override only
actually_shoot to change
projectile logic while keeping
cooldown and ammo logic.
bullets
-------
* dx, dy - movement per frame.
player bullets use -dy
instead.
* enemyspd - multiplier for dx
and dy on enemy bullets.
default is 0.5, making enemy
shots much easier to dodge
* damage - damage per hit;
used by ships
* sprite - sprite index.
* x_off, y_off - renamed for
the next two vars. may revert
* center_off_x - the horizontal
centerpoint of the bullet,
for positioning when firing.
assume a pixel's coordinates
refer to the upper left corner
of the pixel; the center of
a 2-width bullet with an
upper left corner at 0 is 1,
not 0.5.
* top_off_y, bottom_off_y -
also for positioning when
firing. positive distance from
top or bottom edge to image.
top_off_y will usually be 0,
bottom_off_y will not be when
bullets are smaller than
the sprite box.
* width, height - measured in
full sprites (8x8 boxes), not
pixels. used for drawing.
bullets despawn when above or
below the screen (player or
enemy bullets, respectively).
by default, bullets despawn
when they hit something.
override hitship to change this.
ships
____
ships move by calculating
momentum, then offsetting their
position by that momentum, then
clamping their position to the
screen (horizontally only for
ships that autoscroll). ships
that autoscroll (slip==true)
then slide down by scrollspeed.
fractional coordinates are ok.
after movement, ships lose
momentum (ship.drag along each
axis). abs(momentum) can't
exceed ship.maxspeed.
ships gain momentum by acting
like a player pushing buttons.
the player ship actually reads
buttons for this.
act -- returns new acceleration:
dx, dy, shoot_spec, shoot_main.
dx and dy are change in momentum
in px/frame. this is controls
only -- friction is handled in
ship:move (`drag` value).
ships hitting another ship take
1 damage per frame of overlap.
ships hitting a bullet check
bullet.damage to find out how
much damage they take. damage
is applied to shields, then hp.
damaged ships flash briefly -
blue (12) if all damage was
shielded, white (7) if hp was
damaged. a ship that then has 0
or less hp calls self:die() and
tells the main game loop to
remove it.
shieldcooldown is the interval
between restoring shield points.
shieldpenalty is the delay
before restoring points after
any damage, reset to this value
on every damaging hit (whether
it is absorbed by the shield or
not) -- shield behaves like
halo and other shooters in its
heritage, where it recovers if
you avoid damage for a while.
not that there is any safe cover
in this kind of game.
ships do not repair hp on their
own. negative-damage bullets
are treated as 0, but a bullet
can choose to repair the ship
it hits in its own hitship
method, or otherwise edit it
(changing weapons, refilling
weapon ammo). powerups are
therefore a kind of bullet.
levels
======
a level is a table mapping
effective frame number to
functions. when a level starts,
it sets lframe ("level frame")
and distance to 0.
every frame, level_frame
increments lframe by 0x0.0001.
then if the level is not frozen,
it increments distance by 1.0
and runs the function in the
level table for exactly that
frame number (if any). distance
is therefore "nonfrozen frames",
and is used to trigger level
progress. lframe always
increments. ships are encouraged
to use lframe to control
animation and movement, and may
use distance to react to level
progress separately from overall
time. remember to multiply
lframe-related stuff by 0x0001.
a special sentinel value, eol,
marks the end of the level.
(the level engine doesn't know
when it's out of events, so
without eol, the level will
simply have no events forever.)
when it finds eol, level_frame
throws away the current level
and tells the main loop that it
might be done. the main loop
agrees the level is over and the
player has won when the level
has reached eol and there are
no more enemy ships, enemy
bullets, or background events
remaining. player ships, player
bullets, and intangibles are
not counted.
level freezing
--------------
the level is frozen when the
global value freeze > 0.
generally, something intending
to block level progress (a
miniboss, a minigame, etc.)
increments freeze and prepares
some means of decrementing it
when it no longer wants to block
level progress.
most commonly, we want to block
until some specific ship or
group of ships has died. for
these ships, override ship:die
to decrement freeze. make sure
to set ship.dead in any new
ship:die method so anything else
looking at it can recognize
the ship as dead.
for anything else, you probably
want an event to figure out when
to unfreeze.
levels start at 1
-----------------
distance is initialized to 0
but gets incremented before the
first time the engine looks for
events. therefore, the first
frame of the level executes
level[1]. since levelframe
executes before anything else,
level[1] sets up the first frame
drawn in the level. the player
does not see a blank world
before level[1] runs.
level[1] can therefore be used
to reconfigure the player ship,
set up backgrounds, start music,
kick off some kind of fade-in
animation, etc.
events
======
the global list "events" stores
0-argument functions which are
called every frame. if they
return true, they are removed
from the list and not run again;
if they return false, they stay
and will be called in later
frames. the level does not end
while the events table is
nonempty.
events are most commonly used
to set up something for later
(for example, blip uses an event
to remove the fx_pallete from
the flashing ship when the blip
expires), but can also be used
to implement a "level within a
level" that does something
complicated until it's done. if
you froze the level when
creating the event, remember
to thaw it (freeze -= 1) on all
paths that return true.
to do complex stuff in events,
use a closure or a metatable
that specifies __call.
to avoid editing the events
list while it is being iterated,
events that create new events
must add those events to
new_events rather than events.
new_events is only valid during
the "event execution" stage, so
events created at any other time
must go directly on events
without using new_events.
intangibles
===========
the intangibles_fg and
intangibles_bg lists contain
items with :move and :draw.
like ships and bullets, they
move during _update60 and
draw during _draw. they are
not checked for collisions.
intangibles_bg moves/draws
before anything else moves or
draws. intangibles_fg
moves/draws last. this controls
whether your intangible object
draws in front of or behind
other stuff. you probably want
intangibles_bg for decorative
elements and intangibles_fg
for explosions, score popups,
etc.
there's no scrolling background
engine but intangibles_bg could
be used to create one, including
using the map (otherwise unused
in this engine) for the purpose.
intangibles do not prevent the
level from ending. like bullets
and ships, if :move returns
true, they are dropped.

View File

@ -1,87 +0,0 @@
pico-8 cartridge // http://www.pico-8.com
version 42
__lua__
-- vacuum gambit
-- by kistaro windrider
function _draw()
cls()
draw_hud_placeholder()
draw_weap_opt(0,0,frame_col(item==1),1,"hull","\n +1\n max\nhealth")
draw_weap_opt(56,0,frame_col(item==2),2,"vulc"," rate\n\n faster\n firing\n rate")
draw_rearm(frame_col(item<0))
end
function _init()
item=1
bfm=1
end
function _update()
if (btn(3) and item > 0 or btn(2) and item < 0) item = -item
if (btn(0)) item = 1
if (btn(1)) item = 2
if (btn() & 0xF ~= 0) and bfm >= 10 or bfm >= 30 then
bfm = 1
else
bfm += 1
end
end
function draw_hud_placeholder()
rectfill(112, 0, 127, 127,0x56)
rect(112,0,127,127,7)
line(127,1,127,127,5)
line(113,127)
end
function glow_box(x0, y0, x1, y1, c, cf)
rect(x0, y0, x1, y1, c[1])
rect(x0+1, y0+1, x1-1, y1-1, c[2])
rect(x0+2, y0+2, x1-2, y1-2, c[1])
if cf then
-- todo: animate "dot crawl" background
fillp(…)
rectfill(x0+3, y0+3, x1-3, y1-3, cf)
fillp()
end
end
function frame_col(hot)
if (not hot) return {4,10}
if (bfm<=16) return {14,7}
return {2,8}
end
function draw_weap_opt(x, y, c, s, hdr, body)
camera(-x,-y)
glow_box(0,0,55,100,c,1)
spr(s,5, 5)
print(hdr, 13, 8, 7)
print(body, 5, 15, 6)
camera()
end
function draw_rearm(c)
glow_box(0,101,111,127,c,1)
spr(5,15,107,4,2)
print("full ammo\nfull shield\n+50% health",54, 106, 6)
end
__gfx__
000000000b00000000000a0007700770000aa0000444440004444444000000000000000000000000000000000000000000000000000000000000000000000000
00000000bba80880000008000aa00aa00a0880a0447777700477777a000000000000000000000000000000000000000000000000000000000000000000000000
007007000aaa28780a0000000990099008000080477aaa7a0477aaaa000000000000000000000000000000000000000000000000000000000000000000000000
0007000008a8887808000000099009900080080047a0047a047a0000000000000000000000000000000000000000000000000000000000000000000000000000
00007000088888820000a000088008800000000047a0447a047a0000000000000000000000000000000000000000000000000000000000000000000000000000
00700700008888200000800008800880a000000a47a4477a047a4440000000000000000000000000000000000000000000000000000000000000000000000000
000000000008820000a0000008800880080aa080477777a00477777a000000000000000000000000000000000000000000000000000000000000000000000000
0000000000002000008000000880088000088000477770000422aaaa222200020000020000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000047a77700022ee0002eeee002e00022e000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000047a4777002ea2e002e002e02ee022ee000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000047a0477a22ea2e002e002e02e2e2e2e000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000047a0047a2e2222e02e222e02e02e02e000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000047a0047a2eeeeeea2eeee002e02e02e000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000aa000aa2e7aa2ea2e00e002e02e02e000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000002e0002e02e002e02e02e02e000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000e0000e00e000e00e00e00e000000000000000000000000000000000000000000000000000000000

File diff suppressed because it is too large Load Diff