Compare commits

..

7 Commits

2 changed files with 400 additions and 383 deletions

View File

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

View File

@ -26,9 +26,9 @@ end
-- generate standard "overlay" -- generate standard "overlay"
-- constructor for type tt. -- constructor for type tt.
-- if tt.init is defined, generated -- if more is defined, generated
-- new calls tt.init(ret) after -- new calls more(ret) after
-- ret is definitely not nil, -- ret is definitely not nil
-- before calling setmetatable. -- before calling setmetatable.
-- use to initialize mutables. -- use to initialize mutables.
-- --
@ -37,8 +37,8 @@ end
-- object *after* more, because -- object *after* more, because
-- this works better with the -- this works better with the
-- `more` impls i use. -- `more` impls i use.
function mknew(tt) function mknew(tt, more)
local mt,oldnew,more = {__index=tt},tt.new,rawget(tt, "init") local mt,oldnew = {__index=tt},tt.new
tt.new=function(ret) tt.new=function(ret)
if(not ret) ret = {} if(not ret) ret = {}
if(more) more(ret) if(more) more(ret)
@ -46,18 +46,15 @@ function mknew(tt)
setmetatable(ret, mt) setmetatable(ret, mt)
return ret return ret
end end
return tt
end end
-- intrusive singly-linked list. -- intrusive singly-linked list.
-- cannot be nested! -- cannot be nested!
linked_list = mknew{ linked_list = {is_linked_list=true}
is_linked_list=true, mknew(linked_list, function(x)
init = function(x)
x.next=nil x.next=nil
x.tail=x x.tail=x
end, end)
}
function linked_list:push_back(x) function linked_list:push_back(x)
self.tail.next = x self.tail.next = x
@ -337,32 +334,30 @@ function drawhud()
line(113,127) line(113,127)
draw_gun_info("❎",1,116,3,primary_ship.main_gun) draw_gun_info("❎",1,116,3,primary_ship.main_gun)
draw_gun_info("🅾️",1,116,29,primary_ship.special_gun) draw_gun_info("🅾️",1,116,31,primary_ship.special_gun)
inset(114,57,119,118) dropshadow("p h",114,59,1)
rectfill(119,57,124,58,13) inset(114,66,119,125)
inset(120,64,125,125)
rectfill(114,124,120,125,7)
print("XP",119,55,1)
print("HP",114,122,1)
fillp(0x5a5a) fillp(0x5a5a)
vertmeter(115,58,118,117,primary_ship.xp, primary_ship.xptarget, powcols) vertmeter(115,67,118,124,primary_ship.power, primary_ship.max_power, powcols)
-- 59 px vertically
inset(120,66,125,125)
-- 57 px vertically
local mxs, cs, mxh, ch = primary_ship.maxshield, primary_ship.shield, primary_ship.maxhp, primary_ship.hp local mxs, cs, mxh, ch = primary_ship.maxshield, primary_ship.shield, primary_ship.maxhp, primary_ship.hp
if (mxs > 0) and (mxh > 0) then if (mxs > 0) and (mxh > 0) then
local split = 59 * (mxs / (mxs + mxh)) \ 1 + 64 local split = 57 * (mxs / (mxs + mxh)) \ 1 + 66
line(121, split, 124, split, 0xba) line(121, split, 124, split, 0xba)
vertmeter(121,65,124,split-1,cs, mxs,shlcols) vertmeter(121,67,124,split-1,cs, mxs,shlcols)
vertmeter(121,split+1,124,124,ch, mxh, hpcols) vertmeter(121,split+1,124,124,ch, mxh, hpcols)
elseif mxs > 0 then elseif mxs > 0 then
vertmeter(121,65,124,124,cs,mxs,shlcols) vertmeter(121,67,124,124,cs,mxs,shlcols)
elseif mxh > 0 then elseif mxh > 0 then
vertmeter(121,65,124,124,ch,mxh,hpcols) vertmeter(121,67,124,124,ch,mxh,hpcols)
else else
print("!", 122, 93, 9) print("!", 122, 94, 9)
print("!", 121, 92, 8) print("!", 121, 93, 8)
end end
fillp(0) fillp(0)
end end
function draw_gun_info(lbl,fgc,x,y,gun) function draw_gun_info(lbl,fgc,x,y,gun)
@ -409,7 +404,7 @@ function inset(x0,y0,x1,y1)
-- fillp -- fillp
rect(x0,y0,x1,y1,119) rect(x0,y0,x1,y1,119)
line(x1,y0,x0,y0,85) line(x1,y0,x0,y0,85)
line(x0,y1-1,85) line(x0,y1,85)
end end
function dropshadow(str, x, y, col) function dropshadow(str, x, y, col)
@ -422,14 +417,19 @@ end
scrollrate = 0.25 --in px/frame scrollrate = 0.25 --in px/frame
ship_m = mknew{ ship_m = {
-- ships have no shield by default -- ships have no shield by default
shield = 0, shield = 0,
maxshield = 0, maxshield = 0,
shieldcost = 32767.9,
shieldcooldown = 0x0.003c,--1s shieldcooldown = 0x0.003c,--1s
shieldpenalty = 0x0.012c, --5s shieldpenalty = 0x0.012c, --5s
max_power = 120,
power = 120,
generator = 2, -- power gen per frame
slip = true, -- most enemies slide slip = true, -- most enemies slide
xmomentum = 0, xmomentum = 0,
@ -442,6 +442,7 @@ ship_m = mknew{
-- ymin, ymax default to nil -- ymin, ymax default to nil
-- pship needs more constraint -- pship needs more constraint
} }
mknew(ship_m)
function ship_m:die() function ship_m:die()
self.dead = true self.dead = true
@ -489,6 +490,7 @@ end
function ship_m:move() function ship_m:move()
self:refresh_shield() self:refresh_shield()
self.power = min(self.max_power, self.power + self.generator)
local dx, dy, shoot_spec, shoot_main = self:act() local dx, dy, shoot_spec, shoot_main = self:act()
dx = self:constrain(self.x, self.xmomentum, self.xmin, self.xmax, dx) dx = self:constrain(self.x, self.xmomentum, self.xmin, self.xmax, dx)
dy = self:constrain(self.y, self.ymomentum, self.ymin, self.ymax, dy) dy = self:constrain(self.y, self.ymomentum, self.ymin, self.ymax, dy)
@ -530,7 +532,9 @@ end
function ship_m:maybe_shoot(gun) function ship_m:maybe_shoot(gun)
if (not gun) return if (not gun) return
return gun:shoot(self.x + self.fire_off_x, self.y + self.fire_off_y) if (self.power < gun.power) return
if (not gun:shoot(self.x + self.fire_off_x, self.y + self.fire_off_y)) return
self.power -= gun.power
end end
function ship_m:hitship(other) function ship_m:hitship(other)
@ -571,8 +575,10 @@ end
function ship_m:refresh_shield() function ship_m:refresh_shield()
if (self.shield >= self.maxshield) return if (self.shield >= self.maxshield) return
if (lframe < self.shield_refresh_ready) return if (lframe < self.shield_refresh_ready) return
if (self.power < self.shieldcost) return
self.shield += 1 self.shield += 1
self.shield = min(self.shield, self.maxshield) self.shield = min(self.shield, self.maxshield)
self.power -= self.shieldcost
self.shield_refresh_ready = lframe + self.shieldcooldown self.shield_refresh_ready = lframe + self.shieldcooldown
end end
@ -587,34 +593,14 @@ function enemy_blt_cat()
return ebullets return ebullets
end end
-- x, y: position bullet_base = { }
-- dx, dy: movement (linear) mknew(bullet_base)
-- f: frames remaining; nil for no limit
-- sprite: what sprite to draw
-- hurt -- hurtbox
-- width, height -- in sprites
-- x_off, y_off -- how to
-- initially position relative
-- to firing point. weird
-- details, check impl
-- damage -- damage to do to
-- a ship that gets hit
-- category -- function that
-- returns which bullet list
-- to spawn onto
-- hitship -- event handler,
-- takes ship as argument.
-- default: die, return true.
-- returns whether to delete
-- the bullet
-- die -- on-removal event,
-- default no-op
bullet_base = mknew{ }
gun_base = mknew{ gun_base = {
shoot_ready = -32768, shoot_ready = -32768,
icon = 20 icon = 20
} }
mknew(gun_base)
function bullet_base:hitship(_) function bullet_base:hitship(_)
self:die() self:die()
@ -627,8 +613,7 @@ end
function bullet_base:move() function bullet_base:move()
self.x += self.dx self.x += self.dx
self.y += self.dy self.y += self.dy
if (self.f) self.f -= 1 if (self.y > 128) or (self.y < -8 * self.height) then
if (self.y > 128) or (self.y < -8 * self.height) or (self.f and self.f < 0) then
self:die() self:die()
return true return true
end end
@ -667,9 +652,9 @@ end
-->8 -->8
-- bullets and guns -- bullets and guns
zap_e = mknew(bullet_base.new{ zap_e = bullet_base.new{
--shape --shape
sprite = 9, --index of ammo sprite sprite = 9, --index of enemy ammo sprite
width = 1, --in 8x8 blocks width = 1, --in 8x8 blocks
height = 1, height = 1,
hurt = { -- hurtbox - where this ship can be hit hurt = { -- hurtbox - where this ship can be hit
@ -688,26 +673,31 @@ zap_e = mknew(bullet_base.new{
hitship = const_fxn(true), hitship = const_fxn(true),
category = enemy_blt_cat, category = enemy_blt_cat,
}) }
mknew(zap_e)
zap_p = mknew(zap_e.new{ zap_p = zap_e.new{
sprite = 8, sprite = 8,
dy = -8, dy = -8,
y_off = 0, y_off = 0,
category = player_blt_cat, category = player_blt_cat,
}) }
mknew(zap_p)
zap_gun_e = mknew(gun_base.new{ zap_gun_e = gun_base.new{
power = 20, -- power consumed per shot
cooldown = 0x0.000a, -- frames between shots cooldown = 0x0.000a, -- frames between shots
ammo = nil, -- unlimited ammo - main gun ammo = nil, -- unlimited ammo - main gun
actually_shoot = spawn_one(zap_e), actually_shoot = spawn_one(zap_e),
}) }
mknew(zap_gun_e)
zap_gun_p = mknew(zap_gun_e.new{ zap_gun_p = zap_gun_e.new{
actually_shoot = spawn_one(zap_p), actually_shoot = spawn_one(zap_p),
}) }
mknew(zap_gun_p)
blast = mknew(bullet_base.new{ blast = bullet_base.new{
--shape --shape
sprite = 12, --index of player ammo sprite sprite = 12, --index of player ammo sprite
width = 1, --in 8x8 blocks width = 1, --in 8x8 blocks
@ -750,17 +740,20 @@ blast = mknew(bullet_base.new{
end end
end, end,
category=player_blt_cat category=player_blt_cat
}) }
mknew(blast)
blast_gun = mknew(gun_base.new{ blast_gun = gun_base.new{
icon = 13, icon = 13,
power = 0, -- only cost is ammo
cooldown = 0x0.0020, -- frames between shots cooldown = 0x0.0020, -- frames between shots
ammo = 5, ammo = 5,
maxammo = 5, maxammo = 5,
actually_shoot = spawn_one(blast), actually_shoot = spawn_one(blast),
}) }
mknew(blast_gun)
protron_e = mknew(bullet_base.new{ protron_e = bullet_base.new{
--shape --shape
sprite = 24, sprite = 24,
width = 1, --in 8x8 blocks width = 1, --in 8x8 blocks
@ -778,22 +771,26 @@ protron_e = mknew(bullet_base.new{
dym = 0.5, -- gun sets dy; dym = 0.5, -- gun sets dy;
-- this is mult -- this is mult
category = enemy_blt_cat, category = enemy_blt_cat,
}) }
mknew(protron_e)
protron_p = mknew(protron_e.new{ protron_p = protron_e.new{
sprite=23, sprite=23,
dym = -1, dym = -1,
y_off = 0, y_off = 0,
category=player_blt_cat, category=player_blt_cat,
}) }
mknew(protron_p)
protron_gun_e = mknew(gun_base.new{ protron_gun_e = gun_base.new{
icon = 25, icon = 25,
power = 60,
cooldown = 0x0.000f, -- frames between shots cooldown = 0x0.000f, -- frames between shots
ammo = nil, ammo = nil,
maxammo = nil, maxammo = nil,
munition = protron_e munition = protron_e
}) }
mknew(protron_gun_e)
function protron_gun_e:actually_shoot(x, y) function protron_gun_e:actually_shoot(x, y)
local m = self.munition.dym local m = self.munition.dym
@ -816,11 +813,12 @@ function protron_gun_e:actually_shoot(x, y)
bup:spawn_at(x,y) bup:spawn_at(x,y)
end end
protron_gun_p = mknew(protron_gun_e.new{ protron_gun_p = protron_gun_e.new{
munition = protron_p, munition = protron_p,
}) }
mknew(protron_gun_p)
vulcan_e = mknew(bullet_base.new{ vulcan_e = bullet_base.new{
--shape --shape
sprite = 21, sprite = 21,
width = 1, --in 8x8 blocks width = 1, --in 8x8 blocks
@ -838,18 +836,21 @@ vulcan_e = mknew(bullet_base.new{
-- dx from gun -- dx from gun
dy = 2, dy = 2,
category=enemy_blt_cat category=enemy_blt_cat
}) }
mknew(vulcan_e)
vulcan_p = mknew(vulcan_e.new{ vulcan_p = vulcan_e.new{
sprite=22, sprite=22,
y_off = 4, y_off = 4,
dy = -4, dy = -4,
category=player_blt_cat category=player_blt_cat
}) }
mknew(vulcan_p)
vulcan_gun_e = mknew(gun_base.new{ vulcan_gun_e = gun_base.new{
icon = 37, icon = 37,
enemy = false, enemy = false,
power = 8,
cooldown = 0x0.0002, -- frames between shots cooldown = 0x0.0002, -- frames between shots
ammo = nil, ammo = nil,
maxammo = nil, maxammo = nil,
@ -865,11 +866,13 @@ vulcan_gun_e = mknew(gun_base.new{
self.dxidx += 1 self.dxidx += 1
if (self.dxidx > #self.dxs) self.dxidx = 1 if (self.dxidx > #self.dxs) self.dxidx = 1
end end
}) }
mknew(vulcan_gun_e)
vulcan_gun_p = mknew(vulcan_gun_e.new{ vulcan_gun_p = vulcan_gun_e.new{
munition=vulcan_p, munition=vulcan_p,
}) }
mknew(vulcan_gun_p)
-->8 -->8
--ships, including player --ships, including player
@ -877,7 +880,7 @@ vulcan_gun_p = mknew(vulcan_gun_e.new{
firespark = split"9, 8, 2, 5, 1" firespark = split"9, 8, 2, 5, 1"
smokespark = split"13, 13, 5, 5" smokespark = split"13, 13, 5, 5"
player = mknew(ship_m.new{ player = ship_m.new{
--shape --shape
sprite = 1, --index of ship sprite sprite = 1, --index of ship sprite
size = 1, --all ships are square; how many 8x8 sprites? size = 1, --all ships are square; how many 8x8 sprites?
@ -891,16 +894,13 @@ player = mknew(ship_m.new{
sparkodds = 2, sparkodds = 2,
boss = true, -- dramatic special effects boss = true, -- dramatic special effects
-- health -- health and power
hp = 3, -- current health, non-regenerating hp = 3, -- current health, non-regenerating
maxhp = 3, -- player only; other ships never heal maxhp = 3, -- player only; other ships never heal
shield = 2, -- regenerates shield = 2, -- regenerates, using power
maxshield = 2, maxshield = 2,
shieldcost = 60, -- power cost to refill shield
-- xp, increments of 0x0.01 generator = 2,
xp = 0,
xptarget = 0x0.05,
level = 1,
-- gun -- gun
main_gun = nil, -- assign at spawn time main_gun = nil, -- assign at spawn time
@ -930,9 +930,10 @@ player = mknew(ship_m.new{
end end
--dx, dy, shoot_spec, shoot_main --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 return (((b&0x2)>>1) - (b&0x1)) * th, (((b&0x8)>>3) - ((b&0x4)>>2)) * th, (b&0x10) > 0, (b&0x20) > 0
end, end
}
init = function(p) mknew(player,
function(p)
p.main_gun = zap_gun_p.new() p.main_gun = zap_gun_p.new()
-- ONE HIT MODE -- ONE HIT MODE
-- --
@ -940,10 +941,10 @@ player = mknew(ship_m.new{
-- p.maxhp = 0 -- p.maxhp = 0
-- p.shield = 0 -- p.shield = 0
-- p.maxshield = 0 -- p.maxshield = 0
end, end
}) )
frownie = mknew(ship_m.new{ frownie = ship_m.new{
--shape --shape
sprite = 3, --index of ship sprite sprite = 3, --index of ship sprite
size = 1, --all ships are square; how many 8x8 sprites? size = 1, --all ships are square; how many 8x8 sprites?
@ -956,7 +957,7 @@ frownie = mknew(ship_m.new{
sparks = smokespark, sparks = smokespark,
sparkodds = 8, sparkodds = 8,
-- health -- health and power
hp = 0.5, -- enemy ships need no max hp hp = 0.5, -- enemy ships need no max hp
-- position -- position
@ -974,9 +975,10 @@ frownie = mknew(ship_m.new{
if (tstate>=4) dx=self.thrust if (tstate>=4) dx=self.thrust
return dx,0,false,false return dx,0,false,false
end, end,
}) }
mknew(frownie)
blocky = mknew(frownie.new{ blocky = frownie.new{
sprite = 10, sprite = 10,
hp = 1.5, hp = 1.5,
hurt = { hurt = {
@ -994,10 +996,12 @@ blocky = mknew(frownie.new{
end end
ship_m.ow(self) ship_m.ow(self)
end end
}) }
mknew(blocky)
spewy = mknew(frownie.new{ spewy = frownie.new{
sprite=26, sprite=26,
power=-20,
hurt = { hurt = {
x_off=0, x_off=0,
y_off=1, y_off=1,
@ -1005,18 +1009,20 @@ spewy = mknew(frownie.new{
height=5 height=5
}, },
hp=0.5, hp=0.5,
maxpower=70,
generator=0.5,
fire_off_x=4, fire_off_x=4,
fire_off_y=7, fire_off_y = 7,
act=function(self) act=function(self)
local dx,dy,shoot_spec=frownie.act(self) local dx,dy,shoot_spec=frownie.act(self)
return dx, dy, shoot_spec, self.y > 10 return dx, dy, shoot_spec, true
end,
init = function(ship)
ship.main_gun=ship.main_gun or protron_gun_e.new{}
end end
}) }
mknew(spewy, function(ship)
ship.main_gun=ship.main_gun or protron_gun_e.new{enemy=true}
end)
chasey = mknew(ship_m.new{ chasey = ship_m.new{
sprite = 5, sprite = 5,
size = 1, size = 1,
hurt = { hurt = {
@ -1030,6 +1036,7 @@ chasey = mknew(ship_m.new{
hp = 1.5, hp = 1.5,
shield = 1, shield = 1,
maxshield = 1, maxshield = 1,
shieldcost = 180,
fire_off_x = 4, fire_off_x = 4,
fire_off_y = 7, fire_off_y = 7,
@ -1038,19 +1045,18 @@ chasey = mknew(ship_m.new{
thrust = 0.2, thrust = 0.2,
drag = 0.075, drag = 0.075,
slip = true, slip = true,
}
init = function(ship) mknew(chasey, function(ship)
ship.main_gun=ship.main_gun or zap_gun_e.new{} ship.main_gun=ship.main_gun or zap_gun_e.new{}
end end)
})
function chasey:act() function chasey:act()
self.xmin = max(primary_ship.x-8, 0) self.xmin = max(primary_ship.x-8, 0)
self.xmax = min(primary_ship.x + 8, 112 - 8*self.size) self.xmax = min(primary_ship.x + 8, 112 - 8*self.size)
return 0, 0, false, self.y > 10 and self.x - 16 < primary_ship.x and self.x + 16 > primary_ship.x return 0, 0, false, self.x - 16 < primary_ship.x and self.x + 16 > primary_ship.x
end end
xl_chasey=mknew(chasey.new{ xl_chasey=chasey.new{
size=2, size=2,
maxspd=1.25, maxspd=1.25,
hurt = { hurt = {
@ -1075,11 +1081,10 @@ xl_chasey=mknew(chasey.new{
sspr(40, 0, 8, 8, self.x, self.y, 16, 16) sspr(40, 0, 8, 8, self.x, self.y, 16, 16)
pal() pal()
end, end,
init = function(ship) }
ship.main_gun=ship.main_gun or zap_gun_e.new{} mknew(xl_chasey, function(ship)
end, ship.main_gun=ship.main_gun or zap_gun_e.new{}
}) end)
-->8 -->8
-- collisions -- collisions
@ -1093,11 +1098,12 @@ function collides(box1, box2)
or box1.y+box1.height<box2.y) or box1.y+box1.height<box2.y)
end end
collider = mknew{ collider = { }
init = function(x) mknew(collider,
function(x)
x.suppress = {} x.suppress = {}
end, end
} )
function collider_indexes(box) function collider_indexes(box)
local ret = {} local ret = {}
@ -1293,17 +1299,7 @@ function spawn_bonus_vulcan_chasey()
end end
c.sprite=4 c.sprite=4
return c return c
end end
function spawn_bonus_shield_chasey()
local c = spawn_chasey()
c.die = function(self)
spawn_shield_upgrade_at(self.x-1, self.y-1)
chasey.die(self)
end
c.sprite=4
return c
end
helpers = { helpers = {
spawn_frownie, spawn_frownie,
@ -1394,7 +1390,7 @@ example_level_csv=[[1,spawn_frownie
115,spawn_spewy 115,spawn_spewy
130,spawn_bonus_frownie 130,spawn_bonus_frownie
145,spawn_spewy 145,spawn_spewy
200,spawn_bonus_shield_chasey 200,spawn_chasey
250,spawn_blocking_blocky 250,spawn_blocking_blocky
285,spawn_spec_gun_at,35,-11,blast_gun 285,spawn_spec_gun_at,35,-11,blast_gun
310,spawn_blocking_blocky 310,spawn_blocking_blocky
@ -1411,9 +1407,8 @@ example_level_csv=[[1,spawn_frownie
500,multi,20,12,spawn_blocking_blocky 500,multi,20,12,spawn_blocking_blocky
501,spawn_bonus_frownie 501,spawn_bonus_frownie
620,spawn_blocking_blocky 620,spawn_blocking_blocky
630,spawn_bonus_shield_chasey 700,spawn_blocking_boss_chasey
720,spawn_blocking_boss_chasey 701,eol]]
721,eol]]
-->8 -->8
-- readme.md -- readme.md
@ -1465,6 +1460,10 @@ algorithm expressed.
guns guns
---- ----
* power - cost in generator
power to fire. may be 0.
field directly read by ships;
required in all guns.
* t - metatable for bullet type. * t - metatable for bullet type.
fired once in the bullet's fired once in the bullet's
default direction per shot. default direction per shot.
@ -1492,6 +1491,11 @@ actually_shoot to change
projectile logic while keeping projectile logic while keeping
cooldown and ammo logic. cooldown and ammo logic.
ships manage generator power
before asking the gun to shoot.
this behavior is in
ship_m:maybe_shoot.
bullets bullets
------- -------
* dx, dy - movement per frame. * dx, dy - movement per frame.
@ -1578,19 +1582,39 @@ or less hp calls self:die() and
tells the main game loop to tells the main game loop to
remove it. remove it.
shieldcooldown is the interval ships have power, from 0 to
between restoring shield points. ship.maxpower, increasing by
shieldpenalty is the delay ship.generator per frame.
before restoring points after in maybe_shoot, ships check that
any damage, reset to this value they have power to fire before
on every damaging hit (whether trying to fire (the gun itself
it is absorbed by the shield or checks ammo and cooldown), and
not) -- shield behaves like spend that power if they fire.
halo and other shooters in its
heritage, where it recovers if power is also used to restore
you avoid damage for a while. shields - ship.shieldcost per
not that there is any safe cover point of shields. shieldcooldown
in this kind of game. is the interval between
restoring shield points, which
is reset to shieldpenalty when a
ship takes damage (regardless of
whether that damage is stopped
by the shield or not).
shieldpenalty is much worse than
shieldcooldown (hALO shield).
therefore:
* damaged ships spend power
repairing shields, which may
affect ability to fire guns.
this looks like a slow firing
rate because the ship will
eventually recover enough
energy to fire.
* a ship firing nonstop will
typically be unable to recover
any shields because it will
not have energy to do so.
ships do not repair hp on their ships do not repair hp on their
own. negative-damage bullets own. negative-damage bullets
@ -1774,7 +1798,7 @@ true, they are dropped.
-->8 -->8
-- standard events -- standard events
blip_fx = mknew{ blip_fx = {
cancel=false cancel=false
} }
@ -1792,6 +1816,8 @@ function blip_fx:abort()
self.cancel=true self.cancel=true
end end
mknew(blip_fx)
blip_pals = {} blip_pals = {}
function init_blip_pals() function init_blip_pals()
for i=0,15 do for i=0,15 do
@ -1826,7 +1852,8 @@ function boom(x,y,boominess,is_boss)
return return
end end
spark_particle=mknew{} spark_particle={}
mknew(spark_particle)
function spark_particle:move() function spark_particle:move()
if (rnd(4) < 1) self.sidx += 1 if (rnd(4) < 1) self.sidx += 1
@ -1855,7 +1882,7 @@ end
-->8 -->8
-- powerups -- powerups
powerup = mknew(bullet_base.new{ powerup = bullet_base.new{
-- animated sprite array: "sprites" -- animated sprite array: "sprites"
-- to draw under or over anim, -- to draw under or over anim,
-- override draw, draw the -- override draw, draw the
@ -1876,7 +1903,8 @@ powerup = mknew(bullet_base.new{
anim_speed = 2, anim_speed = 2,
loop_pause = 30 -- affected by animspeed loop_pause = 30 -- affected by animspeed
}) }
mknew(powerup)
-- sprite indexes for "sheen" animation -- sprite indexes for "sheen" animation
sheen8x8 = split"2,54,55,56,57,58,59,60,61" sheen8x8 = split"2,54,55,56,57,58,59,60,61"
@ -1896,7 +1924,7 @@ function powerup:draw()
self.width, self.height) self.width, self.height)
end end
repair = mknew(powerup.new{ repair = powerup.new{
hurt = { hurt = {
x_off = -2, x_off = -2,
y_off = -2, y_off = -2,
@ -1906,37 +1934,23 @@ repair = mknew(powerup.new{
x_off = 4, x_off = 4,
y_off = 0, y_off = 0,
sprites = sheen8x8, sprites = sheen8x8,
icon = 53,
hitship = function(self, ship) hitship = function(self, ship)
if (ship ~= primary_ship) return false if (ship ~= primary_ship) return false
primary_ship.hp = min(primary_ship.maxhp, primary_ship.hp + 1) primary_ship.hp = min(primary_ship.maxhp, primary_ship.hp + 1)
return true return true
end, end,
draw = function(self) draw = function(self)
spr(self.icon, self.x, self.y, self.width, self.height) spr(53, self.x, self.y, self.width, self.height)
powerup.draw(self) powerup.draw(self)
end end
}) }
mknew(repair)
function spawn_repair_at(x, y) function spawn_repair_at(x, y)
repair.new():spawn_at(x, y) repair.new():spawn_at(x, y)
end end
shield_upgrade = mknew(repair.new{ gun_swap = powerup.new{
icon=52
})
function shield_upgrade:hitship(ship)
if (ship ~= primary_ship) return false
primary_ship.maxshield += 1
return true
end
function spawn_shield_upgrade_at(x, y)
shield_upgrade.new():spawn_at(x,y)
end
gun_swap = mknew(powerup.new{
hurt = { hurt = {
x_off = -2, x_off = -2,
y_off = -2, y_off = -2,
@ -1958,7 +1972,8 @@ gun_swap = mknew(powerup.new{
powerup.draw(self) powerup.draw(self)
spr(self.gun.icon, self.x+2, self.y+2, 1, 1) spr(self.gun.icon, self.x+2, self.y+2, 1, 1)
end end
}) }
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] if (type(gunt)=="string") gunt=_ENV[gunt]
@ -2017,14 +2032,14 @@ __gfx__
00000000000000000000000000000000000000000009080000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000009080000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000cccccccccccccccc77000000007700000000770000000077000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000cccccccc77000000007700000000770000000077000000000000000000000000000000000000000000000000
00000000000000000000000000000000c116611dc11ee11d70000000077000000007700000000770000000070000000000000000000000000000000000000000 0000000000000000000000000000000000000000c11ee11d70000000077000000007700000000770000000070000000000000000000000000000000000000000
00000000000000000000000000000000c1611c1dc11ee11d00000000770000000077000000007700000000770000000700000000000000000000000000000000 0000000000000000000000000000000000000000c11ee11d00000000770000000077000000007700000000770000000700000000000000000000000000000000
00000000000000000000000000000000c61111cdceeeeeed00000000700000000770000000077000000007700000007700000000000000000000000000000000 0000000000000000000000000000000000000000ceeeeeed00000000700000000770000000077000000007700000007700000000000000000000000000000000
00000000000000000000000000000000c6111bcdceeeeeed00000000000000007700000000770000000077000000077000000007000000000000000000000000 0000000000000000000000000000000000000000ceeeeeed00000000000000007700000000770000000077000000077000000007000000000000000000000000
00000000000000000000000000000000c161bbbdc11ee11d00000000000000007000000007700000000770000000770000000077000000000000000000000000 0000000000000000000000000000000000000000c11ee11d00000000000000007000000007700000000770000000770000000077000000000000000000000000
00000000000000000000000000000000c11ccb1dc11ee11d00000000000000000000000077000000007700000007700000000770000000070000000000000000 0000000000000000000000000000000000000000c11ee11d00000000000000000000000077000000007700000007700000000770000000070000000000000000
00000000000000000000000000000000cdddddddcddddddd00000000000000000000000070000000077000000077000000007700000000770000000000000000 0000000000000000000000000000000000000000cddddddd00000000000000000000000070000000077000000077000000007700000000770000000000000000
cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000 cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000cccccccccccc0000
c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000ceee2222eeed0000c2221111222d0000 c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000ceee2222eeed0000c2221111222d0000
c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000c1ee2222ee1d0000ce22111122ed0000c2111111112d0000 c1111111111d0000c1111111111d0000c1111111111d0000c1111111111d0000c111eeee111d0000c1ee2222ee1d0000ce22111122ed0000c2111111112d0000